#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* TODO
 * - should check for close() errors, theoretically
 */

int make_server_socket(const struct sockaddr_un *sa, int backlog) {
    int server_socket;

    server_socket = socket(AF_UNIX, SOCK_STREAM, 0);

    if (server_socket == -1) {
        perror("socket");
        exit(1);
    }

    /* The standard seems to be to unlink whatever file might be there
     * before binding. This seems dangerous and bad to me, but it's what
     * I see everywhere and allows me to use the same accept program as
     * with tcplisten, so I'll let it be for now. */
    /* unlink() naturally fails if the file didn't exist. For other
     * cases, let bind produce the error */
    unlink(sa->sun_path);

    if (bind(server_socket, (struct sockaddr *) sa, sizeof(*sa)) != 0) {
        perror("bind");
        exit(1);
    }

    if (listen(server_socket, backlog) != 0) {
        perror("listen");
        exit(1);
    }
    return server_socket;

}

int main(int argc, char *const argv[]) {
    int server_socket;
    struct sockaddr_un sa;
    char *const *new_argv;
    int option;
    int listen_backlog = 20;
    const char *socket_path;

    while ((option = getopt(argc, argv, "b:")) != -1) {
        switch (option) {
            case 'b':
                listen_backlog = atoi(optarg);
                break;
        }
    }

    if (optind + 1 >= argc) {
        fprintf(stderr,
            "Usage: %s [-b listen_backlog] socket_path command...\n", argv[0]);
        exit(1);
    }

    sa.sun_family = AF_UNIX;

    socket_path = argv[optind];
    if (strlen(socket_path) >= sizeof(sa.sun_path)) {
        fprintf(stderr, "Socket name too long: %s\n", socket_path);
        exit(100);
    }
    strcpy(sa.sun_path, socket_path);

    server_socket = make_server_socket(&sa, listen_backlog);

    if (dup2(server_socket, STDIN_FILENO) == -1) {
        perror("dup2");
        exit(1);
    }
    close(server_socket);

    new_argv = argv + optind + 1;

    execvp(*new_argv, new_argv);
    perror("execvp");
    exit(1);
}


syntax highlighted by Code2HTML, v. 0.9.1