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

 #ifndef INCLUDE_MSHELL_SIGNAL_H_
#define INCLUDE_MSHELL_SIGNAL_H_ #include "mshell_common.h"
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h> extern void mshell_signal_Ign(void);
extern void mshell_signal_Catch(void);
extern void mshell_signal_Default(void);
#endif /* INCLUDE_MSHELL_SIGNAL_H_ */

  mshell_signal.c

 #include "mshell_signal.h"

 /** ================ parent handler handler ==================== */
/** 忽略某些信号 */
void mshell_signal_Ign(void)
{
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
} /** mshell 的信号处理函数 */
static void mshell_signal_Handler(int signo)
{
/** 子进程终止信号捕获 */
if(signo == SIGCHLD){
/** 回收进程组中的子进程, 非阻塞模式 */
waitpid(-, NULL, WNOHANG);
/** 将 minishell 所在的组调度为前台进程组 */
tcsetpgrp(, getpgid(getpid()));
}
} /** 捕获信号 */
void mshell_signal_Catch(void)
{
signal(SIGCHLD, mshell_signal_Handler);
} /** =============== child process handler =================== */
void mshell_signal_Default(void)
{
signal(SIGTTIN, SIG_DFL);
signal(SIGTTOU, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGTSTP, SIG_DFL);
signal(SIGCHLD, SIG_DFL);
}

35.2.1 mshell_handler 修改

  mshell_handler.h

 #ifndef __MSHELL_HANDLER_H__
