三十五、minishell(3)

35.1 内容

  在当前的 minishell 中,如果执行 date clear 命令等,minishell 会停止:

  

  这是因为引入进程组的时候,mshell 放置在前台进程组,同时之后在子进程中又创建了一个进程组,在代码中,第二个进程组在没有将其设置为前台进程组之前,一直是后台进程组。那么后台进程组读写 minishell 的时候,会产生 SIGTTIN 和 SIGTTOU 这两个信号。

  SIGTTIN:后台进程组的成员读控制终端

  SIGTTOU:后台进程组的成员读控制终端

  产生这两个信号默认的操作就是停止进程。

  minishell 被停止的原因就是对这两个信号未作处理。我们处理的有些命令是通过 FORK 执行的,必须处理这两个信号。

  所以我们必须对作业控制信号进行处理。

35.2 修改部分

  其他部分参考第 29 节:https://www.cnblogs.com/kele-dad/p/9201411.html

35.2.1 signal 部分

  mshell_signal.h

 1 #ifndef INCLUDE_MSHELL_SIGNAL_H_
 2 #define INCLUDE_MSHELL_SIGNAL_H_
 3 
 4 #include "mshell_common.h"
 5 #include <signal.h>
 6 #include <unistd.h>
 7 #include <sys/types.h>
 8 #include <sys/wait.h>
 9 
10 extern void mshell_signal_Ign(void);
11 extern void mshell_signal_Catch(void);
12 extern void mshell_signal_Default(void);
13 #endif /* INCLUDE_MSHELL_SIGNAL_H_ */

  mshell_signal.c

 1 #include "mshell_signal.h"
 2 
 3 /** ================ parent handler handler ==================== */
 4 /** 忽略某些信号 */
 5 void mshell_signal_Ign(void)
 6 {
 7     signal(SIGTTIN, SIG_IGN);
 8     signal(SIGTTOU, SIG_IGN);
 9     signal(SIGINT, SIG_IGN);
10     signal(SIGTSTP, SIG_IGN);
11 }
12 
13 /** mshell 的信号处理函数 */
14 static void mshell_signal_Handler(int signo)
15 {
16     /** 子进程终止信号捕获 */
17     if(signo == SIGCHLD){
18         /** 回收进程组中的子进程, 非阻塞模式 */
19         waitpid(-1, NULL, WNOHANG);
20         /** 将 minishell 所在的组调度为前台进程组 */
21         tcsetpgrp(0, getpgid(getpid()));
22     }
23 }
24 
25 /** 捕获信号 */
26 void mshell_signal_Catch(void)
27 {
28     signal(SIGCHLD, mshell_signal_Handler);
29 }
30 
31 /** =============== child process handler =================== */
32 void mshell_signal_Default(void)
33 {
34     signal(SIGTTIN, SIG_DFL);
35     signal(SIGTTOU, SIG_DFL);
36     signal(SIGINT, SIG_DFL);
37     signal(SIGTSTP, SIG_DFL);
38     signal(SIGCHLD, SIG_DFL);
39 }

35.2.1 mshell_handler 修改

  mshell_handler.h

 1 #ifndef __MSHELL_HANDLER_H__
 2 #define __MSHELL_HANDLER_H__
 3 
 4 
 5 #include "mshell_common.h"
 6 #include "mshell_signal.h"
 7 #include "mshell_process.h"
 8 #include "mshell_cmd_fun.h"
 9 #include "mshell_program.h"
