E138: No se puede escribir el archivo viminfo

0

Estoy usando ncurses para crear una tui para moverme a través de directorios. Tengo el programa abriendo archivos editables en vi usando una llamada al sistema

def_prog_mode();
endwin();
sprintf(command, "%s %s", di->Settings.editor, di->Directory.File[di->Variables.item_selection].Path);
system(command);
reset_prog_mode();

pero cuando salgo de vi para volver al programa vi informa el error

E138: Can't write viminfo file /home/user/.di/.viminfo!
Press ENTER or type command to continue

.di es el archivo de configuración de mi programa y no tengo idea de por qué está tratando de incluirse en la ruta del archivo .viminfo.

¿Alguien tiene alguna idea de cómo solucionar esto? Todas mis variables tienen el prefijo di_, por lo que no tengo idea de por qué sucede esto. ¡Toda ayuda es muy apreciada!

  1. El error ocurre dentro de vi y no en mi programa.
  2. No hay desbordamiento en sprintf porque todo tiene un carácter de terminación nulo colocado en el final.
  3. La preferencia del editor viene como un valor predeterminado de vi, pero es manipulada por el usuario a través del archivo de configuración.
  4. /home/user/.di no es una carpeta, es un archivo y solo se llama en la adquisición de los contenidos de los archivos de configuración, y en la creación inicial y el llenado del archivo y todas las instancias de fopen se cierran inmediatamente después.
  5. El propósito de no usar ncurses para crear un editor es darle al usuario la opción de usar su propio editor (muchos disponibles en el servidor que se usa)
  6. No parece haber un fallo de syscall. Este estilo parece ser un error por parte de vi.


Solo para tener en cuenta: este es un problema meramente molesto. La falla en vi no causa una falla en mi programa.

Esto se implementó en mi programa en mi reciente reescritura de todo el programa. Permite al usuario cambiar la configuración en un archivo de configuración ".di" en el directorio de inicio. Desde esta implementación, al salir de vi (o vim), vi (o vim) declara el error y luego regresa con éxito al programa.

#include "di.h"

void settings(DI *di, int mode) {

    check_settings_exist(di);

    switch (mode) {

        case 0 :
            read_settings(di);
            break;

        case 1 :
            write_settings(di);
            break;

    }

}

void check_settings_exist(DI *di) {

    if (!di->Settings.file_location) {

        char *di_settings_file_path = (char *) getenv("HOME");
        strcat(di_settings_file_path, "/");
        strcat(di_settings_file_path, di_default_settings_file);
        strcat(di_settings_file_path, "\0");

        di->Settings.file_location = (char *) calloc(sizeof(di_settings_file_path) + 12, sizeof(char));
        strcpy(di->Settings.file_location, di_settings_file_path);

    }

    if(access(di->Settings.file_location, F_OK)) {

        int counter;
        FILE * di_settings_file = fopen(di->Settings.file_location, "w+");

        for (counter = 0; di_settings_file_default[counter][0]; counter++) {

            fprintf(di_settings_file, "%s%s\n", di_settings_file_default[counter][0], di_settings_file_default[counter][1]);

        }

        fclose(di_settings_file);

    }

}

void read_settings(DI *di) {

    FILE * di_settings_file = fopen(di->Settings.file_location, "r");

    di->Settings.editor = calloc(16, sizeof(char));
    di->Settings.deletion_mode = calloc(16, sizeof(char));

    fscanf(di_settings_file, "%*[^:]:%[^\n]\n", di->Settings.editor);
    fscanf(di_settings_file, "%*[^:]:%[^\n]\n", di->Settings.deletion_mode);

    fclose(di_settings_file);

}

