Эта адаптация вашего кода работает, по крайней мере, для pwd & ls
в качестве командной строки. Одна из проблем заключалась в том, что цикл поиска пути к команде был в неправильном месте. Другая проблема заключалась в том, что цикл wait()
был не в том месте.
Другая проблема заключалась в том, что аргументы команды не были должным образом разделены.
Код показывает типографию (довольно много), которую я добавил, чтобы убедиться, что я понял, что происходит, и которая высветила некоторые из проблем.
Исходный код (exec29.c
):
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char input[100];
char *path[15];
path[0] = "/bin/";
FILE *fp;
if (argc == 2)
{
if ((fp = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "Error! opening file %s\n", argv[1]);
exit(1);
}
}
do
{
if (argc != 2)
{
printf("dash> ");
if (fgets(input, 100, stdin) == NULL)
exit(0);
}
else if (argc == 2)
{
if (fgets(input, 100, fp) == NULL)
exit(0);
}
input[strcspn(input, "\n")] = '\0';
printf("%s\n", input);
char *token = strtok(input, " ");
int temp = 0;
if (strcmp(token, "exit") == 0)
{
exit(0);
}
else if (strcmp(token, "cd") == 0)
{
token = strtok(NULL, " ");
if (chdir(token) == -1)
fprintf(stderr, "error: cd %s\n", token);
}
else if (strcmp(token, "path") == 0)
{
int counter = 0;
while (path[counter] != NULL)
{
path[counter] = strtok(NULL, " ");
if (path[counter] != NULL)
printf("PATH: %s\n", path[counter]);
counter++;
}
}
else
{
char *myargs[15];
char *par[15];
myargs[0] = token;
int counter = 0;
int n_cmds = 1;
while (myargs[counter] != NULL)
{
counter++;
myargs[counter] = strtok(NULL, " ");
}
for (int i = 0; i < counter; i++)
printf("%d: [[%s]]\n", i, myargs[i]);
for (int i = 0; i < counter; i++)
{
if (strcmp(myargs[i], "&") == 0)
n_cmds++;
}
temp = n_cmds;
printf("Num commands: %d\n", n_cmds);
int t = 0;
for (int i = 0; i < n_cmds; i++)
{
int a = 0;
for (int j = t; j < counter; j++)
{
if (strcmp(myargs[j], "&") == 0)
{
t = j + 1;
break;
}
par[a++] = myargs[j];
}
par[a] = NULL;
int rc = fork();
if (rc < 0)
{
fprintf(stderr, "Error: fork failed\n");
return 1;
}
else if (rc == 0)
{
char str[200];
printf("hello, I am child (pid:%d)\n", (int)getpid());
int c = 0;
do
{
if (path[c] == NULL)
{
fprintf(stderr, "path error - no PATH left\n");
break;
}
strcpy(str, path[c++]);
strcat(str, par[0]);
} while (access(str, X_OK) == -1);
printf("Cmd: [[%s]]\n", str);
char **args = par;
while (*args != NULL)
printf("[[%s]]\n", *args++);
fflush(stdout);
execv(str, par);
fprintf(stderr, "%s: failed\n", str);
exit(1);
}
}
}
while (temp > 0)
{
int status;
pid_t pid = wait(&status);
printf("%d: Child with PID %ld exited with status 0x%.4x.\n",
(int)getpid(), (long)pid, status);
--temp;
}
} while (strcmp(input, "exit") != 0);
return 0;
}
Имеется файл test-exec
, содержащий:
pwd & ls
pwd -P & ls -l
Я получил пример вывода (exec29 test-exec
):
pwd & ls
0: [[pwd]]
1: [[&]]
2: [[ls]]
Num commands: 2
hello, I am child (pid:4247)
Cmd: [[/bin/pwd]]
[[pwd]]
hello, I am child (pid:4248)
Cmd: [[/bin/ls]]
[[ls]]
/Users/jleffler/soq/so-5225-1783
4246: Child with PID 4247 exited with status 0x0000.
exec23.c exec29 exec29.c exec29.dSYM exec97.c makefile test-exec test-exec-2
4246: Child with PID 4248 exited with status 0x0000.
pwd -P & ls -l
0: [[pwd]]
1: [[-P]]
2: [[&]]
3: [[ls]]
4: [[-l]]
Num commands: 2
hello, I am child (pid:4249)
Cmd: [[/bin/pwd]]
[[pwd]]
[[-P]]
hello, I am child (pid:4250)
Cmd: [[/bin/ls]]
[[ls]]
[[-l]]
/Users/jleffler/soq/so-5225-1783
4246: Child with PID 4249 exited with status 0x0000.
total 80
-rw-r--r-- 1 jleffler staff 3722 Sep 10 20:43 exec23.c
-rwxr-xr-x 1 jleffler staff 9644 Sep 10 21:41 exec29
-rw-r--r-- 1 jleffler staff 4054 Sep 10 21:41 exec29.c
drwxr-xr-x 3 jleffler staff 96 Sep 10 21:05 exec29.dSYM
-rw-r--r-- 1 jleffler staff 4549 Sep 10 21:45 exec97.c
-rw-r--r-- 1 jleffler staff 163 Sep 10 21:41 makefile
-rw-r--r-- 1 jleffler staff 24 Sep 10 21:47 test-exec
-rw-r--r-- 1 jleffler staff 34 Sep 10 21:38 test-exec-2
4246: Child with PID 4250 exited with status 0x0000.
Я удалил код, который, казалось, был связан с перенаправлением ввода-вывода; Я не удалял код, связанный с cd
, exit
или path
, но я также не проверял их.
Один второстепенный, неясный момент: стандартный заголовок <iso646.h>
определяет макрос and
, который расширяется до &&
. Лучше не использовать какие-либо имена из этого заголовка в качестве имен переменных, хотя действительно редко люди используют заголовок в C (но имена зарезервированы как «альтернативные представления» в C ++).