contributed by < robertlin0401
>
linux2021
TODO: 此處補上本程式的功能、設計考量,和實作議題,在實際逐行分析程式碼之前。
一如所有事物的解說,應從高階總覽到個別子系統模組的順序。
:notes: jserv
{command} {argument list}
的命令>>
(append), 2>
(導向到 stderr), &
(背景執行) 等語法retval
為系統呼叫之回傳值,若為負值則表示有錯誤,須進行處理
chdir
, fork
, open
, creat
, execvp
?
符號告知使用者錯誤發生prompt
函式生成命令列起始符號run
函式解析並執行命令buf
內,值得一提的是
buf[1]
的位置)開始儲存echo hello world
,則儲存方式如下圖所示
run
函式執行前,會將指向 buf
開頭之指標移到該命令之結尾字元的下一個位址
echo hello world
為例,其結果如下圖所示
以下分為數個部分說明
v
為長度 99 的字元指標的陣列,u
則為指向陣列 v
的最後一個空間(v[98]
的位置)的指標is_delim
成立
|
),此時的處理為離開迴圈受限於 pipe 的機制,若前方的命令未執行完成並產生輸出,後方的命令無法完成執行
節錄自 pipe(7) — Linux manual page:
If a process attempts to read from an empty pipe, then read(2) will block until data is available.
is_special
不成立
u
所指向的位置的前一個位置echo hello world
為例,則處理過程如下圖所示
v
的最後一個位置之值保留為 0,不會被更動,作為一命令之 argument list 的結尾標記,詳見這裡is_redir
成立
<
或 >
),此時的處理為記錄欲重新導向的路徑u
所指向的字元指標所指向的字串即為欲重新導向的路徑redir_stdin
或 resir_stdout
後,便執行 u++
,使後續解析的命令將其覆蓋掉,可視為將其指標從陣列 v
中移除v
(即指向 v[0]
的指標)與 u
(原本為指向 v[98]
的指標)之差,若正好為 98 則表示 u
在該次解析前後一致,故可將其視為一個空命令u
所指向的字元指標所指向的字串為 cd
,則 u[1]
便應是欲切換的路徑cd
為一 builtin command,故直接使用系統呼叫 chdir(u[1])
來實現
節錄自 GNU bash 手冊內容:
Builtin commands are contained within the shell itself. When the name of a builtin command is used as the first word of a simple command, the shell executes the command directly, without invoking another program.
c
所指向的空間仍有內容,則代表是因為遇到 pipe 符號而離開迴圈的pipe
系統呼叫來建立一個 pipe,並將其 read、write end 的 file descriptors 分別記錄在整數變數 pipefds[0]
與 pipefds[1]
中fork
系統呼叫建立子行程 (process),負責執行該輪解析出來的命令,此作法為模擬非 builtin command 的行為。父行程則在命令未解析完的狀況(即存在 pipe 的狀況),遞迴呼叫 run
來繼續解析run
來繼續解析命令,須將先前建立的 pipe 的 write end file descriptor 傳入,使前方命令的輸出寫入 pipe 中的 buffer,作為後方命令的輸入dup2
系統呼叫,將原本代表 stdin 的 file descriptor,改寫成代表先前建立的 pipe 的 read end,使其能夠讀取前方命令的輸出
節錄自 dup(2) - Linux manual page:
The file descriptor
newfd
is adjusted so that it now refers to the same open file description asoldfd
.
<
),則關閉 file decriptor 為 0 者(stdin 或先前建立的 pipe 的 read end),並使用 open
系統呼叫開啟指定檔案,使其 file descriptor 成為 0,因此被當作新的輸入位置run
時有傳入 file descriptor,則將 stdout 以 dup2
系統呼叫做更改>
),則關閉 file decriptor 為 1 者(stdout、先前建立的 pipe 的 write end 或其他檔案位置),並使用 creat
系統呼叫開啟指定檔案。其中,438
為檔案 mode,轉換為二進位為 110110110
,表示對所有使用者而言此檔案可讀可寫用八進位 (對! C 語言內建八進位就為了檔案權限的描述) 來解讀上述數值的作用。見: CHMOD Calculator
:notes: jserv
更新:
438
為檔案 mode(以十進位表示),將其轉換為八進位為 666
execvp
系統呼叫執行當前指令,而若系統呼叫出錯亦將此行程終止
節錄自 exec(3) — Linux manual page:
The
char *const argv[]
argument is an array of pointers to null-terminated strings that represent the argument list available to the new program.
The first argument, by convention, should point to the filename associated with the file being executed. The array of pointers must be terminated by a null pointer.
isatty(0)
判斷是否有做輸入重新導向,若有,則無須輸出如命令列起始符號等資訊至螢幕
output_class
說明
tab
鍵自動補其功能與 ↑
、↓
鍵瀏覽命令輸入歷史紀錄功能