void write_settings(DI *di) {

    FILE * di_settings_file = fopen(di->Settings.file_location, "w+");

    //

    fclose(di_settings_file);

}
James C
fuente
No entiendo cual es tu command buffer antes de ejecutar system(command)
Basile Starynkevitch
Y google para can't write viminfo file Da muchas respuestas relevantes.
Basile Starynkevitch
El búfer de comando para un archivo de ejemplo sería "vi (ruta de acceso absoluta al archivo)"
James C
Generalmente (absolute path to file) no es un nombre de archivo. Si resulta que es su nombre de archivo, no puede funcionar (porque necesita escapar de esos espacios, y el paréntesis, para el sh contener system(command) ....)
Basile Starynkevitch
sustituya (ruta absoluta al archivo) con /home/user/file.c, simplemente puse eso allí para mostrar que cada vez que se realiza la llamada tiene el formato "(editor) (ruta absoluta al archivo)" vi es simplemente el valor por defecto. El error no se encuentra en esta parte del programa, ya que solo ha ocurrido desde que reescribí todo el programa e implementé un archivo de configuración. También compruebo el sistema para ver si hay un error y ninguno se devuelve.
James C

Respuestas:

1

Mi página de manual de getenv dice:

As typically implemented, getenv() returns a pointer to a string within
the  environment  list.   The  caller must take care not to modify this
string, since that would change the environment of the process.

Rompiste esa regla aquí:

char *di_settings_file_path = (char *) getenv("HOME");
strcat(di_settings_file_path, "/");
strcat(di_settings_file_path, di_default_settings_file);
strcat(di_settings_file_path, "\0");

Por lo tanto, está modificando la memoria que no debe modificar, en particular, está modificando el valor de la variable de entorno HOME (además, probablemente esté matando a otra variable de entorno o corrompiendo de cualquier otra forma lo que venga después de HOME en la memoria) .

vim hereda el nuevo valor de $HOME y trata de usarlo como su directorio personal, incluido el depósito de su viminfo cosas allí

Debe copiar getenv ("HOME") en su propio búfer, y asegurarse de que el búfer tenga suficiente espacio para la copia más lo que desea añadirle. Una forma de hacerlo es con asprintf:

asprintf(&di_settings_file_path , "%s/%s",
    getenv("HOME"), di_default_settings_file);
/* ... use it ... */
free(di_settings_file_path);
Wumpus Q. Wumbley
fuente
0

Primero, debes compilar con gcc -Wall -g y aprender a usar el gdb depurador Mira esto command tiene el valor que quieres que tenga. (No estoy seguro de que funcionaría como desea si algún directorio o nombre de archivo tiene espacios en él).

Utilizando sprintf está en desuso y es peligroso (posible desbordamiento del búfer). Utilizar snprintf (3) o (específico de libc de GNU) asprintf .

Entonces, supongo que tu llamada a system devuelve un código que no es 0. Nunca debe ignorar el resultado de system función de biblioteca. Ver esta respuesta para más detalles.

Por lo menos, deberías tener

int editfailedcode = system(command);

y mostrar el editfailedcode (En realidad manejarlo) con el command cuando editfailedcode no es cero.

Y por fin, la convención es utilizar el EDITOR Variable ambiental. Leer ambiente (7) página de manual

Estás seguro que /home/user/.di Existe y es un directorio escribible? Es posible que desee utilizar el stat (2) syscall para comprobar que.

Además, ya que estás usando ncurses ya, puedes considerar usarlo para tu propio editor interno ...

Por cierto, podrías usar strace (1) (tal vez como strace -f ) para averiguar qué syscall está fallando y por qué ...

Basile Starynkevitch
fuente
1. El error ocurre dentro de vi y no en mi programa. 2. No hay desbordamiento en sprintf porque todo tiene un carácter de terminación nulo colocado en el final. 3. La preferencia del editor viene como un valor predeterminado de vi, pero es manipulada por el usuario a través del archivo de configuración.
James C
4. /home/user/.di no es una carpeta, es un archivo y solo se llama en la adquisición de los contenidos de los archivos de configuración, y en la creación inicial y la población del archivo y todas las instancias de fopen se cierran inmediatamente después. 5. El propósito de no usar ncurses para crear un editor es darle al usuario la opción de usar su propio editor (muchos disponibles en el servidor que se está usando). 6. No parece haber un error de syscall. Este estilo parece ser un error por parte de vi.
James C
Usted podría tener un desbordamiento en sprintf así que debes usar snprintf; debe verificar -a través del depurador o al registrar- qué comando exacto está ejecutando y cuál es el código de retorno dado por system(command); en efecto vi Podría fallar y usted debería manejar tales fallas ....
Basile Starynkevitch