Skip to content

Instantly share code, notes, and snippets.

@syntactician
Created November 22, 2016 20:32
Show Gist options
  • Select an option

  • Save syntactician/5a96d86caab8f0fce5dc7e51ed0c81ca to your computer and use it in GitHub Desktop.

Select an option

Save syntactician/5a96d86caab8f0fce5dc7e51ed0c81ca to your computer and use it in GitHub Desktop.
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/wait.h>
/* 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;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment