1. 程式人生 > >三十五、minishell(3)

三十五、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