/**************************************************************/ /* */ /* UNIX 1 / WS 92/93 Gruppe ux803 */ /* 7. Uebung - Aufgabe 5 - command.c */ /* */ /* Vorname Name Matrikelnr. */ /* --------- ------- ------------- */ /* Torsten Buller 117894 */ /* Roman Czyborra 127221 */ /* Gerasimos Paliatsaras 140956 */ /* */ /**************************************************************/ #include /* strchr, malloc etc. */ #include /* O_RDONLY */ #include /* WNOHANG */ #include /* ENOENT */ #include /* TIOCSPGRP */ #include /* MAXPATHLEN */ #include "msh.h" /* SLOTS, struct kommando */ /* shell process table, hopefully initialized with zeros */ static struct proc { int pid, stopped; char *cmd; } job [SLOTS]; /* useful global variables */ static waiting, fd [2]; extern shellpid; static void quit () { waiting = 0; } static void fatal (char * error) { perror (error); exit (0); } static void giveterminal (pgrp) { ioctl(0, TIOCSPGRP, & pgrp); } /* find index to pid in job table * pid == -1: any active job * findjob == -1: not found */ static findjob (pid) { static slot; for (slot = 0; slot < SLOTS; ++ slot) if (pid == -1? job[slot].pid : job[slot].pid == pid) break; return (slot < SLOTS? slot: -1); } static char * stopsignal (jid) { switch (job[jid].stopped) { case 0: return "running"; case SIGSTOP: return "stopped-sig"; case SIGTSTP: return "stopped-key"; case SIGTTIN: return "stopped-inp"; case SIGTTOU: return "stopped-out"; default: return "strange"; } } /* process a wait () result */ static stopped (status, jid, echo) { if (jid == -1) return 0; if (WIFSTOPPED (status)) return job[jid].stopped = WSTOPSIG (status); if (echo) printf ("[%d] done: %s\n", jid, job[jid].cmd); job[jid].pid = job[jid].stopped = 0; free (job[jid].cmd); return 0; } /* wait for started processes * jid: mode: when: * -1 0 release zombies before prompt * jid 0 foreground active, wait quietly * 1 builtin interruptible wait * -1 1 for random first * jid 1 for particular background process */ void do_wait (jid, mode) { static pid, status, terminated, done; if (mode && findjob (-1) == -1) { printf ("no job active!\n"); return; } if (jid != -1) { pid = job[jid].pid; if (!pid) { printf ("job[%d] not active!\n", jid); return; }} /* wait quietly for foreground, then repossess terminal control */ if (jid != -1 && !mode) { wait4 (pid, &status, WUNTRACED, 0); giveterminal (shellpid); if (stopped (status, jid, 0)) printf ("..suspended\n"); return; } /* or wait for background processes with termination message */ waiting = 1; if (mode) signal (SIGINT, & quit), signal (SIGQUIT, & quit); while (waiting && findjob (-1) != -1) { done = findjob (terminated = wait3 (& status, WNOHANG | WUNTRACED, 0)); terminated == 0 ? mode ? sleep (1) : quit () : terminated == -1 ? fatal ("wait3") : stopped (status, done, 1) ? printf ("[%d] %s: %s\n", done, stopsignal(done), job[done].cmd) : mode ? jid == -1 || terminated == pid ? quit () : 0 : 0; } signal (SIGINT, SIG_IGN); signal (SIGQUIT, SIG_IGN); } void do_jobs () { static i; do_wait (-1, 0); for (i=0; i < SLOTS; i++) if (job[i].pid) printf ("[%d] %d %s: %s\n",i,job[i].pid, stopsignal(i), job[i].cmd); } static job2Bcont (jid) { do_wait (-1, 0); jid == -1 ? (jid = findjob (-1)) == -1 ? printf ("no job active!\n") : 0 : job[jid].pid ? 0 : printf ("job not active!\n", jid = -1); return jid; } static void contin (jid) { killpg (job[jid].pid, SIGCONT); job[jid].stopped = 0; } void do_bg (jid) { (jid = job2Bcont (jid)) == -1? 0 : printf ("[%d] %s &\n",jid,job[jid].cmd), contin (jid); } void do_fg (jid) { jid = job2Bcont (jid); if (jid == -1) return; printf ("...%s:\n",job[jid].cmd); giveterminal (job[jid].pid); contin (jid); do_wait (jid, 0); } static S, L; static sumlen (char ** argv) { for (S = 0; *argv; ++ argv) S += strlen (*argv); return S;} static char *copy, *write; static void copyword (char *src) { while (*write++ = *src++); write[-1] = ' ';} static void copyargv (char **argv) { while (*argv) copyword (*argv++);} static char *copycommand (struct kommando * kp) { L = kp->num_tok1 + kp->num_tok2 /*spaces*/ + sumlen (kp -> token_1); if (kp -> is_pipe) L += 2 + sumlen (kp -> token_2); if (kp -> inp_tok) L += 2 + strlen (kp -> inp_tok); if (kp -> out_tok) L += 2 + strlen (kp -> out_tok); copy = write = malloc (L); if (write) { copyargv (kp -> token_1); if (kp -> inp_tok) copyword ("<"), copyword (kp -> inp_tok); if (kp -> is_pipe) copyword ("|"), copyargv (kp -> token_2); if (kp -> out_tok) copyword (">"), copyword (kp -> out_tok); write[-1] = '\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 (struct kommando *kp) { static pid, slot; static char chr, *path, *next, *name, **argv, longname [MAXPATHLEN]; argv = kp->token_1; name = argv [0]; slot = findjob (0); if (slot == -1) printf("job table too full for %s ...\n", name); else switch (pid = fork ()) { case -1: fatal ("fork"); case 0: /* execute command */ pid = getpid (); if (! kp -> is_ampersand) giveterminal (pid); setpgrp (pid, pid); signal(SIGTSTP, SIG_DFL); signal(SIGTTIN, SIG_DFL); signal(SIGTTOU, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); 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: /* fill out birth certificate */ job[slot].pid = pid; job[slot].cmd = copycommand (kp); kp -> is_ampersand ? printf("[%d] %d\n", slot, pid) : do_wait (slot, 0); } }