#define __MSHELL_HANDLER_H__ #include "mshell_common.h"
#include "mshell_signal.h"
#include "mshell_process.h"
#include "mshell_cmd_fun.h"
#include "mshell_program.h"
#include "mshell_job.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <unistd.h>
#include <string.h>
#include <memory.h>
#include <sys/wait.h> #define MSHELL_PROMPT "mshell =>"
#define MSHELL_COMMAND_LEN 256
#define MSHELL_ARGS_SIZE 100 mshell_error_t mshell_Handler(); #endif

  mshell_handler.c

 #include "mshell_handler.h"

 static mshell_error_t mshell_cmd_Parsed(mshell_job_t *job, char *line, mshell_process_Flag_t *process_flag)
{
/** Create args secondary pointer stored in program */
char **args_tmp = (char **)malloc(MSHELL_ARGS_SIZE * sizeof(char *));
if(NULL == args_tmp) {
return MSHELL_ERROR_MALLOC;
} /** Split the command line */
char *cmd = strtok(line, " "); /** The first parameter is the command itself */
args_tmp[] = (char *)calloc(strlen(cmd + ), sizeof(char));
if(NULL == args_tmp[]) {
return MSHELL_ERROR_MALLOC;
}
strcpy(args_tmp[], cmd); /** Start with the second parameter */
int i = ;
char *cmd_param;
mshell_redirection_t *redirections[MSHELL_REDIRECTION_NUMBER];
int redirection_num = ; while(NULL != (cmd_param = strtok(NULL, " "))) { /** 对命令行进行解析,判断是否为后台进程 */
int process_ret;
*process_flag = mshell_process_BackParse(cmd_param, &process_ret);
if( == process_ret) {
continue;
} /** 分析重定向 */
mshell_error_t redirection_ret;
redirections[redirection_num] =
mshell_redirection_Parse(redirections, redirection_num, cmd_param, &redirection_ret);
if(NULL != redirections[redirection_num] && MSHELL_ERROR_NONE == redirection_ret){
redirection_num++;
continue;
}
else if (NULL == redirections[redirection_num] && MSHELL_ERROR_REDIRECION_PARAM == redirection_ret) {
printf("need param\n");
continue;
}
else if(NULL == redirections[redirection_num] && MSHELL_ERROR_REDIRECTION_CREATE == redirection_ret)
{
perror("error create redirection");
return MSHELL_ERROR_REDIRECTION_CREATE;
} /** 分析命令 */
args_tmp[i] = (char *)calloc(strlen(cmd_param + ), sizeof(char));
if(NULL == args_tmp[i]) {
return MSHELL_ERROR_MALLOC;
}
strcpy(args_tmp[i], cmd_param);
i++;
}
args_tmp[i] = NULL; /** Store all command line parameters in program and free args_tmp*/
mshell_prog_t *prog = mshell_prog_Create(args_tmp);
if(NULL == prog) {
return MSHELL_ERROR_PROG_CREATE;
}
mshell_args_Free(args_tmp); /** Add redirection to job and free redirections*/
for(i = ; i < redirection_num; i++){
mshell_prog_RedirectionAdd(prog, redirections[i]);
}
mshell_redirections_Free(redirections, redirection_num); /** Add program to the job*/
if(MSHELL_ERROR_NONE != mshell_job_AddProg(job, prog)) {
return MSHELL_ERROR_JOB_PROGADD;
} return ;
} static void mshell_cmd_ExcuProcess(mshell_job_t job, int order, mshell_process_Flag_t process_flag)
{
pid_t pid;
if((pid = fork()) < ) {
perror("fork error");
}
else if(pid == ) {
/** child process */ /** 信号处理 */
mshell_signal_Default(); if(order == ) {
/** order = 0, 则为 minishell 当中启动的第一个子进程,设置其为组长进程 */
job.pgid = mshell_process_GroupGet(getpid(), getpid());
}
else {
/** order > 0, 则为启动的第二个进程,将其设置进程组的成员进程 */
job.pgid = mshell_process_GroupGet(getpid(), job.pgid);
}
mshell_process_GroupSet(process_flag, getpid());
/** 对便准输入、标准输出和追加进行重定向 */
mshell_prog_RedirectionExcu(job.progs[order]); /** 调用 exec 函数执行系统中的其他命令 */
if(MSHELL_ERROR_CMD_NONECMD == mshell_Cmd_ExcuOther(job.progs[order].args))
exit();
}
else {
/** parent process */
if(order == ) {
job.pgid = mshell_process_GroupGet(pid, pid);
}
else {
job.pgid = mshell_process_GroupGet(pid, job.pgid);
}
mshell_process_GroupSet(process_flag, job.pgid); mshell_process_Wait(process_flag, job.pgid);
} } static mshell_error_t mshell_cmd_Excu(mshell_job_t *job, mshell_process_Flag_t process_flag)
{
int ret = MSHELL_ERROR_NONE;
int i;
for(i = ; i < job->progs_num; i++)
{
ret = mshell_Cmd_ExcuFun(job->progs[i].args);
if(MSHELL_ERROR_NONE == ret || MSHELL_ERROR_PARAM == ret) {
return MSHELL_ERROR_NONE;
} /** 执行其他命令 */
mshell_cmd_ExcuProcess(*job, i, process_flag);
} return ;
} mshell_error_t mshell_Handler()
{
/**创建一个进程组,将 minishell 进程设置为进程组的组长 */
setpgid(getpid(), getpid()); /** 信号处理 */
mshell_signal_Ign();
mshell_signal_Catch(); char buffer[MSHELL_COMMAND_LEN];
memset(buffer, , MSHELL_COMMAND_LEN); ssize_t size = strlen(MSHELL_PROMPT) * sizeof(char);
write(STDOUT_FILENO, MSHELL_PROMPT, size); mshell_process_Flag_t process_flag; ///< 设置前台和后台进程的标志
ssize_t len;
while() { len = read(STDIN_FILENO, buffer, MSHELL_COMMAND_LEN); ///< 从命令行读取内容到 buffer
buffer[len - 1] = 0;
if(strlen(buffer) > ){
mshell_job_t *job = mshell_job_Create(buffer);
if(NULL == job) {
return MSHELL_ERROR_JOB_CREATE;
} mshell_cmd_Parsed(job, buffer, &process_flag);
mshell_cmd_Excu(job, process_flag);
//mshell_job_Destroy(job);
} write(STDOUT_FILENO, MSHELL_PROMPT, size);
memset(buffer, , MSHELL_COMMAND_LEN);
}
}

  

