一、pwd

1.学习pwd命令

man pwd查看pwd功能

可以得知pwd功能是打印当前目录

2.研究pwd实现需要的系统调用(man -k; grep),写出伪代码

(1)man -k directory | grep 2查看是否有可用命令

(2) 可以得知getcwd命令可以获得当前目录路径

man getcwd查看getcwd命令功能

找到所需要的头文件以及函数

#include <unistd.h>
char *getcwd(char *buf, size_t size);
(3)由刚才man -k directory | grep 2获得的相关命令中我们也可以发现chdir命令会被用到

man chdir查看chdir命令功能

找到所需要的头文件以及函数

#include <unistd.h>
int chdir(const char *path);
(4)由刚才man -k directory | grep 2获得的相关命令中我们也可以发现readdir命令会被用到

man readdir查看readdir命令功能

找到所需要的头文件以及函数

#include <dirent.h>
struct dirent *readdir(DIR *dirp);

伪代码

  • 用“.”获取当前目录的i-node
  • 用“..”获取父级目录的i-node
  • 判断当前目录的i-node和父级目录的i-node是否相同
  • 相同:到达根目录,输出完整路径,退出程序
  • 不同:还未到根目录,切换至父级目录,返回(1)再次执行相同操作直至两个i-node相同

3.实现mypwd

#include<stdio.h>
#include<sys/stat.h>
#include<dirent.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include <unistd.h>
void printpath();
char *inode_to_name(int);
int getinode(char *);
//功能:打印当前目录路径
void printpath()
{
int inode,up_inode;
char *str;
inode = getinode(".");
up_inode = getinode("..");
chdir("..");
str = inode_to_name(inode);
//当当前目录的i-node与父级目录的i-node相同时,到达根目录
if(inode == up_inode) {
return;
}
//打印路径
printpath();
printf("/%s",str);
}
//功能:获取当前目录的i-node
int getinode(char *str)
{
struct stat st;
if(stat(str,&st) == -1){
perror(str);
exit(-1);
}
return st.st_ino;
}
//功能:获取当前路径
char *inode_to_name(int inode)
{
char *str;
DIR *dirp;
struct dirent *dirt;
if((dirp = opendir(".")) == NULL){
perror(".");
exit(-1);
}
while((dirt = readdir(dirp)) != NULL)
{
if(dirt->d_ino == inode){
str = (char *)malloc(strlen(dirt->d_name)*sizeof(char));
strcpy(str,dirt->d_name);
return str;
}
}
perror(".");
exit(-1);
}
//主函数
int main()
{
printpath();
putchar('\n');
return 0;
}

4.测试mypwd

二、bash

1.有关fork(),exec(),wait()

  • fork()

fork() 函数通过系统调用创建一个与原来进程几乎完全相同的进程,每个进程都启动一个从代码的同一位置开始执行的线程,父子两个进程中的线程能同时执行不同的指令要求。若调用成功返回的是两个值:父进程返回的值为子进程标志;子进程返回的值为0,不成功返回为-1。

找到所需要的头文件以及函数

#include <unistd.h>
pid_t fork(void);
  • exec()

系统调用 execv() 对当前进程进行替换,替换者为一个指定的可执行程序,其参数包括文件名(filename)、参数列表(argv) 以及环境变量 (envp) 。

找到所需要的头文件以及函数

#include <unistd.h>
int execv(const char *path, char *const argv[]);
  • wait()

wait() 函数用于使父进程(也就是调用wait()的进程)阻塞,直到一个子进程结束或者该进程接收到了一个指定的信号为止。若该父进程没有子进程或者它的子进程已经结束,wait() 函数就会立即返回。

找到所需要的头文件以及函数

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);

2.伪代码及实现

