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); 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); int server_add_client(struct server *server, int fd);
#endif #endif

View file

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

View file

@ -1,5 +1,7 @@
#include <errno.h> #include <errno.h>
#include <grp.h>
#include <poll.h> #include <poll.h>
#include <pwd.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -13,10 +15,44 @@
#include "poller.h" #include "poller.h"
#include "server.h" #include "server.h"
int main(int argc, char *argv[]) { #define LISTEN_BACKLOG 16
(void)argc;
(void)argv;
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"); char *loglevel = getenv("SEATD_LOGLEVEL");
enum log_level level = LOGLEVEL_ERROR; enum log_level level = LOGLEVEL_ERROR;
if (loglevel != NULL) { if (loglevel != NULL) {
@ -30,23 +66,82 @@ int main(int argc, char *argv[]) {
} }
log_init(level); 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}; struct server server = {0};
if (server_init(&server) == -1) { if (server_init(&server) == -1) {
log_errorf("server_create failed: %s", strerror(errno)); log_errorf("server_create failed: %s", strerror(errno));
return 1; 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) { int socket_fd = open_socket(socket_path, uid, gid);
log_errorf("server_listen failed: %s", strerror(errno)); 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); server_finish(&server);
return 1; return 1;
} }
@ -61,6 +156,6 @@ int main(int argc, char *argv[]) {
} }
server_finish(&server); server_finish(&server);
unlink(path); unlink(socket_path);
return 0; return 0;
} }

View file

@ -1,7 +1,6 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <grp.h>
#include <signal.h> #include <signal.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
@ -20,8 +19,6 @@
#include "server.h" #include "server.h"
#include "terminal.h" #include "terminal.h"
#define LISTEN_BACKLOG 16
static int server_handle_vt_acq(int signal, void *data); static int server_handle_vt_acq(int signal, void *data);
static int server_handle_vt_rel(int signal, void *data); static int server_handle_vt_rel(int signal, void *data);
static int server_handle_kill(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; 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) { int server_add_client(struct server *server, int fd) {
if (set_nonblock(fd) != 0) { if (set_nonblock(fd) != 0) {
close(fd); 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)); log_errorf("could not add client socket to poller: %s", strerror(errno));
return -1; return -1;
} }
log_infof("new client connected (pid: %d, uid: %d, gid: %d)", client->pid, client->uid,
client->gid);
return 0; return 0;
} }
int server_listen(struct server *server, const char *path) { int server_handle_connection(int fd, uint32_t mask, void *data) {
union { struct server *server = data;
struct sockaddr_un unix; if (mask & (EVENT_ERROR | EVENT_HANGUP)) {
struct sockaddr generic; shutdown(fd, SHUT_RDWR);
} addr = {{0}}; server->running = false;
int fd = socket(AF_UNIX, SOCK_STREAM, 0); log_errorf("server socket recieved an error: %s", strerror(errno));
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; return -1;
} }
addr.unix.sun_family = AF_UNIX; if (mask & EVENT_READABLE) {
strncpy(addr.unix.sun_path, path, sizeof addr.unix.sun_path - 1); int new_fd = accept(fd, NULL, NULL);
socklen_t size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.unix.sun_path); if (fd == -1) {
if (bind(fd, &addr.generic, size) == -1) { log_errorf("could not accept client connection: %s", strerror(errno));
log_errorf("could not bind socket: %s", strerror(errno)); return 0;
close(fd); }
return -1;
} if (server_add_client(server, new_fd) == -1) {
if (listen(fd, LISTEN_BACKLOG) == -1) { return 0;
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; return 0;
} }