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