进程实践——myshell

要求:

解释执行命令,支持输入输出重定向,支持管道,后台运行程序。

/*************************************************************************
> File Name: shell.c
> Author:wyf 
> Mail:Catherine199787@outlook.com 
> Created Time: 2016年07月30日 星期六 10时54分55秒
************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>
#include<dirent.h>
#include<string.h>
#include<malloc.h>

#define normal 0
#define out 1
#define in 2
#define pipe 3

//自定义错误函数
void err(char* err_string, int line){
    perror(err_string);
    fprintf(stderr, "line:%d", line);
    return;
}

//判断命名的正确性
int right(char *arg){
    DIR *dir;
    struct dirent* ptr;
    char *path[] = {"./","/bin","/usr/bin/",NULL};   //环境变量PATH的路径
    int i;

    if(strncmp(arg, "./", 2) == 0){  //将路径改为当前目录
        arg = arg + 2;                  //指针移到/下一个字节
    }

    for(i = 0; path[i] != NULL; i++){           //查找命令
        dir = opendir(path[i]);
        if(dir == NULL){
            err("open_bin error", __LINE__);
        }
        while((ptr = readdir(dir)) != NULL){
            if(strcmp(ptr->d_name, arg) == 0){
                closedir(dir);
                return 1;
            }
        }
        closedir(dir);
    }
    return 0;
}

//管道的执行函数
void argpipe(char *argn[], char *arg[]){
    int pid;
    int status;
    int fd;

    pid = fork();
    if(pid < 0){
        err("pipe_fork", __LINE__);
    }

    else if(pid == 0){
        if(!right(arg[0])){
            err("pipe arg", __LINE__);
        }
        fd = open("/tmp/youdonotknowfile", O_WRONLY | O_CREAT | O_TRUNC,0644);
        dup2(fd, 1);
        execvp(arg[0], arg);
        exit(0);
    }

    if(waitpid(pid, &status, 0) == -1){
        err("pipe_wait", __LINE__);
    }
    if(!right(argn[0])){
        err("pipe_arg", __LINE__);
    }

    fd = open("/tmp/youdonotknowfile", O_RDONLY);
    dup2(fd, 0);
    execvp(argn[0], argn);

    if(remove("/tmp/youdonotknowfile")){
        err("remove", __LINE__);
    }
}

//输入函数
void arginput(char *buf){
    int len = 0;

    gets(buf);
    len = strlen(buf);

    if(len >= 255){
        err("arginput", __LINE__);
    }
}


//解析输入的命令
void argexplain(char * buf, char arglist[][255], int *argcount)
{   
    int number = 0;
    int i = 0;
    while(1){
        if(buf[i] == '\0'){
            break;
        }
        else if(buf[i] != ' '){
            arglist[*argcount][number] = buf[i];
            number++;
        } 
        else{
            arglist[*argcount][number] = '\0';
            number = 0;
            *argcount = *argcount + 1;           //*argcount 为下标
         }
        i++;
    }
}

//执行输入
void argdo(int argcount, char arglist[][255]){
    char *arg[argcount+1];
    int wrong = 0;
    int how = 0;
    int background = 0;
    int fd;
    int i;
    int status;
    char path[100];   //各种无法清空path的缓存,有八阿哥。
    char *argn[argcount+1];
    pid_t pid;

    for(i = 0; i <= argcount ; i++){       //准备execvp的第二个参数
        arg[i] = arglist[i];
    }
    arg[i] = NULL;

    for(i = 0; i <= argcount; i++){
        if(strcmp(arg[i], "&") == 0){
            if(i == (argcount - 1)){
                background = 1;
                arg[argcount-1] = NULL;
                break;
            }
            else{
                err("too many '&'", __LINE__);
                return;
            }
        }      
    }

    for(i = 0; arg[i] != NULL; i++){
        if(strcmp(arg[i], ">") == 0){
            wrong++;
            how = out;
            if(arg[i+1] == NULL){
                wrong++;
            }
        }
        else if(strcmp(arg[i], "<") == 0){
            wrong++;
            how = in;
            if(arg[i+1] == NULL){
                wrong++;
            }
        }
        else if(strcmp(arg[i], "|") == 0){
            wrong++;
            how = pipe;
            if(arg[i+1] == NULL){
                wrong++;
            }
            else if(i == 0){
                wrong++;
            }
        }
    }

    if(wrong > 1){            
        err("too many arg", __LINE__);
    }
    pid = fork();
    if(pid < 0){
        err("fork error", __LINE__);
    }
    switch(how){
        case 0:{
            if(pid == 0){
                if( !right(arg[0]) ){
                //    perror("wrong arg");
                    exit(0);
                }
                execvp(arg[0], arg);
                exit(0);
            }
        }
        break;
        case 1:{
            for(i = 0; arg[i] != NULL; i++){
                if(strcmp(arg[i], ">") == 0){
                    strcpy(path, arg[i+1]);
                    arg[i] = NULL;
                }
            }

            if(pid == 0){
                if( !right(arg[0]) ){
                    err("wrong arg", __LINE__);
                }
                printf("%s\n",path);
                fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644);
                if(fd < 0){
                    err("open faild", __LINE__);
                }
                dup2(fd, 1);  //通过dup2实现标准输出
                execvp(arg[0], arg);
            }
        }
        break;
        case  2:{
            for(i = 0; arg[i] != NULL; i++){
                if(strcmp(arg[i], "<") == 0){
                    strcpy(path, arg[i+1]);
                    arg[i] = NULL;
                }
            }
            if(pid == 0){
                if( !right(arg[0]) ){
                    err("wrong arg", __LINE__);
                }
                fd = open(path, O_RDONLY);
                if(fd < 0){
                    err("open faild", __LINE__);
                }
                dup2(fd, 0);
                execvp(arg[0], arg);
                exit(0);
            }
        }
    break;
case 3:{
    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++){  //管道命令数组
                argn[j-i-1] = arg[j];    
            }
            argn[j-1-i] = NULL;
            break;
        }
    }
    if(pid == 0){
        argpipe(argn, arg);
    }
}
break;
        default:
            break;
    }//switch

    if(background == 1){     //后台运行父进程不管子进程直接返回
        return ;
    }
    if(waitpid(pid, &status, 0) == -1){  //他爸等他娃结束
        err("wait for chil error", __LINE__);
    }
    }

/******************主函数***********************/

int main(int argc,char *argv[]){
    char *buf;
    int argcount = 0, i;
    char arglist[100][255];
    char **arg = NULL;

    buf = (char *)malloc(255);
    if(buf == NULL){
        err("malloc", __LINE__);
    }

    while(1){
        memset(buf, 0 ,256);
        printf("my_shell$$");
        arginput(buf);
        if(strcmp(buf, "exit") == 0 || strcmp(buf, "logout") == 0)
        {
            break;
        }
        for(i = 0; i < 100; i++){
            arglist[i][0] = '\0';
        }
        argcount = 0;
        argexplain(buf, arglist, &argcount);
        argdo(argcount, arglist);
    }
    if(buf != NULL){
        free(buf);
        buf = NULL;
    }

    return 0;
}

总结:

参考了课本,对于重定向,管道的概念不是很清晰,程序的布局把握的不好,二级指针的运用不是很熟练。

问题:

很多。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值