Move session data and functions to session.c/.h
[lttng-tools.git] / ltt-sessiond / main.c
1 /*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #define _GNU_SOURCE
20 #include <fcntl.h>
21 #include <getopt.h>
22 #include <grp.h>
23 #include <limits.h>
24 #include <pthread.h>
25 #include <signal.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/ipc.h>
30 #include <sys/shm.h>
31 #include <sys/socket.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35
36 #include <urcu/list.h> /* URCU list library (-lurcu) */
37 #include <ust/ustctl.h> /* UST control lib (-lust) */
38 #include <lttng/liblttngctl.h>
39
40 #include "liblttsessiondcomm.h"
41 #include "ltt-sessiond.h"
42 #include "lttngerr.h"
43 #include "session.h"
44
45 /* Const values */
46 const char default_home_dir[] = DEFAULT_HOME_DIR;
47 const char default_tracing_group[] = DEFAULT_TRACING_GROUP;
48 const char default_ust_sock_dir[] = DEFAULT_UST_SOCK_DIR;
49 const char default_global_apps_pipe[] = DEFAULT_GLOBAL_APPS_PIPE;
50
51 /* Static functions */
52 static int set_signal_handler(void);
53 static int set_socket_perms(void);
54 static void sighandler(int sig);
55 static void cleanup(void);
56 static void copy_common_data(struct lttcomm_lttng_msg *llm, struct lttcomm_session_msg *lsm);
57 static int check_existing_daemon(void);
58 static int notify_apps(const char* name);
59 static int connect_app(pid_t pid);
60 static int find_app_by_pid(pid_t pid);
61 static int init_daemon_socket(void);
62 static int process_client_msg(int sock, struct lttcomm_session_msg*);
63 static int send_unix_sock(int sock, void *buf, size_t len);
64 static int setup_data_buffer(char **buf, size_t size, struct lttcomm_lttng_msg *llm);
65 static void add_traceable_app(struct ltt_traceable_app *lta);
66 static void del_traceable_app(struct ltt_traceable_app *lta);
67
68 /* Command function */
69 static void get_list_apps(pid_t *pids);
70
71 static void *thread_manage_clients(void *data);
72 static void *thread_manage_apps(void *data);
73
74 /* Variables */
75 const char *progname;
76 const char *opt_tracing_group;
77 static int opt_sig_parent;
78 static int opt_daemon;
79 int opt_verbose;
80 int opt_quiet;
81 static int is_root; /* Set to 1 if the daemon is running as root */
82 static pid_t ppid;
83
84 static char apps_unix_sock_path[PATH_MAX]; /* Global application Unix socket path */
85 static char client_unix_sock_path[PATH_MAX]; /* Global client Unix socket path */
86
87 static int client_socket;
88 static int apps_socket;
89
90 static struct ltt_session *current_session;
91
92 /* Number of element for the list below. */
93 static unsigned int traceable_app_count;
94
95 /* Init ust traceabl application's list */
96 static struct ltt_traceable_app_list ltt_traceable_app_list = {
97 .head = CDS_LIST_HEAD_INIT(ltt_traceable_app_list.head),
98 };
99
100 /* List mutex */
101 pthread_mutex_t ltt_traceable_app_list_mutex;
102
103 /*
104 * thread_manage_apps
105 *
106 * This thread manage the application socket communication
107 */
108 static void *thread_manage_apps(void *data)
109 {
110 int sock, ret;
111 struct ltt_traceable_app *lta;
112
113 /* TODO: Something more elegant is needed but fine for now */
114 struct {
115 int reg; /* 1:register, 0:unregister */
116 pid_t pid;
117 uid_t uid;
118 } reg_msg;
119
120 /* Notify all applications to register */
121 notify_apps(default_global_apps_pipe);
122
123 ret = lttcomm_listen_unix_sock(apps_socket);
124 if (ret < 0) {
125 goto error;
126 }
127
128 while (1) {
129 /* Blocking call, waiting for transmission */
130 sock = lttcomm_accept_unix_sock(apps_socket);
131 if (sock < 0) {
132 goto error;
133 }
134
135 /* Basic recv here to handle the very simple data
136 * that the libust send to register (reg_msg).
137 */
138 ret = recv(sock, &reg_msg, sizeof(reg_msg), 0);
139 if (ret < 0) {
140 perror("recv");
141 continue;
142 }
143
144 /* Add application to the global traceable list */
145 if (reg_msg.reg == 1) {
146 /* Registering */
147 lta = malloc(sizeof(struct ltt_traceable_app));
148 lta->pid = reg_msg.pid;
149 lta->uid = reg_msg.uid;
150 add_traceable_app(lta);
151 } else {
152 /* Unregistering */
153 cds_list_for_each_entry(lta, &ltt_traceable_app_list.head, list) {
154 if (lta->pid == reg_msg.pid && lta->uid == reg_msg.uid) {
155 del_traceable_app(lta);
156 free(lta);
157 break;
158 }
159 }
160 }
161 }
162
163 error:
164
165 return NULL;
166 }
167
168 /*
169 * thread_manage_clients
170 *
171 * This thread manage all clients request using the unix
172 * client socket for communication.
173 */
174 static void *thread_manage_clients(void *data)
175 {
176 int sock, ret;
177 struct lttcomm_session_msg lsm;
178
179 ret = lttcomm_listen_unix_sock(client_socket);
180 if (ret < 0) {
181 goto error;
182 }
183
184 /* Notify parent pid that we are ready
185 * to accept command for client side.
186 */
187 if (opt_sig_parent) {
188 kill(ppid, SIGCHLD);
189 }
190
191 while (1) {
192 /* Blocking call, waiting for transmission */
193 sock = lttcomm_accept_unix_sock(client_socket);
194 if (sock < 0) {
195 goto error;
196 }
197
198 /*
199 * Data is received from the lttng client. The struct
200 * lttcomm_session_msg (lsm) contains the command and data
201 * request of the client.
202 */
203 ret = lttcomm_recv_unix_sock(sock, &lsm, sizeof(lsm));
204 if (ret <= 0) {
205 continue;
206 }
207
208 /* This function dispatch the work to the LTTng or UST libs
209 * and then sends back the response to the client. This is needed
210 * because there might be more then one lttcomm_lttng_msg to
211 * send out so process_client_msg do both jobs.
212 */
213 ret = process_client_msg(sock, &lsm);
214 if (ret < 0) {
215 /* Error detected but still accept command */
216 continue;
217 }
218 }
219
220 error:
221 return NULL;
222 }
223
224 /*
225 * add_traceable_app
226 *
227 * Add a traceable application structure to the global
228 * list protected by a mutex.
229 */
230 static void add_traceable_app(struct ltt_traceable_app *lta)
231 {
232 pthread_mutex_lock(&ltt_traceable_app_list_mutex);
233 cds_list_add(&lta->list, &ltt_traceable_app_list.head);
234 traceable_app_count++;
235 pthread_mutex_unlock(&ltt_traceable_app_list_mutex);
236 }
237
238 /*
239 * del_traceable_app
240 *
241 * Delete a traceable application structure from the
242 * global list protected by a mutex.
243 */
244 static void del_traceable_app(struct ltt_traceable_app *lta)
245 {
246 pthread_mutex_lock(&ltt_traceable_app_list_mutex);
247 cds_list_del(&lta->list);
248 /* Sanity check */
249 if (traceable_app_count != 0) {
250 traceable_app_count--;
251 }
252 pthread_mutex_unlock(&ltt_traceable_app_list_mutex);
253 }
254
255 /*
256 * send_unix_sock
257 *
258 * Send data on a unix socket using the liblttsessiondcomm API.
259 *
260 * Return lttcomm error code.
261 */
262 static int send_unix_sock(int sock, void *buf, size_t len)
263 {
264 /* Check valid length */
265 if (len <= 0) {
266 return -1;
267 }
268
269 return lttcomm_send_unix_sock(sock, buf, len);
270 }
271
272 /*
273 * connect_app
274 *
275 * Return a socket connected to the libust communication socket
276 * of the application identified by the pid.
277 *
278 * If the pid is not found in the traceable list,
279 * return -1 to indicate error.
280 */
281 static int connect_app(pid_t pid)
282 {
283 int sock, ret;
284
285 ret = find_app_by_pid(pid);
286 if (ret == 0) {
287 return -1;
288 }
289
290 sock = ustctl_connect_pid(pid);
291 if (sock < 0) {
292 ERR("Fail connecting to the PID %d\n", pid);
293 }
294
295 return sock;
296 }
297
298 /*
299 * notify_apps
300 *
301 * Notify apps by writing 42 to a named pipe using name.
302 * Every applications waiting for a ltt-sessiond will be notified
303 * and re-register automatically to the session daemon.
304 *
305 * Return open or write error value.
306 */
307 static int notify_apps(const char *name)
308 {
309 int fd;
310 int ret = -1;
311
312 /* Try opening the global pipe */
313 fd = open(name, O_WRONLY);
314 if (fd < 0) {
315 goto error;
316 }
317
318 /* Notify by writing on the pipe */
319 ret = write(fd, "42", 2);
320 if (ret < 0) {
321 perror("write");
322 }
323
324 error:
325 return ret;
326 }
327
328 /*
329 * find_app_by_pid
330 *
331 * Iterate over the traceable apps list.
332 * On success, return 1, else return 0
333 */
334 static int find_app_by_pid(pid_t pid)
335 {
336 struct ltt_traceable_app *iter;
337
338 pthread_mutex_lock(&ltt_traceable_app_list_mutex);
339 cds_list_for_each_entry(iter, &ltt_traceable_app_list.head, list) {
340 if (iter->pid == pid) {
341 pthread_mutex_unlock(&ltt_traceable_app_list_mutex);
342 /* Found */
343 return 1;
344 }
345 }
346 pthread_mutex_unlock(&ltt_traceable_app_list_mutex);
347
348 return 0;
349 }
350
351 /*
352 * ust_create_trace
353 *
354 * Create an userspace trace using pid.
355 * This trace is then appended to the current session
356 * ust trace list.
357 */
358 static int ust_create_trace(pid_t pid)
359 {
360 int sock, ret;
361 struct ltt_ust_trace *trace;
362
363 trace = malloc(sizeof(struct ltt_ust_trace));
364 if (trace == NULL) {
365 perror("malloc");
366 ret = -1;
367 goto error;
368 }
369
370 /* Init */
371 trace->pid = pid;
372 trace->shmid = 0;
373
374 /* Connect to app using ustctl API */
375 sock = connect_app(pid);
376 if (sock < 0) {
377 ret = LTTCOMM_NO_TRACEABLE;
378 goto error;
379 }
380
381 ret = ustctl_create_trace(sock, "auto");
382 if (ret < 0) {
383 ret = LTTCOMM_CREATE_FAIL;
384 goto error;
385 }
386
387 /* Check if current session is valid */
388 if (current_session) {
389 cds_list_add(&trace->list, &current_session->ust_traces);
390 }
391
392 error:
393 return ret;
394 }
395
396 /*
397 * get_list_apps
398 *
399 * List traceable user-space application and fill an
400 * array of pids.
401 */
402 static void get_list_apps(pid_t *pids)
403 {
404 int i = 0;
405 struct ltt_traceable_app *iter;
406
407 /* Protected by a mutex here because the threads manage_client
408 * and manage_apps can access this list.
409 */
410 pthread_mutex_lock(&ltt_traceable_app_list_mutex);
411 cds_list_for_each_entry(iter, &ltt_traceable_app_list.head, list) {
412 pids[i] = iter->pid;
413 i++;
414 }
415 pthread_mutex_unlock(&ltt_traceable_app_list_mutex);
416 }
417
418 /*
419 * copy_common_data
420 *
421 * Copy common data between lttcomm_lttng_msg and lttcomm_session_msg
422 */
423 static void copy_common_data(struct lttcomm_lttng_msg *llm, struct lttcomm_session_msg *lsm)
424 {
425 llm->cmd_type = lsm->cmd_type;
426 llm->pid = lsm->pid;
427
428 /* Manage uuid */
429 if (!uuid_is_null(lsm->session_id)) {
430 uuid_copy(llm->session_id, lsm->session_id);
431 }
432
433 strncpy(llm->trace_name, lsm->trace_name, strlen(llm->trace_name));
434 llm->trace_name[strlen(llm->trace_name) - 1] = '\0';
435 }
436
437 /*
438 * setup_data_buffer
439 *
440 * Setup the outgoing data buffer for the response
441 * data allocating the right amount of memory.
442 *
443 * Return total size of the buffer pointed by buf.
444 */
445 static int setup_data_buffer(char **buf, size_t s_data, struct lttcomm_lttng_msg *llm)
446 {
447 int ret = 0;
448 size_t buf_size;
449
450 buf_size = sizeof(struct lttcomm_lttng_msg) + s_data;
451 *buf = malloc(buf_size);
452 if (*buf == NULL) {
453 perror("malloc");
454 ret = -1;
455 goto error;
456 }
457
458 /* Setup lttcomm_lttng_msg data and copy
459 * it to the newly allocated buffer.
460 */
461 llm->size_payload = s_data;
462 memcpy(*buf, llm, sizeof(struct lttcomm_lttng_msg));
463
464 return buf_size;
465
466 error:
467 return ret;
468 }
469
470 /*
471 * process_client_msg
472 *
473 * This takes the lttcomm_session_msg struct and process the command requested
474 * by the client. It then creates response(s) and send it back to the
475 * given socket (sock).
476 *
477 * Return any error encountered or 0 for success.
478 */
479 static int process_client_msg(int sock, struct lttcomm_session_msg *lsm)
480 {
481 int ret;
482 int buf_size;
483 size_t header_size;
484 char *send_buf = NULL;
485 struct lttcomm_lttng_msg llm;
486
487 /* Copy common data to identify the response
488 * on the lttng client side.
489 */
490 copy_common_data(&llm, lsm);
491
492 /* Check command that needs a session */
493 if (lsm->cmd_type != LTTNG_CREATE_SESSION &&
494 lsm->cmd_type != LTTNG_LIST_SESSIONS &&
495 lsm->cmd_type != UST_LIST_APPS)
496 {
497 current_session = find_session_by_uuid(lsm->session_id);
498 if (current_session == NULL) {
499 ret = LTTCOMM_SELECT_SESS;
500 goto end;
501 }
502 }
503
504 /* Default return code.
505 * In our world, everything is OK... right? ;)
506 */
507 llm.ret_code = LTTCOMM_OK;
508
509 header_size = sizeof(struct lttcomm_lttng_msg);
510
511 /* Process by command type */
512 switch (lsm->cmd_type) {
513 case LTTNG_CREATE_SESSION:
514 {
515 ret = create_session(lsm->session_name, &llm.session_id);
516 if (ret < 0) {
517 if (ret == -1) {
518 ret = LTTCOMM_EXIST_SESS;
519 } else {
520 ret = LTTCOMM_FATAL;
521 }
522 goto end;
523 }
524
525 buf_size = setup_data_buffer(&send_buf, 0, &llm);
526 if (buf_size < 0) {
527 ret = LTTCOMM_FATAL;
528 goto end;
529 }
530
531 break;
532 }
533 case LTTNG_DESTROY_SESSION:
534 {
535 ret = destroy_session(&lsm->session_id);
536 if (ret < 0) {
537 ret = LTTCOMM_NO_SESS;
538 } else {
539 ret = LTTCOMM_OK;
540 }
541
542 /* No auxiliary data so only send the llm struct. */
543 goto end;
544 }
545 case UST_CREATE_TRACE:
546 {
547 ret = ust_create_trace(lsm->pid);
548 if (ret < 0) {
549 ret = LTTCOMM_CREATE_FAIL;
550 goto end;
551 }
552
553 /* No auxiliary data so only send the llm struct. */
554 goto end;
555 }
556 case UST_LIST_APPS:
557 {
558 /* Stop right now if no apps */
559 if (traceable_app_count == 0) {
560 ret = LTTCOMM_NO_APPS;
561 goto end;
562 }
563
564 /* Setup data buffer and details for transmission */
565 buf_size = setup_data_buffer(&send_buf,
566 sizeof(pid_t) * traceable_app_count, &llm);
567 if (buf_size < 0) {
568 ret = LTTCOMM_FATAL;
569 goto end;
570 }
571
572 get_list_apps((pid_t *)(send_buf + header_size));
573
574 break;
575 }
576 case LTTNG_LIST_SESSIONS:
577 {
578 unsigned int session_count = get_session_count();
579 /* Stop right now if no session */
580 if (session_count == 0) {
581 ret = LTTCOMM_NO_SESS;
582 goto end;
583 }
584
585 /* Setup data buffer and details for transmission */
586 buf_size = setup_data_buffer(&send_buf,
587 (sizeof(struct lttng_session) * session_count), &llm);
588 if (buf_size < 0) {
589 ret = LTTCOMM_FATAL;
590 goto end;
591 }
592
593 get_lttng_session((struct lttng_session *)(send_buf + header_size));
594
595 break;
596 }
597 default:
598 {
599 /* Undefined command */
600 ret = LTTCOMM_UND;
601 goto end;
602 }
603 }
604
605 ret = send_unix_sock(sock, send_buf, buf_size);
606
607 if (send_buf != NULL) {
608 free(send_buf);
609 }
610
611 return ret;
612
613 end:
614 /* Notify client of error */
615 llm.ret_code = ret;
616 llm.size_payload = 0;
617 send_unix_sock(sock, (void*) &llm, sizeof(llm));
618
619 return ret;
620 }
621
622 /*
623 * usage function on stderr
624 */
625 static void usage(void)
626 {
627 fprintf(stderr, "Usage: %s OPTIONS\n\nOptions:\n", progname);
628 fprintf(stderr, " -h, --help Display this usage.\n");
629 fprintf(stderr, " -c, --client-sock PATH Specify path for the client unix socket\n");
630 fprintf(stderr, " -a, --apps-sock PATH Specify path for apps unix socket.\n");
631 fprintf(stderr, " -d, --daemonize Start as a daemon.\n");
632 fprintf(stderr, " -g, --group NAME Specify the tracing group name. (default: tracing)\n");
633 fprintf(stderr, " -V, --version Show version number.\n");
634 fprintf(stderr, " -S, --sig-parent Send SIGCHLD to parent pid to notify readiness.\n");
635 fprintf(stderr, " -q, --quiet No output at all.\n");
636 }
637
638 /*
639 * daemon argument parsing
640 */
641 static int parse_args(int argc, char **argv)
642 {
643 int c;
644
645 static struct option long_options[] = {
646 { "client-sock", 1, 0, 'c' },
647 { "apps-sock", 1, 0, 'a' },
648 { "daemonize", 0, 0, 'd' },
649 { "sig-parent", 0, 0, 'S' },
650 { "help", 0, 0, 'h' },
651 { "group", 1, 0, 'g' },
652 { "version", 0, 0, 'V' },
653 { "quiet", 0, 0, 'q' },
654 { NULL, 0, 0, 0 }
655 };
656
657 while (1) {
658 int option_index = 0;
659 c = getopt_long(argc, argv, "dhqVS" "a:c:g:s:", long_options, &option_index);
660 if (c == -1) {
661 break;
662 }
663
664 switch (c) {
665 case 0:
666 fprintf(stderr, "option %s", long_options[option_index].name);
667 if (optarg) {
668 fprintf(stderr, " with arg %s\n", optarg);
669 }
670 break;
671 case 'c':
672 snprintf(client_unix_sock_path, PATH_MAX, "%s", optarg);
673 break;
674 case 'a':
675 snprintf(apps_unix_sock_path, PATH_MAX, "%s", optarg);
676 break;
677 case 'd':
678 opt_daemon = 1;
679 break;
680 case 'g':
681 opt_tracing_group = strdup(optarg);
682 break;
683 case 'h':
684 usage();
685 exit(EXIT_FAILURE);
686 case 'V':
687 fprintf(stdout, "%s\n", VERSION);
688 exit(EXIT_SUCCESS);
689 case 'S':
690 opt_sig_parent = 1;
691 break;
692 case 'q':
693 opt_quiet = 1;
694 break;
695 default:
696 /* Unknown option or other error.
697 * Error is printed by getopt, just return */
698 return -1;
699 }
700 }
701
702 return 0;
703 }
704
705 /*
706 * init_daemon_socket
707 *
708 * Creates the two needed socket by the daemon.
709 * apps_socket - The communication socket for all UST apps.
710 * client_socket - The communication of the cli tool (lttng).
711 */
712 static int init_daemon_socket()
713 {
714 int ret = 0;
715 mode_t old_umask;
716
717 old_umask = umask(0);
718
719 /* Create client tool unix socket */
720 client_socket = lttcomm_create_unix_sock(client_unix_sock_path);
721 if (client_socket < 0) {
722 ret = -1;
723 goto end;
724 }
725
726 /* File permission MUST be 660 */
727 ret = chmod(client_unix_sock_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
728 if (ret < 0) {
729 perror("chmod");
730 goto end;
731 }
732
733 /* Create the application unix socket */
734 apps_socket = lttcomm_create_unix_sock(apps_unix_sock_path);
735 if (apps_socket < 0) {
736 ret = -1;
737 goto end;
738 }
739
740 /* File permission MUST be 660 */
741 ret = chmod(apps_unix_sock_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
742 if (ret < 0) {
743 perror("chmod");
744 goto end;
745 }
746
747 end:
748 umask(old_umask);
749 return ret;
750 }
751
752 /*
753 * check_existing_daemon
754 *
755 * Check if the global socket is available.
756 * If yes, error is returned.
757 */
758 static int check_existing_daemon()
759 {
760 int ret;
761
762 ret = access(client_unix_sock_path, F_OK);
763 if (ret == 0) {
764 ret = access(apps_unix_sock_path, F_OK);
765 }
766
767 return ret;
768 }
769
770 /*
771 * get_home_dir
772 *
773 * Return pointer to home directory path using
774 * the env variable HOME.
775 *
776 * Default : /tmp
777 */
778 static const char *get_home_dir(void)
779 {
780 const char *home_path;
781
782 if ((home_path = (const char *) getenv("HOME")) == NULL) {
783 home_path = default_home_dir;
784 }
785
786 return home_path;
787 }
788
789 /*
790 * set_socket_perms
791 *
792 * Set the tracing group gid onto the client socket.
793 */
794 static int set_socket_perms(void)
795 {
796 int ret;
797 struct group *grp;
798
799 /* Decide which group name to use */
800 (opt_tracing_group != NULL) ?
801 (grp = getgrnam(opt_tracing_group)) :
802 (grp = getgrnam(default_tracing_group));
803
804 if (grp == NULL) {
805 ERR("Missing tracing group. Aborting execution.\n");
806 ret = -1;
807 goto end;
808 }
809
810 ret = chown(client_unix_sock_path, 0, grp->gr_gid);
811 if (ret < 0) {
812 perror("chown");
813 }
814
815 end:
816 return ret;
817 }
818
819 /*
820 * set_signal_handler
821 *
822 * Setup signal handler for :
823 * SIGINT, SIGTERM, SIGPIPE
824 */
825 static int set_signal_handler(void)
826 {
827 int ret = 0;
828 struct sigaction sa;
829 sigset_t sigset;
830
831 if ((ret = sigemptyset(&sigset)) < 0) {
832 perror("sigemptyset");
833 return ret;
834 }
835
836 sa.sa_handler = sighandler;
837 sa.sa_mask = sigset;
838 sa.sa_flags = 0;
839 if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
840 perror("sigaction");
841 return ret;
842 }
843
844 if ((ret = sigaction(SIGINT, &sa, NULL)) < 0) {
845 perror("sigaction");
846 return ret;
847 }
848
849 if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) {
850 perror("sigaction");
851 return ret;
852 }
853
854 return ret;
855 }
856
857 /**
858 * sighandler
859 *
860 * Signal handler for the daemon
861 */
862 static void sighandler(int sig)
863 {
864 switch (sig) {
865 case SIGPIPE:
866 return;
867 case SIGINT:
868 case SIGTERM:
869 cleanup();
870 break;
871 default:
872 break;
873 }
874
875 exit(EXIT_SUCCESS);
876 }
877
878 /*
879 * cleanup
880 *
881 * Cleanup the daemon on exit
882 */
883 static void cleanup()
884 {
885 /* <fun> */
886 MSG("\n%c[%d;%dm*** assert failed *** ==> %c[%dm", 27,1,31,27,0);
887 MSG("%c[%d;%dmMatthew, BEET driven development works!%c[%dm",27,1,33,27,0);
888 /* </fun> */
889
890 unlink(client_unix_sock_path);
891 unlink(apps_unix_sock_path);
892 }
893
894 /*
895 * main
896 */
897 int main(int argc, char **argv)
898 {
899 int i;
900 int ret = 0;
901 void *status;
902 pthread_t threads[2];
903
904 /* Parse arguments */
905 progname = argv[0];
906 if ((ret = parse_args(argc, argv) < 0)) {
907 goto error;
908 }
909
910 /* Daemonize */
911 if (opt_daemon) {
912 ret = daemon(0, 0);
913 if (ret < 0) {
914 perror("daemon");
915 goto error;
916 }
917 }
918
919 /* Check if daemon is UID = 0 */
920 is_root = !getuid();
921
922 /* Set all sockets path */
923 if (is_root) {
924 if (strlen(apps_unix_sock_path) == 0) {
925 (snprintf(apps_unix_sock_path, PATH_MAX,
926 DEFAULT_GLOBAL_APPS_UNIX_SOCK));
927 }
928
929 if (strlen(client_unix_sock_path) == 0) {
930 (snprintf(client_unix_sock_path, PATH_MAX,
931 DEFAULT_GLOBAL_CLIENT_UNIX_SOCK));
932 }
933 } else {
934 if (strlen(apps_unix_sock_path) == 0) {
935 (snprintf(apps_unix_sock_path, PATH_MAX,
936 DEFAULT_HOME_APPS_UNIX_SOCK, get_home_dir()));
937 }
938
939 /* Set the cli tool unix socket path */
940 if (strlen(client_unix_sock_path) == 0) {
941 (snprintf(client_unix_sock_path, PATH_MAX,
942 DEFAULT_HOME_CLIENT_UNIX_SOCK, get_home_dir()));
943 }
944 }
945
946 /* See if daemon already exist. If any of the two
947 * socket needed by the daemon are present, this test fails
948 */
949 if ((ret = check_existing_daemon()) == 0) {
950 ERR("Already running daemon.\n");
951 /* We do not goto error because we must not
952 * cleanup() because a daemon is already working.
953 */
954 return EXIT_FAILURE;
955 }
956
957 if (set_signal_handler() < 0) {
958 goto error;
959 }
960
961 /* Setup the two needed unix socket */
962 if (init_daemon_socket() < 0) {
963 goto error;
964 }
965
966 /* Set credentials to socket */
967 if (is_root && (set_socket_perms() < 0)) {
968 goto error;
969 }
970
971 /* Get parent pid if -S, --sig-parent is specified. */
972 if (opt_sig_parent) {
973 ppid = getppid();
974 }
975
976 while (1) {
977 /* Create thread to manage the client socket */
978 ret = pthread_create(&threads[0], NULL, thread_manage_clients, (void *) NULL);
979 if (ret != 0) {
980 perror("pthread_create");
981 goto error;
982 }
983
984 /* Create thread to manage application socket */
985 ret = pthread_create(&threads[1], NULL, thread_manage_apps, (void *) NULL);
986 if (ret != 0) {
987 perror("pthread_create");
988 goto error;
989 }
990
991 for (i = 0; i < 2; i++) {
992 ret = pthread_join(threads[i], &status);
993 if (ret != 0) {
994 perror("pthread_join");
995 goto error;
996 }
997 }
998 }
999
1000 cleanup();
1001 return 0;
1002
1003 error:
1004 cleanup();
1005
1006 return EXIT_FAILURE;
1007 }
This page took 0.048773 seconds and 4 git commands to generate.