10 #include "mshell_job.h"
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <malloc.h>
14 #include <unistd.h>
15 #include <string.h>
16 #include <memory.h>
17 #include <sys/wait.h>
18 
19 #define MSHELL_PROMPT    "mshell =>"
20 #define MSHELL_COMMAND_LEN     256
21 #define MSHELL_ARGS_SIZE    100
22 
23 mshell_error_t mshell_Handler();
24 
25 #endif
View Code

  mshell_handler.c

  1 #include "mshell_handler.h"
  2 
  3 static mshell_error_t mshell_cmd_Parsed(mshell_job_t *job, char *line, mshell_process_Flag_t *process_flag)
  4 {
  5     /** Create args secondary pointer stored in program */
  6     char **args_tmp = (char **)malloc(MSHELL_ARGS_SIZE * sizeof(char *));
  7     if(NULL == args_tmp) {
  8         return MSHELL_ERROR_MALLOC;
  9     }
 10 
 11     /** Split the command line */
 12     char *cmd = strtok(line, " ");
 13 
 14     /** The first parameter is the command itself */
 15     args_tmp[0] = (char *)calloc(strlen(cmd + 1), sizeof(char));
 16     if(NULL == args_tmp[0]) {
 17         return MSHELL_ERROR_MALLOC;
 18     }
 19     strcpy(args_tmp[0], cmd);
 20 
 21     /** Start with the second parameter */
 22     int i = 1;
 23     char *cmd_param;
 24     mshell_redirection_t *redirections[MSHELL_REDIRECTION_NUMBER];
 25     int redirection_num = 0;
 26 
 27     while(NULL != (cmd_param = strtok(NULL, " "))) {
 28 
 29         /** 对命令行进行解析,判断是否为后台进程 */
 30         int process_ret;
 31         *process_flag = mshell_process_BackParse(cmd_param, &process_ret);
 32         if(0 == process_ret) {
 33             continue;
 34         }
 35 
 36         /** 分析重定向 */
 37         mshell_error_t redirection_ret;
 38         redirections[redirection_num] =
 39                 mshell_redirection_Parse(redirections, redirection_num, cmd_param, &redirection_ret);
 40         if(NULL != redirections[redirection_num] && MSHELL_ERROR_NONE == redirection_ret){
 41             redirection_num++;
 42             continue;
 43         }
 44         else if (NULL == redirections[redirection_num] && MSHELL_ERROR_REDIRECION_PARAM == redirection_ret) {
 45             printf("need param\n");
 46             continue;
 47         }
 48         else if(NULL == redirections[redirection_num] && MSHELL_ERROR_REDIRECTION_CREATE == redirection_ret)
 49         {
 50             perror("error create redirection");
 51             return MSHELL_ERROR_REDIRECTION_CREATE;
 52         }
 53 
 54         /** 分析命令 */
 55         args_tmp[i] = (char *)calloc(strlen(cmd_param + 1), sizeof(char));
 56         if(NULL == args_tmp[i]) {
 57             return MSHELL_ERROR_MALLOC;
 58         }
 59         strcpy(args_tmp[i], cmd_param);
 60         i++;
 61     }
 62     args_tmp[i] = NULL;
 63 
 64     /** Store all command line parameters in program and free args_tmp*/
 65     mshell_prog_t *prog = mshell_prog_Create(args_tmp);
 66     if(NULL == prog) {
 67         return MSHELL_ERROR_PROG_CREATE;
 68     }
 69     mshell_args_Free(args_tmp);
 70 
 71     /** Add redirection to job and free redirections*/
 72     for(i = 0; i < redirection_num; i++){
 73         mshell_prog_RedirectionAdd(prog, redirections[i]);
 74     }
 75     mshell_redirections_Free(redirections, redirection_num);
 76 
 77     /** Add program to the job*/
 78     if(MSHELL_ERROR_NONE != mshell_job_AddProg(job, prog)) {
 79         return MSHELL_ERROR_JOB_PROGADD;
 80     }
 81 
 82     return 0;
 83 }
 84 
 85 static void mshell_cmd_ExcuProcess(mshell_job_t job, int order, mshell_process_Flag_t process_flag)
 86 {
 87     pid_t pid;
 88     if((pid = fork()) < 0) {
 89         perror("fork error");
 90     }
 91     else if(pid == 0) {
 92         /** child process */
 93 
 94         /** 信号处理 */
 95         mshell_signal_Default();
 96 
 97         if(order == 0) {
 98             /** order = 0, 则为 minishell 当中启动的第一个子进程,设置其为组长进程 */
 99             job.pgid = mshell_process_GroupGet(getpid(), getpid());
100         }
101         else {
102             /** order > 0, 则为启动的第二个进程,将其设置进程组的成员进程 */
103             job.pgid = mshell_process_GroupGet(getpid(), job.pgid);
104         }
105         mshell_process_GroupSet(process_flag, getpid());
106         /** 对便准输入、标准输出和追加进行重定向 */
107         mshell_prog_RedirectionExcu(job.progs[order]);
108 
109         /** 调用 exec 函数执行系统中的其他命令 */
110         if(MSHELL_ERROR_CMD_NONECMD == mshell_Cmd_ExcuOther(job.progs[order].args))
111             exit(1);
112     }
113     else {
114         /** parent process */
115         if(order == 0) {
116             job.pgid = mshell_process_GroupGet(pid, pid);
117         }
118         else {
119             job.pgid = mshell_process_GroupGet(pid, job.pgid);
120         }
121         mshell_process_GroupSet(process_flag, job.pgid);
122 
123         mshell_process_Wait(process_flag, job.pgid);
124     }
125 
126 }
127 
128 static mshell_error_t mshell_cmd_Excu(mshell_job_t *job, mshell_process_Flag_t process_flag)
129 {
130     int ret = MSHELL_ERROR_NONE;
131     int i;
132     for(i = 0; i < job->progs_num; i++)
133     {
134         ret = mshell_Cmd_ExcuFun(job->progs[i].args);
135         if(MSHELL_ERROR_NONE == ret || MSHELL_ERROR_PARAM == ret) {
136             return MSHELL_ERROR_NONE;
137         }
138 
139         /** 执行其他命令 */
140         mshell_cmd_ExcuProcess(*job, i, process_flag);
141     }
142 
143     return 0;
144 }
145 
146 mshell_error_t mshell_Handler()
147 {
148     /**创建一个进程组,将 minishell 进程设置为进程组的组长 */
149     setpgid(getpid(), getpid());
150 
151     /** 信号处理 */
152     mshell_signal_Ign();
153     mshell_signal_Catch();
154 
155     char buffer[MSHELL_COMMAND_LEN];
156     memset(buffer, 0, MSHELL_COMMAND_LEN);
157 
158 
159     ssize_t size = strlen(MSHELL_PROMPT) * sizeof(char);
160     write(STDOUT_FILENO, MSHELL_PROMPT, size);
161 
162     mshell_process_Flag_t process_flag;    ///< 设置前台和后台进程的标志
163     ssize_t len;
164     while(1) {
165 
166         len = read(STDIN_FILENO, buffer, MSHELL_COMMAND_LEN); ///< 从命令行读取内容到 buffer
167         buffer[len - 1] = 0;
168         if(strlen(buffer) > 0){
169             mshell_job_t *job = mshell_job_Create(buffer);
170             if(NULL == job) {
171                 return MSHELL_ERROR_JOB_CREATE;
172             }
173 
174             mshell_cmd_Parsed(job, buffer, &process_flag);
175             mshell_cmd_Excu(job, process_flag);
176             //mshell_job_Destroy(job);
177         }
178 
179         write(STDOUT_FILENO, MSHELL_PROMPT, size);
180         memset(buffer, 0, MSHELL_COMMAND_LEN);
181     }
182 }
View Code

 

  

 

posted @ 2018-12-30 22:51  游戏进行中  阅读(397)  评论(0编辑  收藏  举报