20155322 2017-2018-1 《信息安全系统设计》第五周 MyBash实现
#20155322 2017-2018-1《信息安全系统设计》第五周 MyBash实现
[博客目录]
- 实现要求
- 相关知识
- bash
- fork
- exec
- wait
- 相关问题
- fork返回两次
- execvp函数原型
- fork函数的理解
- 代码链接
- 实现
- 伪代码
- 产品代码
- 本周结对学习情况
- 结对学习博客
- 结对学习图片
- 结对学习内容
参考资料
实现要求
- 使用fork,exec,wait实现mybash
- 写出伪代码,产品代码和测试代码
- 发表知识理解,实现过程和问题解决的博客(包含代码托管链接)
返回目录
相关知识
bash
bash 是一个为GNU计划编写的Unix shell。它的名字是一系列缩写:Bourne-Again SHell — 这是关于Bourne shell(sh)的一个双关语(Bourne again / born again)
bash是大多数Linux系统以及Mac OS X默认的shell,它能运行于大多数类Unix风格的操作系统之上,甚至被移植到了Microsoft Windows上的Cygwin系统中,以实现Windows的POSIX虚拟接口。此外,它也被DJGPP项目移植到了MS-DOS上。
- bash参数
- c字符串
若用-c参数,则bash从字符串中读入命令,如果字符串后还有变量就被设定为从$0开始的位置参数。 - i
若用-i参数,则bash是交互的。 - s
若用-s参数,则bash从标准输入中读入命令(在执行完-c带的命令之后。)直到输入exit。
-“-”
单一的号表明参数执行完毕,并且屏蔽此后所跟参数,后面的所有变量都被看作是文件名。 - norc
如果bash是交互的,则不执行个人初始化文件:-/.bashrc,如果bash作为sh来运行,这个参数缺省是关闭的。 - noprofile
不执行系统范围的启动文件/etc/profile也不执行个人的启动文件-/.bash_profile,-/.bash_login或-/.profile,缺省情况下,bash作为登录的shell时以这些文件作为启动文件。 - -refile文件名
如果bash是交互的,则以此文件作为bash的启动文件。替代-/.bashrc。 - version
在bash开始时显示此bash的版本号。 - quiet
不显示版本号和其他信息,这是缺省值。 - login
激活bash,伪装为登录shell。 - nobraceexpansion
不执行大括号扩展。 - nolineediting
在交互状态下不使用GNU的readline库去读取命令。即取消了命令行编辑功能。 - posix
改变bash的行为,使其符合Posix 1003.2规定的标准。
- c字符串
返回目录
fork
计算机程序设计中的分叉函数。fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。
- 函数原型:
pid_t fork( void);
//pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中
- 返回值:
若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1 - 函数说明:
一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。UNIX将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。在不同的UNIX (Like)系统下,我们无法确定fork之后是子进程先运行还是父进程先运行,这依赖于系统的实现。所以在移植代码的时候我们不应该对此作出任何的假设。
man查询结果如下:
返回目录
exec
把当前进程映像替换成新的程序文件,而且该程序通常在main函数开始执行。
- exec函数族:
#include <unistd.h>extern char **environ;int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
- 其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。
- exec函数的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件
man查询结果如下:
返回目录
wait
等待子进程中断或结束(等待直到一个进程标识终止)。
- 函数原型:
pid_t wait (int * status);
- 表头文件:
#include<sys/types.h>
#include<sys/wait.h>
- 调用 wait 函数时,调用进程将会出现下面的情况:
- 如果其所有子进程都还在运行, 则阻塞。
- 如果一个子进程已经终止,正等待父进程获取其终止状态,则获取该子进程的终止状态然后立即返回。
- 如果没有任何子进程,则立即出错返回。
man查询结果如下:
- 实例代码:
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>main()
{pid_t pid;int status,i;if(fork()= =0){printf(“This is the child process .pid =%d\n”,getpid());exit(5);}else{sleep(1);printf(“This is the parent process ,wait for child...\n”;pid=wait(&status);i=WEXITSTATUS(status);printf(“child’s pid =%d .exit status=%d\n”,pid,i);
}
结果:
This is the child process.pid=1501
This is the parent process .wait for child...
child’s pid =1501,exit status =5
返回目录
相关问题
- 问题:为什么fork会返回两次?
- 通过百度百科我得到了答案:由于在复制时复制了父进程的堆栈段,所以两个进程都停留在fork函数中,等待返回。因此fork函数会返回两次,一次是在父进程中返回,另一次是在子进程中返回,这两次的返回值是不一样的。过程如下图。
fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:- 在父进程中,fork返回新创建子进程的进程ID;
- 在子进程中,fork返回0;
- 如果出现错误,fork返回一个负值。
在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID我们可以通过fork返回的值来判断当前进程是子进程还是父进程。
引用一位网友的话来解释fork函数返回的值为什么在父子进程中不同:“其实就相当于链表,进程形成了链表,父进程的fork函数返回的值指向子进程的进程id, 因为子进程没有子进程,所以其fork函数返回的值为0.调用fork之后,数据、堆、栈有两份,代码仍然为一份但是这个代码段成为两个进程的共享代码段都从fork函数中返回,箭头表示各自的执行处。当父子进程有一个想要修改数据或者堆栈时,两个进程真正分裂。
- 实例代码:
#include<sys/types.h>//对于此程序而言此头文件types.h用不到
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>int main(int argc,char *argv[])/*整数类型主函数*/
{
pid_t pid=fork();/*传递参数*/
if(pid<0)/*如果(进程标记<0)*/
{
fprintf(stderr,"错误!");
}
else if(pid==0)/*否则如果(进程标记==0)*/
{
printf("这是子进程!");
exit(0);
}
else/*否则*/{
printf("这是父进程!子进程的进程标记为=%d",pid);
}
//可能需要时候wait或waitpid函数等待子进程的结束并获取结束状态
exit(0);
}
返回目录
- 问题:对于execvp函数原型中的
int execvp(const char *file, char *const argv[])
中*file
的定义? - 解决:是程序的可执行文件的名字。
- execlp和execvp的第1个参数 file可以简单到仅仅是一个文件名,如 "ls",这两个函数可以自动到环境变量PATH制定的目录里去寻找。
- 实例测试:
#include <stdio.h>
#include <unistd.h>int main() {char *arglist[3];arglist[0] = "ls";arglist[1] = 0;arglist[2] = 0;//NULLprintf("*** I want to exec "ls" ***\n");execvp("ls", arglist);printf("*** "ls" is done ***\n");return 0;
}
结果
返回目录
- 问题:关于fork函数的理解
- 解决:这里我参考了刘子健同学的博客中关于fork的demo,并进行了测试,通过sleep函数的来体现出fork的效果,我觉得这个demo非常好,便于理解fork,在此记录:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main() {int ret_from_fork, mypid;mypid = getpid();printf("Before: my pid is %d\n", mypid);ret_from_fork = fork();sleep(1);printf("After: my pid is %d, fork() said %d\n", getpid(), ret_from_fork);return 0;
}
- 结果:
返回目录
代码链接
返回目录
实现
伪代码(流程):
- 循环 {
- 输入指令;
- 判断是否为回车
- 是:结束输入,存储指令,fork,执行
- 否:继续输入
}
返回目录
产品代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>#define MAXARGS 20
#define ARGLEN 100int mybash5322(char *arglist[]);
int execute(char *arglist[]);
char *makestring(char *buf);int main() {char *arglist[MAXARGS + 1];int numargs;char argbuf[ARGLEN];numargs = 0;while (numargs < MAXARGS) {printf("Arg[%d]? ", numargs);if (fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n')arglist[numargs++] = makestring(argbuf);else {if (numargs > 0) {arglist[numargs] = NULL;mybash5322(arglist);numargs = 0;}}}return 0;
}int mybash5322(char *arglist[])
{int pc,pr;pc=fork();pr=wait(NULL);if(pc==0) execute(arglist);else return 0;
}int execute(char *arglist[])
{execvp(arglist[0],arglist);perror("execvp failed");exit(1);
}char *makestring(char *buf)
{char *cp;buf[strlen(buf)-1] = '\0';cp = malloc( strlen(buf)+1 );if ( cp == NULL ){fprintf(stderr,"no memory\n");exit(1);}strcpy(cp, buf);return cp;
}
- 实现结果:
返回目录
本周结对学习情况
- 结对学习博客
20155302 - 结对学习图片
- 结对学习内容
- 教材第三章
返回目录
参考资料
- Linux 进程与信号的概念和操作 linux process and signals
- fork函数
- EXEC函数
- Wait函数
- perror
- Exit()
- SLEEP函数
- 课后实践之mybash
返回目录
转载于:https://www.cnblogs.com/blackay03/p/7714449.html
20155322 2017-2018-1 《信息安全系统设计》第五周 MyBash实现相关推荐
- 20155322 2017-2018-1《信息安全系统设计》第六周学习总结
# 20155322 2017-2018-1<信息安全系统设计>第六周学习总结 教材学习内容总结 第八章: 什么是异常控制流: 控制流:控制转移序列. 控制转移:从一条指令到下一条指令. ...
- 2017~2018学年《信息安全》考试试题(A2卷)
北京信息科技大学,2017~2018 学年第二学期<信息安全>考试试题(A 卷) 适用专业班级:计科15级 重修课程所在学院:计算机学院 考试形式:闭卷 一.单选题(本题满分20分,共含1 ...
- 2017~2018学年《信息安全》考试试题(A3卷)
北京信息科技大学 2017 ~2018 学年第一学期 <信息安全>考试试题 (A3 卷) 课程所在学院:计算机学院 适用专业班级: - 考试形式:闭卷 一.单选题(本题满分 20 分,共含 ...
- 2017~2018学年《信息安全》考试试题(A1卷)
北京信息科技大学 2017 ~2018 学年第二学期<信息安全>考试试题 (A 卷) 课程所在学院:计算机学院 适用专业班级:计科 1504-6.重修 考试形式:闭卷 一.单选题(本题满分 ...
- 20162329 张旭升 2017 - 2018 《程序设计与数据结构》第五周总结
20162329 2017-2018-1 <程序设计与数据结构>第五周学习总结 教材学习内容总结 1.学习目标 了解集合的概念 了解并使用抽象数据类型 初步了解使用Java泛型 学习栈这种 ...
- 20145326蔡馨熠《信息安全系统设计》第2周学习总结
20145326蔡馨熠<信息安全系统设计>第2周学习总结 教材学习内容总结 一.计算机系统与链接 信息就是位+上下文,都是由一串位表示的,区分不同数据对象的唯一方法是我们读到这些数据对象时 ...
- 2018上半年信息安全工程师真题含答案(下午题)
2018上半年信息安全工程师真题含答案(下午题) 试题一 阅读下列说明,回答问题1至问题4,将解答填入答题纸的对应栏内. [说明]恶意代码是指为达到恶意目的专门设计的程序或者代码.常见的恶意代码类型 ...
- 安徽大学java期末_安微大学2017~2018年度期末考试题卷
原标题:安微大学2017~2018年度期末考试题卷 备考备考备考! 六月来啦,期末考还会远吗? 别人家的形势与政策课试题又一次刷新三观 你会做这样的题吗 怎么判断自己是不是个合格的AHUer? 锵锵锵 ...
- c语言输出教学日历表 节假日突出,2017 -2018 学年第二学期教学日历及教学环节表(一)(4页)-原创力文档...
2017 -2018 学年第二学期教学日历及教学环节表(一) 周次 星期 一 二 三 四 五 六 七 八 九 十 十一 十二 十三 十四 十五 十六 十七 十八 一 15/1 22 5/3 12 19 ...
最新文章
- phpcms标签大全V9
- 【转】给博客园博文标题加个漂亮的背景色
- 中如何构造有参和无惨_CAD制图初学入门:CAD机械软件中如何构造孔?
- Linux操作系统的进程管理详解
- Oracle相关报错
- Word中摘要和正文同时分栏后,正文跑到下一页,怎么办?或Word分栏后第一页明明有空位后面的文字却自动跳到第二页了,怎么办?...
- spark 上下游shuffle结果的存放获取
- 步骤1:mybatis工程的创建
- java反射代码,java反射
- 【PC工具】更新win10关闭更新工具Windows Update Blocker
- Digester基本用法
- Scrum敏捷开发框架
- android课程设计的需求分析,安卓课程设计心得体会.doc
- 上海交大吴齐天的科研思考
- 团队协作常见问题分析与解决
- java中cookie的有效时间设置
- maya 白天室内灯光_Maya课时:白天的灯光构建视频教程_翼狐网
- 算法-求数组的子数组之和的最大值
- 独立站运营 | 强烈推荐,这5款WordPress电子商务插件
- DNF纯图色起号源码