00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <sys/types.h>
00039 #include <sys/wait.h>
00040 #include <assert.h>
00041 #include <unistd.h>
00042 #include <stdlib.h>
00043 #include <stdio.h>
00044 #include <string.h>
00045 #include <limits.h>
00046 #include <errno.h>
00047 #include <err.h>
00048
00049 #ifdef HOST
00050 #include "hostcompat.h"
00051 #endif
00052
00053 #ifndef NARG_MAX
00054
00055 #define NARG_MAX 1024
00056 #endif
00057
00058
00059 #if ARG_MAX > 4096
00060 #define CMDLINE_MAX 4096
00061 #else
00062 #define CMDLINE_MAX ARG_MAX
00063 #endif
00064
00065
00066 static int timing = 0;
00067
00068
00069 #define MAXBG 128
00070 static pid_t bgpids[MAXBG];
00071
00072
00073
00074
00075
00076 static
00077 int
00078 can_bg(void)
00079 {
00080 int i;
00081
00082 for (i = 0; i < MAXBG; i++) {
00083 if (bgpids[i] == 0) {
00084 return 1;
00085 }
00086 }
00087
00088 return 0;
00089 }
00090
00091
00092
00093
00094
00095
00096 static
00097 void
00098 remember_bg(pid_t pid)
00099 {
00100 int i;
00101 for (i = 0; i < MAXBG; i++) {
00102 if (bgpids[i] == 0) {
00103 bgpids[i] = pid;
00104 return;
00105 }
00106 }
00107 assert(0);
00108 }
00109
00110
00111
00112
00113
00114 static
00115 void
00116 printstatus(int status)
00117 {
00118 if (WIFEXITED(status)) {
00119 printf("Exit %d", WEXITSTATUS(status));
00120 }
00121 else if (WIFSIGNALED(status) && WCOREDUMP(status)) {
00122 printf("Signal %d (core dumped)", WTERMSIG(status));
00123 }
00124 else if (WIFSIGNALED(status)) {
00125 printf("Signal %d", WTERMSIG(status));
00126 }
00127 else if (WIFSTOPPED(status)) {
00128 printf("Stopped on signal %d", WSTOPSIG(status));
00129 }
00130 else {
00131 printf("Invalid status code %d", status);
00132 }
00133 }
00134
00135
00136
00137
00138
00139 static
00140 void
00141 dowait(pid_t pid)
00142 {
00143 int status;
00144 if (waitpid(pid, &status, 0)<0) {
00145 warn("pid %d", pid);
00146 }
00147 else {
00148 printf("pid %d: ", pid);
00149 printstatus(status);
00150 printf("\n");
00151 }
00152 }
00153
00154 #ifdef WNOHANG
00155
00156
00157
00158
00159 static
00160 int
00161 dowaitpoll(pid_t pid)
00162 {
00163 int status;
00164 pid_t result;
00165 result = waitpid(pid, &status, WNOHANG);
00166 if (result<0) {
00167 warn("pid %d", pid);
00168 }
00169 else if (result!=0) {
00170 printf("pid %d: ", pid);
00171 printstatus(status);
00172 printf("\n");
00173 return 1;
00174 }
00175 return 0;
00176 }
00177
00178
00179
00180
00181
00182 static
00183 void
00184 waitpoll(void)
00185 {
00186 int i;
00187 for (i=0; i < MAXBG; i++) {
00188 if (bgpids[i] != 0) {
00189 if (dowaitpoll(bgpids[i])) {
00190 bgpids[i] = 0;
00191 }
00192 }
00193 }
00194 }
00195 #endif
00196
00197
00198
00199
00200
00201
00202
00203 static
00204 int
00205 cmd_wait(int ac, char *av[])
00206 {
00207 int i;
00208 pid_t pid;
00209
00210 if (ac == 2) {
00211 pid = atoi(av[1]);
00212 dowait(pid);
00213 for (i = 0; i < MAXBG; i++) {
00214 if (bgpids[i]==pid) {
00215 bgpids[i] = 0;
00216 }
00217 }
00218 return 0;
00219 }
00220 else if (ac == 1) {
00221 for (i=0; i < MAXBG; i++) {
00222 if (bgpids[i] != 0) {
00223 dowait(bgpids[i]);
00224 bgpids[i] = 0;
00225 }
00226 }
00227 return 0;
00228 }
00229 printf("Usage: wait [pid]\n");
00230 return 1;
00231 }
00232
00233
00234
00235
00236
00237
00238 static
00239 int
00240 cmd_chdir(int ac, char *av[])
00241 {
00242 if (ac == 2) {
00243 if (chdir(av[1])) {
00244 warn("chdir");
00245 return 1;
00246 }
00247 return 0;
00248 }
00249 printf("Usage: chdir dir\n");
00250 return 1;
00251 }
00252
00253
00254
00255
00256
00257
00258 static
00259 int
00260 cmd_exit(int ac, char *av[])
00261 {
00262 int code;
00263
00264 if (ac == 1) {
00265 code = 0;
00266 }
00267 else if (ac == 2) {
00268 code = atoi(av[1]);
00269 }
00270 else {
00271 printf("Usage: exit [code]\n");
00272 return 1;
00273 }
00274
00275 exit(code);
00276
00277 return 0;
00278 }
00279
00280
00281
00282
00283
00284 static struct {
00285 const char *name;
00286 int (*func)(int, char **);
00287 } builtins[] = {
00288 { "cd", cmd_chdir },
00289 { "chdir", cmd_chdir },
00290 { "exit", cmd_exit },
00291 { "wait", cmd_wait },
00292 { NULL, NULL }
00293 };
00294
00295
00296
00297
00298
00299
00300
00301
00302 static
00303 int
00304 docommand(char *buf)
00305 {
00306 char *args[NARG_MAX + 1];
00307 int nargs, i;
00308 char *s;
00309 pid_t pid;
00310 int status;
00311 int bg=0;
00312 time_t startsecs, endsecs;
00313 unsigned long startnsecs, endnsecs;
00314
00315 nargs = 0;
00316 for (s = strtok(buf, " \t\r\n"); s; s = strtok(NULL, " \t\r\n")) {
00317 if (nargs >= NARG_MAX) {
00318 printf("%s: Too many arguments "
00319 "(exceeds system limit)\n",
00320 args[0]);
00321 return 1;
00322 }
00323 args[nargs++] = s;
00324 }
00325 args[nargs] = NULL;
00326
00327 if (nargs==0) {
00328
00329 return 0;
00330 }
00331
00332 for (i=0; builtins[i].name; i++) {
00333 if (!strcmp(builtins[i].name, args[0])) {
00334 return builtins[i].func(nargs, args);
00335 }
00336 }
00337
00338
00339
00340 if (nargs > 0 && !strcmp(args[nargs-1], "&")) {
00341
00342 if (!can_bg()) {
00343 printf("%s: Too many background jobs; wait for "
00344 "some to finish before starting more\n",
00345 args[0]);
00346 return -1;
00347 }
00348 nargs--;
00349 args[nargs] = NULL;
00350 bg = 1;
00351 }
00352
00353 if (timing) {
00354 __time(&startsecs, &startnsecs);
00355 }
00356
00357 pid = fork();
00358 switch (pid) {
00359 case -1:
00360
00361 warn("fork");
00362 return _MKWAIT_EXIT(255);
00363 case 0:
00364
00365 execv(args[0], args);
00366 warn("%s", args[0]);
00367
00368
00369
00370
00371
00372
00373
00374 _exit(1);
00375 default:
00376 break;
00377 }
00378
00379
00380 if (bg) {
00381
00382 remember_bg(pid);
00383 printf("[%d] %s ... &\n", pid, args[0]);
00384 return 0;
00385 }
00386
00387 if (waitpid(pid, &status, 0) < 0) {
00388 warn("waitpid");
00389 status = -1;
00390 }
00391
00392 if (timing) {
00393 __time(&endsecs, &endnsecs);
00394 if (endnsecs < startnsecs) {
00395 endnsecs += 1000000000;
00396 endsecs--;
00397 }
00398 endnsecs -= startnsecs;
00399 endsecs -= startsecs;
00400 warnx("subprocess time: %lu.%09lu seconds",
00401 (unsigned long) endsecs, (unsigned long) endnsecs);
00402 }
00403
00404 return status;
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 static
00418 void
00419 getcmd(char *buf, size_t len)
00420 {
00421 size_t pos = 0;
00422 int done=0, ch;
00423
00424
00425
00426
00427
00428 while (!done) {
00429 ch = getchar();
00430 if ((ch == '\b' || ch == 127) && pos > 0) {
00431 putchar('\b');
00432 putchar(' ');
00433 putchar('\b');
00434 pos--;
00435 }
00436 else if (ch == '\r' || ch == '\n') {
00437 putchar('\r');
00438 putchar('\n');
00439 done = 1;
00440 }
00441 else if (ch >= 32 && ch < 127 && pos < len-1) {
00442 buf[pos++] = ch;
00443 putchar(ch);
00444 }
00445 else {
00446
00447 putchar('\a');
00448 }
00449 }
00450 buf[pos] = 0;
00451 }
00452
00453
00454
00455
00456
00457
00458
00459 static
00460 void
00461 interactive(void)
00462 {
00463 char buf[CMDLINE_MAX];
00464 int status;
00465
00466 while (1) {
00467 printf("OS/161$ ");
00468 getcmd(buf, sizeof(buf));
00469 status = docommand(buf);
00470 if (status) {
00471 printstatus(status);
00472 printf("\n");
00473 }
00474 #ifdef WNOHANG
00475 waitpoll();
00476 #endif
00477 }
00478 }
00479
00480 static
00481 void
00482 check_timing(void)
00483 {
00484 time_t secs;
00485 unsigned long nsecs;
00486 if (__time(&secs, &nsecs) != -1) {
00487 timing = 1;
00488 warnx("Timing enabled.");
00489 }
00490 }
00491
00492
00493
00494
00495
00496
00497 int
00498 main(int argc, char *argv[])
00499 {
00500 #ifdef HOST
00501 hostcompat_init(argc, argv);
00502 #endif
00503 check_timing();
00504
00505
00506
00507
00508
00509 if (argc == 0 || argc == 1) {
00510 interactive();
00511 }
00512 else if (argc == 3 && !strcmp(argv[1], "-c")) {
00513 return docommand(argv[2]);
00514 }
00515 else {
00516 errx(1, "Usage: sh [-c command]");
00517 }
00518 return 0;
00519 }