1
本題目檢驗學員對 lab0 作業的認知,主要是命令直譯器的實作
考慮一個小型 Unix shell 風格的實作,具備以下能力:
vim
, echo hello world
, uname -a
等等ls /dev | wc -l
hello > x
再執行 cat < x | grep hello
,預期可見 hello
字樣這個 Unix shell 風格實作的程式碼如下: (picosh.c
)
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
/* Display prompt */
static void prompt()
{
write(2, "$ ", 2);
}
/* Display error message, optionally - exit */
static void fatal(int retval, int leave)
{
if (retval >= 0)
return;
write(2, "?\n", 2);
if (leave)
exit(1);
}
/* Helper functions to detect token class */
static inline int is_delim(int c)
{
return c == 0 || c == '|';
}
static inline int is_redir(int c)
{
return c == '>' || c == '<';
}
static inline int is_blank(int c)
{
return c == ' ' || c == '\t' || c == '\n';
}
static int is_special(int c)
{
return is_delim(c) || is_redir(c) || is_blank(c);
}
/* Recursively run right-most part of the command line printing output to the
* file descriptor @t
*/
static void run(char *c, int t)
{
char *redir_stdin = NULL, *redir_stdout = NULL;
int pipefds[2] = {0, 0}, outfd = 0;
char *v[99] = {0};
char **u = &v[98]; /* end of words */
for (;;) {
c--;
if (is_delim(*c)) /* if NULL (start of string) or pipe: break */
break;
if (!is_special(*c)) {
c++; /* Copy word of regular chars into previous u */
XXXXX /* 在此提交你的程式碼 */
}
if (is_redir(*c)) { /* If < or > */
if (*c == '<')
redir_stdin = *u;
else
redir_stdout = *u;
if ((u - v) != 98)
u++;
}
}
if ((u - v) == 98) /* empty input */
return;
if (!strcmp(*u, "cd")) { /* built-in command: cd */
fatal(chdir(u[1]), 0);
return; /* actually, should run() again */
}
if (*c) {
pipe(pipefds);
outfd = pipefds[1]; /* write end of the pipe */
}
pid_t pid = fork();
if (pid) { /* Parent or error */
fatal(pid, 1);
if (outfd) {
run(c, outfd); /* parse the rest of the cmdline */
close(outfd); /* close output fd */
close(pipefds[0]); /* close read end of the pipe */
}
wait(0);
return;
}
if (outfd) {
dup2(pipefds[0], 0); /* dup read fd to stdin */
close(pipefds[0]); /* close read fd */
close(outfd); /* close output */
}
if (redir_stdin) {
close(0); /* replace stdin with redir_stdin */
fatal(open(redir_stdin, 0), 1);
}
if (t) {
dup2(t, 1); /* replace stdout with t */
close(t);
}
if (redir_stdout) {
close(1);
fatal(creat(redir_stdout, 438), 1); /* replace stdout with redir */
}
fatal(execvp(*u, u), 1);
}
int main()
{
while (1) {
prompt();
char buf[512] = {0}; /* input buffer */
char *c = buf;
if (!fgets(c + 1, sizeof(buf) - 1, stdin))
exit(0);
for (; *++c;) /* skip to end of line */
;
run(c, 0);
}
return 0;
}
作答時,請列出 static void run(char *c, int t)
到 if ((u - v) == 98) /* empty input */
之間的程式碼,並儘量提供程式碼註解和說明你的考量。
延伸問題:
picosh.c
缺乏對 >>
(append), 2>
(導向到 stderr), &
(背景執行) 等語法的支援,請評估增加以上功能到 picosh.c
的修改幅度picosh.c
,甚至取代 init
行程
注意: 可運用 static linking
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up