#include #include #include #include #include #include #include /** * NOTE: requires fdescfs to be mounted to run interpreted files (starting with #!) */ #define DEFAULT_FD 3 #define BIN_HDR_LEN 2 char *args[] = { "batchrun", NULL }; void set_async(int fd, int on) { int flags; if ((flags = fcntl(fd, F_GETFL)) == -1) err(1, "fcntl()"); if (on) { flags |= O_NONBLOCK; } else { flags &= ~O_NONBLOCK; } if (fcntl(fd, F_SETFL, flags) == -1) err(1, "fcntl()"); } void set_cloexec(int fd, int on) { if (fcntl(fd, F_SETFD, on ? FD_CLOEXEC : 0) == -1) err(1, "fcntl()"); } int main(int argc, char **argv) { char buf[BIN_HDR_LEN], *end = NULL; ssize_t ret; int tries = 0, fd = DEFAULT_FD; if (argc > 1) { fd = strtol(argv[1], &end, 10); if (end == argv[1]) errx(1, "Filedescriptor supplied (\"%s\") is not a number", argv[1]); } set_cloexec(fd, 1); set_async(fd, 1); retry: if (tries++ >= 3) errx(1, "Failed to read file header"); ret = pread(fd, buf, sizeof(buf), 0); if (ret == sizeof(buf)) { if (strncmp(buf, "#!", sizeof(buf)) == 0) { set_cloexec(fd, 0); } } else if (ret == -1) { if (errno == EINTR) goto retry; else if (errno != EAGAIN) err(1, "pread()"); } else if (ret != 0) { /** * We take a lazy approach here and only want to know if the * file has more contents (and don't care about errors). */ ret = pread(fd, buf + ret, sizeof(buf) - ret, ret); if (ret != 0) { goto retry; } } set_async(fd, 0); fexecve(fd, args, NULL); err(1, "fexecve()"); }