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