E138: Não é possível gravar o arquivo viminfo

0

Estou usando o ncurses para criar um tui para navegar pelos diretórios. Eu tenho o programa abrindo arquivos editáveis no vi usando uma chamada de 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();

mas quando saio do vi para retornar ao programa vi relata o erro

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

.di é o arquivo de configuração do meu programa e não tenho idéia do porquê ele está tentando se incluir no caminho do arquivo .viminfo.

Alguém tem alguma idéia de como corrigir isso? Todas as minhas variáveis são prefixadas com di_, então não tenho idéia do porquê isso está acontecendo. Toda ajuda é bem-vinda!

  1. O erro ocorre no vi e não no meu programa.
  2. Não há estouro no sprintf porque everyting tem um caractere de terminação nulo colocado no final.
  3. A preferência do editor vem como padrão do vi, mas é manipulada pelo usuário por meio do arquivo de configuração.
  4. /home/user/.di não é uma pasta, é um arquivo e só é chamado na aquisição do conteúdo dos arquivos de configuração e na criação e no preenchimento inicial do arquivo, e todas as instâncias de fopen são encerradas imediatamente após .
  5. o propósito de não usar ncurses para criar um editor é dar ao usuário a opção de usar seu próprio editor (muitos disponíveis no servidor sendo usado)
  6. Parece não haver uma falha no syscall. Este stil parece ser um erro da parte do vi.

Apenas para notar: Esta é apenas uma questão de aborrecimento. A falha no vi não causa uma falha no meu programa.

Isso foi implementado no meu programa na minha recente reescrita de todo o programa. Ele permite que o usuário altere as configurações em um arquivo de configuração ".di" no diretório inicial. Desde essa implementação, ao sair do vi (ou vim), o vi (ou vim) declara o erro e retorna com sucesso ao 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, "
def_prog_mode();
endwin();
sprintf(command, "%s %s", di->Settings.editor, di->Directory.File[di->Variables.item_selection].Path);
system(command);
reset_prog_mode();
"); 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); }
    
por James C 22.06.2013 / 16:55

2 respostas

1

Minha página man do getenv diz:

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.

Você quebrou essa regra aqui:

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, "
asprintf(&di_settings_file_path , "%s/%s",
    getenv("HOME"), di_default_settings_file);
/* ... use it ... */
free(di_settings_file_path);
");

Então você está modificando a memória que você não deveria modificar, em particular você está modificando o valor da variável de ambiente HOME (além disso, você provavelmente está matando alguma outra variável de ambiente, ou corrompendo o que vier depois de HOME na memória).

vim herda o novo valor de $HOME e tenta usá-lo como seu diretório pessoal, incluindo o depósito de suas viminfo stuff.

Você precisa copiar getenv ("HOME") para o seu próprio buffer e certificar-se de que o buffer tenha espaço suficiente para a cópia, além do que você deseja anexar a ela. Uma maneira de fazer isso é com asprintf :

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.
    
por 23.06.2013 / 02:00
0

Primeiro, você deve compilar com gcc -Wall -g e aprender a usar o depurador gdb . Verifique se command tem o valor que você deseja ter. (Não tenho certeza de que funcionaria como você deseja se algum diretório ou nome de arquivo contiver espaços).

Usar sprintf está obsoleto e perigoso (possível estouro de buffer). Use snprintf (3) ou (GNU libc específico) asprintf .

Então, eu suponho que a sua chamada para system retorne um código não-0. Você nunca deve ignorar o resultado da função de biblioteca system . Veja esta resposta para mais detalhes.

No mínimo, você deve ter

int editfailedcode = system(command);

e mostra o editfailedcode (na verdade, manipulá-lo) com o command quando editfailedcode é diferente de zero.

Por fim, a convenção é usar a variável de ambiente EDITOR . Leia a página do manual environ (7) .

Tem certeza de que /home/user/.di existe e é um diretório gravável? Você pode usar o stat (2) syscall para verificar isso.

Além disso, como você já usa ncurses , pode considerar usá-lo para seu próprio editor interno ...

BTW, você pode usar strace (1) (talvez como strace -f ) para descobrir qual syscall está falhando e por que ...

    
por 22.06.2013 / 17:05

Tags