Простая оболочка Linux — ошибка execvp()

Мне нужна помощь с простой оболочкой для класса, и я беспокоюсь, что не совсем понимаю, как работает функция execvp().

Оболочка мало что делает, не поддерживает конвейерную обработку, перенаправление, сценарии или что-то в этом роде. Он только читает команду, читает опции (с командой как option[0]) и разветвляется.

Это сработало несколько раз, а затем начало выдавать ошибки о невозможности найти команды. Другие подобные вопросы, размещенные здесь, были связаны с конвейером или перенаправлением.

Пожалуйста, простите noobcode, это не красиво, но я надеюсь, что это разборчиво:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>

#define OPT_AMT 10

const size_t SIZE = 256;
int i = 0;
int o = 0;

int main(void) {

    // initializing data

    int exit = 0;
    char cwd[SIZE];
    char cmd[SIZE];
    char input[SIZE * OPT_AMT];
    char *opt[OPT_AMT];
    getcwd(cwd, SIZE);

    // main loop

    while (exit == 0) {
        // reset everything
        o = 1;
        i = 0;
        cmd[0] = "\0";
        while (i < OPT_AMT) {
            opt[i++] = "\0";
        }

        // get input
        printf("%s $ ", cwd);
        scanf("%s", cmd);
        gets(input);
        opt[0] = cmd;

        char *t = strtok(input, " ");
        while (t != NULL) {
            opt[o++] = t;
            t = strtok(NULL, " ");
        }

        // if exit, exit
        if (strcmp(cmd, "exit") == 0) {
            exit = 1;
        }
        // else fork and execute
        else {
            pid_t pID = fork();

            if (pID == 0) { // child process
                execvp(cmd, opt);
            } else if (pID < 0) { // failed to fork
                printf("\nFailed to fork\n");
            } else { // parent process
                wait(0);
            }
        }
    }

    // cleanup

    printf("\nFinished!  Exiting...\n");
    return 0;
}

Что-то явно не так? Совсем недавно я добавил условие выхода и сброс массива параметров.

Кроме того, это мой первый вопрос, так что напомните мне, какие правила я нарушил.


person Will    schedule 15.11.2014    source источник
comment
Не используйте gets(). Это по своей сути небезопасно, и это даже больше не часть C. Вместо этого используйте fgets() и не забудьте удалить символ новой строки в конце, если это необходимо.   -  person Crowman    schedule 15.11.2014


Ответы (1)


Для начала это

cmd[0] = "\0";

должно быть

cmd[0] = '\0';

Прислушайтесь к предупреждениям вашего компилятора.

Чтобы включить их, используйте опции -Wall -Wextra -pedantic (для gcc).


Также вам может быть лучше инициализировать элементы opt, чтобы они указывали на «ничего», то есть NULL, но на литерал "\0":

    while (i < OPT_AMT) {
        opt[i++] = NULL;
    }

поскольку execvp() требует, чтобы opt был массивом, заканчивающимся NULL, C-"strings" (спасибо Paul за упоминание/формулировку соответствующего фона).


Также ^ 2: Не используйте gets(), так как это зло и даже больше не является частью стандарта C. Вместо

gets(input);

использовать

fgets(input, sizeof input, stdin);

gets() легко позволяет пользователю переполнить переданный (входной) буфер. (Упоминание об этом пришло мне в голову без Пола, кстати... ;-))

person alk    schedule 15.11.2014
comment
Действительно, execvp() требует, чтобы opt был списком строк, завершающимся NULL. - person Crowman; 15.11.2014
comment
Спасибо, ребята, я внес изменения, но выдает ту же ошибку. Это как-то связано с символом новой строки из fgets? - person Will; 16.11.2014
comment
@Will: Вы бы очень помогли себе, если бы предприняли некоторые шаги, чтобы выяснить, что делает ваша программа, например, printf() вычислить значение cmd и каждого элемента opt перед вызовом execvp(), чтобы вы могли видеть, что именно делает ваша программа. вы переходите к нему. Это ответит на большинство вопросов такого типа. - person Crowman; 16.11.2014
comment
@Will: использование отладчика для отслеживания кода и проверки (промежуточных) значений задействованных переменных также может помочь. - person alk; 16.11.2014
comment
Итак, с gets() все работает нормально, мне просто нужно немного глубже изучить fgets(). Спасибо за помощь @alk и @Paul_Griffiths! - person Will; 16.11.2014