execvp() - неподдерживаемая опция SysV

Я пытаюсь написать простую оболочку на C, которая принимает команду и использует дочерний процесс для выполнения этой команды. Например, если я ввожу:

ps -ael  

мой дочерний процесс должен выполнить эту команду вместе со своими аргументами. Я распечатываю свои команды, поскольку они хранятся в массиве. Это то, что я вижу:

Array[0] = ps
Array[1] = -ael  
Array[2] = NULL

Когда я выполняю, я получаю это:

error: unsupported SysV option

Usage:
 ps [options]

 Try 'ps --help <simple|list|output|threads|misc|all>'
  or 'ps --help <s|l|o|t|m|a>'
 for additional help text.

For more details see ps(1). 

Мой код ниже.

int main(void)
{
    char *args[MAX_LINE/2 +1]; // command line arguments
    char *cmdLine;
    int should_run = 1; // flag to determine when to exit the program
    int i, x;


    printf("osh> ");
    fflush(stdout);
    fgets(cmdLine, MAX_LINE, stdin);


    char *token = strtok(cmdLine, " ");
    int position = 0;
    while (token != NULL)
    {
        args[position++] = token;
        token = strtok(NULL, " ");
    }
    i = 0;
    while (args[i] != NULL)
    {
        printf("Array[%d] = %s\n", i, args[i]);
        i++;
    }
    if (args[i] == NULL) printf("Array[%d] = NULL", i);
    x = 0;
    pid_t pid;

    /* fork a child process*/
    pid = fork();

    if (pid < 0)
    {
        /*Error occured*/
        fprintf(stderr, "Fork failed.");
        return 1;
    }
    else if (pid == 0)
    {
        /*child process*/

        execvp(args[0], args); //error here
    }
    else
    {
        /*Parent process*/

        wait(NULL);

        printf("\nChild complete\n");
    }

}

person Connor Orischak    schedule 08.03.2018    source источник
comment
@ Бармар Убунту 16.04   -  person Connor Orischak    schedule 08.03.2018
comment
запустите его с помощью strace -f -eexecve your-prog, чтобы увидеть, что происходит на самом деле. И проверьте, чтобы не было скрытых пробелов (например, напечатайте Array.. . = '%s')   -  person ensc    schedule 08.03.2018
comment
функция fgets() вводит все, включая '\n' (или буфер почти заполнен), а затем добавляет байт NUL. В опубликованном коде необходимо заменить '\n' байтом NUL. В противном случае '\n' является частью параметров, помещенных в args[], поэтому появляется сообщение об ошибке.   -  person user3629249    schedule 08.03.2018
comment
относительно: fgets(cmdLine, MAX_LINE, stdin); и char *cmdLine; Ожидается, что первый параметр функции fgets() будет указателем на массив/буфер для получения прочитанных данных. cmdLine объявлен как «неинициализированный указатель». т.е. этот указатель содержит тот мусор, который когда-либо оказывался в стеке по адресу cmdLine. Это приводит к неопределенному поведению и может привести к сбою сегмента. Предложить: char cmdLine[ MAX_LINE ];   -  person user3629249    schedule 08.03.2018
comment
размещенный код не компилируется! Среди прочего, в нем отсутствуют необходимые операторы #include и отсутствует определение MAX_LINE. Вы ожидаете, что мы прочитаем ваши мысли относительно того, какой заголовочный файл включен и какое значение вы определили для MAX_LINE?   -  person user3629249    schedule 08.03.2018
comment
относительно: while (args[i] != NULL) Как код может ожидать, что любой из указателей, составляющих args[], когда-либо будет NULL, если код никогда не устанавливал ни один из указателей в NULL? Из-за этого отсутствующего оператора результатом является неопределенное поведение, которое может привести к событию сбоя сегмента.   -  person user3629249    schedule 08.03.2018
comment
относительно: execvp(args[0], args); функции exec...() никогда не возвращаются, если только не удалось создать подпроцесс. Таким образом, за оператором должно сразу же следовать: perror( "execvp failed" ); exit( EXIT_FAILURE );, которое выводит, почему вызов execvp() не удался (и прилагаемый текст) к stderr.   -  person user3629249    schedule 08.03.2018
comment
для простоты чтения и понимания: следуйте аксиоме: только одно выражение в строке и (максимум) одно объявление переменной в выражении.   -  person user3629249    schedule 08.03.2018
comment
относительно: fprintf(stderr, "Fork failed."); лучше вывести, ПОЧЕМУ вызов функции не удался. Предлагайте заменить на: perror( "fork failed' ); Таким образом, и заключенный текст, и причина сбоя выводятся в stderr   -  person user3629249    schedule 08.03.2018


Ответы (1)


Строка, возвращаемая fgets(), включает новую строку, но вы не удаляете ее из строки. Итак, вы устанавливаете args[1] на "-ael\n", а \n не является допустимым вариантом.

Включите новую строку в разделители strtok():

char *token = strtok(cmdLine, " \n");
int position = 0;
while (token != NULL)
{
    args[position++] = token;
    token = strtok(NULL, " \n");
}

и тогда он не будет включен в токены.

Вы должны были увидеть это в своем выводе, готов поспорить, что он напечатан:

Array[0] = ps
Array[1] = -ael  

Array[2] = NULL

с пустой строкой там.

Кстати, я не понимаю, где вы когда-либо устанавливали последний аргумент равным NULL. Цикл while останавливается, когда strtok() возвращает NULL, поэтому он никогда не присваивает этот результат args[position++]. Вам нужно добавить:

args[position] = NULL;

после петли.

И нет необходимости в if (args[i] == NULL) — цикл перед этим останавливается, когда это условие выполняется, так что это гарантированно верно.

person Barmar    schedule 08.03.2018
comment
Большое спасибо, это сработало! У меня было ощущение, что у него есть что-то, чтобы сделать пустое пространство.. - person Connor Orischak; 08.03.2018
comment
в этом ответе не упоминаются два случая неопределенного поведения в опубликованном коде. - person user3629249; 08.03.2018
comment
@user3629249 user3629249 Я упомянул об отсутствующем нулевом указателе, но не просматривал весь код, я просто искал причину сообщения об ошибке. - person Barmar; 08.03.2018
comment
Отсутствующие #define и #include предположительно просто потому, что он не скопировал их в вопрос. - person Barmar; 08.03.2018
comment
эти вопросы на stackoverflow.com о проблеме времени выполнения «не по теме», если опубликованный код не является минимально воспроизводимым примером. Код, который не компилируется из-за отсутствия частей, не соответствует требованиям. - person user3629249; 08.03.2018