Использование execvp в C для копирования файлов под Linux

Леди и джентельмены. У меня проблема при использовании execvp внутри программы C для копирования файлов, она просто не хочет работать. Команды tar и mv также не работают, и я предполагаю, что все, что связано с созданием файлов, также имеет какую-то проблему. Странно то, что такие команды, как ls (с его параметрами) и echo, также работают при вызове с помощью execvp.

Вот рассматриваемый код:

int main () {

char *curr_working_dir, *input, *inputCpy, *command, **args;

struct timeval start, end, duration;

system("clear");


while(1) {

    curr_working_dir = getcwd(NULL, 0);

    printf("%s $ ", curr_working_dir);

    free(curr_working_dir);

    fgets(input, 200, stdin);

    input[strlen(input) - 1] = '\0';

    inputCpy = cpyInput(input);

    command = strtok(input, " ");

    if(!(strcmp(command, "exit"))) {
        break;
    }
    else if(!(strcmp(command, "cd"))) {

        command = strtok(NULL, " ");

        struct stat s;

        if(!stat(command, &s) && S_ISDIR(s.st_mode)) {
            chdir(command);
        }
        else {
            chdir(getenv("HOME"));
        }

        free(inputCpy);
        command = NULL;
    }
    else {

        int pid = fork();

        if(pid < 0) {

            printf("Error al crear el proceso hijo\n");

        }
        else if(pid == 0) {

            args = constructArgs(inputCpy);

            execvp(command, args);

            printf("execvp fallo: %s\n", strerror(errno));

        }
        else {

            gettimeofday(&start, NULL);

            wait((int*)NULL);

            gettimeofday(&end, NULL);

            timersub(&end, &start, &duration);

            printf("Duracion del comando: %ld.%06ld\n", (long int)duration.tv_sec, (long int)duration.tv_usec);

            free(inputCpy);
            command = NULL;
        }
    }
}

return 0;

}

Вот некоторые вспомогательные функции, которые я использую в своей программе:

    char **constructArgs(char *input) {

    int i = 0;
    char *argActual, **args;

    argActual = strtok(input, " ");

    args = malloc(sizeof(char *));

    while(argActual != NULL) {

        args[i] = malloc((strlen(argActual) + 1) * sizeof(char));

        strcpy(args[i], argActual);

        i += 1;

        args = realloc(args, (i + 1) * sizeof(char *));

        argActual = strtok(NULL, " ");
    }

    args[i] = NULL;

    return args;

}

char *cpyInput(char *input) {

    char *cpy;

    cpy = malloc((strlen(input) + 1) * sizeof(char));

    strcpy(cpy, input);

    return cpy;

}

Я используюstructArgs для создания массива аргументов для конкретной программы, которую я буду вызывать через execvp, анализируя входную строку, содержащую команды с ее аргументами. Я могу менять каталоги, вызывать эхо, просматривать содержимое каталогов, но когда я пытаюсь запустить cp, mv или tar, ничего не происходит.

Я проверил, что отправляю правильную информацию в execvp; взгляните на это, например:

допустим, у меня есть файл в /home/john/r1.sav, и я хочу скопировать его в другую папку, расположенную в /home/john/anotherfolder. Я отладил свою программу, и вот что я получаю в качестве содержимого аргументов команды и аргументов прямо перед вызовом execvp:

команда = КП

аргументы [0] = cp

args[1] = /home/john/r1.sav

args[2] = /home/john/anotherfolder

Это ожидаемые входные данные для execvp, если вы хотите использовать через него cp. Но отказывается что-либо делать. execvp получает в качестве первого аргумента имя программы, которая должна быть выполнена, и массив аргументов, которые потребуются программе, причем первый аргумент в массиве аргументов также имеет имя программы, что и я делаю. Все отлично работает с ls или echo, но не с cp, mv или tar.

Заранее благодарим вас за любую помощь, которую вы можете оказать по этой своеобразной проблеме.


person Greg    schedule 18.02.2015    source источник
comment
Несколько (не связанных) моментов: передача NULL в getcwd как и вы, является расширением в glibc, и что ввод, который вы получаете от fgets на самом деле может не заканчиваться новой строкой, например, если пользователь вводит 199 символов (в вашем случае). Кроме того, sizeof(char) определяется в спецификации C как всегда 1. А в glibc есть функция strdup, так что вам не нужно ваша cpyInput функция.   -  person Some programmer dude    schedule 18.02.2015
comment
Не могли бы вы уточнить, что происходит, когда он ничего не делает? Ошибка execvp? Ребенок и родитель висят? Что просходит? Если execvp завершается сбоем, то и дочерний, и родительский процессы будут запущены и попытаются выполнить чтение/запись с одного и того же стандартного ввода и стандартного вывода. Возможно, вы захотите поставить выход после printf после execvp.   -  person jschultz410    schedule 18.02.2015
comment
Что касается вашей проблемы, возвращается ли execvp? С какой ошибкой?   -  person Some programmer dude    schedule 18.02.2015
comment
Спасибо за наводку. Я уже знал все это, кроме того, что касается strdup :). Я надеюсь, что кто-нибудь может пролить свет на то, почему execvp не хочет запускать cp...   -  person Greg    schedule 18.02.2015
comment
@ jschultz410 это не подводит. Родитель продолжает работать и принимать ввод. Как будто он вообще отбрасывает команду с аргументом   -  person Greg    schedule 18.02.2015
comment
Родитель то виснет? Или он получает статус возврата от ребенка, когда он заканчивается? (Я вижу, вы передаете NULL для статуса возврата)   -  person jschultz410    schedule 18.02.2015
comment
Получите дочерний статус из функции wait, а также как проверить, что он возвращает (вы знаете, это может привести к сбою). Что касается этого вызова wait, не повторяйте тип NULL.   -  person Some programmer dude    schedule 18.02.2015
comment
как получить дочерний статус из функции ожидания? Я просто проверяю его возвращаемое значение? Если да, то означает ли проверка значения 0, что дочерний процесс успешно завершен?   -  person Greg    schedule 18.02.2015
comment
Хорошо, я изменил свою программу, чтобы включить дочерний статус выхода, и она успешно завершается. Все равно не будет копировать файлы   -  person Greg    schedule 18.02.2015


Ответы (1)


Я наткнулся на этот пост, потому что у меня была такая же проблема. Я не знаю, в чем проблема, но как только я объявил int для возвращаемого значения, это сработало!

char *cmd = "cp";

char *argv[3];

argv[0] = "cp";

argv[1] = "source.c";

argv[2] = "destination.c;

int value = execvp(cmd, argv);

//Unreachable

person JustAnotherGuy    schedule 13.11.2017