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. nio再学习之通道channel

    通道(Channel):用于在数据传输过程中,进行输入输出的通道,其与(流)Stream不一样,流是单向的,在BIO中我们分为输入流,输出流,但是在通道中其又具有读的功能也具有写的功能或者两者同时进行 ...

  2. SQL查询语句的进阶使用

    MySQL的进阶使用 sql语句一些功能的使用 导入现有大量数据文件步骤 1) 把*.sql文件拷贝到Linux某一位置(例如Desktop) 2) Linux命令行进入该位置 cd ~/Deskto ...

  3. NoSQL还是SQL?这一篇讲清楚

    https://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=2653550127&idx=1&sn=93f79e007d757a ...

  4. HEOI2019 游记——240秒处的起死回生

    我还没死 Day-1 最后一场模拟赛! T1:自然数幂次和再前缀和,还是O(k)次多项式,拉格朗日插值,,,,,不能总想斯特林数啊!!! T2:神仙DP预处理... T3:AC自动机+LCA处差分+暴 ...

  5. 【P2303】Longge的问题

    题目大意:求\[\sum\limits_{i=1}^ngcd(n,i)\] 题解:发现 gcd 中有很多是重复的,因此考虑枚举 gcd. \[\sum\limits_{i=1}^ngcd(n,i)=\ ...

  6. Spring MVC 架构的java web工程如何添加登录过滤器

    发布到外网的web工程必须添加登录过滤器来阻挡一些非法的请求,即只有登录的用户才能对web工程进行请求,否则无论请求什么资源都需要调整到登录页面进行登录操作.这时就需要用到过滤器,其实非常简单,只需要 ...

  7. JDBC的简单笔记

    JDBC笔记: JDBC:java database connectivity SUN公司提供的一套操作数据库的标准规范. JDBC与数据库驱动的关系:接口与实现的关系. JDBC规范(掌握四个核心对 ...

  8. 数位DP入门题

    站点一览: hdu 2089"不要62" hdu 4734"F(X)" poj 3252"Round Numbers" hdu 3709&q ...

  9. Vuex速学篇:(2)利用state保存新闻数据

    回顾 以前我们在做这个新闻列表的时候,是一个写死的数据 export default{ data(){ return{ newslist:[ {newsid:"101",pubti ...

  10. iis8.0 https配置教程

    打开iis>选择左侧根>点击右侧服务器证书 打开界面后 空白处点击右键选择导入 成功导入证书 选择需要绑定证书的网站点击选择>编辑绑定>ssl证书请选择您导入的证书 点击SSL ...