Где в моем коде следует «дождаться окончания детей»? У меня есть программа на C, которая похожа на пользовательскую оболочку. Теперь у меня встроенная функция checkEnv
, которая может печатать отсортированные переменные среды. Так что я могу начать свою оболочку и список моих переменных окружения:Какой сигнал я должен обрабатывать и как?
$ ./a.out
miniShell>> checkEnv
"'><;|&(:
_=./a.out
CLUTTER_IM_MODULE=xim
COMPIZ_CONFIG_PROFILE=ubuntu
COMP_WORDBREAKS=
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-mh5oMhyCI6
DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path
DESKTOP_SESSION=ubuntu
код позади, что делает это выглядит следующим образом:
if(StartsWith(line, "checkEnv")) {
built_in_command=1;
pagerValue = getenv ("PAGER");
if (! pagerValue) {
if (ret == 0) {
pager_cmd[0]="less";
} else {
pager_cmd[0]="more";
}
}
else {
pager_cmd[0]=pagerValue;
}
if(i==1) {
cmd[0].argv= printenv;
cmd[1].argv= sort;
cmd[2].argv= pager_cmd;
fork_pipes(3, cmd);
}
else {
for (k = 1; k < i; k++)
{
len += strlen(argv2[k]) + 2;
}
tmp = (char *) malloc(len);
tmp[0] = '\0';
for (k = 1; k < i; k++)
{
pos += sprintf(tmp + pos, "%s%s", (k == 1 ? "" : "|"), argv2[k]);
}
grep[0]="grep";
grep[1]="-E";
grep[2]= tmp;
grep[3]= NULL;
cmd2[0].argv= printenv;
cmd2[1].argv= grep;
cmd2[2].argv= sort;
cmd2[3].argv= pager_cmd;
fork_pipes(4, cmd2);
free(tmp);
}
Теперь я хочу, чтобы поймать сигнал завершения вывода при перечислении переменных среды используя пейджер, чтобы программа возвращалась к пользовательской оболочке вместо завершения всей программы. Поэтому я полагаю, что я должен использовать некоторую обработку сигналов, но как и какой сигнал?
Настоящая вилка от этой функции.
/* Helper function that forks pipes */
void fork_pipes(int n, struct command *cmd) {
int i;
int in = 0;
int fd[2];
/** loop and fork() */
for (i = 0; i < n - 1; ++i) {
if (pipe(fd) == -1) {
err_syserr("Failed creating pipe");
}
spawn_proc(in, fd[1], cmd + i);
close(fd[1]);
in = fd[0];
}
if (dup2(in, 0) < 0) {
err_syserr("dup2() failed on stdin for %s: ", cmd[i].argv[0]);
}
fprintf(stderr, "%d: executing %s\n", (int) getpid(), cmd[i].argv[0]);
execvp(cmd[i].argv[0], cmd[i].argv);
err_syserr("failed to execute %s: ", cmd[i].argv[0]);
}
Куда должна проходить обработка сигнала? Где минимальный рабочий пример того, что я пытаюсь сделать? Я не вижу примера, который делает это, и я думаю, что документация ужасная, только фрагменты и полный пример.
Мой помощник функция
/* Helper function that spawns processes */
int spawn_proc(int in, int out, struct command *cmd) {
pid_t pid;
pid = fork();
if (pid == 0) {
if (in != 0) {
if (dup2(in, 0) < 0)
err_syserr("dup2() failed on stdin for %s: ", cmd->argv[0]);
close(in);
}
if (out != 1) {
if (dup2(out, 1) < 0)
err_syserr("dup2() failed on stdout for %s: ", cmd->argv[0]);
close(out);
}
printf("** we are executing parent ***");
fprintf(stderr, "%d: executing %s\n", (int) getpid(), cmd->argv[0]);
execvp(cmd->argv[0], cmd->argv);
err_syserr("failed to execute %s: ", cmd->argv[0]);
}
else if (pid < 0) {
err_syserr("fork failed: ");
} else {
/* */
printf("** we are the parent ***");
}
return pid;
}
Мои main()
теперь выглядит следующим образом:
int main(int argc, char *argv[]) {
sourceCount = 0;
const char *commandFile;
commandFile = NULL;
char *pathValue;
/* struct sigaction sa, osa;
struct sigaction sa2;*/
int errflag;
int cOption;
struct sigaction action;
/* use getopt_long() */
char *argv1[] = {"version", "par2", 0};
/* char *argv2[] = {"help", "-m", "arg1", 0};*/
/* use sigaction */
sigemptyset(&action.sa_mask);
action.sa_handler = handle_sigchld;
action.sa_flags = 0;
sigaction(SIGPIPE, &action, NULL); //Not work with kill -13 process_id
//works well
sigaction(SIGINT, &action, NULL); //work with kill -2 process_id
errflag = 0;
/* use getopt_long() */
while ((cOption = getopt(2, argv1, "m:t:n:fs?")) != -1) {
switch (cOption) {
case 'a':
printf("apples\n");
break;
case 'b':
printf("bananas\n");
break;
case 't':
printf("tree = %s\n", optarg);
break;
case '?':
++errflag;
break;
}
}
/*
while ((cOption = getopt (3, argv2, "m:t:n:fs?")) != -1) {
switch (cOption) {
case 'm':
printf("\n Help msg : %s \n", optarg);
exit(0);
case '?':
printf("\n -? Arg : %s \n", optarg);
break;
case 'n':
printf("\n -n Arg : %s \n", optarg);
break;
}
}
*/
/* get the PATH environment to find if less is installed */
pathValue = getenv("PATH");
if (!pathValue || getenv("PATH") == NULL) {
printf("'%s' is not set.\n", "PATH");
/* Default our path if it is not set. */
putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc");
}
else {
printf("'%s' is set to %s.\n", "PATH", pathValue);
}
exec_program(commandFile);
return (0);
}
Если я запускаю свою оболочку в gdb
я получаю нормальный выход.
(gdb) run
Starting program: /home/dac/ClionProjects/shell2/openshell/shell
'PATH' is set to /home/dac/proj/google-cloud-sdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin.
dac:/home/dac/ClionProjects/shell2/openshell $ checkenv
7429: executing printenv
7430: executing grep
7417: executing less
7431: executing sort
process 7417 is executing new program: /bin/less
[Inferior 1 (process 7417) exited normally]
(gdb)
Какой сигнал вызывающую программу прекратить? SIGPIPE? Ваша настоящая оболочка должна рассказать вам. –