伪代码
  • 读取用户输入的指令
  • 调用fork函数生成一个子进程,并将fork返回的pid值赋给父进程fpid
  • 调用wait函数,传入参数NULL
  • 判断fpid是否为0
  • 若为0,则调用execvp函数,将用户输入的指令传进去,实现功能
  • 若不为0,则提示错误,并返回(1)等待用户下一个指令
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <pwd.h>
#include <sys/wait.h>
#define LEN 10 char* Cmd[LEN] = {0};
int count = 0;
char OLDPWD[1024] = {0};
void out_flag()
{
char flag = '$';
struct passwd *pw = getpwuid(getuid());
if(getuid() == 0)
{
flag = '#';
}
struct utsname host;
uname(&host);
char *hostname = strtok(host.nodename, ".");
char path[128] = {0};
getcwd(path, 127);//获取当前目录的绝对路径
char *p = strtok(path, "/");
char *nowdir = NULL;
while(p!= NULL)
{
nowdir = p;
p = strtok(NULL, "/");
}
if(nowdir == NULL)
{
nowdir = "/";
}
if(strcmp(nowdir, pw->pw_name) == 0)
{
nowdir = "~";
}
printf("[%s@%s %s]mybash%c ", pw->pw_name, hostname, nowdir, flag);
fflush(stdout);
}
void cut_cmd(char *cmd)
{
char *p = strtok(cmd, " ");
while(p != NULL)
{
Cmd[count++] = p;
p = strtok(NULL, " ");
}
}
int special_cmd()
{
//cd exit
if(strncmp("cd", Cmd[0], 2) == 0)
{
if(Cmd[1] == NULL || strncmp(Cmd[1], "~", 1) == 0)
{
//切换到家目录
struct passwd *pw = getpwuid(getuid());
Cmd[1] = pw->pw_dir;
}
else if(strncmp(Cmd[1], "-", 1) == 0)
{
//切换到家目录到上一次所在目录
if(strlen(OLDPWD) == 0)
{
printf("mybash: cd :: OLDPWD not set\n");
return 1;
}
Cmd[1] = OLDPWD;
printf("%s\n", Cmd[1]);
}
char str[1024] = {0};
getcwd(str, 1023);
chdir(Cmd[1]); // 切换路径
strcpy(OLDPWD, str);
return 1;
}
if(strncmp("exit", Cmd[0], 4) == 0)
{
exit(0);
}
return 0;
}
void clear_cmd()
{
int i = 0;
for(;i < count; ++i)
{
Cmd[i] = 0;
}
count = 0;
}
void main()
{
while(1)
{
out_flag();
char cmd[128] = {0};
fgets(cmd, 128, stdin); //获取命令
cmd[strlen(cmd) - 1] = 0; //去掉最后一个回车符
if(strlen(cmd) == 0) // 判别用户的无效输入
{
continue;
}
cut_cmd(cmd); // 切割cmd
int res = special_cmd(); // 判别是否是需要集成到bash中的特殊命令
if(res == 1)
{
clear_cmd(); //清空全局的指针数组,并将count归0
continue;
}
pid_t pid = fork();
assert(pid != -1);
if(pid == 0)
{
// 用命令的可执行文件(./mypwd)替换当前进程
char path[1024] = "/home/darkeye/computer-systems/src/mybash
";
if(strstr(Cmd[0], "/") != NULL)
{
memset(path, 0, 1024);
}
strcat(path, Cmd[0]);
execv(path, Cmd);
printf("mybash: %s : command not found\n", Cmd[0]);
exit(0);
}
else
{
wait(NULL);
}
clear_cmd();
}
}

实现mypwd和mybash的更多相关文章

  1. 实现mypwd&mybash&myod&读者写者

    目录: 一.mypwd 二.mybash 三.myod 四.读者.写者 一.实现mypwd 学习pwd命令 研究pwd实现需要的系统调用(man -k; grep),写出伪代码 实现mypwd 测试m ...

  2. 20165223 《信息安全系统设计基础》 实现mybash

    一.了解 mybash 1. 简介   bash 是 Bourne Again Shell 的缩写,是linux默认的标准shell(也是大家常说的系统内核),bash也是Unix/Linux上常见的 ...

  3. Mybash的实现

    Mybash的实现 要求: 使用fork,exec,wait实现mybash 写出伪代码,产品代码和测试代码 发表知识理解,实现过程和问题解决的博客(包含代码托管链接) 背景知识 1. fork 使用 ...

  4. 2017-2018-1 20155205 实现mypwd

    2017-2018-1 20155205 实现mypwd 课堂总结 根据上课对ls -l功能的实现,我总结了实现一个linux命令需要的步骤: 使用man -k xx | grep xx查看帮助文档, ...

  5. 2017-2018-1 20155215 第五周 mybash的实现

    题目要求 使用fork,exec,wait实现mybash 写出伪代码,产品代码和测试代码 发表知识理解,实现过程和问题解决的博客(包含代码托管链接) 学习fork,exec,wait fork ma ...

  6. 20155227 实现mypwd

    20155227 实现mypwd 1 学习pwd命令 2 研究pwd实现需要的系统调用(man -k; grep),写出伪代码 3 实现mypwd 4 测试mypwd 课堂学习笔记 实现mypwd 在 ...

  7. 2017-2018-1 20155306 mypwd的实现

    2017-2018-1 20155306 mypwd的实现 一.pwd的使用 功能: Linux中用 pwd 命令来查看"当前工作目录"的完整路径. 命令格式:pwd [选项] 命 ...

  8. 2017-2018-1 20155306 《信息安全系统设计基础》Mybash的实现

    2017-2018-1 20155306 <信息安全系统设计基础>Mybash的实现 要求: 使用fork,exec,wait实现mybash 写出伪代码,产品代码和测试代码 发表知识理解 ...

  9. 实现mypwd

    1 学习pwd命令 2 研究pwd实现需要的系统调用(man -k; grep),写出伪代码 3 实现mypwd 4 测试mypwd 提交过程博客的链接 代码如图

随机推荐

  1. mysql数据库的备份

    有时会遇到需要重装虚拟机的情况,这时候之前创建好的数据库就需要备份啦,等重新装好虚拟机直接导入就可以正常使用. 数据库备份大体分为两步: 第一步.导出数据库,因为是备份,会将所有的数据库导出,因此需要 ...

  2. L3-015 球队“食物链” (30 分)

    L3-015 球队“食物链” (30 分)   某国的足球联赛中有N支参赛球队,编号从1至N.联赛采用主客场双循环赛制,参赛球队两两之间在双方主场各赛一场. 联赛战罢,结果已经尘埃落定.此时,联赛主席 ...

  3. 神州数码NAT地址转换配置

    实验要求:熟练掌握NAT地址转换的配置方法 拓扑如下 R1 enable 进入特权模式 config 进入全局模式 hostname R1 修改名称 interface s0/1 进入端口 ip ad ...

  4. Vue小技巧-懒加载

    Vue懒加载包括图片懒加载与路由懒加载 1.图片懒加载: 首先安装 vue-lazyload包 然后导入并加载事先下载好的加载图片 import VueLazyLoad from 'vue-lazyl ...

  5. Java基础知识——算术操作符、自增自减、关系操作符,你真的了解吗?

    三人行,必有我师焉.欢迎大家加我的微信 yh18482155461,或扫描下方二维码,关注我的微信公众号,共同探讨Java相关技术问题. 温故知新 上一节我们讲到了Java中的赋值操作符,用案例的方式 ...

  6. MFC中关于运行时类信息及动态创建对象的两个宏的意义(转)

    http://blog.csdn.net/ligand/article/details/49839507 MFC运行时类信息 用途: 程序在运行时,获取对象类的信息及类的继承关系 实现: 1.定义的类 ...

  7. 嵌入页面的几种方法(转载自萤火虫小Q)

    一.应用框架技术 ---- 要在宿主页面中嵌入外部页面的方法是,在宿主页面中包含外部页面的位置插入“< IFRAME name="XXX" width=X height=X ...

  8. mock数据,尽量随机,1次插入多条

    建表,多设置一个字段id_tmp create table if not exists mall_data.dtw_mall2_adm_customer_d_tmp( id_tmp string co ...

  9. JVM运行时数据区域

    上面已经聊过JVM是什么东东,也谈过了JVM内存的垃圾回收机制.这一篇博客我们来聊聊JVM运行时数据区域. JVM运行时数据区域由5块部分组成,分别是堆,方法区,栈,本地方法栈,以及程序计数器组成. ...

  10. Python练习十

    1.生成随机整数,从1-5取出来然后输入一个数字,来猜,如果大于,则打印bigger小了,则打印less如果相等,则打印equal. import random num1 = random.randi ...