XINU
shell.c
Go to the documentation of this file.
1 /* shell.c - shell */
2 
3 #include <xinu.h>
4 #include <stdio.h>
5 #include "shprototypes.h"
6 
7 /************************************************************************/
8 /* Table of Xinu shell commands and the function associated with each */
9 /************************************************************************/
10 const struct cmdent cmdtab[] = {
11  {"argecho", TRUE, xsh_argecho},
12  {"arp", FALSE, xsh_arp},
13  {"cat", FALSE, xsh_cat},
14  {"clear", TRUE, xsh_clear},
15  {"date", FALSE, xsh_date},
16  {"devdump", FALSE, xsh_devdump},
17  {"echo", FALSE, xsh_echo},
18  {"exit", TRUE, xsh_exit},
19  {"help", FALSE, xsh_help},
20  {"kill", TRUE, xsh_kill},
21  {"memdump", FALSE, xsh_memdump},
22  {"memstat", FALSE, xsh_memstat},
23  {"netinfo", FALSE, xsh_netinfo},
24  {"ping", FALSE, xsh_ping},
25  {"ps", FALSE, xsh_ps},
26  {"sleep", FALSE, xsh_sleep},
27  {"udp", FALSE, xsh_udpdump},
28  {"udpecho", FALSE, xsh_udpecho},
29  {"udpeserver", FALSE, xsh_udpeserver},
30  {"uptime", FALSE, xsh_uptime},
31  {"?", FALSE, xsh_help}
32 
33 };
34 
35 uint32 ncmd = sizeof(cmdtab) / sizeof(struct cmdent);
36 
37 /************************************************************************/
38 /* shell - Provide an interactive user interface that executes */
39 /* commands. Each command begins with a command name, has */
40 /* a set of optional arguments, has optional input or */
41 /* output redirection, and an optional specification for */
42 /* background execution (ampersand). The syntax is: */
43 /* */
44 /* command_name [args*] [redirection] [&] */
45 /* */
46 /* Redirection is either or both of: */
47 /* */
48 /* < input_file */
49 /* or */
50 /* > output_file */
51 /* */
52 /************************************************************************/
53 
55  did32 dev /* ID of tty device from which */
56  ) /* to accept commands */
57 {
58  char buf[SHELL_BUFLEN]; /* Input line (large enough for */
59  /* one line from a tty device */
60  int32 len; /* Length of line read */
61  char tokbuf[SHELL_BUFLEN + /* Buffer to hold a set of */
62  SHELL_MAXTOK]; /* Contiguous null-terminated */
63  /* Strings of tokens */
64  int32 tlen; /* Current length of all data */
65  /* in array tokbuf */
66  int32 tok[SHELL_MAXTOK]; /* Index of each token in */
67  /* array tokbuf */
68  int32 toktyp[SHELL_MAXTOK]; /* Type of each token in tokbuf */
69  int32 ntok; /* Number of tokens on line */
70  pid32 child; /* Process ID of spawned child */
71  bool8 backgnd; /* Run command in background? */
72  char *outname, *inname; /* Pointers to strings for file */
73  /* names that follow > and < */
74  did32 stdinput, stdoutput; /* Descriptors for redirected */
75  /* input and output */
76  int32 i; /* Index into array of tokens */
77  int32 j; /* Index into array of commands */
78  int32 msg; /* Message from receive() for */
79  /* child termination */
80  int32 tmparg; /* Address of this var is used */
81  /* when first creating child */
82  /* process, but is replaced */
83  char *src, *cmp; /* Pointers used during name */
84  /* comparison */
85  bool8 diff; /* Was difference found during */
86  /* comparison */
87  char *args[SHELL_MAXTOK]; /* Argument vector passed to */
88  /* builtin commands */
89 
90  /* Print shell banner and startup message */
91 
92  fprintf(dev, "\n\n%s%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
95 
96  fprintf(dev, "%s\n\n", SHELL_STRTMSG);
97 
98  /* Continually prompt the user, read input, and execute command */
99 
100  while (TRUE) {
101 
102  /* Display prompt */
103 
104  fprintf(dev, SHELL_PROMPT);
105 
106  /* Read a command */
107 
108  len = read(dev, buf, sizeof(buf));
109 
110  /* Exit gracefully on end-of-file */
111 
112  if (len == EOF) {
113  break;
114  }
115 
116  /* If line contains only NEWLINE, go to next line */
117 
118  if (len <= 1) {
119  continue;
120  }
121 
122  buf[len] = SH_NEWLINE; /* terminate line */
123 
124  /* Parse input line and divide into tokens */
125 
126  ntok = lexan(buf, len, tokbuf, &tlen, tok, toktyp);
127 
128  /* Handle parsing error */
129 
130  if (ntok == SYSERR) {
131  fprintf(dev,"%s\n", SHELL_SYNERRMSG);
132  continue;
133  }
134 
135  /* If line is empty, go to next input line */
136 
137  if (ntok == 0) {
138  fprintf(dev, "\n");
139  continue;
140  }
141 
142  /* If last token is '&', set background */
143 
144  if (toktyp[ntok-1] == SH_TOK_AMPER) {
145  ntok-- ;
146  tlen-= 2;
147  backgnd = TRUE;
148  } else {
149  backgnd = FALSE;
150  }
151 
152 
153  /* Check for input/output redirection (default is none) */
154 
155  outname = inname = NULL;
156  if ( (ntok >=3) && ( (toktyp[ntok-2] == SH_TOK_LESS)
157  ||(toktyp[ntok-2] == SH_TOK_GREATER))){
158  if (toktyp[ntok-1] != SH_TOK_OTHER) {
159  fprintf(dev,"%s\n", SHELL_SYNERRMSG);
160  continue;
161  }
162  if (toktyp[ntok-2] == SH_TOK_LESS) {
163  inname = &tokbuf[tok[ntok-1]];
164  } else {
165  outname = &tokbuf[tok[ntok-1]];
166  }
167  ntok -= 2;
168  tlen = tok[ntok];
169  }
170 
171 
172  if ( (ntok >=3) && ( (toktyp[ntok-2] == SH_TOK_LESS)
173  ||(toktyp[ntok-2] == SH_TOK_GREATER))){
174  if (toktyp[ntok-1] != SH_TOK_OTHER) {
175  fprintf(dev,"%s\n", SHELL_SYNERRMSG);
176  continue;
177  }
178  if (toktyp[ntok-2] == SH_TOK_LESS) {
179  if (inname != NULL) {
180  fprintf(dev,"%s\n", SHELL_SYNERRMSG);
181  continue;
182  }
183  inname = &tokbuf[tok[ntok-1]];
184  } else {
185  if (outname != NULL) {
186  fprintf(dev,"%s\n", SHELL_SYNERRMSG);
187  continue;
188  }
189  outname = &tokbuf[tok[ntok-1]];
190  }
191  ntok -= 2;
192  tlen = tok[ntok];
193  }
194 
195  /* Verify remaining tokens are type "other" */
196 
197  for (i=0; i<ntok; i++) {
198  if (toktyp[i] != SH_TOK_OTHER) {
199  break;
200  }
201  }
202  if ((ntok == 0) || (i < ntok)) {
203  fprintf(dev, SHELL_SYNERRMSG);
204  continue;
205  }
206 
207  stdinput = stdoutput = dev;
208 
209  /* Lookup first token in the command table */
210 
211  for (j = 0; j < ncmd; j++) {
212  src = cmdtab[j].cname;
213  cmp = tokbuf;
214  diff = FALSE;
215  while (*src != NULLCH) {
216  if (*cmp != *src) {
217  diff = TRUE;
218  break;
219  }
220  src++;
221  cmp++;
222  }
223  if (diff || (*cmp != NULLCH)) {
224  continue;
225  } else {
226  break;
227  }
228  }
229 
230  /* Handle command not found */
231 
232  if (j >= ncmd) {
233  fprintf(dev, "command %s not found\n", tokbuf);
234  continue;
235  }
236 
237  /* Handle built-in command */
238 
239  if (cmdtab[j].cbuiltin) { /* No background or redirect. */
240  if (inname != NULL || outname != NULL || backgnd){
241  fprintf(dev, SHELL_BGERRMSG);
242  continue;
243  } else {
244  /* Set up arg vector for call */
245 
246  for (i=0; i<ntok; i++) {
247  args[i] = &tokbuf[tok[i]];
248  }
249 
250  /* Call builtin shell function */
251 
252  if ((*cmdtab[j].cfunc)(ntok, args)
253  == SHELL_EXIT) {
254  break;
255  }
256  }
257  continue;
258  }
259 
260  /* Open files and redirect I/O if specified */
261 
262  if (inname != NULL) {
263  stdinput = open(NAMESPACE,inname,"ro");
264  if (stdinput == SYSERR) {
265  fprintf(dev, SHELL_INERRMSG, inname);
266  continue;
267  }
268  }
269  if (outname != NULL) {
270  stdoutput = open(NAMESPACE,outname,"w");
271  if (stdoutput == SYSERR) {
272  fprintf(dev, SHELL_OUTERRMSG, outname);
273  continue;
274  } else {
275  control(stdoutput, F_CTL_TRUNC, 0, 0);
276  }
277  }
278 
279  /* Spawn child thread for non-built-in commands */
280 
281  child = create(cmdtab[j].cfunc,
283  cmdtab[j].cname, 2, ntok, &tmparg);
284 
285  /* If creation or argument copy fails, report error */
286 
287  if ((child == SYSERR) ||
288  (addargs(child, ntok, tok, tlen, tokbuf, &tmparg)
289  == SYSERR) ) {
290  fprintf(dev, SHELL_CREATMSG);
291  continue;
292  }
293 
294  /* Set stdinput and stdoutput in child to redirect I/O */
295 
296  proctab[child].prdesc[0] = stdinput;
297  proctab[child].prdesc[1] = stdoutput;
298 
299  msg = recvclr();
300  resume(child);
301  if (! backgnd) {
302  msg = receive();
303  while (msg != child) {
304  msg = receive();
305  }
306  }
307  }
308 
309  /* Terminate the shell process by returning from the top level */
310 
311  fprintf(dev,SHELL_EXITMSG);
312  return OK;
313 }
process shell(did32 dev)
Definition: shell.c:54
#define NULL
連結リスト用のNULLポインタ
Definition: kernel.h:68
#define F_CTL_TRUNC
ファイルを切り捨てる。
Definition: file.h:23
shellcmd xsh_ping(int32, char *[])
Definition: xsh_ping.c:11
shellcmd xsh_cat(int32, char *[])
Definition: xsh_cat.c:11
#define SHELL_EXITMSG
XINUシェル終了時のメッセージ
Definition: shell.h:43
#define SH_TOK_GREATER
大なり&#39;>&#39;トークン
Definition: shell.h:79
shellcmd xsh_kill(int32, char *[])
Definition: xsh_kill.c:11
全てのシステムヘッダファイルをインクルードする。
#define SYSERR
処理が失敗した場合
Definition: kernel.h:79
shellcmd xsh_sleep(int32, char *[])
Definition: xsh_sleep.c:11
shellcmd xsh_echo(int32, char *[])
STDOUT(標準出力)に引数に指定した文字列を出力する。
Definition: xsh_echo.c:15
#define SHELL_BAN5
シェル起動時のバナー その5
Definition: shell.h:28
syscall read(did32, char *, uint32)
Definition: read.c:9
bool8 cbuiltin
ビルトインコマンドかどうか
Definition: shell.h:102
#define OK
処理が成功した場合
Definition: kernel.h:77
#define EOF
ファイルの終端(End of File)に達した場合(読み込み処理に用いる)
Definition: kernel.h:81
#define SHELL_CMDPRIO
コマンドに対するプロセス優先度
Definition: shell.h:15
byte bool8
Boolean値
Definition: kernel.h:36
int32 lexan(char *, int32, char *, int32 *, int32[], int32[])
Definition: lexan.c:10
syscall control(did32, int32, int32, int32)
Definition: control.c:9
umsg32 receive(void)
メッセージの受信を待ち、受信後にreceive()の呼び出し者にメッセージを返す。
Definition: receive.c:17
#define SH_TOK_OTHER
その他(&#39;&&#39;、&#39;<&#39;、&#39;>以外&#39;)のトークン(例:英数字文字列)
Definition: shell.h:81
#define SHELL_INERRMSG
インプットとして用いるファイルが開けなかった場合のエラーメッセージ
Definition: shell.h:49
#define SHELL_BAN0
シェル起動時のバナー その0(文字色を赤くするANSIエスケープシーケンス)
Definition: shell.h:18
#define SHELL_BAN6
シェル起動時のバナー その6
Definition: shell.h:30
#define SHELL_EXIT
XINUシェルを終了させる返り値
Definition: shell.h:88
#define SHELL_BAN7
シェル起動時のバナー その7
Definition: shell.h:32
#define SHELL_CMDSTK
コマンドを実行するプロセスに対するスタックサイズ
Definition: shell.h:11
status addargs(pid32, int32, int32[], int32, char *, void *)
XINUシェルが作成したコマンドプロセスのスタックに引数argv(任意個)のローカルコピーを追加する。 ...
Definition: addargs.c:33
shellcmd xsh_argecho(int32, char *[])
引数を順に表示する。
Definition: xsh_argecho.c:15
char * cname
コマンド名称
Definition: shell.h:100
shellcmd xsh_udpecho(int32, char *[])
Definition: xsh_udpecho.c:14
shellcmd xsh_ps(int32, char *[])
Definition: xsh_ps.c:11
#define FALSE
Boolean False(0)
Definition: kernel.h:63
#define SH_NEWLINE
LF改行コード&#39; &#39;(字句解析時に用いる)
Definition: shell.h:56
#define TRUE
Boolean True(1)
Definition: kernel.h:65
umsg32 recvclr(void)
受信メッセージをクリアし、待機している場合はメッセージを返す。
Definition: recvclr.c:14
#define SHELL_BAN3
シェル起動時のバナー その3
Definition: shell.h:24
#define SHELL_BAN1
シェル起動時のバナー その1
Definition: shell.h:20
shellcmd xsh_clear(int32, char *[])
ディスプレイウィンドウをクリアする(xtermやVT100を想定している)
Definition: xsh_clear.c:18
#define SHELL_MAXTOK
一行あたりの最大トークン数
Definition: shell.h:9
shellcmd xsh_memdump(int32, char *[])
Definition: xsh_memdump.c:15
#define SHELL_PROMPT
コマンドプロンプト
Definition: shell.h:39
shellcmd xsh_memstat(int32, char *[])
Definition: xsh_memstat.c:14
int16 prdesc[NDESC]
プロセス用のデバイスディスクリプタ
Definition: process.h:108
int int32
符号あり32ビット整数(int)
Definition: kernel.h:11
shellcmd xsh_date(int32, char *[])
Definition: xsh_date.c:11
int32 did32
デバイスID
Definition: kernel.h:28
pri16 resume(pid32)
プロセスを休止状態(サスペンド)からREADY状態に遷移させる。
Definition: resume.c:20
pid32 create(void *, uint32, pri16, char *, uint32,...)
関数の実行を開始するプロセスを作成する。
Definition: create.c:55
shellcmd xsh_udpdump(int32, char *[])
Definition: xsh_udpdump.c:11
shellcmd xsh_devdump(int32, char *[])
Definition: xsh_devdump.c:10
#define SHELL_STRTMSG
Welcomeメッセージ
Definition: shell.h:41
#define SHELL_CREATMSG
コマンド実行時にプロセスを生成できなかった場合のエラーメッセージ
Definition: shell.h:47
struct procent proctab[]
プロセステーブル。
Definition: initialize.c:23
shellcmd xsh_exit(int32, char *[])
exitコマンドとして、シェル終了を引き起こす終了コードを返す。
Definition: xsh_exit.c:17
int32 pid32
プロセスID
Definition: kernel.h:26
#define SHELL_BGERRMSG
I/Oリダイレクトできなかった場合もしくはバックグラウンドのXINUシェルビルトインコマンドエラー用のメッセ...
Definition: shell.h:53
shellcmd xsh_uptime(int32, char *[])
Definition: xsh_uptime.c:11
XINUシェルコマンドテーブルエントリ用の構造体
Definition: shell.h:97
int32 fprintf(int, char *,...)
Definition: fprintf.c:14
shellcmd xsh_udpeserver(int32, char *[])
Definition: xsh_udpserver.c:12
#define SH_TOK_AMPER
アンパサンド&#39;&&#39;トークン
Definition: shell.h:75
syscall open(did32, char *, char *)
Definition: open.c:9
#define SHELL_BAN2
シェル起動時のバナー その2
Definition: shell.h:22
#define SHELL_BAN4
シェル起動時のバナー その4
Definition: shell.h:26
#define NAMESPACE
Definition: conf.h:35
unsigned int uint32
符号なし32ビット整数(unsigned int)
Definition: kernel.h:15
shellcmd xsh_arp(int32, char *[])
Definition: xsh_arp.c:12
#define SHELL_OUTERRMSG
アウトプットとして用いるファイルが開けなかった場合のエラーメッセージ
Definition: shell.h:51
const struct cmdent cmdtab[]
XINUシェルが提供するコマンドを管理する配列
Definition: shell.c:10
int32(* cfunc)(int32, char *[])
コマンドの機能を提供する関数(正確には関数ポインタ)
Definition: shell.h:104
uint32 ncmd
XINUシェルが提供するコマンドの数
Definition: shell.c:35
shellcmd xsh_help(int32, char *[])
Definition: xsh_help.c:11
shellcmd xsh_netinfo(int32, char *[])
Definition: xsh_netinfo.c:12
#define SHELL_SYNERRMSG
シンタックスエラー時のメッセージ
Definition: shell.h:45
#define NULLCH
NULL文字(NULL終端)
Definition: kernel.h:70
#define SHELL_BUFLEN
インプットバッファの長さ
Definition: shell.h:7
int32 process
プロセスの最上位レベル関数 返り値の型
Definition: kernel.h:53
#define SHELL_BAN9
シェル起動時のバナー その9(文字色をデフォルトに戻すANSIエスケープシーケンス)
Definition: shell.h:36
#define SHELL_BAN8
シェル起動時のバナー その8
Definition: shell.h:34
#define SH_TOK_LESS
小なり&#39;<&#39;トークン
Definition: shell.h:77