/* minish.c - example of a minimalistic shell * Comments in code deliberately omitted. :-) */ #include #include #include #include #include #include #include #include #include #define MAXLINE 80 static int cpid = 0; void inthandler(int sig) { if (cpid) { kill(cpid, sig); waitpid(cpid, NULL, 0); fprintf(stderr, "killed child with pid %d\n", cpid); cpid = 0; } signal(SIGINT, inthandler); } int main(int argc, char **argv) { char line[MAXLINE+1], *args[MAXLINE], *p, **arg; int bg, tmppid, i; glob_t globbuf; int globflags; if (argc>=2 && !freopen(argv[1], "r", stdin)) { perror(argv[1]); exit(errno); } signal(SIGINT, inthandler); while (printf("%s","$ "), fgets(line, MAXLINE, stdin)) { bg = 0; if ((p = strchr(line, '\n'))) { *p=0; } else { fprintf(stderr, "line too long\n"); exit(1); } p = line; while (*p == ' ') ++p; if (*p == '#' || !*p) continue; else { *(arg=args) = p; while ((p = strchr(p, ' '))) { while (*p == ' ') *p++ = 0; if (*p) { if (*p == '&') bg = 1; else *++arg=p; } } } *++arg=NULL; globflags = GLOB_NOCHECK | GLOB_NOSORT | GLOB_ERR; for (i=0; args[i]; i++) { glob(args[i], globflags, NULL, &globbuf); globflags |= GLOB_APPEND; } if (!strcmp(line,"exit")) { exit(args[1] ? atoi(args[1]) : 0); } switch ((cpid=fork())) { case 0: execvp(args[0], globbuf.gl_pathv); perror(args[0]); exit(errno); case -1: perror("fork() failed"); break; default: if (!bg) waitpid(cpid,NULL,0); else fprintf(stderr,"** Backrounded, pid %d\n", cpid); cpid = 0; if ((tmppid = waitpid(-1,NULL,WNOHANG)) > 0) fprintf(stderr, "** Child with pid %d finished\n", tmppid); } } exit(0); }