linux核心實驗two實作過程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>
#define normal 0 /*一般的指令*/
#define out_redirect 1 /*輸出重定向*/
#define in_redirect 2 /*輸入重定向*/
#define have_pipe 3 /*指令中有管道*/
int commandcounts=0;/*指令條數*/
void print_prompt(); /*列印提示符*/
void get_input(char *); /*得到輸入的指令*/
void explain_input(char *,int *,char a[100][256]); /*對輸入指令進行解析*/
void do_cmd(int ,char a[100][256]); /*執行指令*/
int find_command(char *); /*查找指令中的可執行程式*/
int main(int argc,char **argv)
{
int i;
int argcount = 0;
char arglist[100][256];
char **arg = NULL;
char *buf = NULL;
buf = (char *)malloc(256);
if (buf == NULL){
perror("malloc failed");
exit(-1);
}
char* commands[10];
while(1){
/*将buf所指向的空間清零*/
memset(buf,0,256);
print_prompt();
get_input(buf);
/*若輸入的指令為exit或logout則退出本程式*/
if (strcmp(buf,"exit\n") == 0 || strcmp(buf,"logout\n") == 0)
break;
//找出有幾條指令,多條指令以分号分割
int index=0;
commandcounts=1;
for(index=0;index<strlen(buf);index++){
if(buf[index]==';')
commandcounts++;
}
if(commandcounts>10){
printf("%s\n","commandcounts over.max num is 10");
continue;
}
index=0;
char *p=strtok(buf,";");
do{
commands[index]=p;
index++;
}
while(p=strtok(NULL,";"));
for(index=0;index<commandcounts;index++){
for (i=0;i<100;i++){
arglist[i][0] = '\0';
}
argcount = 0;
explain_input(commands[index],&argcount,arglist);
do_cmd(argcount,arglist);
}
}
if (buf != NULL){
free(buf);
buf = NULL;
}
exit(0);
}
void print_prompt()
{
printf("myshell$$");
}
/*擷取使用者輸入*/
void get_input(char *buf)
{
int len = 0;
int ch;
ch = getchar();
while (len <256 && ch != '\n'){
buf[len++] = ch;
ch = getchar();
}
if (len ==256){
printf("commond is too long \n");
exit(-1); /*輸入的指令過長則退出程式*/
}
buf[len] = '\n';
len++;
buf[len] = '\0';
}
/*解析buf中的指令,将結果存入arglist中,指令以回車符号\n結束*/
/*如輸入指令為“ls -l /tmp”,則arglist[0],arglist[1],arglist[2]分别為ls,-l和/tmp*/
void explain_input(char *buf,int *argcount,char arglist[100][256])
{
char *p = buf;
char *q = buf;
int number = 0;
while(1){
if (p[0] == '\n')
break;
if (p[0] == ' ')
p++;
else {
q = p;
number = 0;
while ((q[0] != ' ') && (q[0] != '\n')){
number++;
q++;
}
strncpy(arglist[*argcount],p,number+1);
arglist[*argcount][number] = '\0';
*argcount = *argcount + 1;
p = q;
}
}
}
void do_cmd (int argcount,char arglist[100][256])
{
int flag = 0;
int how = 0; /*用于訓示指令中是否含有>,<,|*/
int background = 0; /*辨別指令中是否有背景運作辨別符*/
int status;
int i;
int fd;
char *arg[argcount+1];
char *argnext[argcount+1];
char *file;
pid_t pid;
/*将指令取出*/
for (i=0;i<argcount;i++){
arg[i] = (char *)arglist[i];
}
arg[argcount] = NULL;
/*檢視指令行是否有背景運作符*/
for (i=0;i<argcount;i++){
if (strncmp(arg[i],"&",1) == 0){
if (i == argcount - 1){
background = 1;
arg[argcount-1] = NULL;
break;
}
else {
printf("wrong command\n");
return;
}
}
}
for (i=0;arg[i] != NULL;i++){
if (strcmp(arg[i],">") == 0){
flag++;
how = out_redirect;
if (arg[i+1] == NULL)
flag++;
}
if (strcmp(arg[i],"<") == 0){
flag++;
how = in_redirect;
if (i == 0)
flag++;
}
if (strcmp(arg[i],"|") == 0){
flag++;
how = have_pipe;
if (arg[i+1] == NULL)
flag++;
if (i == 0)
flag++;
}
}
/*flag大于1,說明指令中含有多個>,<,|符号,本程式是不支援這樣的指令的,
或者指令格式不對,如“ls -l /tmp >”*/
if (flag > 1){
printf("wrong command\n");
return;
}
if (how == out_redirect){/*指令隻含有一個輸出重定向符号>*/
for (i=0;arg[i] != NULL;i++){
if (strcmp(arg[i],">") == 0){
file = arg[i+1];
arg[i] = NULL;
}
}
}
if (how == in_redirect){/*指令隻含有一個輸入重定向符号<*/
for (i=0;arg[i] != NULL;i++){
if (strcmp(arg[i],"<") == 0){
file = arg[i+1];
arg[i] = NULL;
}
}
}
if (how == have_pipe){/*指令隻含有一個管道符号|*/
/*把管道符号後面的部分存入argnext中,管道後面的部分是一個可執行的Shell指令*/
for (i=0;arg[i] != NULL;i++){
if (strcmp(arg[i],"|") == 0){
arg[i] = NULL;
int j;
for (j=i+1;arg[j] != NULL;j++){
argnext[j-i-1] =arg[j];
}
argnext[j-i-1] = arg[j];
break;
}
}
}
if ((pid = fork()) < 0) {
printf("fork error\n");
return;
}
switch(how) {
case 0:
/*pid為0說明是子程序,在子程序中執行輸入的指令*/
/*輸入的指令中不含>,<和|*/
if (pid == 0){
if (!(find_command(arg[0]))){
printf("%s:command not found\n",arg[0]);
exit(0);
}
execvp(arg[0],arg);
exit(0);
}
break;
case 1:
if (pid == 0){
if (!(find_command(arg[0]))){
printf("%s: commandnot found\n",arg[0]);
exit(0);
}
fd = open(file,O_RDWR|O_CREAT|O_TRUNC,0644);
dup2(fd,1);
execvp(arg[0],arg);
exit(0);
}
break;
case 2:
/*輸入的指令中含有重定向符<*/
if (pid == 0){
if (!(find_command(arg[0]))){
printf("%s:command not found\n",arg[0]);
exit(0);
}
fd = open(file,O_RDONLY);
dup2(fd,0);
execvp(arg[0],arg);
exit(0);
}
break;
case 3:
/*輸入的指令中含有管道*/
if (pid == 0){
int pid2;
int status2;
int fd2;
if ((pid2 = fork()) < 0){
printf("fork2 error\n");
return;
}
else if (pid2 == 0){
if (!(find_command(arg[0]))){
printf("%s:command not found\n",arg[0]);
exit(0);
}
fd2 = open("/tmp/youdonotknowfile",O_WRONLY|O_CREAT|O_TRUNC,0644);
dup2(fd2,1);
execvp(arg[0],arg);
exit(0);//子程序在此退出
}
//父程序在此執行
if (waitpid(pid2,&status2,0) == -1)
printf("wait for child process error\n");
if (!(find_command(argnext[0]))){
printf("%s:command not found\n",argnext[0]);
exit(0);
}
fd2 = open("/tmp/youdonotknowfile",O_RDONLY);
dup2(fd2,0);
execvp(argnext[0],argnext);
if (remove("/tmp/youdonotknowfile"))
printf("remove error\n");
exit(0);
}
break;
default:
break;
}
/*若指令中有&,表示背景執行,父程序直接傳回,不等待子程序結束*/
if (background == 1){
printf("[process id %d]\n",pid);
return;
}
/*父程序等待子程序結束*/
if (waitpid(pid,&status,0) == -1)
printf("wait for child process error\n");
}
/*
* 産看這個指令是否存在
*/
int find_command(char *command)
{
DIR *dp;
struct dirent *dirp;
char *path[] = {"./","/bin","/usr/bin",NULL};
/*使目前目錄下的程式可以運作,如指令"./fork"可以被正确解釋和執行*/
if (strncmp(command,"./",2) == 0)
command = command + 2;
/*分别在目前目錄、/bin和/usr/bin目錄查找要執行的程式*/
int i = 0;
while (path[i] != NULL){
if ((dp = opendir(path[i])) == NULL)
printf("can not open /bin \n");
while((dirp = readdir(dp))!= NULL){//讀目錄中的所有的檔案
if (strcmp(dirp->d_name,command) == 0){//有這個檔案
closedir(dp);
return 1;
}
}
closedir(dp);
i++;
}
return 0;
}