/* * Serve a program over a Unix domain socket. * * Dan Cross */ #include #include #include #include #include #include #include #include #include #include #include #include void background(void) { pid_t pid; if ((pid = fork()) < 0) { perror("fork"); exit(EXIT_FAILURE); } if (pid != 0) { exit(EXIT_SUCCESS); } } /* ARGSUSED */ void child(int signo) { wait(NULL); } void setsigs(void) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = child; sigaction(SIGCHLD, &sa, NULL); } int srvfile(char *file) { int sd; struct sockaddr_un sock; unlink(file); memset(&sock, 0, sizeof(sock)); sock.sun_family = AF_UNIX; strncpy(sock.sun_path, file, sizeof(sock.sun_path)); if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(EXIT_FAILURE); } if (bind(sd, (struct sockaddr *)&sock, sizeof(sock)) < 0) { perror("bind"); exit(EXIT_FAILURE); } if (listen(sd, 5) < 0) { perror("listen"); exit(EXIT_FAILURE); } return(sd); } int main(int argc, char *argv[]) { pid_t pid; int nsd, sd; struct sockaddr_un sock; socklen_t clen; if (argc < 3) { fprintf(stderr, "Usage: %s path prog [args].\n", argv[0]); return(EXIT_FAILURE); } background(); setsigs(); sd = srvfile(argv[1]); for ( ; ; ) { clen = sizeof(sock); if ((nsd = accept(sd, (struct sockaddr *)&sock, &clen)) < 0) { if (errno == EINTR) { /* Probably got a SIGCHLD. */ continue; } perror("accept"); exit(EXIT_FAILURE); } if ((pid = fork()) < 0) { perror("fork"); close(nsd); continue; } else if (pid == 0) { close(sd); dup2(nsd, STDIN_FILENO); dup2(nsd, STDOUT_FILENO); dup2(nsd, STDERR_FILENO); execvp(argv[2], argv + 2); } else { close(nsd); } } return(EXIT_SUCCESS); }