Move session data and functions to session.c/.h
[lttng-tools.git] / ltt-sessiond / main.c
CommitLineData
826d496d
MD
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
fac6795d
DG
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.
fac6795d
DG
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) */
ca95a216 38#include <lttng/liblttngctl.h>
fac6795d
DG
39
40#include "liblttsessiondcomm.h"
41#include "ltt-sessiond.h"
75462a81 42#include "lttngerr.h"
5b74c7b1 43#include "session.h"
fac6795d 44
75462a81 45/* Const values */
686204ab
MD
46const char default_home_dir[] = DEFAULT_HOME_DIR;
47const char default_tracing_group[] = DEFAULT_TRACING_GROUP;
48const char default_ust_sock_dir[] = DEFAULT_UST_SOCK_DIR;
49const char default_global_apps_pipe[] = DEFAULT_GLOBAL_APPS_PIPE;
50
fac6795d
DG
51/* Static functions */
52static int set_signal_handler(void);
53static int set_socket_perms(void);
1fd70b72 54static void sighandler(int sig);
fac6795d 55static void cleanup(void);
e065084a 56static void copy_common_data(struct lttcomm_lttng_msg *llm, struct lttcomm_session_msg *lsm);
fac6795d 57static int check_existing_daemon(void);
1fd70b72
DG
58static int notify_apps(const char* name);
59static int connect_app(pid_t pid);
379473d2 60static int find_app_by_pid(pid_t pid);
fac6795d 61static int init_daemon_socket(void);
e065084a
DG
62static int process_client_msg(int sock, struct lttcomm_session_msg*);
63static int send_unix_sock(int sock, void *buf, size_t len);
aaf97519 64static int setup_data_buffer(char **buf, size_t size, struct lttcomm_lttng_msg *llm);
c01bdd9d
DG
65static void add_traceable_app(struct ltt_traceable_app *lta);
66static void del_traceable_app(struct ltt_traceable_app *lta);
ca95a216
DG
67
68/* Command function */
aaf97519 69static void get_list_apps(pid_t *pids);
fac6795d 70
1fd70b72
DG
71static void *thread_manage_clients(void *data);
72static void *thread_manage_apps(void *data);
fac6795d 73
fac6795d
DG
74/* Variables */
75const char *progname;
76const char *opt_tracing_group;
5b8719f5 77static int opt_sig_parent;
fac6795d 78static int opt_daemon;
75462a81
DG
79int opt_verbose;
80int opt_quiet;
fac6795d 81static int is_root; /* Set to 1 if the daemon is running as root */
5b8719f5 82static pid_t ppid;
fac6795d
DG
83
84static char apps_unix_sock_path[PATH_MAX]; /* Global application Unix socket path */
85static char client_unix_sock_path[PATH_MAX]; /* Global client Unix socket path */
86
87static int client_socket;
88static int apps_socket;
89
90static struct ltt_session *current_session;
e065084a
DG
91
92/* Number of element for the list below. */
e065084a 93static unsigned int traceable_app_count;
fac6795d 94
e065084a 95/* Init ust traceabl application's list */
fac6795d
DG
96static struct ltt_traceable_app_list ltt_traceable_app_list = {
97 .head = CDS_LIST_HEAD_INIT(ltt_traceable_app_list.head),
98};
99
c01bdd9d
DG
100/* List mutex */
101pthread_mutex_t ltt_traceable_app_list_mutex;
102
fac6795d
DG
103/*
104 * thread_manage_apps
105 *
106 * This thread manage the application socket communication
107 */
108static 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 */
686204ab 114 struct {
fac6795d 115 int reg; /* 1:register, 0:unregister */
686204ab
MD
116 pid_t pid;
117 uid_t uid;
118 } reg_msg;
fac6795d
DG
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;
c01bdd9d 150 add_traceable_app(lta);
fac6795d
DG
151 } else {
152 /* Unregistering */
fac6795d
DG
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) {
c01bdd9d 155 del_traceable_app(lta);
379473d2 156 free(lta);
fac6795d
DG
157 break;
158 }
159 }
fac6795d
DG
160 }
161 }
162
163error:
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 */
174static void *thread_manage_clients(void *data)
175{
176 int sock, ret;
177 struct lttcomm_session_msg lsm;
fac6795d
DG
178
179 ret = lttcomm_listen_unix_sock(client_socket);
180 if (ret < 0) {
181 goto error;
182 }
183
5b8719f5
DG
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
fac6795d
DG
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));
87378cf5 204 if (ret <= 0) {
fac6795d
DG
205 continue;
206 }
207
208 /* This function dispatch the work to the LTTng or UST libs
e065084a
DG
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.
fac6795d 212 */
e065084a
DG
213 ret = process_client_msg(sock, &lsm);
214 if (ret < 0) {
215 /* Error detected but still accept command */
216 continue;
fac6795d
DG
217 }
218 }
219
220error:
221 return NULL;
222}
223
c01bdd9d
DG
224/*
225 * add_traceable_app
226 *
227 * Add a traceable application structure to the global
228 * list protected by a mutex.
229 */
230static 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 */
244static 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
e065084a
DG
255/*
256 * send_unix_sock
257 *
258 * Send data on a unix socket using the liblttsessiondcomm API.
259 *
260 * Return lttcomm error code.
261 */
262static 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
fac6795d
DG
272/*
273 * connect_app
274 *
275 * Return a socket connected to the libust communication socket
276 * of the application identified by the pid.
379473d2
DG
277 *
278 * If the pid is not found in the traceable list,
279 * return -1 to indicate error.
fac6795d
DG
280 */
281static int connect_app(pid_t pid)
282{
379473d2
DG
283 int sock, ret;
284
285 ret = find_app_by_pid(pid);
286 if (ret == 0) {
287 return -1;
288 }
fac6795d
DG
289
290 sock = ustctl_connect_pid(pid);
291 if (sock < 0) {
75462a81 292 ERR("Fail connecting to the PID %d\n", pid);
fac6795d
DG
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 */
307static 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
324error:
325 return ret;
326}
327
379473d2
DG
328/*
329 * find_app_by_pid
330 *
331 * Iterate over the traceable apps list.
332 * On success, return 1, else return 0
333 */
334static int find_app_by_pid(pid_t pid)
335{
336 struct ltt_traceable_app *iter;
337
c01bdd9d 338 pthread_mutex_lock(&ltt_traceable_app_list_mutex);
379473d2
DG
339 cds_list_for_each_entry(iter, &ltt_traceable_app_list.head, list) {
340 if (iter->pid == pid) {
c01bdd9d 341 pthread_mutex_unlock(&ltt_traceable_app_list_mutex);
379473d2
DG
342 /* Found */
343 return 1;
344 }
345 }
c01bdd9d 346 pthread_mutex_unlock(&ltt_traceable_app_list_mutex);
379473d2
DG
347
348 return 0;
349}
350
379473d2
DG
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 */
358static 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
392error:
393 return ret;
394}
395
fac6795d 396/*
ca95a216 397 * get_list_apps
fac6795d
DG
398 *
399 * List traceable user-space application and fill an
400 * array of pids.
fac6795d 401 */
aaf97519 402static void get_list_apps(pid_t *pids)
fac6795d 403{
aaf97519
DG
404 int i = 0;
405 struct ltt_traceable_app *iter;
fac6795d 406
c01bdd9d
DG
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);
e065084a 411 cds_list_for_each_entry(iter, &ltt_traceable_app_list.head, list) {
aaf97519
DG
412 pids[i] = iter->pid;
413 i++;
fac6795d 414 }
c01bdd9d 415 pthread_mutex_unlock(&ltt_traceable_app_list_mutex);
ca95a216 416}
fac6795d 417
e065084a
DG
418/*
419 * copy_common_data
420 *
421 * Copy common data between lttcomm_lttng_msg and lttcomm_session_msg
422 */
423static 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;
aaf97519
DG
427
428 /* Manage uuid */
8028d920
DG
429 if (!uuid_is_null(lsm->session_id)) {
430 uuid_copy(llm->session_id, lsm->session_id);
e065084a 431 }
aaf97519
DG
432
433 strncpy(llm->trace_name, lsm->trace_name, strlen(llm->trace_name));
8028d920 434 llm->trace_name[strlen(llm->trace_name) - 1] = '\0';
e065084a
DG
435}
436
ca95a216
DG
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 */
aaf97519 445static int setup_data_buffer(char **buf, size_t s_data, struct lttcomm_lttng_msg *llm)
ca95a216
DG
446{
447 int ret = 0;
ca95a216
DG
448 size_t buf_size;
449
450 buf_size = sizeof(struct lttcomm_lttng_msg) + s_data;
aaf97519
DG
451 *buf = malloc(buf_size);
452 if (*buf == NULL) {
ca95a216
DG
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;
aaf97519 462 memcpy(*buf, llm, sizeof(struct lttcomm_lttng_msg));
ca95a216
DG
463
464 return buf_size;
465
466error:
467 return ret;
468}
469
fac6795d
DG
470/*
471 * process_client_msg
472 *
473 * This takes the lttcomm_session_msg struct and process the command requested
e065084a
DG
474 * by the client. It then creates response(s) and send it back to the
475 * given socket (sock).
fac6795d 476 *
e065084a 477 * Return any error encountered or 0 for success.
fac6795d 478 */
e065084a 479static int process_client_msg(int sock, struct lttcomm_session_msg *lsm)
fac6795d 480{
e065084a 481 int ret;
ca95a216 482 int buf_size;
7e6e59cd 483 size_t header_size;
aaf97519
DG
484 char *send_buf = NULL;
485 struct lttcomm_lttng_msg llm;
fac6795d
DG
486
487 /* Copy common data to identify the response
488 * on the lttng client side.
489 */
e065084a 490 copy_common_data(&llm, lsm);
fac6795d 491
379473d2
DG
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
fac6795d 504 /* Default return code.
e065084a 505 * In our world, everything is OK... right? ;)
fac6795d 506 */
e065084a 507 llm.ret_code = LTTCOMM_OK;
fac6795d 508
7e6e59cd
DG
509 header_size = sizeof(struct lttcomm_lttng_msg);
510
fac6795d
DG
511 /* Process by command type */
512 switch (lsm->cmd_type) {
aaf97519
DG
513 case LTTNG_CREATE_SESSION:
514 {
8028d920 515 ret = create_session(lsm->session_name, &llm.session_id);
aaf97519 516 if (ret < 0) {
27673bb6
DG
517 if (ret == -1) {
518 ret = LTTCOMM_EXIST_SESS;
519 } else {
520 ret = LTTCOMM_FATAL;
521 }
8028d920 522 goto end;
aaf97519
DG
523 }
524
aaf97519
DG
525 buf_size = setup_data_buffer(&send_buf, 0, &llm);
526 if (buf_size < 0) {
527 ret = LTTCOMM_FATAL;
8028d920 528 goto end;
aaf97519
DG
529 }
530
aaf97519
DG
531 break;
532 }
8028d920
DG
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 }
df0da139
DG
545 case UST_CREATE_TRACE:
546 {
379473d2 547 ret = ust_create_trace(lsm->pid);
df0da139
DG
548 if (ret < 0) {
549 ret = LTTCOMM_CREATE_FAIL;
379473d2 550 goto end;
df0da139
DG
551 }
552
379473d2 553 /* No auxiliary data so only send the llm struct. */
df0da139
DG
554 goto end;
555 }
fac6795d
DG
556 case UST_LIST_APPS:
557 {
ca95a216
DG
558 /* Stop right now if no apps */
559 if (traceable_app_count == 0) {
e065084a 560 ret = LTTCOMM_NO_APPS;
8028d920 561 goto end;
e065084a
DG
562 }
563
ca95a216
DG
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;
8028d920 569 goto end;
ca95a216
DG
570 }
571
7e6e59cd 572 get_list_apps((pid_t *)(send_buf + header_size));
ca95a216 573
fac6795d
DG
574 break;
575 }
57167058
DG
576 case LTTNG_LIST_SESSIONS:
577 {
5b74c7b1 578 unsigned int session_count = get_session_count();
ca95a216
DG
579 /* Stop right now if no session */
580 if (session_count == 0) {
57167058 581 ret = LTTCOMM_NO_SESS;
8028d920 582 goto end;
57167058
DG
583 }
584
ca95a216
DG
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;
8028d920 590 goto end;
ca95a216
DG
591 }
592
5b74c7b1 593 get_lttng_session((struct lttng_session *)(send_buf + header_size));
ca95a216 594
57167058
DG
595 break;
596 }
fac6795d 597 default:
e065084a 598 {
fac6795d 599 /* Undefined command */
e065084a 600 ret = LTTCOMM_UND;
8028d920 601 goto end;
e065084a 602 }
fac6795d
DG
603 }
604
1fd70b72
DG
605 ret = send_unix_sock(sock, send_buf, buf_size);
606
ca95a216
DG
607 if (send_buf != NULL) {
608 free(send_buf);
609 }
610
e065084a
DG
611 return ret;
612
8028d920 613end:
e065084a
DG
614 /* Notify client of error */
615 llm.ret_code = ret;
ca95a216 616 llm.size_payload = 0;
e065084a
DG
617 send_unix_sock(sock, (void*) &llm, sizeof(llm));
618
8028d920 619 return ret;
fac6795d
DG
620}
621
622/*
623 * usage function on stderr
624 */
625static void usage(void)
626{
b716ce68
DG
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");
fac6795d
DG
636}
637
638/*
639 * daemon argument parsing
640 */
641static 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' },
5b8719f5 649 { "sig-parent", 0, 0, 'S' },
fac6795d
DG
650 { "help", 0, 0, 'h' },
651 { "group", 1, 0, 'g' },
652 { "version", 0, 0, 'V' },
75462a81 653 { "quiet", 0, 0, 'q' },
fac6795d
DG
654 { NULL, 0, 0, 0 }
655 };
656
657 while (1) {
658 int option_index = 0;
75462a81 659 c = getopt_long(argc, argv, "dhqVS" "a:c:g:s:", long_options, &option_index);
fac6795d
DG
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;
b716ce68 671 case 'c':
fac6795d
DG
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);
5b8719f5
DG
689 case 'S':
690 opt_sig_parent = 1;
691 break;
75462a81
DG
692 case 'q':
693 opt_quiet = 1;
694 break;
fac6795d
DG
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 */
712static 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
747end:
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 */
758static 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 */
778static const char *get_home_dir(void)
779{
780 const char *home_path;
781
686204ab 782 if ((home_path = (const char *) getenv("HOME")) == NULL) {
fac6795d
DG
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 */
794static 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) {
75462a81 805 ERR("Missing tracing group. Aborting execution.\n");
fac6795d
DG
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
815end:
816 return ret;
817}
818
fac6795d
DG
819/*
820 * set_signal_handler
821 *
822 * Setup signal handler for :
823 * SIGINT, SIGTERM, SIGPIPE
824 */
825static 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 */
862static void sighandler(int sig)
863{
864 switch (sig) {
865 case SIGPIPE:
87378cf5 866 return;
fac6795d
DG
867 case SIGINT:
868 case SIGTERM:
869 cleanup();
686204ab 870 break;
fac6795d
DG
871 default:
872 break;
873 }
874
875 exit(EXIT_SUCCESS);
876}
877
878/*
879 * cleanup
880 *
881 * Cleanup the daemon on exit
882 */
883static void cleanup()
884{
885 /* <fun> */
b716ce68
DG
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);
fac6795d
DG
888 /* </fun> */
889
890 unlink(client_unix_sock_path);
891 unlink(apps_unix_sock_path);
892}
893
894/*
895 * main
896 */
897int 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) {
53094c05
DG
912 ret = daemon(0, 0);
913 if (ret < 0) {
914 perror("daemon");
915 goto error;
916 }
fac6795d
DG
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) {
75462a81 950 ERR("Already running daemon.\n");
ab118b20
DG
951 /* We do not goto error because we must not
952 * cleanup() because a daemon is already working.
953 */
954 return EXIT_FAILURE;
fac6795d
DG
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
5b8719f5
DG
971 /* Get parent pid if -S, --sig-parent is specified. */
972 if (opt_sig_parent) {
973 ppid = getppid();
974 }
975
fac6795d
DG
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
1003error:
1004 cleanup();
1005
1006 return EXIT_FAILURE;
1007}
This page took 0.067712 seconds and 5 git commands to generate.