三十五、minishell(3)的更多相关文章

  1. NeHe OpenGL教程 第三十五课:播放AVI

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  2. JAVA之旅(三十五)——完结篇,终于把JAVA写完了,真感概呐!

    JAVA之旅(三十五)--完结篇,终于把JAVA写完了,真感概呐! 这篇博文只是用来水经验的,写这个系列是因为我自己的java本身也不是特别好,所以重温了一下,但是手比较痒于是就写出了这三十多篇博客了 ...

  3. Java进阶(三十五)java int与integer的区别

    Java进阶(三十五)java int与Integer的区别 前言 int与Integer的区别从大的方面来说就是基本数据类型与其包装类的区别: int 是基本类型,直接存数值,而Integer是对象 ...

  4. Gradle 1.12用户指南翻译——第三十五章. Sonar 插件

    本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  5. SQL注入之Sqli-labs系列第三十四关(基于宽字符逃逸POST注入)和三十五关

    开始挑战第三十四关和第三十五关(Bypass add addslashes) 0x1查看源码 本关是post型的注入漏洞,同样的也是将post过来的内容进行了 ' \ 的处理. if(isset($_ ...

  6. “全栈2019”Java多线程第三十五章:如何获取线程被等待的时间?

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  7. Python进阶(三十五)-Fiddler命令行和HTTP断点调试

    Python进阶(三十五)-Fiddler命令行和HTTP断点调试 一. Fiddler内置命令   上一节(使用Fiddler进行抓包分析)中,介绍到,在web session(与我们通常所说的se ...

  8. 第三百三十五节,web爬虫讲解2—Scrapy框架爬虫—豆瓣登录与利用打码接口实现自动识别验证码

    第三百三十五节,web爬虫讲解2—Scrapy框架爬虫—豆瓣登录与利用打码接口实现自动识别验证码 打码接口文件 # -*- coding: cp936 -*- import sys import os ...

  9. centos shell脚本编程1 正则 shell脚本结构 read命令 date命令的用法 shell中的逻辑判断 if 判断文件、目录属性 shell数组简单用法 $( ) 和${ } 和$(( )) 与 sh -n sh -x sh -v 第三十五节课

    centos   shell脚本编程1 正则  shell脚本结构  read命令  date命令的用法  shell中的逻辑判断  if 判断文件.目录属性  shell数组简单用法 $( ) 和$ ...

  10. “全栈2019”Java第三十五章:面向对象

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

随机推荐

  1. 编写高质量代码:改善Java程序的151个建议 --[106~117]

    编写高质量代码:改善Java程序的151个建议 --[106~117] 动态代理可以使代理模式更加灵活 interface Subject { // 定义一个方法 public void reques ...

  2. Go 语言 HTTP Server 源码分析

    http://www.codeceo.com/go-http-server-code.html

  3. C# winfrom 递归(城市名)

    递归的定以:递归在运行过程中,自己调用自己的过程: List<ChinaStates> list = new ChinaData().SelectAll();//查询所有中国的城市的方法: ...

  4. MVC WebAPI框架里设置异常返回格式统一

    webApi里设置全局异常返回格式今天为了设置api返回格式统一,在网上找了一推资料,各种资料参差不齐的,最后自己捣鼓,终于弄出来了,直接上代码 /// <summary> /// 消息代 ...

  5. flask Blueprint蓝图

    首先要了解蓝图的作用,模拟场景在团队开发过程中团队每个人都在写自己负责的功能模块,那多个py文件模板,我们如果完成后需要运行是不是要运行多个服务?但是我们的项目是一个整体,而不是零散的,所以我们怎么把 ...

  6. numpy学习之前的必要数学知识:线性代数

    行列式 主要内容 1.行列式的定义及性质 2.行列式的展开公式 一.行列式的定义 1.排列和逆序 排列:由n个数1,2,…,n组成的一个有序数组称为一个n级排列,n级排列共有n!个 逆序:在一个排列中 ...

  7. 第三十二节,使用谷歌Object Detection API进行目标检测、训练新的模型(使用VOC 2012数据集)

    前面已经介绍了几种经典的目标检测算法,光学习理论不实践的效果并不大,这里我们使用谷歌的开源框架来实现目标检测.至于为什么不去自己实现呢?主要是因为自己实现比较麻烦,而且调参比较麻烦,我们直接利用别人的 ...

  8. ElasticSearch6.3.2------查询

    进入Kibana的控制台:http://localhost:5601/app/kibana#/dev_tools/ 先放一些测试数据进去,不想一条一条,就用bulk 注意格式 正确格式: 解释:ES期 ...

  9. 22. Generate Parentheses(ML)

    22. Generate Parentheses . Generate Parentheses Given n pairs of parentheses, write a function to ge ...

  10. tput

    tput : 改变终端显示特性,常见用法如下: tput lines : 显示终端的行数 tput cols : 显示终端的列数 tput cup line_number collum_number ...