2 * This file is part of buxton.
4 * Copyright (C) 2013 Intel Corporation
6 * buxton is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
13 * \file core/main.c Buxton daemon
15 * This file provides the buxton daemon
26 #include <sys/signalfd.h>
27 #include <sys/socket.h>
30 #include <systemd/sd-daemon.h>
36 #include <attr/xattr.h>
46 #include "configurator.h"
47 #include "buxtonlist.h"
49 #define SOCKET_TIMEOUT 5
51 static BuxtonDaemon self;
53 static void print_usage(char *name)
55 printf("%s: Usage\n\n", name);
57 printf(" -c, --config-file Path to configuration file\n");
58 printf(" -h, --help Display this help message\n");
62 * Entry point into buxtond
63 * @param argc Number of arguments passed
64 * @param argv An array of string arguments
65 * @returns EXIT_SUCCESS if the operation succeeded, otherwise EXIT_FAILURE
67 int main(int argc, char *argv[])
72 struct sockaddr_un remote;
75 bool manual_start = false;
78 bool leftover_messages = false;
81 BuxtonList *map_list = NULL;
85 static struct option opts[] = {
86 { "config-file", 1, NULL, 'c' },
87 { "help", 0, NULL, 'h' },
94 c = getopt_long(argc, argv, "c:h", opts, &i);
102 ret = stat(optarg, &st);
104 buxton_log("Invalid configuration file path\n");
107 if (st.st_mode & S_IFDIR) {
108 buxton_log("Configuration file given is a directory\n");
113 buxton_add_cmd_line(CONFIG_CONF_FILE, optarg);
122 print_usage(argv[0]);
126 if (!buxton_cache_smack_rules()) {
129 smackfd = buxton_watch_smack_rules();
130 if (smackfd < 0 && errno) {
135 self.accepting_alloc = 0;
137 self.buxton.client.direct = true;
138 self.buxton.client.uid = geteuid();
139 if (!buxton_direct_open(&self.buxton)) {
144 ret = sigaddset(&mask, SIGINT);
148 ret = sigaddset(&mask, SIGTERM);
152 ret = sigaddset(&mask, SIGPIPE);
157 ret = sigprocmask(SIG_BLOCK, &mask, NULL);
162 sigfd = signalfd(-1, &mask, 0);
167 add_pollfd(&self, sigfd, POLLIN, false);
169 /* For client notifications */
170 self.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
171 /* Store a list of connected clients */
172 LIST_HEAD_INIT(client_list_item, self.client_list);
174 descriptors = sd_listen_fds(0);
175 if (descriptors < 0) {
176 buxton_log("sd_listen_fds: %m\n");
178 } else if (descriptors == 0) {
179 /* Manual invocation */
183 struct sockaddr_un un;
186 fd = socket(AF_UNIX, SOCK_STREAM, 0);
188 buxton_log("socket(): %m\n");
192 memzero(&sa, sizeof(sa));
193 sa.un.sun_family = AF_UNIX;
194 strncpy(sa.un.sun_path, buxton_socket(), sizeof(sa.un.sun_path) - 1);
195 sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;
197 ret = unlink(sa.un.sun_path);
198 if (ret == -1 && errno != ENOENT) {
202 if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
203 buxton_log("bind(): %m\n");
207 chmod(sa.un.sun_path, 0666);
209 if (listen(fd, SOMAXCONN) < 0) {
210 buxton_log("listen(): %m\n");
213 add_pollfd(&self, fd, POLLIN | POLLPRI, true);
215 /* systemd socket activation */
216 for (fd = SD_LISTEN_FDS_START + 0; fd < SD_LISTEN_FDS_START + descriptors; fd++) {
217 if (sd_is_fifo(fd, NULL)) {
218 add_pollfd(&self, fd, POLLIN, false);
219 buxton_debug("Added fd %d type FIFO\n", fd);
220 } else if (sd_is_socket_unix(fd, SOCK_STREAM, -1, buxton_socket(), 0)) {
221 add_pollfd(&self, fd, POLLIN | POLLPRI, true);
222 buxton_debug("Added fd %d type UNIX\n", fd);
223 } else if (sd_is_socket(fd, AF_UNSPEC, 0, -1)) {
224 add_pollfd(&self, fd, POLLIN | POLLPRI, true);
225 buxton_debug("Added fd %d type SOCKET\n", fd);
231 /* add Smack rule fd to pollfds */
232 add_pollfd(&self, smackfd, POLLIN | POLLPRI, false);
235 buxton_log("%s: Started\n", argv[0]);
237 /* Enter loop to accept clients */
239 ret = poll(self.pollfds, self.nfds, leftover_messages ? 0 : -1);
242 buxton_log("poll(): %m\n");
246 if (!leftover_messages) {
251 leftover_messages = false;
253 /* check sigfd if the daemon was signaled */
254 if (self.pollfds[0].revents != 0) {
256 struct signalfd_siginfo si;
258 sinfo = read(self.pollfds[0].fd, &si, sizeof(struct signalfd_siginfo));
259 if (sinfo != sizeof(struct signalfd_siginfo)) {
263 if (si.ssi_signo == SIGINT || si.ssi_signo == SIGTERM) {
268 for (nfds_t i = 1; i < self.nfds; i++) {
269 client_list_item *cl = NULL;
272 if (self.pollfds[i].revents == 0) {
276 if (self.pollfds[i].fd == -1) {
277 /* TODO: Remove client from list */
278 buxton_debug("Removing / Closing client for fd %d\n", self.pollfds[i].fd);
279 del_pollfd(&self, i);
284 if (self.pollfds[i].fd == smackfd) {
285 if (!buxton_cache_smack_rules()) {
288 buxton_log("Reloaded Smack access rules\n");
289 /* discard inotify data itself */
290 while (read(smackfd, &discard, 256) == 256);
295 if (self.accepting[i] == true) {
300 addr_len = sizeof(remote);
302 if ((fd = accept(self.pollfds[i].fd,
303 (struct sockaddr *)&remote, &addr_len)) == -1) {
304 buxton_log("accept(): %m\n");
308 buxton_debug("New client fd %d connected through fd %d\n", fd, self.pollfds[i].fd);
310 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
315 cl = malloc0(sizeof(client_list_item));
320 LIST_INIT(client_list_item, item, cl);
323 cl->cred = (struct ucred) {0, 0, 0};
324 LIST_PREPEND(client_list_item, item, self.client_list, cl);
326 /* poll for data on this new client as well */
327 add_pollfd(&self, cl->fd, POLLIN | POLLPRI, false);
329 /* Mark our packets as high prio */
330 if (setsockopt(cl->fd, SOL_SOCKET, SO_PRIORITY, &on, sizeof(on)) == -1) {
331 buxton_log("setsockopt(SO_PRIORITY): %m\n");
334 /* Set socket recv timeout */
335 tv.tv_sec = SOCKET_TIMEOUT;
337 if (setsockopt(cl->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
338 sizeof(struct timeval)) == -1) {
339 buxton_log("setsockopt(SO_RCVTIMEO): %m\n");
342 /* check if this is optimal or not */
346 assert(self.accepting[i] == 0);
348 assert(self.pollfds[i].fd != smackfd);
351 /* handle data on any connection */
352 /* TODO: Replace with hash table lookup */
353 LIST_FOREACH(item, cl, self.client_list)
354 if (self.pollfds[i].fd == cl->fd) {
359 if (handle_client(&self, cl, i)) {
360 leftover_messages = true;
365 buxton_log("%s: Closing all connections\n", argv[0]);
368 unlink(buxton_socket());
370 for (int i = 0; i < self.nfds; i++) {
371 close(self.pollfds[i].fd);
373 for (client_list_item *i = self.client_list; i;) {
374 client_list_item *j = i->item_next;
378 /* Clean up notification lists */
379 HASHMAP_FOREACH_KEY(map_list, notify_key, self.notify_mapping, iter) {
380 hashmap_remove(self.notify_mapping, notify_key);
382 BUXTON_LIST_FOREACH(map_list, elem) {
383 BuxtonNotification *notif = (BuxtonNotification*)elem->data;
384 if (notif->old_data) {
385 free_buxton_data(&(notif->old_data));
389 buxton_list_free_all(&map_list);
392 hashmap_free(self.notify_mapping);
393 buxton_direct_close(&self.buxton);
398 * Editor modelines - http://www.wireshark.org/tools/modelines.html
403 * indent-tabs-mode: t
406 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
407 * :indentSize=8:tabSize=8:noTabs=false: