zoukankan      html  css  js  c++  java
  • UIUC 系统编程 assignment 1 simple shell

    完成了一个简单的shell,完成了assignment提到的所有功能,

    执行非built in 指令,执行built in 指令 1.cd  2. exit  3 !# 类似history !#N 显示最近N条指令。  !3执行历史记录3的命令。

    核心就是fork exec wait 不过纯用c感觉比较烦,资源需要小心管理,难于控制复杂程度,代码也仅仅是完成要求的基本功能,如果加入更多功能代码就更加容易出错,在记录历史和输入的顺序上处理的不太好,当前输入后counter就++了,应该先输入,然后分析命令,然后执行,如果historyf命令出错不加入历史,否则加入历史命令列表,counter++.

    下一步考虑改用c++实现。

     测试如下

    allen:~/study/system_programming/uiuc_assignment/smp1$ ./shell
    Shell(pid=16153)1:
    Child failed to exec: No such file or directory
    Shell(pid=16153)2:
    allen:~/study/system_programming/uiuc_assignment/smp1$ ./shell
    Shell(pid=16159)1:ls
    CS241.txt  Makefile  README.pdf  README.txt  shell  shell2  shell2.c  shell2.cc  shell.c  shell.cc  shell.h  shell.o  smp1.zip svn-commit.tmp TEAM.txt  test
    Shell(pid=16159)2:/bin/ls
    CS241.txt  Makefile  README.pdf  README.txt  shell  shell2  shell2.c  shell2.cc  shell.c  shell.cc  shell.h  shell.o  smp1.zip svn-commit.tmp TEAM.txt  test
    Shell(pid=16159)3:pwd
    /home/allen/study/system_programming/uiuc_assignment/smp1
    Shell(pid=16159)4:cd ..
    Shell(pid=16159)5:pwd
    /home/allen/study/system_programming/uiuc_assignment
    Shell(pid=16159)6:cd smp1
    Shell(pid=16159)7:ls
    CS241.txt  Makefile  README.pdf  README.txt  shell  shell2  shell2.c  shell2.cc  shell.c  shell.cc  shell.h  shell.o  smp1.zip svn-commit.tmp TEAM.txt  test
    Shell(pid=16159)8:ls -l
    总用量 236
    -rwxr-xr-x 1 allen allen   8064 2009-07-14 16:41 CS241.txt
    -rwxr-xr-x 1 allen allen    182 2009-07-17 10:41 Makefile
    -rwxr-xr-x 1 allen allen 119738 2009-07-14 16:41 README.pdf
    -rwxr-xr-x 1 allen allen   7429 2009-07-14 16:41 README.txt
    -rwxr-xr-x 1 allen allen  16764 2009-07-17 17:54 shell
    -rwxr-xr-x 1 allen allen  11764 2009-07-17 12:39 shell2
    -rw-r--r-- 1 allen allen   3727 2009-07-17 12:39 shell2.c
    -rwxr-xr-x 1 allen allen   3197 2009-07-17 11:01 shell2.cc
    -rwxr-xr-x 1 allen allen   8516 2009-07-17 17:54 shell.c
    -rw-r--r-- 1 allen allen   3475 2009-07-16 21:54 shell.cc
    -rw-r--r-- 1 allen allen    943 2009-07-16 22:02 shell.h
    -rw-r--r-- 1 allen allen  11748 2009-07-17 17:54 shell.o
    -rwxr-xr-x 1 allen allen   7296 2009-07-14 16:41 smp1.zip
    -rw-r--r-- 1 allen allen     57 2009-07-15 10:45 svn-commit.tmp
    -rwxr-xr-x 1 allen allen    560 2009-07-14 16:41 TEAM.txt
    drwxr-xr-x 2 allen allen   4096 2009-07-17 11:32 test
    Shell(pid=16159)9:cd shell
    shell is not a directory
    Shell(pid=16159)10:cd dfsdf
    Cannot stat dfsdf: No such file or directory
    Shell(pid=16159)11:!#
     !  1 ls 
     !  2 /bin/ls 
     !  3 pwd 
     !  4 cd .. 
     !  5 pwd 
     !  6 cd smp1 
     !  7 ls 
     !  8 ls -l 
     !  9 cd shell 
     ! 10 cd dfsdf 
     ! 11 !# 
    Shell(pid=16159)12:!#3
     ! 10 cd dfsdf 
     ! 11 !# 
     ! 12 !#3 
    Shell(pid=16159)13:!9
    cd shell 
    shell is not a directory
    Shell(pid=16159)14:!#
     !  1 ls 
     !  2 /bin/ls 
     !  3 pwd 
     !  4 cd .. 
     !  5 pwd 
     !  6 cd smp1 
     !  7 ls 
     !  8 ls -l 
     !  9 cd shell 
     ! 10 cd dfsdf 
     ! 11 !# 
     ! 12 !#3 
     ! 13 cd shell 
     ! 14 !# 
    Shell(pid=16159)15:exit
    allen:~/study/system_programming/uiuc_assignment/smp1$ 

    shell.c

      1 /* SMP1:Simple Shell */
      2 // to do 可以引入vector 管理,vector < vector < char*> > 不要用string因为c api接口问题
      3 /* LIBRARY SECTION */
      4 #include <ctype.h>              /* Character types                       */
      5 #include <stdio.h>              /* Standard buffered input/output        */
      6 #include <stdlib.h>             /* Standard library functions            */
      7 #include <string.h>             /* String operations                     */
      8 #include <sys/types.h>          /* Data types                            */
      9 #include <sys/wait.h>           /* Declarations for waiting              */
     10 #include <unistd.h>             /* Standard symbolic constants and types */
     11 #include <sys/stat.h>           /* wee need stat */
     12 /* DEFINE SECTION */
     13 #define SHELL_BUFFER_SIZE 256   /* Size of the Shell input buffer        */
     14 const int CommandsNum = 10//初始commands_vec 的容量
     15 static int capacity;    //当前commands_vec的最大容量,会根据指令数目超出后自动增加容量每次*2,模拟vector
     16 
     17 static pid_t pid;   //shell 进程id
     18 static int counter; //指令计数,从0开始,当用户输入一个命令,counter++,当前命令应为counter - 1,注意print的时候从1开始
     19 static char ***commands_vec;    //记录所有的命令,commands_vec[0]表示第0个命令,该命令会由多个args构成(空格已去)
     20 
     21 // 初始化,得到进程id,counter置0.. 
     22 void Init() 
     23 {
     24     pid = getpid();
     25     counter = 0;
     26     commands_vec = (char ***) malloc (CommandsNum * sizeof(char **));
     27     capacity = CommandsNum;
     28 }
     29 
     30 //打印命令,所有的args
     31 void EchoArgs(char **args) 
     32 {
     33     while(*args) {
     34         printf("%s "*args);
     35         args++;
     36     }
     37     printf("\n");
     38 }
     39 
     40 //释放一个命令所占的内存资源
     41 void FreeResouce(char **args) 
     42 {
     43     if (!args)
     44         return;
     45     char **arg = args;
     46     while(*arg) {
     47         free(*arg);
     48         *arg = 0;
     49         arg++;
     50     }
     51     free(args);
     52 }
     53 
     54 //是否历史记录的所有命令所占资源
     55 void FreeComandsResouce()
     56 {
     57     int i;
     58     for (i = 0; i < counter; i++) {
     59         FreeResouce((char **)commands_vec[i]);   
     60         commands_vec[i] = NULL;     //do not forget to make it NULL
     61     }
     62     free(commands_vec);
     63     commands_vec = NULL;
     64 }
     65 
     66 //将命令arglist加入命令历史列表中,counter计数+1,如需要增加
     67 //历史记录列表的容量,直接调用realloc更好
     68 void AddHistory(char **arglist) 
     69 {
     70     commands_vec[counter++= arglist; 
     71     if (counter == capacity) {
     72         char ***tmp;
     73         tmp = (char ***) malloc (2 * capacity * sizeof(char **));
     74         int i;
     75         for (i = 0; i < capacity; i++) {
     76             tmp[i] = commands_vec[i];
     77             commands_vec[i] = NULL;
     78         }
     79         //memset(tmp + capacity, NULL, capacity * sizeof(char **));
     80         free(commands_vec);
     81         commands_vec = tmp;
     82         capacity *= 2;
     83     } 
     84 }
     85 
     86 //打印提示信息,接受用户输入的命令,并进行预处理去掉空格存储,
     87 //然后将命指针加入历史记录列表,返回当前命令指针
     88 char** GetInput() 
     89 {
     90     char input[SHELL_BUFFER_SIZE];
     91     //char *arglist[SHELL_BUFFER_SIZE];
     92     char** arglist;
     93     arglist = (char **) malloc(SHELL_BUFFER_SIZE * sizeof(char *));
     94     //memset(arglist, NULL, SHELL_BUFFER_SIZE * sizeof (char *));
     95     int i = 0;
     96     int j = 0;
     97     int start = 0;
     98     char c;
     99     
    100     //打印提示信息
    101     printf("Shell(pid=%d)%d:",pid,counter + 1);
    102 
    103     //接受用户输入command,并且将各个命令参数存储起来,去空格识别
    104     while (i < SHELL_BUFFER_SIZE && (c = getchar()) != '\n') {
    105         if (c == ' ') { 
    106             if (input[i - 1!= ' ') {
    107                 arglist[j] = (char *) malloc(i - start + 1);
    108                 strncpy(arglist[j], input + start, i - start);
    109                 arglist[j][i - start] = '\0';
    110                 j++;
    111                 start = i + 1;
    112             } else {
    113                 start++;
    114             }
    115         }
    116         
    117         input[i++= c;
    118     }
    119     arglist[j] = (char *) malloc(i - start + 1);
    120     strncpy(arglist[j], input + start, i - start);
    121     arglist[j][i - start] = '\0';
    122     j++;
    123     arglist[j] = NULL;  //标志结束
    124 
    125     if (i == SHELL_BUFFER_SIZE) {   //错误处理,输入的command大小要小于256包括空格
    126         while(c = getchar() != '\n')  //需要把剩下的输入数据读完!
    127                 ;
    128         printf("Commands should be withen the size of 256\n");
    129         FreeResouce(arglist);
    130         return NULL;
    131     }
    132 
    133     AddHistory(arglist);
    134 
    135     return arglist;
    136 }
    137 
    138 //通过fork新开子进程执行non built in 命令
    139 //通过主进程wait
    140 void ExcuteNonBuiltinCommand(char **args)
    141 {
    142     pid_t p_id;
    143     p_id = fork();
    144     
    145     if (p_id == -1) {
    146         perror("Failed to fork");
    147         return;
    148     }
    149 
    150     //child code
    151     if (p_id == 0) {   
    152         if (strstr(args[0],"/"))  //如果命令中找到/,则按照绝对路径寻找
    153             execv(args[0],args);
    154         else    //find command from PATH
    155             execvp( args[0], args );
    156         
    157         perror("Child failed to exec");
    158         exit(1);    //注意不要用return 子进程应该结束,即使它失败了,exit(1) not exit(0)
    159     } 
    160 
    161     //parent code p_id != 0
    162     if (wait(NULL) != p_id) {
    163         perror("Parent failed to wait for child");
    164     }
    165 
    166 }
    167 
    168 //打印最近n个命令历史记录
    169 void PrintCommandHistory(int n) {
    170     int i;
    171     for (i = counter - n; i < counter; i++) {
    172         printf(" !%3d ", i + 1);
    173         EchoArgs(commands_vec[i]);
    174     }
    175 }
    176 
    177 // 删除当前命令历史记录,因为按照当前的处理流程,用户输入后命令就被记录
    178 // 对于需要删除不执行并且不记录的命令,需要将其删除
    179 void DeleteCurrentCommand()
    180 {
    181     free(commands_vec[counter - 1]);
    182     commands_vec[counter - 1= NULL;
    183     counter--;
    184 }
    185 
    186 int IsNum(char a)
    187 {
    188     if (a >= '0' && a <= '9')
    189         return 1;
    190     else
    191         return 0;
    192 }
    193 //给定字符串中一个起始一个结束位置,返回所对应的数字大小,只处理正数
    194 //如果出现非数字视为出错则返回-1,调用者确保arg,i, j的正确性
    195 int GetNumFromString(char *arg, int start, int end)
    196 {
    197     int i;
    198     int base = 1;
    199     int sum = 0;
    200     for(i = end; i >= start; i--) {
    201         if(!IsNum(arg[i]))
    202             return -1;
    203         sum += (arg[i] - '0'* base;
    204         base *= 10;
    205     }
    206     return sum;
    207 }
    208 
    209 //执行命令,区别built in 和 non built in
    210 //built in 当前支持 cd, exit, !#, !,
    211 //non built in 调用ExcuteNonBuiltinCommand
    212 void ExcuteCommand(char **args) 
    213 {
    214     if (!args)
    215         return;
    216 
    217     /* built in command */
    218     
    219     /* cd */
    220     char * str = "cd";
    221     if (strcmp(args[0], str) == 0) {
    222        
    223         struct stat info;
    224 
    225         /*if no such file or dir */
    226         if ( stat( args[1] , &info ) == -1 ){ 
    227             fprintf(stderr, "Cannot stat ");
    228             perror(args[1]);
    229             return;
    230         }
    231         if(!S_ISDIR(info.st_mode)) {
    232             fprintf(stderr, "%s is not a directory\n", args[1]);
    233             return;
    234         }
    235         
    236         /*now ok to cd*/
    237         chdir(args[1]);
    238         return;
    239     }
    240     
    241     /* exit */
    242     str = "exit";
    243     if (strcmp(args[0], str) == 0) {
    244         FreeComandsResouce();
    245         exit(0);
    246         return;
    247     }
    248    
    249     /* !#  print history */
    250     int len = strlen(args[0]);
    251     if (args[0][0== '!' && args[0][1== '#') {
    252         
    253         if (len == 2) {
    254             /* !#  print all the history*/
    255             PrintCommandHistory(counter);
    256         }
    257 
    258         /* !#N print the last N commands */
    259         if (len > 2) {
    260             int n = GetNumFromString(args[0], 2, len - 1);
    261             if (n == -1 || n > counter) {
    262                 printf("Not valid\n");
    263                 DeleteCurrentCommand();
    264                 return;
    265             }
    266             PrintCommandHistory(n);
    267         }
    268 
    269         return;
    270     }
    271 
    272     /* !N 执行历史记录标号为N的指令 */
    273     if(args[0][0== '!' && len > 1 && args[0][1!= '#') {
    274         int n = GetNumFromString(args[0], 1, len - 1);
    275         
    276         if (n == -1 || n == 0 || n >= counter) {
    277             printf("Not valid\n");
    278             DeleteCurrentCommand();
    279             return;
    280         }
    281         
    282         DeleteCurrentCommand();
    283         EchoArgs(commands_vec[n - 1]);
    284         AddHistory(commands_vec[n - 1]);
    285         ExcuteCommand(commands_vec[n - 1]);
    286         return;
    287     }
    288     
    289     /* non built in command*/
    290     ExcuteNonBuiltinCommand(args);
    291 }
    292 
    293 
    294 /* MAIN PROCEDURE SECTION */
    295 int main(int argc, char **argv)
    296 {
    297     Init();
    298     while (1) {
    299         char **args = GetInput();
    300         ExcuteCommand(args);
    301         args = NULL;
    302     }
    303     FreeComandsResouce();

    304 /* end main() */ 

  • 相关阅读:
    Linux
    python 鸢尾花数据集报表展示
    python 词云
    毕业设计回顾
    editor.md
    杂记
    垃圾回收器
    杂记
    随笔
    杂记
  • 原文地址:https://www.cnblogs.com/rocketfan/p/1525686.html
Copyright © 2011-2022 走看看