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);
}
}
}