seatd: Add command-line arguments

This commit is contained in:
Kenny Levinsen 2020-08-07 15:48:24 +02:00
parent 420f973004
commit a98e0c4ce9
4 changed files with 129 additions and 95 deletions

View file

@ -20,7 +20,7 @@ void server_finish(struct server *server);
struct seat *server_get_seat(struct server *server, const char *seat_name);
int server_listen(struct server *server, const char *path);
int server_handle_connection(int fd, uint32_t mask, void *data);
int server_add_client(struct server *server, int fd);
#endif

View file

@ -27,6 +27,7 @@ add_project_arguments(
'-Wl,--exclude-libs=ALL',
'-D_XOPEN_SOURCE=700',
'-D__BSD_VISIBLE',
'-DSEATD_VERSION="@0@"'.format(meson.project_version()),
],
language: 'c',
)

View file

@ -1,5 +1,7 @@
#include <errno.h>
#include <grp.h>
#include <poll.h>
#include <pwd.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@ -13,10 +15,44 @@
#include "poller.h"
#include "server.h"
int main(int argc, char *argv[]) {
(void)argc;
(void)argv;
#define LISTEN_BACKLOG 16
static int open_socket(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 (fchown(fd, uid, gid) == -1) {
log_errorf("could not chown socket to uid %d, gid %d: %s", uid, gid,
strerror(errno));
} else if (fchmod(fd, 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 log_level level = LOGLEVEL_ERROR;
if (loglevel != NULL) {
@ -30,23 +66,82 @@ int main(int argc, char *argv[]) {
}
log_init(level);
const char *usage = "Usage: seatd [options]\n"
"\n"
" -h Show this help message\n"
" -u <user> User to own the seatd socket\n"
" -g <group> Group to own the seatd socket\n"
" -s <path> Where to create the seatd socket\n"
" -v Show the version number\n"
"\n";
int c;
int uid = 0, gid = 0;
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 = "/run/seatd.sock";
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;
}
char *path = getenv("SEATD_SOCK");
if (path == NULL) {
path = "/run/seatd.sock";
struct stat st;
if (stat(path, &st) == 0) {
log_info("removing leftover seatd socket");
unlink(path);
}
}
if (server_listen(&server, path) == -1) {
log_errorf("server_listen failed: %s", strerror(errno));
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;
}
@ -61,6 +156,6 @@ int main(int argc, char *argv[]) {
}
server_finish(&server);
unlink(path);
unlink(socket_path);
return 0;
}

View file

@ -1,7 +1,6 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <signal.h>
#include <stddef.h>
#include <stdlib.h>
@ -20,8 +19,6 @@
#include "server.h"
#include "terminal.h"
#define LISTEN_BACKLOG 16
static int server_handle_vt_acq(int signal, void *data);
static int server_handle_vt_rel(int signal, void *data);
static int server_handle_kill(int signal, void *data);
@ -117,42 +114,6 @@ static int set_nonblock(int fd) {
return 0;
}
static int server_handle_connection(int fd, uint32_t mask, void *data) {
struct server *server = data;
if (mask & (EVENT_ERROR | EVENT_HANGUP)) {
shutdown(fd, SHUT_RDWR);
server->running = false;
log_errorf("server socket recieved an error: %s", strerror(errno));
return -1;
}
if (mask & EVENT_READABLE) {
int new_fd = accept(fd, NULL, NULL);
if (fd == -1) {
log_errorf("could not accept client connection: %s", strerror(errno));
return 0;
}
if (set_nonblock(new_fd) != 0) {
close(new_fd);
log_errorf("could not prepare new client socket: %s", strerror(errno));
return 0;
}
struct client *client = client_create(server, new_fd);
client->event_source = poller_add_fd(&server->poller, new_fd, EVENT_READABLE,
client_handle_connection, client);
if (client->event_source == NULL) {
client_destroy(client);
log_errorf("could not add client socket to poller: %s", strerror(errno));
return 0;
}
log_infof("new client connected (pid: %d, uid: %d, gid: %d)", client->pid,
client->uid, client->gid);
}
return 0;
}
int server_add_client(struct server *server, int fd) {
if (set_nonblock(fd) != 0) {
close(fd);
@ -168,53 +129,30 @@ int server_add_client(struct server *server, int fd) {
log_errorf("could not add client socket to poller: %s", strerror(errno));
return -1;
}
log_infof("new client connected (pid: %d, uid: %d, gid: %d)", client->pid, client->uid,
client->gid);
return 0;
}
int server_listen(struct server *server, const char *path) {
union {
struct sockaddr_un unix;
struct sockaddr generic;
} addr = {{0}};
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
int server_handle_connection(int fd, uint32_t mask, void *data) {
struct server *server = data;
if (mask & (EVENT_ERROR | EVENT_HANGUP)) {
shutdown(fd, SHUT_RDWR);
server->running = false;
log_errorf("server socket recieved an error: %s", strerror(errno));
return -1;
}
if (mask & EVENT_READABLE) {
int new_fd = accept(fd, NULL, NULL);
if (fd == -1) {
log_errorf("could not create socket: %s", strerror(errno));
return -1;
}
if (set_nonblock(fd) == -1) {
close(fd);
log_errorf("could not prepare socket: %s", strerror(errno));
return -1;
log_errorf("could not accept client connection: %s", strerror(errno));
return 0;
}
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 (server_add_client(server, new_fd) == -1) {
return 0;
}
if (listen(fd, LISTEN_BACKLOG) == -1) {
log_errorf("could not listen on socket: %s", strerror(errno));
close(fd);
return -1;
}
struct group *videogrp = getgrnam("video");
if (videogrp != NULL) {
if (chown(path, 0, videogrp->gr_gid) == -1) {
log_errorf("could not chown socket to video group: %s", strerror(errno));
} else if (chmod(path, 0770) == -1) {
log_errorf("could not chmod socket: %s", strerror(errno));
}
} else {
log_errorf("could not get video group: %s", strerror(errno));
}
if (poller_add_fd(&server->poller, fd, EVENT_READABLE, server_handle_connection, server) ==
NULL) {
log_errorf("could not add socket to poller: %s", strerror(errno));
close(fd);
return -1;
}
return 0;
}