您的位置:首页 > 运维架构 > Shell

Linux.实现一个简单的shell

2017-03-25 13:26 686 查看
fork & execve

Shell框架

shell start and wait for inputing command and paraments

identify the command

cannot identify then print ‘bad command’ and go back to wait

if exit then exit() shell

else fork(), child execve() the Executable file, father wait() for the child



实现简单的命令

my_pwd

print current working directory

/*
* my_pwd.c
*/
#include <unistd.h>
#include <stdio.h>

char curp[255];
void main(int argc,char *argv[])
{
getcwd(curp,255);
printf("PWD: %s\n",curp);
return;
}


my_ls

list the directory and regular file contained by the given directory

support absolue path and relative path

/*
* my_ls.c
*
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
...
char **pths = NULL;    //store the pathes to list
int pth_n = 0;         //the number of paths
...
int res = 0;
struct stat st_f;
DIR* dir = NULL;
struct dirent* dir_ent = NULL;
for(int i = 0; i < pth_n; ++i){
char pth[255];
if(pths[i][0] == '/')
sprintf(pth,"%s",pths[i]);
else // char cwd[255] & getcwd(cwd,sizeof(cwd))
sprintf(pth,"%s/%s", cwd, pths[i]);

res = stat(pth, &st_f);
if(res < 0){
printf("cannot stat path %s\n", pth);
continue;
}

if(!S_ISDIR(st_f.st_mode)){
printf("%s is not a directory\n", pth);
continue;
}else{
dir = opendir( pth );
if(dir == NULL)
printf("cannot open ab_path %s\n", pth);

dir_ent = readdir( dir );
while( dir_ent != NULL ){
//ignore ".." "." and ".*" which are hidden files
if(dir_ent->d_name[0] == '.'){
dir_ent = readdir( dir );
continue;
}

if(dir_ent->d_type == DT_DIR)
printf("d %s\n",dir_ent->d_name);
else if(dir_ent->d_type == DT_REG)
printf("r %s\n",dir_ent->d_name);

dir_ent = readdir( dir );
}
}
}


my_cd

fork & execve cannnot change father process’s current working directory

then chdir() should called by shell itself

/*
* test_cwd.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

void main(int argc,char**argv)
{
char cwd[255];
int cwd_size = sizeof(cwd);
printf("cwd_size = %d\n", cwd_size);
getcwd(cwd, cwd_size);
printf("riginal father cwd = %s\n", cwd );

pid_t pid = fork();
if(pid == 0){
chdir("/home");
getcwd(cwd, 255);
printf("child cwd = %s\n", cwd );
}
else if(pid > 0){
wait(pid);
getcwd(cwd, 255);
printf("father cwd = %s\n", cwd );
}
}


MyShell Process

void my_exec(char *filename) to fork & execve with the given filename, and father process should wait()

int dispatch(char *input) to identify command and paraments, then store them(include cmd and paras) in char* cmd_paras[]

void get_input(char *cmd) to read up to 255 charactors from user input

/*
* my_shell.c
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pwd.h>
#include <sys/types.h>

char* cmd_set[] = {"exit","my_cd","my_ls","my_pwd"};
char* cmd_paras[MY_CMD_NUM];
int cmd_paras_n = 0;

char cwd[ MY_CWD_SIZE ];

void my_exec(char *path)
{
int pid = fork();
if(pid == 0)        execve(path, cmd_paras, env);
else if(pid > 0){
int status = 0;
pid_t pidd = 0;
pidd = wait(&status);
}
else if(pid < 0)    printf("fail to fork process.\n");
}

int dispatch(char *input)
{
int ret = -1, res = 0;
...
//cmd_paras[0] is the command
//cmd_paras[1..n] are the paramenst
//cmd_paras_n = n+1
if(!strcmp(cmd_paras[0], cmd_set[0])) ret = 0;   //exit
if(!strcmp(cmd_paras[0], cmd_set[1])){           //cd
ret = 1;
char dir[MY_CWD_SIZE];
if(cmd_paras_n == 1){
uid_t usrid = getuid();
struct passwd* pwd = getpwuid(usrid);
sprintf(dir, "/home/%s", pwd->pw_name);
}
else{
char* new_cwd = cmd_paras[1];
if(new_cwd[0] == '/') sprintf(dir, "%s", new_cwd);
else sprintf(dir, "%s/%s", cwd, new_cwd);
}
res = chdir(dir);
if(res < 0)printf("failed to change cwd to %s\n",dir);
}
if(!strcmp(cmd_paras[0], cmd_set[2])) ret = 2;  //ls
if(!strcmp(cmd_paras[0], cmd_set[3])) ret = 3;  //pwd

return ret;
}

void get_input(char *cmd)
{
int i = 0;
char c = getchar();
while( c != '\n' && i < 255 ){
cmd[ i++ ] = c;
c = getchar();
}
cmd[ i ] = '\0';
}

void main(int argc,char **argv)
{
char cmd[ MY_CMD_SIZE ];
const char * cmd_path = "/home/niugen/LINUX_CLASS";

int cmd_n = 0, loop = 1;

char cmd_file[ MY_CMD_SIZE ];
while(loop){
getcwd(cwd, MY_CWD_SIZE);
printf("MyShell@%s > ", cwd);
get_input( cmd );

cmd_n = dispatch( cmd );

if(cmd_n < 0)printf("Bad Command.\n");    //bad command
else if(cmd_n == 0) loop = 0;             //exit
else if(cmd_n != 1){                      //not 'cd'
sprintf(cmd_file,"%s/%s", cmd_path, cmd_paras[0]);
my_exec(cmd_file);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: