C语言 实现一个简单的Shell (支持管道和"cd")
2011-09-11 22:15
531 查看
废话不说,直接上代码
shell.h
shell.c
shell.h
/******************************************************** * @author Airead Fan <fgh1987168@gmail.com> * * @date 2011 9月 08 12:44:18 CST * ******************************************************** * after studying C 52 days * * after studying APUE 17 days * ********************************************************/ #ifndef SHELL_H #define SHELL_H #define SHELL_CD 1 #define SHELL_FORK 2 #define SHELL_EMPTY 3 int read_char(char *str); int parse_args(char *args[], char *arg); int isquit(char *args); char *shell_prompt(char *promptbuf); int dealarg(char *arg); int shell_cd(char *args[]); int shell_fork(char *args[]); int get_cmdnum(char *cmd); int mutifork(char *args[]); #endif
shell.c
/******************************************************** * @author Airead Fan <fgh1987168@gmail.com> * * @date 2011 9月 09 20:00:47 CST * ******************************************************** * after studying C 53 days * * after studying APUE 18 days * ********************************************************/ /* * This program implement shell */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #include "shell.h" #define DEBUG 1 #define BUFSIZE 1024 #define CMDNUMBER 100 int main(int argc, char *argv[]) { char arg[BUFSIZE]; ssize_t readbytes; char str_prompt[BUFSIZE + 1]; while(1){ fprintf(stdout, "%s", shell_prompt(str_prompt)); fflush(stdout); //void *memset(void *s, int c, size_t n); memset(arg, 0, sizeof(arg)); //ssize_t read(int fd, void *buf, size_t count); if((readbytes = read(STDIN_FILENO, arg, BUFSIZE)) < 0){ fprintf(stderr, "read failed: %s\n", strerror(errno)); exit(1); } if(arg[readbytes - 1] == '\n'){ /* clear '\n' at end of arg */ arg[readbytes - 1] = '\0'; } if(isquit(arg) == 1){ /* check quit or not */ break; } //int dealarg(char *arg); dealarg(arg); } return 0; } /* * parse args * note that: args and arg shared memory! */ int parse_args(char *args[], char *arg) { char **p; char *q; int ch; int count; p = args; q = arg; count = 0; while(*q != '\0'){ //int read_char(char *arg); while((ch = read_char(q)) == ' '){ /* skip space */ q++; } *p++ = q++; count++; ch = read_char(q); while(ch != ' ' && ch != '\0'){ /* find first space after word */ q++; ch = read_char(q); } if(ch != '\0'){ *q++ = '\0'; ch = read_char(q); } } return count; } /* * filter string */ int read_char(char *str) { char filter[] = " \t\n"; char *p; int flag; /* flag 1 return ' ', 0 return *str */ flag = 0; p = filter; while(*p != '\0'){ if(*str == *p){ flag = 1; break; } p++; } if(flag == 1){ return ' '; }else{ return *str; } } /* * print shell prompt */ char *shell_prompt(char *promptbuf) { char tmpbuf[BUFSIZE + 1]; //void *memset(void *s, int c, size_t n); memset(promptbuf, 0, BUFSIZE + 1); memset(tmpbuf, 0, sizeof(tmpbuf)); //char *getcwd(char *buf, size_t size); if(getcwd(tmpbuf, sizeof(tmpbuf) - 1) == NULL){ fprintf(stderr, "%s:%d: getcwd failed: %s\n", __FILE__, __LINE__, strerror(errno)); exit(1); } //int snprintf(char *str, size_t size, const char *format, ...); snprintf(promptbuf, BUFSIZE, "%s$ ", tmpbuf); return promptbuf; } /* * if args == quit */ int isquit(char *arg) { //int strcmp(const char *s1, const char *s2); if(strcmp(arg, "quit") == 0){ return 1; }else{ return 0; } } /* * Receive message and deal something */ int dealarg(char *arg) { int cmdnum; char *args[CMDNUMBER]; int argnum; //int parse_args(char *args[], char *arg); argnum = parse_args(args, arg); args[argnum] = NULL; #if DEBUG int i; fprintf(stdout, "argnum = %d\n", argnum); for(i = 0; i < argnum; i++){ fprintf(stdout, "[%d]%s\n", i, args[i]); } #endif //int get_cmdnum(char *cmd) cmdnum = get_cmdnum(args[0]); switch(cmdnum){ case SHELL_EMPTY: break; case SHELL_CD: //int shell_cd(char *args[]) shell_cd(args); break; case SHELL_FORK: //int shell_fork(char *args[]) shell_fork(args); break; default: fprintf(stdout, "%s:%d: getcmd failed\n", __FILE__, __LINE__); break; } return 0; } /* * fork and called exec */ int shell_fork(char *args[]) { pid_t pid[CMDNUMBER]; int status; int fork_num; char **p; /* point args */ char *q; /* point *args */ /* get numbers of child process*/ fork_num = 1; p = args; while(*p != NULL){ q = *p; while(*q != '\0'){ if(*q == '|'){ fork_num++; } q++; } p++; } #if DEBUG fprintf(stdout, "fork_num = %d\n", fork_num); #endif /* case: child process number is one */ if(fork_num < 2){ //pid_t fork(void); if((pid[0] = fork()) < 0){ /* error */ perror("fork"); exit(1); }else if(pid[0] == 0){ /* child process */ //int execvp(const char *file, char *const argv[]); if(execvp(args[0], args) < 0){ perror(""); exit(1); } exit(0); } } /* parent process */ //pid_t waitpid(pid_t pid, int *status, int options); if(fork_num < 2){ waitpid(pid[0], &status, 0); }else{ //int mutifork(char *args[]) status = mutifork(args); } return status; } /* * likes shell's cd */ int shell_cd(char *args[]) { char buf[BUFSIZE + 1]; memset(buf, 0, BUFSIZE + 1); if(args[1][0] != '/' && args[1][0] != '.'){ //char *getcwd(char *buf, size_t size); if(getcwd(buf, BUFSIZE) == NULL){ fprintf(stderr, "%s:%d: getcwd failed: %s\n", __FILE__, __LINE__, strerror(errno)); return -1; } strncat(buf, "/", BUFSIZE - strlen(buf)); } //char *strncat(char *dest, const char *src, size_t n); strncat(buf, args[1], BUFSIZE - strlen(buf)); #if DEBUG fprintf(stdout, "%s\n", buf); #endif //int chdir(const char *path); if(chdir(buf) == -1){ fprintf(stderr, "%s:%d: chdir failed: %s\n", __FILE__, __LINE__, strerror(errno)); } return 0; } /* * Change cmd to int, according to shell.h */ int get_cmdnum(char *cmd) { if(cmd == NULL) return SHELL_EMPTY; if(strcmp(cmd, "cd") == 0) return SHELL_CD; return SHELL_FORK; } int mutifork(char *args[]) { int pipefd[CMDNUMBER][2]; pid_t pid[CMDNUMBER]; int i, j; int count; int status; char **arg_child[CMDNUMBER]; char **p; char ***q; /* parse and split args to child arg */ count = 0; p = args; q = arg_child; while(*p != NULL && p != NULL){ *q++ = p; count++; while(*p != NULL && strcmp(*p, "|") != 0){ p++; } if(*p != NULL){ *p++ = NULL; } } *q = NULL; #if DEBUG /* check child args */ fprintf(stdout, "----------------------------------------\n"); fprintf(stdout, "count = %d\n", count); q = arg_child; i = 0; while(*q != NULL){ p = *q++; while(*p != NULL){ fprintf(stdout, "[%d]%s\n", i, *p++); } i++; } #endif /* fork count child process */ for(i = 0; i < count; i++){ /* init pipe file descriptor */ if(pipe(pipefd[i]) < 0){ /* FIXME: excess one */ perror("pipe"); return -1; } /* fork child i */ if((pid[i] = fork()) < 0){ fprintf(stderr, "%s:%d: fork() failed: %s\n", __FILE__, __LINE__, strerror(errno)); return -1; }else if(pid[i] == 0){ /* child i */ //int dup2(int oldfd, int newfd); if(i == 0){ /* the first child */ close(pipefd[i][0]); /* close curr process read */ if(dup2(pipefd[i][1], STDOUT_FILENO) < 0){ perror("dup2 failed"); return -1; } }else if(i == count - 1){ /* the last child */ for(j = 0; j < i - 1; j++){ /* close unuse pipefd */ close(pipefd[j][1]); close(pipefd[j][0]); } close(pipefd[j][1]); /* close prev process end of write */ close(pipefd[i][0]); /* close curr process end of read */ if(dup2(pipefd[j][0], STDIN_FILENO) < 0){ perror("dup2 failed"); return -1; } }else{ for(j = 0; j < i - 1; j++){ /* close unuse pipefd */ close(pipefd[j][1]); close(pipefd[j][0]); } close(pipefd[j][1]); /* close prev process end of write */ close(pipefd[i][0]); /* close curr process end of read */ if(dup2(pipefd[j][0], STDIN_FILENO) < 0){ perror("dup2 failed"); return -1; } if(dup2(pipefd[i][1], STDOUT_FILENO) < 0){ perror("dup2 failed"); return -1; } } //int execvp(const char *file, char *const argv[]); if(execvp(arg_child[i][0], arg_child[i]) < 0){ fprintf(stderr, "%s:%d: fork() failed: %s\n", __FILE__, __LINE__, strerror(errno)); exit(1); } exit(0); /* child process exit */ } } /* parent process */ for(i = 0; i < count; i++){ /* close all pipe file descriptor */ close(pipefd[i][0]); close(pipefd[i][1]); } for(i = 0; i < count; i++){ //pid_t waitpid(pid_t pid, int *status, int options); waitpid(pid[i], &status, 0); if(status != 0){ return status; } } return status; }
相关文章推荐
- 实现一个简单shell(支持重定向)
- 利用线性布局和相对布局实现一个简单的页面并且使应用支持国际化语言
- 你知道的,javascript语言的执行环境是"单线程模式",这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行,因此很多时候需要进行“异步模式”,请列举js异步编程的方法。
- ASP.NET 管道事件与HttpModule一个简单地实现
- 【Linux】实现一个简单的shell
- 一个Go语言接口和多操作系统实现的简单例子
- javascript学习之简单实现jquery的$("div").text()。
- Linux编程实现一个简单的Shell
- go语言实现一个简单的http客户端抓取远程url的方法
- Yii2中把"Home"改成"首页"的方法 【Yii2支持多语言】
- 网站上有一个mp3文件,但是用<a href="my.mp3">下载</a>时,会在播放器里打开,请问我要怎样才能实现点击后下载呢?
- 用HTML+PHP写一个留言板来进行XSS测试&学习 第三篇(简单的过滤标签功能实现&绕过)
- CListCtrlEx:一个支持文件拖放和实时监视的列表控件——用未公开API函数实现Shell实时监视
- JAVA实现一个简单的代数运算语言编译器(四)-- 表达式计算
- [翻译] Effective C++, 3rd Edition, Item 38: 通过 composition(复合)模拟 "has-a"(有一个)或 "is-implemented-in-terms-of"(是根据……实现的)
- 已知字母序列【d, g, e, c, f, b, o, a】,请实现一个函数针对输入的一组字符串 input[] = {"bed", "dog", "dear", "eye"},按照字母顺序排序并打印
- 神奇的sh:管道操作|原理 ,实现一个支持管道操作的grep
- 分形介绍 && 一个简单的Kotch curve实现代码
- C 语言 简单桶排序 算法&实现
- 使用管道实现简单的CMD后门程序,并转化为Shellcode