/**************************************************************/ /* */ /* UNIX 1 / WS 92/93 Gruppe ux803 */ /* 6. Uebung - Aufgabe 4 - command.c */ /* */ /* Vorname Name Matrikelnr. */ /* --------- ------- ------------- */ /* Dietmar Dierks 125761 */ /* Roman Czyborra 127221 */ /* Torsten Buller 117894 */ /* Gerasimos Paliatsaras 140956 */ /* */ /**************************************************************/ #include /* strchr, malloc etc. */ #include /* O_RDONLY */ #include /* WNOHANG */ #include /* ENOENT */ #include /* TIOCSPGRP */ #include /* MAXPATHLEN */ #include "3/parser.h" /* struct kommando */ #define MAXPROC 10 /* shell process table, hopefully initialized with zeros */ static struct proc { int pid; char **argv; } ps [MAXPROC]; /* useful global variables */ static waiting, fd [2]; extern shellpid; static void quit () { waiting = 0; } static void fatal (error) { perror (error); exit (0); } /* clear a ps entry */ static void clearps (index, echo) { static char **argv; if (index == -1) return; if (echo) { printf ("[%d] %d Done:", index, ps[index].pid); for (argv = ps[index].argv; argv && *argv; printf(" %s", *argv++)); printf("\n"); } ps[index].pid = 0; for ((argv = ps[index].argv) && free(argv); argv && *argv ; free(*argv++)); } /* find index to pid in ps * pid == -1: any active job * findjob == -1: not found */ static int findjob (pid) { static int slot; for (slot = 0; slot < MAXPROC; ++ slot) if (pid == -1? ps[slot].pid : ps[slot].pid == pid) break; return (slot < MAXPROC? slot: -1); } /* wait for started processes * pid: mode: when: * -1 0 release zombies before prompt * pid 0 foreground active, wait quietly * 1 builtin interruptible wait * -1 1 for random first * pid 1 for particular background process */ void do_wait (pid, mode) { static int terminated, jid; jid = findjob (pid); if (jid == -1) return; /* wait quietly for foreground, repossess terminal control */ if (pid > 0 && !mode) { waitpid (pid, 0, 0); ioctl (0, TIOCSPGRP, & shellpid); clearps (jid, 0); return; } /* or wait for background processes with termination message */ waiting = 1; if (mode) signal (SIGINT, & quit), signal (SIGQUIT, & quit); while (waiting && findjob (-1) != -1) { terminated = wait3 (0, WNOHANG, 0); if (terminated) { terminated == -1 ? fatal ("wait3") : clearps (findjob (terminated), 1); if (mode && (pid == -1 || terminated == pid)) quit (); } else { if (mode) sleep (1); else return; } } signal (SIGINT, SIG_IGN); signal (SIGQUIT, SIG_IGN); } /* duplicate an argument vector */ static char ** copyargs (argc, argv) int argc; char ** argv; { static char ** copy, ** next; next = copy = (char **) malloc ((argc + 1) * sizeof (char *)); if (next) { while (*argv) *next++ = (char *) strdup (*argv++); *next = 0; } return copy; } /* redirect stdin (0) or stdout (1) to fd[io] */ static void redirect (io) { close(io); dup (fd [io]) == io ? close(fd [io]) : fatal ("dup"); } /* execute a command */ void do_command (kp) struct kommando *kp; { static int pid, slot; static char chr, *path, *next, *name, **argv, longname [MAXPATHLEN]; /* catch null commands */ if (! kp->num_tok1) return; argv = kp->token_1; switch (pid = fork ()) { case -1: fatal ("fork"); case 0: /* execute command */ argv && (name = argv [0]) ? pid = getpid () : exit (0); if (! kp -> is_ampersand) { ioctl(0, TIOCSPGRP, & pid); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); } setpgrp(pid,pid); if (kp->out_tok) { fd[1] = creat (kp->out_tok, 0666); fd[1] == -1 ? fatal ("creat") : redirect (1); } if (kp->inp_tok) { fd[0] = open (kp->inp_tok, O_RDONLY); fd[0] == -1 ? fatal ("open") : redirect (0); } if (kp->is_pipe) { pipe(fd) == -1? fatal ("pipe"): 0; switch (fork ()) { case -1: fatal ("fork"); case 0: /* child writes into pipe */ redirect (1); close (fd[0]); break; default: /* parent reads from pipe */ argv = kp->token_2; name = argv [0]; redirect (0); close (fd[1]); } } if (!strchr (name, '/') && (path = getenv ("PATH"))) /* parse $PATH and compose long name */ for (chr = *path; chr;) { /* copy path name */ for (next = longname; (chr = *path++) && chr != ':'; *next++ = chr); /* append slash */ next > longname ? *next++ = '/': 0; /* append command name and go */ strcpy (next, name); execv (longname, argv); /* continue when failed */ } else execv (name, argv); errno == ENOENT ? printf ("command %s not found\n",name) : perror (name); exit (0); default: /* find free record */ slot = findjob (0); if (slot == -1) { printf("ps too full for %s\n", argv[0]); kill(-pid, SIGKILL); return; } /* fill out birth certificate */ ps[slot].pid = pid; ps[slot].argv = copyargs (kp->num_tok1, argv); kp -> is_ampersand ? printf("[%d] %d\n", slot, pid) : do_wait (pid, 0); } }