zoukankan      html  css  js  c++  java
  • 三十五、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
    ");
     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

      

  • 相关阅读:
    Java为何大行其道
    Centos安装成功mysql-5.5.37
    ADO.NET与Oracle(一):获取多行记录集
    【spring data jpa】【mybatis】通过反射实现 更新/保存 实体的任意字段的操作
    【spring data jpa】spring data jpa的in查询
    【mybatis】mybatis中的<if test=“”>test中多条件
    【mybatis】in查询+判断list查询条件是否进行in查询
    【spring boot】【log4jdbc】使用log4jdbc打印mybatis的sql和Jpa的sql语句运行情况
    【mybatis】mybatis中 的# 和 $的区别
    【mybatis】时间范围 处理时间格式问题 + 查询当天 本月 本年 + 按当天 当月 范围 查询 分组
  • 原文地址:https://www.cnblogs.com/kele-dad/p/10200996.html
Copyright © 2011-2022 走看看