A simple shell.

Source: Internet
Author: User

Recently, follow the MIT operating system engineering Course (6.828/fall 2014) to write a simple operating system from scratch.

Job 1 of the first lesson is to write a simple shell that can run the command and Support redirection (' > ', ' < ') and pipe (' | '), but not script programming.

The source code of the course has already realized the parameter analysis

1 struct cmd * parsecmd (char *s);

The function will contain ' > '/' < ' and ' | ' according to the command in each line Returns a different CMD structure:

1 structcmd {2     inttype;3 };4 5 structExecCmd {6     inttype;7     Char*Argv[maxargs];8 };9 Ten structRedircmd { One     inttype; A     structCMD *cmd; -     Char*file; -     intmode; the     intFD; - }; -  - structPipecmd { +     inttype; -     structCMD *Left ; +     structCMD *Right ; A};

Although the C language does not natively support object-oriented technology, it can still achieve a certain object-oriented effect by careful pointer manipulation.

The Parsecmd () function creates 3 kinds of cmd:execcmd, pipecmd, or Redircmd. But how to return what kind of cmd can be identified by the caller? Notice that the first member variable of the 3 cmd is all int type , and that the type value of the 3 cmd is different ("', ' > '/' < ', ' | '), which is intentional. Parsecmd will force the 3 cmd pointers (pointers to specific objects) into (pointers to the struct cmd* base class), and then the caller will determine what kind of cmd to use based on the type value, and then cast it back.

The content of the job is to runcmd() implement 3 types of CMD processing code in:

1 void2Runcmd (structCMD *cmd)3 {4   intp[2], R;5   structExecCmd *Ecmd;6   structPipecmd *Pcmd;7   structRedircmd *Rcmd;8 9   if(cmd = =0)TenExit0); One  A   Switch(cmd->type) { -   default: -fprintf (stderr,"Unknown runcmd\n"); theExit (-1); -  -    Case ' ': -Ecmd = (structexeccmd*) cmd; +     if(ecmd->argv[0] ==0) -Exit0); +fprintf (stderr,"exec not implemented\n"); A     //Your code here ... at      Break; -  -    Case '>': -    Case '<': -Rcmd = (structredircmd*) cmd; -fprintf (stderr,"redir not implemented\n"); in     //Your code here ... -Runcmd (rcmd->cmd); to      Break; +  -    Case '|': thePcmd = (structpipecmd*) cmd; *fprintf (stderr,"Pipe not implemented\n"); $     //Your code here ...Panax Notoginseng      Break; -   }     theExit0); +}

The 1th type , there is no redirection or a single command of the pipeline. You only need to invoke the execvp() replacement executable binary.

1    Case ' ':2Ecmd = (structexeccmd*) cmd;3     if(ecmd->argv[0] ==0)4Exit0);5     if(EXECVP (ecmd->argv[0], ecmd->argv) = =-1)//failed return-1, successfully returned 06Perror ("EXEC Error");7      Break;

The effect is as follows:

1 [email protected]:~/src/6.828$./26.828$ ls3  File1  file2  mysh  sh.c  tags  t.sh46.828

The 2nd type , the command that supports redirection, for example echo "hello, world!" > txt . This requires close()/open() the help of the features. Each process call to open () returns the FD that is always currently available for the smallest FD. Therefore, if you are redirecting the standard input, you need to turn off the standard input (FD is 0), then open the file, and if you are redirecting the standard output, you need to first close the standard output (FD is 1).

1    Case '>':2    Case '<':3Rcmd = (structredircmd*) cmd;4     if(Close (RCMD-&GT;FD) <0) {5Perror ("Close Error");6Exit (-1);7     }   8     if(Rcmd->mode & O_creat) {//If you are redirecting output, you also need to create a new output file9         if(Open (Rcmd->file, Rcmd->mode, S_IRUSR | S_IWUSR) <0) {TenPerror ("Open File Error"); OneExit (-1); A         }    -     }    -     Else if(Open (Rcmd->file, Rcmd->mode) <0) { thePerror ("Open File Error"); -Exit (-1); -     }    -Runcmd (rcmd->cmd); +      Break;

The effect is as follows:

1 6.828 " Hello, world!. " > txt26.828$ cat txt3"Hello, world ! " 4 6.828$

The 3rd type of command that supports pipelines, for example ls | sort | uniq | wc . This requires a new process to handle different cmd, and a pipe () is required to communicate between parent and child processes. It is important to note that the first command is executed by the parent process or by a child process. In the main() parent process, P0 loops through the standard input, and each time a line is read into a sub-process P1 to process the command and wait for the child process P2 to exit and resume looping.

So, here, if the parent process P1 executes the ls command, it will exit when it writes the data to the pipe, which will result in the result that the main process has been waiting until the P1 process exits and will print out 6.828$ to accept the new input, but the P2 process has not finished executing. Its output will be after the main process output 6.828$ . Therefore, the child process P2 is required to execute the first command, and then if there is still a pipeline, the P3 subprocess executes the second command, and finally the P1 process executes the last command. The main process will continue with the next loop only after P1 executes the last command exit.

1   Case '|':2Pcmd = (structpipecmd*) cmd;3     if(pipe (p)) {4Perror ("Create pipe Error");5Exit (-1);6     }   7     if(Fork1 () >0) {8         //Parent9Close0);TenClose (p[1]); One         if(DUP (p[0]) <0) APerror ("DUP"); -Runcmd (pcmd->Right ); -     } theClose1); -Close (p[0]); -     if(DUP (p[1]) <0) -Perror ("DUP"); +Runcmd (pcmd->Left ); -      Break;

The effect is as follows:

1 6.828$ ls | Sort | Uniq | WC 2       7       7       $ 3 6.828$

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

A simple shell.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.