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/socket.h>
29 #include <systemd/sd-daemon.h>
35 #include <attr/xattr.h>
45 #include "configurator.h"
46 #include "buxtonlist.h"
48 #define POLL_TIMEOUT 250
49 #define SOCKET_TIMEOUT 5
51 static volatile bool do_shutdown = false;
52 static BuxtonDaemon self;
54 void my_handler(int sig)
59 static void print_usage(char *name)
61 printf("%s: Usage\n\n", name);
63 printf(" -c, --config-file Path to configuration file\n");
64 printf(" -h, --help Display this help message\n");
68 * Entry point into buxtond
69 * @param argc Number of arguments passed
70 * @param argv An array of string arguments
71 * @returns EXIT_SUCCESS if the operation succeeded, otherwise EXIT_FAILURE
73 int main(int argc, char *argv[])
78 struct sockaddr_un remote;
81 bool manual_start = false;
83 bool leftover_messages = false;
86 BuxtonList *map_list = NULL;
90 static struct option opts[] = {
91 { "config-file", 1, NULL, 'c' },
92 { "help", 0, NULL, 'h' },
99 c = getopt_long(argc, argv, "c:h", opts, &i);
107 ret = stat(optarg, &st);
109 buxton_log("Invalid configuration file path\n");
112 if (st.st_mode & S_IFDIR) {
113 buxton_log("Configuration file given is a directory\n");
118 buxton_add_cmd_line(CONFIG_CONF_FILE, optarg);
127 print_usage(argv[0]);
131 if (!buxton_cache_smack_rules()) {
134 smackfd = buxton_watch_smack_rules();
135 if (smackfd < 0 && errno) {
140 self.accepting_alloc = 0;
142 self.buxton.client.direct = true;
143 self.buxton.client.uid = geteuid();
144 if (!buxton_direct_open(&self.buxton)) {
148 sigemptyset(&sa.sa_mask);
149 sa.sa_flags = SA_RESTART;
150 sa.sa_handler = my_handler;
151 ret = sigaction(SIGINT, &sa, NULL);
155 ret = sigaction(SIGTERM, &sa, NULL);
159 sigemptyset(&sa.sa_mask);
160 sa.sa_handler = SIG_IGN;
161 ret = sigaction(SIGPIPE, &sa, NULL);
166 /* For client notifications */
167 self.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
168 /* Store a list of connected clients */
169 LIST_HEAD_INIT(client_list_item, self.client_list);
171 descriptors = sd_listen_fds(0);
172 if (descriptors < 0) {
173 buxton_log("sd_listen_fds: %m\n");
175 } else if (descriptors == 0) {
176 /* Manual invocation */
180 struct sockaddr_un un;
183 fd = socket(AF_UNIX, SOCK_STREAM, 0);
185 buxton_log("socket(): %m\n");
189 memzero(&sa, sizeof(sa));
190 sa.un.sun_family = AF_UNIX;
191 strncpy(sa.un.sun_path, buxton_socket(), sizeof(sa.un.sun_path) - 1);
192 sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;
194 ret = unlink(sa.un.sun_path);
195 if (ret == -1 && errno != ENOENT) {
199 if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
200 buxton_log("bind(): %m\n");
204 chmod(sa.un.sun_path, 0666);
206 if (listen(fd, SOMAXCONN) < 0) {
207 buxton_log("listen(): %m\n");
210 add_pollfd(&self, fd, POLLIN | POLLPRI, true);
212 /* systemd socket activation */
213 for (fd = SD_LISTEN_FDS_START + 0; fd < SD_LISTEN_FDS_START + descriptors; fd++) {
214 if (sd_is_fifo(fd, NULL)) {
215 add_pollfd(&self, fd, POLLIN, false);
216 buxton_debug("Added fd %d type FIFO\n", fd);
217 } else if (sd_is_socket_unix(fd, SOCK_STREAM, -1, buxton_socket(), 0)) {
218 add_pollfd(&self, fd, POLLIN | POLLPRI, true);
219 buxton_debug("Added fd %d type UNIX\n", fd);
220 } else if (sd_is_socket(fd, AF_UNSPEC, 0, -1)) {
221 add_pollfd(&self, fd, POLLIN | POLLPRI, true);
222 buxton_debug("Added fd %d type SOCKET\n", fd);
228 /* add Smack rule fd to pollfds */
229 add_pollfd(&self, smackfd, POLLIN | POLLPRI, false);
232 buxton_log("%s: Started\n", argv[0]);
234 /* Enter loop to accept clients */
236 ret = poll(self.pollfds, self.nfds, leftover_messages ? 0 : POLL_TIMEOUT);
239 buxton_log("poll(): %m\n");
240 if (errno == EINTR) {
250 if (!leftover_messages) {
255 leftover_messages = false;
257 for (nfds_t i=0; i<self.nfds; i++) {
258 client_list_item *cl = NULL;
261 if (self.pollfds[i].revents == 0) {
265 if (self.pollfds[i].fd == -1) {
266 /* TODO: Remove client from list */
267 buxton_debug("Removing / Closing client for fd %d\n", self.pollfds[i].fd);
268 del_pollfd(&self, i);
273 if (self.pollfds[i].fd == smackfd) {
274 if (!buxton_cache_smack_rules()) {
277 buxton_log("Reloaded Smack access rules\n");
278 /* discard inotify data itself */
279 while (read(smackfd, &discard, 256) == 256);
284 if (self.accepting[i] == true) {
289 addr_len = sizeof(remote);
291 if ((fd = accept(self.pollfds[i].fd,
292 (struct sockaddr *)&remote, &addr_len)) == -1) {
293 buxton_log("accept(): %m\n");
297 buxton_debug("New client fd %d connected through fd %d\n", fd, self.pollfds[i].fd);
299 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
304 cl = malloc0(sizeof(client_list_item));
309 LIST_INIT(client_list_item, item, cl);
312 cl->cred = (struct ucred) {0, 0, 0};
313 LIST_PREPEND(client_list_item, item, self.client_list, cl);
315 /* poll for data on this new client as well */
316 add_pollfd(&self, cl->fd, POLLIN | POLLPRI, false);
318 /* Mark our packets as high prio */
319 if (setsockopt(cl->fd, SOL_SOCKET, SO_PRIORITY, &on, sizeof(on)) == -1) {
320 buxton_log("setsockopt(SO_PRIORITY): %m\n");
323 /* Set socket recv timeout */
324 tv.tv_sec = SOCKET_TIMEOUT;
326 if (setsockopt(cl->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
327 sizeof(struct timeval)) == -1) {
328 buxton_log("setsockopt(SO_RCVTIMEO): %m\n");
331 /* check if this is optimal or not */
335 assert(self.accepting[i] == 0);
337 assert(self.pollfds[i].fd != smackfd);
340 /* handle data on any connection */
341 /* TODO: Replace with hash table lookup */
342 LIST_FOREACH(item, cl, self.client_list)
343 if (self.pollfds[i].fd == cl->fd) {
348 if (handle_client(&self, cl, i)) {
349 leftover_messages = true;
354 buxton_log("%s: Closing all connections\n", argv[0]);
357 unlink(buxton_socket());
359 for (int i = 0; i < self.nfds; i++) {
360 close(self.pollfds[i].fd);
362 for (client_list_item *i = self.client_list; i;) {
363 client_list_item *j = i->item_next;
367 /* Clean up notification lists */
368 HASHMAP_FOREACH_KEY(map_list, notify_key, self.notify_mapping, iter) {
369 hashmap_remove(self.notify_mapping, notify_key);
371 BUXTON_LIST_FOREACH(map_list, elem) {
372 BuxtonNotification *notif = (BuxtonNotification*)elem->data;
373 if (notif->old_data) {
374 free_buxton_data(&(notif->old_data));
378 buxton_list_free_all(&map_list);
381 hashmap_free(self.notify_mapping);
382 buxton_direct_close(&self.buxton);
387 * Editor modelines - http://www.wireshark.org/tools/modelines.html
392 * indent-tabs-mode: t
395 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
396 * :indentSize=8:tabSize=8:noTabs=false: