自己的shell

来源:互联网 发布:丹尼斯·约翰逊数据 编辑:程序博客网 时间:2024/04/28 09:40

      相信接触过linux过,听过的人都知道linux的源代码是公开的,那么我们是不是可以看看我们平时最常用的命令是怎么实现的吧!看其实没那重要,重要的是你要裂解,然后根据自己的理解自己实现,然后和源代码做对比,学习借鉴,取长补短,那应该是一种比较好的学习方式了吧!

     那我今天就来把我自己的想法写在这里!

在写命令之前,我们都知道,命令必须在命令解释器下,才能完美的运行起来,脱离这个平台,那么它不过就是一堆字母吧!

 第一步(很重要的一步):命令解释器的实现,简单来说呢,就是是怎么把命令调起来然后实现的,也许你一会第一反应exec,exec是完全替换自己的代码,把你要调的完全复制过来,成功可是不反悔,失败就返回。对他是我们命令解释器少不了的函数。

不妨将这个函数列举一下:

     1. execl(const char *pathnaem,const char *arg,....(char *)0); 以参数形式列出

举例:当前文件下的main 想调起来,使用execl("./main","./main",(char *)0);

     2. execv(const char *pathname,char *const argv[]); 

举例:当前文件下的main 想调起来,使用

        char *argv[] = {"./main","./main",NULL};

        execv("./main",argv);

    3.execve(const char * pathname,  char *const argv[],  char *const envp[]);

    4.execvp(const char *filename,char *const argv[]); 将系统的环境变量给保护起来。

简单就是这几个,还有很多,还待查。

剩下的就是简单的函数使用了。

看看代码,具体函数具体解释:

#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<assert.h>#include<string.h>#include<signal.h>#include<pwd.h>#define MAXSIZE 10#define MYPATH "/home/yu/Desktop/mbash/mybin/"void printfl(){int id = getuid();char *s = "$";if(id == 0){s = "#";}struct passwd *p = getpwuid(id);char hostname[128] ={0};gethostname(hostname,128);char *m = strtok(hostname,".");char buff[256] = {0};char *ps = "/";getcwd(buff,128);char *ql = strtok(buff,"/");while(ql!= NULL){ps = ql ;ql = strtok(NULL,"/");}printf("[**%s@ %s %s]%s ",p->pw_name,m,ps,s);fflush(stdout);}int main(){while(1){//printf("[yu@localhost %s]$ ");//fflush(stdout);printfl();char buff[128] = {0};fgets(buff,128,stdin);buff[strlen(buff)-1] = 0;char *myargv[MAXSIZE] = {0}; int i = 1;    char*s = strtok(buff," ");    if(s == NULL)    {   continue;    }    myargv[0] = s;while((s = strtok(NULL," ")) != NULL){myargv[i++] = s;}if(strcmp(myargv[0], "cd") == 0){            if(chdir(myargv[1]) == -1)    {               printf("mybash is error!\n");    }continue;}if(strcmp(myargv[0],"exit") == 0){exit(0);}pid_t pid = fork();if(pid == 0){   //execlp(buff,buff,(char *)0);   //execvp(myargv[0],myargv);   char path[512] = {0};   if(strncmp(myargv[0],"/",1) != 0 && strncmp(myargv[0],"./",2)!=0)   { //以绝对路径或者相对路径执行可执行文件。   strcpy(path,MYPATH);   }   strcat(path,myargv[0]);   execv(path,myargv);   printf("mybashis error:\n");   exit(0);子进程结束,那也就是exec失败,那么就会退出子进程。}wait(NULL);}return 0;}

1.getuid() 获取当前用户的uid   如果结果 == 0 那么是root,否则是普通用用户。

2.struct passwd *p = getpwuid(id); 根据当前用户的uid 获取当前用户的名字,名字存在p这个结构体中,pw_name 当前用户的名字。

3.gethostname(hostname,128); 获取当前主机名,

4.strtok(hostname,".");分割字符串,遇到.分割,分割后就将那个地方置换成\0,下次要想再次置换那就从NULL开始,,再次分割。

5.getcwd(buff,128); 获取当前的路径,根据路径可以将终端提示里面的[yu@local. 当前路径]。

     这就是简单的命令解释器的实现,那么我们具体可以根据这些函数,对这个命令解释器的实现有一个很好理解。


0 0
原创粉丝点击