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
#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
*
*/
...
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
#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
#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;
...
if(!strcmp(cmd_paras[0], cmd_set[0])) ret = 0;
if(!strcmp(cmd_paras[0], cmd_set[1])){
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;
if(!strcmp(cmd_paras[0], cmd_set[3])) ret = 3;
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");
else if(cmd_n == 0) loop = 0;
else if(cmd_n != 1){
sprintf(cmd_file,"%s/%s", cmd_path, cmd_paras[0]);
my_exec(cmd_file);
}
}
}