123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 |
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <assert.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <limits.h>
- #include <errno.h>
- #include <err.h>
- #ifdef HOST
- #include "hostcompat.h"
- #endif
- #ifndef NARG_MAX
- #define NARG_MAX 1024
- #endif
- #if ARG_MAX > 4096
- #define CMDLINE_MAX 4096
- #else
- #define CMDLINE_MAX ARG_MAX
- #endif
- static int timing = 0;
- #define MAXBG 128
- static pid_t bgpids[MAXBG];
- static
- int
- can_bg(void)
- {
- int i;
-
- for (i = 0; i < MAXBG; i++) {
- if (bgpids[i] == 0) {
- return 1;
- }
- }
-
- return 0;
- }
- static
- void
- remember_bg(pid_t pid)
- {
- int i;
- for (i = 0; i < MAXBG; i++) {
- if (bgpids[i] == 0) {
- bgpids[i] = pid;
- return;
- }
- }
- assert(0);
- }
- static
- void
- printstatus(int status)
- {
- if (WIFEXITED(status)) {
- printf("Exit %d", WEXITSTATUS(status));
- }
- else if (WIFSIGNALED(status) && WCOREDUMP(status)) {
- printf("Signal %d (core dumped)", WTERMSIG(status));
- }
- else if (WIFSIGNALED(status)) {
- printf("Signal %d", WTERMSIG(status));
- }
- else if (WIFSTOPPED(status)) {
- printf("Stopped on signal %d", WSTOPSIG(status));
- }
- else {
- printf("Invalid status code %d", status);
- }
- }
- static
- void
- dowait(pid_t pid)
- {
- int status;
- if (waitpid(pid, &status, 0)<0) {
- warn("pid %d", pid);
- }
- else {
- printf("pid %d: ", pid);
- printstatus(status);
- printf("\n");
- }
- }
- #ifdef WNOHANG
- static
- int
- dowaitpoll(pid_t pid)
- {
- int status;
- pid_t result;
- result = waitpid(pid, &status, WNOHANG);
- if (result<0) {
- warn("pid %d", pid);
- }
- else if (result!=0) {
- printf("pid %d: ", pid);
- printstatus(status);
- printf("\n");
- return 1;
- }
- return 0;
- }
- static
- void
- waitpoll(void)
- {
- int i;
- for (i=0; i < MAXBG; i++) {
- if (bgpids[i] != 0) {
- if (dowaitpoll(bgpids[i])) {
- bgpids[i] = 0;
- }
- }
- }
- }
- #endif
- static
- int
- cmd_wait(int ac, char *av[])
- {
- int i;
- pid_t pid;
- if (ac == 2) {
- pid = atoi(av[1]);
- dowait(pid);
- for (i = 0; i < MAXBG; i++) {
- if (bgpids[i]==pid) {
- bgpids[i] = 0;
- }
- }
- return 0;
- }
- else if (ac == 1) {
- for (i=0; i < MAXBG; i++) {
- if (bgpids[i] != 0) {
- dowait(bgpids[i]);
- bgpids[i] = 0;
- }
- }
- return 0;
- }
- printf("Usage: wait [pid]\n");
- return 1;
- }
- static
- int
- cmd_chdir(int ac, char *av[])
- {
- if (ac == 2) {
- if (chdir(av[1])) {
- warn("chdir");
- return 1;
- }
- return 0;
- }
- printf("Usage: chdir dir\n");
- return 1;
- }
- static
- int
- cmd_exit(int ac, char *av[])
- {
- int code;
- if (ac == 1) {
- code = 0;
- }
- else if (ac == 2) {
- code = atoi(av[1]);
- }
- else {
- printf("Usage: exit [code]\n");
- return 1;
- }
-
- exit(code);
-
- return 0;
- }
- static struct {
- const char *name;
- int (*func)(int, char **);
- } builtins[] = {
- { "cd", cmd_chdir },
- { "chdir", cmd_chdir },
- { "exit", cmd_exit },
- { "wait", cmd_wait },
- { NULL, NULL }
- };
- static
- int
- docommand(char *buf)
- {
- char *args[NARG_MAX + 1];
- int nargs, i;
- char *s;
- pid_t pid;
- int status;
- int bg=0;
- time_t startsecs, endsecs;
- unsigned long startnsecs, endnsecs;
- nargs = 0;
- for (s = strtok(buf, " \t\r\n"); s; s = strtok(NULL, " \t\r\n")) {
- if (nargs >= NARG_MAX) {
- printf("%s: Too many arguments "
- "(exceeds system limit)\n",
- args[0]);
- return 1;
- }
- args[nargs++] = s;
- }
- args[nargs] = NULL;
- if (nargs==0) {
-
- return 0;
- }
- for (i=0; builtins[i].name; i++) {
- if (!strcmp(builtins[i].name, args[0])) {
- return builtins[i].func(nargs, args);
- }
- }
-
- if (nargs > 0 && !strcmp(args[nargs-1], "&")) {
-
- if (!can_bg()) {
- printf("%s: Too many background jobs; wait for "
- "some to finish before starting more\n",
- args[0]);
- return -1;
- }
- nargs--;
- args[nargs] = NULL;
- bg = 1;
- }
- if (timing) {
- __time(&startsecs, &startnsecs);
- }
- pid = fork();
- switch (pid) {
- case -1:
-
- warn("fork");
- return _MKWAIT_EXIT(255);
- case 0:
-
- execv(args[0], args);
- warn("%s", args[0]);
-
- _exit(1);
- default:
- break;
- }
-
- if (bg) {
-
- remember_bg(pid);
- printf("[%d] %s ... &\n", pid, args[0]);
- return 0;
- }
- if (waitpid(pid, &status, 0) < 0) {
- warn("waitpid");
- status = -1;
- }
- if (timing) {
- __time(&endsecs, &endnsecs);
- if (endnsecs < startnsecs) {
- endnsecs += 1000000000;
- endsecs--;
- }
- endnsecs -= startnsecs;
- endsecs -= startsecs;
- warnx("subprocess time: %lu.%09lu seconds",
- (unsigned long) endsecs, (unsigned long) endnsecs);
- }
- return status;
- }
- static
- void
- getcmd(char *buf, size_t len)
- {
- size_t pos = 0;
- int done=0, ch;
-
- while (!done) {
- ch = getchar();
- if ((ch == '\b' || ch == 127) && pos > 0) {
- putchar('\b');
- putchar(' ');
- putchar('\b');
- pos--;
- }
- else if (ch == '\r' || ch == '\n') {
- putchar('\r');
- putchar('\n');
- done = 1;
- }
- else if (ch >= 32 && ch < 127 && pos < len-1) {
- buf[pos++] = ch;
- putchar(ch);
- }
- else {
-
- putchar('\a');
- }
- }
- buf[pos] = 0;
- }
- static
- void
- interactive(void)
- {
- char buf[CMDLINE_MAX];
- int status;
- while (1) {
- printf("OS/161$ ");
- getcmd(buf, sizeof(buf));
- status = docommand(buf);
- if (status) {
- printstatus(status);
- printf("\n");
- }
- #ifdef WNOHANG
- waitpoll();
- #endif
- }
- }
- static
- void
- check_timing(void)
- {
- time_t secs;
- unsigned long nsecs;
- if (__time(&secs, &nsecs) != -1) {
- timing = 1;
- warnx("Timing enabled.");
- }
- }
- int
- main(int argc, char *argv[])
- {
- #ifdef HOST
- hostcompat_init(argc, argv);
- #endif
- check_timing();
-
- if (argc == 0 || argc == 1) {
- interactive();
- }
- else if (argc == 3 && !strcmp(argv[1], "-c")) {
- return docommand(argv[2]);
- }
- else {
- errx(1, "Usage: sh [-c command]");
- }
- return 0;
- }
|