標籤:jos operating system shell
Implement a Shell by yourself -- MIT xv6 shell
這個其實是作為6.828的一個小課堂作業 ...
著重分析構建思想和過程,具體代碼實現去github可以找到.
https://github.com/jasonleaster/MIT_6_828_assignments_2012/blob/homework1/sh.c
----------------------------------- 大家好,我是分割線 -------------------------------------------------------------------
這裡主要實現了基礎的三類命令
實現的"基類" (原諒我用了這個詞)就是struct cmd這個結構體就一個成員,用於記錄命令的類型.
三類, ‘ ‘ 表示可執行程式 ‘|‘ 表示管道命令, ‘<‘ 和‘>‘ 表示重新導向類型.
每一個類型分別繼承基類,派生出對應的三類結構體
struct execcmd
struct redircmd
struct pipecmd
對於可執行命令,主要記錄可執行程式的程式名字還有各種選項參數.所以會有 char* argv[MAXARGS]
對於重新導向命令,主要記錄 cmd 即觸發這個重新導向的程式比方說 ./a.out > tmp.txt
那麼cmd就是記錄的./a.out 重新導向到那個檔案的檔案名稱 char *file指標指向這個檔案名稱.
對於管道, 則主要記錄管道左右兩側的命令
void runcmd(struct cmd * cmd);
這個函數是真正驅動調用實現shell的核心.負責調用系統介面函數 execv(), open(), close(), dup(), pipe()等等一系列函數,來完成我們既定的目標.
作業也就是補全這個函數.
這是個遞迴的函數!很有意思.
你會發現,shell的命令實現居然是遞迴的哈哈
這裡是主函數:
調用getcmd()在標準輸入讀取sizeof(buf)大小的字元,然後,寫入到buf中.
那個 if(buf[0] .... )是判斷你是不是輸入了 cd命令 如果是把buf尾部賦值為0,這樣buf看起來就是儲存的一個字串,
然後調用chdir() 更換當buf+3開始的字串指定的路徑.
接著continue繼續讀取命令啦...
如果你不更換路徑了
我們就fork1()出一個子進程,parent process就一直等待子進程掛掉...等啊等..等啊等..
這個時候,子進程就開始調用parsecmd()去分析你輸入的命令字串咯...
es指標指向字串的末端,確切的說是Null 字元處
然後去調用 parseline(&s, es)
parseline() 看起來太弱了,就是一層簡單的封裝.實際核心函數還是parsepipe
execcmd()返回一個struct cmd()結構體.
同樣的*cmd()函數都會返回一個對應的 *結構體
值得特彆強調好玩的事情是,你會發現這裡 execcmd()返回的是一個 struct cmd* 指標
但是execcmd()函數確實申請的是一個struct execcmd()結構體.那麼問題就來了..怎麼會這樣.
回過頭去觀察四種結構體的之間的關係你就會發現,這裡巧妙之處就在於,他們的第一個成員都是相同的!
返回了一個"基類"指標.
"騷年別鬧~"
Implement a Shell by yourself -- MIT xv6 shell