2016-04-13 2 views
0

Где в моем коде следует «дождаться окончания детей»? У меня есть программа на 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) 
+1

Какой сигнал вызывающую программу прекратить? SIGPIPE? Ваша настоящая оболочка должна рассказать вам. –

ответ

1

В родитель, вы не должны получить никакого сигнала, только ожидание вызова(), пока он не вернется, что ваш ребенок умер, и теперь пожинал. Теперь ваша оболочка готова к выполнению новой задачи.

код в исходном запросе, если очень неполно, так что здесь приходит один пример:

#include <stdio.h> 
#include <unistd.h> 
#include <wait.h> 

void foobar() 
{ 
    int pipe_fd[2]; 
    pid_t pid1, pid2; 

    pipe(pipe_fd); 

    pid1=fork(); 
    if (pid1 == 0) 
    { 
    /* child1 - let us pretend that we wanted to replace stdin and this child */ 
    close (0); 
    dup(pipe_fd[0]); 
    close(pipe_fd[0]); 
    close(pipe_fd[1]); 
    execlp("wc", "wc", NULL); 
    perror ("execlp(wc)"); 
    _exit(0); 
    } 

    pid2=fork(); 
    if (pid2 == 0) 
    { 
    /* child - let us pretent that we wanted to replace stdout */ 
    close (1); 
    dup(pipe_fd[1]); 
    close(pipe_fd[0]); 
    close(pipe_fd[1]); 
    execlp("ls", "ls", "-l", NULL); 
    perror ("execlp(ls)"); 
    _exit(0); 
    } 

    close(pipe_fd[0]); 
    close(pipe_fd[1]); 

    /* wait until children are finished */ 
    while ((pid1 >= 0) || (pid2 >= 0)) 
    { 
    pid_t pid; 
    int status; 
    pid = wait(&status); 
    if (pid < 0) 
    { 
     continue; 
    } 
    if (pid == pid1) 
    { 
     pid1 = -1; 
    } 
    if (pid == pid2) 
    { 
     pid2 = -1; 
    } 
    } 
} 

int main(int argc, char *argv[]) 
{ 
     foobar(); 
     return 0; 
} 
+0

Спасибо. Мне просто пришлось «размахивать» и ждать теперь, когда я знаю, что делаю. –

1

Вы хотите, чтобы поймать SIGCHLD и пожинать статус ребенка с одним из wait() функций.

Следующая информация от online tutorial.

void handle_sigchld(int sig) { 
    int saved_errno = errno; 
    while (waitpid((pid_t)(-1), 0, WNOHANG) > 0) {} 
    errno = saved_errno; 
} 

struct sigaction sa; 
sa.sa_handler = &handle_sigchld; 
sigemptyset(&sa.sa_mask); 
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; 
if (sigaction(SIGCHLD, &sa, 0) == -1) { 
    perror(0); 
    exit(1); 
} 

Кроме того, вы, вероятно, хотите, чтобы игнорировать SIGPIPE.

struct sigaction sa; 
sa.sa_handler = SIG_IGN; 
sigemptyset(&sa.sa_mask); 
sa.sa_flags = 0; 
if (sigaction(SIGPIPE, &sa, 0) == -1) { 
    perror(0); 
    exit(1); 
} 
+0

Благодарим вас за ответ. Пожалуйста, вы немного разобрались? Я не делал этого раньше, и я не эксперт по С. –

+1

@ Programmer400 Существует ссылка на учебник. Я не думаю, что здесь есть какой-то вопрос о копировании ... –

+0

@EugeneSh. Я не понимаю _where_ в коде, я должен 'wait()', поэтому я награждаю подробности за подробности. –

Смежные вопросы