#include #include #include #include #include #include #include #include #include #include #include #include "client.h" #include "log.h" #include "poller.h" #include "server.h" #define LISTEN_BACKLOG 16 static int open_socket(const char *path, int uid, int gid) { union { struct sockaddr_un unix; struct sockaddr generic; } addr = {{0}}; int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); if (fd == -1) { log_errorf("could not create socket: %s", strerror(errno)); return -1; } addr.unix.sun_family = AF_UNIX; strncpy(addr.unix.sun_path, path, sizeof addr.unix.sun_path - 1); socklen_t size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.unix.sun_path); if (bind(fd, &addr.generic, size) == -1) { log_errorf("could not bind socket: %s", strerror(errno)); close(fd); return -1; } if (listen(fd, LISTEN_BACKLOG) == -1) { log_errorf("could not listen on socket: %s", strerror(errno)); close(fd); return -1; } if (uid != 0 || gid != 0) { if (chown(path, uid, gid) == -1) { log_errorf("could not chown socket to uid %d, gid %d: %s", uid, gid, strerror(errno)); } else if (chmod(path, 0770) == -1) { log_errorf("could not chmod socket: %s", strerror(errno)); } } return fd; } int main(int argc, char *argv[]) { char *loglevel = getenv("SEATD_LOGLEVEL"); enum libseat_log_level level = LIBSEAT_LOG_LEVEL_ERROR; if (loglevel != NULL) { if (strcmp(loglevel, "silent") == 0) { level = LIBSEAT_LOG_LEVEL_SILENT; } else if (strcmp(loglevel, "info") == 0) { level = LIBSEAT_LOG_LEVEL_INFO; } else if (strcmp(loglevel, "debug") == 0) { level = LIBSEAT_LOG_LEVEL_DEBUG; } } log_init(); libseat_set_log_level(level); const char *usage = "Usage: seatd [options]\n" "\n" " -h Show this help message\n" " -u User to own the seatd socket\n" " -g Group to own the seatd socket\n" " -s Where to create the seatd socket\n" " -v Show the version number\n" "\n"; int c; int uid = 0, gid = 0; const char *socket_path = getenv("SEATD_SOCK"); while ((c = getopt(argc, argv, "vhs:g:u:")) != -1) { switch (c) { case 's': socket_path = optarg; break; case 'u': { struct passwd *pw = getpwnam(optarg); if (pw == NULL) { fprintf(stderr, "Could not find user by name '%s'.\n", optarg); return 1; } else { uid = pw->pw_uid; } break; } case 'g': { struct group *gr = getgrnam(optarg); if (gr == NULL) { fprintf(stderr, "Could not find group by name '%s'.\n", optarg); return 1; } else { gid = gr->gr_gid; } break; } case 'v': printf("seatd version %s\n", SEATD_VERSION); return 0; case 'h': printf("%s", usage); return 0; case '?': fprintf(stderr, "Try '%s -h' for more information.\n", argv[0]); return 1; default: abort(); } } if (socket_path == NULL) { socket_path = SEATD_DEFAULTPATH; struct stat st; if (stat(socket_path, &st) == 0) { log_info("removing leftover seatd socket"); unlink(socket_path); } } struct server server = {0}; if (server_init(&server) == -1) { log_errorf("server_create failed: %s", strerror(errno)); return 1; } int socket_fd = open_socket(socket_path, uid, gid); if (socket_fd == -1) { log_errorf("could not create server socket: %s", strerror(errno)); server_finish(&server); return 1; } if (poller_add_fd(&server.poller, socket_fd, EVENT_READABLE, server_handle_connection, &server) == NULL) { log_errorf("could not add socket to poller: %s", strerror(errno)); close(socket_fd); server_finish(&server); return 1; } log_info("seatd started"); while (server.running) { if (poller_poll(&server.poller) == -1) { log_errorf("poller failed: %s", strerror(errno)); return 1; } } server_finish(&server); unlink(socket_path); log_info("seatd stopped"); return 0; }