#include #include #include #include #include #include #include #include /* sysexits.h conventions */ #define EX_OK 0 #define EX_USAGE 64 #define EX_UNAVAILABLE 69 #define EX_OSERR 71 static int qflag = 0; static long int tvalue = -1; static void die(const int, const char *, ...); static int getyes(void); static int respawn(void); void die(const int ret, const char *errstr, ...) { va_list ap; va_start(ap, errstr); vfprintf(stderr, errstr, ap); va_end(ap); exit(ret); } int getyes(void) { int yes; char *line = NULL; size_t len = 0; getline(&line, &len, stdin); yes = !strcmp(line, "yes\n"); free(line); return yes; } int respawn(void) { if (!qflag) { printf("The command finished. " "Please enter \"yes\" if you want to exit: "); fflush(stdout); } if (!tvalue) { printf("\n"); return 0; } else if (tvalue < 0) { return getyes(); } else { fd_set rfds; int retval; struct timeval tv; tv.tv_sec = tvalue; tv.tv_usec = 0; FD_ZERO(&rfds); FD_SET(0, &rfds); if ((retval = select(1, &rfds, NULL, NULL, &tv)) < 0) { die(EX_OSERR, "Unable to read input\n"); /* NOTREACHED */ return 0; } else if (retval) { return getyes(); } else { printf("\n"); return 0; } } } int main(int argc, char **argv) { char *cmd = NULL; char *ptr = NULL; int c, i, returnStatus; int mvalue = -1; pid_t pid; if (!isatty(1)) die(EX_UNAVAILABLE, "%s: not connected to a terminal", argv[0]); while ((c = getopt(argc, argv, "+hm:qst:Vy")) != -1) { switch(c) { case 'h': die(EX_USAGE, "%s: [-hqVy] [-m max] [-t timeout] " "utility [argument...]\n", argv[0]); case 'm': if ((mvalue = strtol(optarg, &ptr, 10)) < 1) die(EX_USAGE, "-m value must be positive\n"); if (!strcmp(optarg, ptr) || errno == EINVAL) die(EX_USAGE, "-m value must be a number\n"); if (errno == ERANGE) die(EX_USAGE, "-m value out of range\n"); break; case 'q': qflag = 1; break; case 't': if ((tvalue = strtol(optarg, &ptr, 10)) < 0) die(EX_USAGE, "-t value may not be negative\n"); if (!strcmp(optarg, ptr) || errno == EINVAL) die(EX_USAGE, "-t value must be a number\n"); if (errno == ERANGE) die(EX_USAGE, "-t value out of range\n"); break; case 'V': die(EX_USAGE, "fenix 0.2\n"); case 'y': tvalue = 0; break; case '?': exit(EX_USAGE); } } if (argc <= optind) die(EX_USAGE, "No command provided\n"); cmd = argv[optind]; for (i = 0; i < optind; ++i) ++argv; while (mvalue) { switch (pid = fork()) { case -1: die(EX_OSERR, "failed to fork\n"); case 0: if (!qflag) { printf("Running \""); for (i = 0; i < argc - optind; ++i) printf("%s ", argv[i]); printf("\b\"\n"); } if (execvp(argv[0], argv) < 0) _exit(EX_UNAVAILABLE); else _exit(EX_OK); default: waitpid(pid, &returnStatus, 0); if (WEXITSTATUS(returnStatus) == EX_UNAVAILABLE) die(EX_UNAVAILABLE, "Cannot execute file \"%s\"\n", cmd); if (mvalue && mvalue != 1 && tvalue) if (respawn() || feof(stdin)) exit(EX_OK); if (mvalue > 0) --mvalue; } } }