ustd: update ustd signal handling to avoid wakeups every 100 ms
[ust.git] / ustd / ustd.c
CommitLineData
c39c72ee 1/* Copyright (C) 2009 Pierre-Marc Fournier
1f8b0dff 2 *
c39c72ee
PMF
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
1f8b0dff 7 *
c39c72ee 8 * This library is distributed in the hope that it will be useful,
1f8b0dff 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
c39c72ee
PMF
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
1f8b0dff 12 *
c39c72ee
PMF
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1f8b0dff
PMF
16 */
17
3796af9b
PMF
18#define _GNU_SOURCE
19
20#include <sys/types.h>
cd226f25 21#include <sys/stat.h>
3796af9b 22#include <sys/shm.h>
688760ef
PMF
23#include <fcntl.h>
24#include <unistd.h>
3a7b90de 25#include <pthread.h>
a3cdd4a7 26#include <signal.h>
3796af9b
PMF
27
28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
a3cdd4a7
PMF
31#include <errno.h>
32#include <assert.h>
cd226f25 33#include <getopt.h>
3796af9b 34
0b0cd937 35#include "ustd.h"
6af64c43 36#include "usterr.h"
3796af9b
PMF
37#include "ustcomm.h"
38
3a7b90de
PMF
39/* return value: 0 = subbuffer is finished, it won't produce data anymore
40 * 1 = got subbuffer successfully
41 * <0 = error
42 */
3796af9b 43
8cefc145
PMF
44#define GET_SUBBUF_OK 1
45#define GET_SUBBUF_DONE 0
46#define GET_SUBBUF_DIED 2
47
a3cdd4a7
PMF
48#define PUT_SUBBUF_OK 1
49#define PUT_SUBBUF_DIED 0
50#define PUT_SUBBUF_PUSHED 2
c970a26f 51#define PUT_SUBBUF_DONE 3
a3cdd4a7 52
c97d4437 53char *sock_path=NULL;
cd226f25 54char *trace_path=NULL;
bce2937a 55int daemon_mode = 0;
2730a7d6 56char *pidfile = NULL;
cd226f25 57
3158b808
PMF
58/* Number of active buffers and the mutex to protect it. */
59int active_buffers = 0;
60pthread_mutex_t active_buffers_mutex = PTHREAD_MUTEX_INITIALIZER;
61/* Whether a request to end the program was received. */
e4f78278 62volatile sig_atomic_t terminate_req = 0;
3158b808 63
688760ef
PMF
64int get_subbuffer(struct buffer_info *buf)
65{
ab805ccd
PMF
66 char *send_msg=NULL;
67 char *received_msg=NULL;
68 char *rep_code=NULL;
688760ef
PMF
69 int retval;
70 int result;
71
72 asprintf(&send_msg, "get_subbuffer %s", buf->name);
3bb56863 73 result = ustcomm_send_request(&buf->conn, send_msg, &received_msg);
53080380 74 if((result == -1 && (errno == ECONNRESET || errno == EPIPE)) || result == 0) {
409e2abe
PMF
75 DBG("app died while being traced");
76 retval = GET_SUBBUF_DIED;
ab805ccd 77 goto end;
a3cdd4a7
PMF
78 }
79 else if(result < 0) {
3bb56863 80 ERR("get_subbuffer: ustcomm_send_request failed");
ab805ccd
PMF
81 retval = -1;
82 goto end;
688760ef 83 }
688760ef
PMF
84
85 result = sscanf(received_msg, "%as %ld", &rep_code, &buf->consumed_old);
3a7b90de 86 if(result != 2 && result != 1) {
688760ef 87 ERR("unable to parse response to get_subbuffer");
ab805ccd 88 retval = -1;
750f9da4 89 free(received_msg);
ab805ccd 90 goto end_rep;
688760ef 91 }
3a7b90de 92
688760ef
PMF
93 if(!strcmp(rep_code, "OK")) {
94 DBG("got subbuffer %s", buf->name);
8cefc145 95 retval = GET_SUBBUF_OK;
688760ef 96 }
3a7b90de 97 else if(nth_token_is(received_msg, "END", 0) == 1) {
ab805ccd
PMF
98 retval = GET_SUBBUF_DONE;
99 goto end_rep;
3a7b90de 100 }
c970a26f 101 else if(!strcmp(received_msg, "NOTFOUND")) {
9c904827 102 DBG("For buffer %s, the trace was not found. This likely means it was destroyed by the user.", buf->name);
463011e4 103 retval = GET_SUBBUF_DIED;
c970a26f
PMF
104 goto end_rep;
105 }
688760ef 106 else {
3a7b90de
PMF
107 DBG("error getting subbuffer %s", buf->name);
108 retval = -1;
688760ef
PMF
109 }
110
3a7b90de 111 /* FIMXE: free correctly the stuff */
ab805ccd
PMF
112end_rep:
113 if(rep_code)
114 free(rep_code);
115end:
116 if(send_msg)
117 free(send_msg);
118 if(received_msg)
119 free(received_msg);
120
688760ef
PMF
121 return retval;
122}
123
124int put_subbuffer(struct buffer_info *buf)
125{
ab805ccd
PMF
126 char *send_msg=NULL;
127 char *received_msg=NULL;
128 char *rep_code=NULL;
688760ef
PMF
129 int retval;
130 int result;
131
132 asprintf(&send_msg, "put_subbuffer %s %ld", buf->name, buf->consumed_old);
3bb56863 133 result = ustcomm_send_request(&buf->conn, send_msg, &received_msg);
53080380 134 if(result < 0 && (errno == ECONNRESET || errno == EPIPE)) {
ab805ccd
PMF
135 retval = PUT_SUBBUF_DIED;
136 goto end;
137 }
c970a26f 138 else if(result < 0) {
688760ef 139 ERR("put_subbuffer: send_message failed");
ab805ccd
PMF
140 retval = -1;
141 goto end;
688760ef 142 }
c970a26f
PMF
143 else if(result == 0) {
144 /* Program seems finished. However this might not be
145 * the last subbuffer that has to be collected.
146 */
147 retval = PUT_SUBBUF_DIED;
148 goto end;
149 }
688760ef
PMF
150
151 result = sscanf(received_msg, "%as", &rep_code);
152 if(result != 1) {
153 ERR("unable to parse response to put_subbuffer");
ab805ccd
PMF
154 retval = -1;
155 goto end_rep;
688760ef 156 }
688760ef
PMF
157
158 if(!strcmp(rep_code, "OK")) {
159 DBG("subbuffer put %s", buf->name);
a3cdd4a7 160 retval = PUT_SUBBUF_OK;
688760ef 161 }
2ddb81a8 162 else if(!strcmp(received_msg, "NOTFOUND")) {
9c904827 163 DBG("For buffer %s, the trace was not found. This likely means it was destroyed by the user.", buf->name);
2ddb81a8
PMF
164 /* However, maybe this was not the last subbuffer. So
165 * we return the program died.
166 */
167 retval = PUT_SUBBUF_DIED;
168 goto end_rep;
169 }
688760ef 170 else {
a3cdd4a7 171 DBG("put_subbuffer: received error, we were pushed");
ab805ccd
PMF
172 retval = PUT_SUBBUF_PUSHED;
173 goto end_rep;
688760ef
PMF
174 }
175
ab805ccd
PMF
176end_rep:
177 if(rep_code)
178 free(rep_code);
179
180end:
181 if(send_msg)
182 free(send_msg);
183 if(received_msg)
184 free(received_msg);
185
688760ef
PMF
186 return retval;
187}
188
3158b808
PMF
189void decrement_active_buffers(void *arg)
190{
191 pthread_mutex_lock(&active_buffers_mutex);
192 active_buffers--;
193 pthread_mutex_unlock(&active_buffers_mutex);
194}
195
72ebd39a
PMF
196int create_dir_if_needed(char *dir)
197{
198 int result;
199 result = mkdir(dir, 0777);
200 if(result == -1) {
201 if(errno != EEXIST) {
4d70f833 202 PERROR("mkdir");
72ebd39a
PMF
203 return -1;
204 }
205 }
206
207 return 0;
208}
209
cd226f25
PMF
210int is_directory(const char *dir)
211{
212 int result;
213 struct stat st;
214
215 result = stat(dir, &st);
216 if(result == -1) {
217 PERROR("stat");
218 return 0;
219 }
220
221 if(!S_ISDIR(st.st_mode)) {
222 return 0;
223 }
224
225 return 1;
226}
227
f99c0b5c 228struct buffer_info *connect_buffer(pid_t pid, const char *bufname)
3a7b90de
PMF
229{
230 struct buffer_info *buf;
231 char *send_msg;
232 char *received_msg;
233 int result;
234 char *tmp;
235 int fd;
a3cdd4a7 236 struct shmid_ds shmds;
3a7b90de
PMF
237
238 buf = (struct buffer_info *) malloc(sizeof(struct buffer_info));
239 if(buf == NULL) {
240 ERR("add_buffer: insufficient memory");
f99c0b5c 241 return NULL;
3a7b90de
PMF
242 }
243
244 buf->name = bufname;
245 buf->pid = pid;
246
4e2a8808
PMF
247 /* connect to app */
248 result = ustcomm_connect_app(buf->pid, &buf->conn);
249 if(result) {
a3cdd4a7 250 WARN("unable to connect to process, it probably died before we were able to connect");
f99c0b5c 251 return NULL;
4e2a8808
PMF
252 }
253
ed1317e7
PMF
254 /* get pidunique */
255 asprintf(&send_msg, "get_pidunique");
256 result = ustcomm_send_request(&buf->conn, send_msg, &received_msg);
257 free(send_msg);
258 if(result == -1) {
259 ERR("problem in ustcomm_send_request(get_pidunique)");
f99c0b5c 260 return NULL;
ed1317e7 261 }
0ed54020
PMF
262 if(result == 0) {
263 goto error;
264 }
ed1317e7
PMF
265
266 result = sscanf(received_msg, "%lld", &buf->pidunique);
267 if(result != 1) {
268 ERR("unable to parse response to get_pidunique");
f99c0b5c 269 return NULL;
ed1317e7
PMF
270 }
271 free(received_msg);
272 DBG("got pidunique %lld", buf->pidunique);
273
3a7b90de
PMF
274 /* get shmid */
275 asprintf(&send_msg, "get_shmid %s", buf->name);
a3cdd4a7 276 result = ustcomm_send_request(&buf->conn, send_msg, &received_msg);
3a7b90de 277 free(send_msg);
a3cdd4a7
PMF
278 if(result == -1) {
279 ERR("problem in ustcomm_send_request(get_shmid)");
f99c0b5c 280 return NULL;
a3cdd4a7 281 }
0ed54020
PMF
282 if(result == 0) {
283 goto error;
284 }
3a7b90de 285
8cefc145
PMF
286 result = sscanf(received_msg, "%d %d", &buf->shmid, &buf->bufstruct_shmid);
287 if(result != 2) {
204141ee 288 ERR("unable to parse response to get_shmid (\"%s\")", received_msg);
f99c0b5c 289 return NULL;
3a7b90de
PMF
290 }
291 free(received_msg);
8cefc145 292 DBG("got shmids %d %d", buf->shmid, buf->bufstruct_shmid);
3a7b90de
PMF
293
294 /* get n_subbufs */
295 asprintf(&send_msg, "get_n_subbufs %s", buf->name);
a3cdd4a7 296 result = ustcomm_send_request(&buf->conn, send_msg, &received_msg);
3a7b90de 297 free(send_msg);
a3cdd4a7
PMF
298 if(result == -1) {
299 ERR("problem in ustcomm_send_request(g_n_subbufs)");
f99c0b5c 300 return NULL;
a3cdd4a7 301 }
0ed54020
PMF
302 if(result == 0) {
303 goto error;
304 }
3a7b90de
PMF
305
306 result = sscanf(received_msg, "%d", &buf->n_subbufs);
307 if(result != 1) {
308 ERR("unable to parse response to get_n_subbufs");
f99c0b5c 309 return NULL;
3a7b90de
PMF
310 }
311 free(received_msg);
312 DBG("got n_subbufs %d", buf->n_subbufs);
313
314 /* get subbuf size */
315 asprintf(&send_msg, "get_subbuf_size %s", buf->name);
0ed54020 316 result = ustcomm_send_request(&buf->conn, send_msg, &received_msg);
3a7b90de 317 free(send_msg);
0ed54020
PMF
318 if(result == -1) {
319 ERR("problem in ustcomm_send_request(get_subbuf_size)");
320 return NULL;
321 }
322 if(result == 0) {
323 goto error;
324 }
3a7b90de
PMF
325
326 result = sscanf(received_msg, "%d", &buf->subbuf_size);
327 if(result != 1) {
328 ERR("unable to parse response to get_subbuf_size");
f99c0b5c 329 return NULL;
3a7b90de
PMF
330 }
331 free(received_msg);
332 DBG("got subbuf_size %d", buf->subbuf_size);
333
334 /* attach memory */
335 buf->mem = shmat(buf->shmid, NULL, 0);
336 if(buf->mem == (void *) 0) {
4d70f833 337 PERROR("shmat");
f99c0b5c 338 return NULL;
3a7b90de 339 }
8cefc145
PMF
340 DBG("successfully attached buffer memory");
341
342 buf->bufstruct_mem = shmat(buf->bufstruct_shmid, NULL, 0);
343 if(buf->bufstruct_mem == (void *) 0) {
4d70f833 344 PERROR("shmat");
f99c0b5c 345 return NULL;
8cefc145
PMF
346 }
347 DBG("successfully attached buffer bufstruct memory");
3a7b90de 348
a3cdd4a7
PMF
349 /* obtain info on the memory segment */
350 result = shmctl(buf->shmid, IPC_STAT, &shmds);
351 if(result == -1) {
4d70f833 352 PERROR("shmctl");
f99c0b5c 353 return NULL;
a3cdd4a7
PMF
354 }
355 buf->memlen = shmds.shm_segsz;
356
3a7b90de 357 /* open file for output */
cd226f25
PMF
358 if(!trace_path) {
359 /* Only create the directory if using the default path, because
360 * of the risk of typo when using trace path override. We don't
361 * want to risk creating plenty of useless directories in that case.
362 */
363 result = create_dir_if_needed(USTD_DEFAULT_TRACE_PATH);
364 if(result == -1) {
365 ERR("could not create directory %s", USTD_DEFAULT_TRACE_PATH);
f99c0b5c 366 return NULL;
cd226f25
PMF
367 }
368
369 trace_path = USTD_DEFAULT_TRACE_PATH;
72ebd39a
PMF
370 }
371
ed1317e7 372 asprintf(&tmp, "%s/%u_%lld", trace_path, buf->pid, buf->pidunique);
72ebd39a
PMF
373 result = create_dir_if_needed(tmp);
374 if(result == -1) {
375 ERR("could not create directory %s", tmp);
376 free(tmp);
f99c0b5c 377 return NULL;
72ebd39a
PMF
378 }
379 free(tmp);
380
204141ee 381 asprintf(&tmp, "%s/%u_%lld/%s", trace_path, buf->pid, buf->pidunique, buf->name);
ed1317e7 382 result = fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 00600);
3a7b90de
PMF
383 if(result == -1) {
384 PERROR("open");
6cb88bc0 385 ERR("failed opening trace file %s", tmp);
f99c0b5c 386 return NULL;
3a7b90de
PMF
387 }
388 buf->file_fd = fd;
389 free(tmp);
390
3158b808
PMF
391 pthread_mutex_lock(&active_buffers_mutex);
392 active_buffers++;
393 pthread_mutex_unlock(&active_buffers_mutex);
394
f99c0b5c 395 return buf;
0ed54020
PMF
396
397error:
398 free(buf);
399 return NULL;
f99c0b5c
PMF
400}
401
750f9da4
PMF
402static void destroy_buffer(struct buffer_info *buf)
403{
404 int result;
405
406 result = ustcomm_close_app(&buf->conn);
407 if(result == -1) {
408 WARN("problem calling ustcomm_close_app");
409 }
410
411 result = shmdt(buf->mem);
412 if(result == -1) {
413 PERROR("shmdt");
414 }
415
416 result = shmdt(buf->bufstruct_mem);
417 if(result == -1) {
418 PERROR("shmdt");
419 }
420
421 result = close(buf->file_fd);
422 if(result == -1) {
423 PERROR("close");
424 }
425
426 free(buf);
427}
428
9be57e24
PMF
429int unwrite_last_subbuffer(struct buffer_info *buf)
430{
431 int result;
432
433 result = ftruncate(buf->file_fd, buf->previous_offset);
434 if(result == -1) {
435 PERROR("ftruncate");
436 return -1;
437 }
438
439 result = lseek(buf->file_fd, buf->previous_offset, SEEK_SET);
440 if(result == (int)(off_t)-1) {
441 PERROR("lseek");
442 return -1;
443 }
444
445 return 0;
446}
447
02af3e60
PMF
448int write_current_subbuffer(struct buffer_info *buf)
449{
450 int result;
451
452 void *subbuf_mem = buf->mem + (buf->consumed_old & (buf->n_subbufs * buf->subbuf_size-1));
453
454 size_t cur_sb_size = subbuffer_data_size(subbuf_mem);
455
9be57e24
PMF
456 off_t cur_offset = lseek(buf->file_fd, 0, SEEK_CUR);
457 if(cur_offset == (off_t)-1) {
458 PERROR("lseek");
459 return -1;
460 }
461
462 buf->previous_offset = cur_offset;
463 DBG("previous_offset: %ld", cur_offset);
464
02af3e60
PMF
465 result = patient_write(buf->file_fd, subbuf_mem, cur_sb_size);
466 if(result == -1) {
467 PERROR("write");
9be57e24 468 return -1;
02af3e60
PMF
469 }
470
471 return 0;
472}
473
f99c0b5c
PMF
474int consumer_loop(struct buffer_info *buf)
475{
476 int result;
477
478 pthread_cleanup_push(decrement_active_buffers, NULL);
479
480 for(;;) {
481 /* get the subbuffer */
482 result = get_subbuffer(buf);
483 if(result == -1) {
484 ERR("error getting subbuffer");
485 continue;
486 }
487 else if(result == GET_SUBBUF_DONE) {
488 /* this is done */
489 break;
490 }
491 else if(result == GET_SUBBUF_DIED) {
492 finish_consuming_dead_subbuffer(buf);
493 break;
494 }
495
496 /* write data to file */
b88f0774
PMF
497 result = write_current_subbuffer(buf);
498 if(result == -1) {
499 ERR("Failed writing a subbuffer to file (channel=%s). Dropping this buffer.", buf->name);
500 }
f99c0b5c
PMF
501
502 /* put the subbuffer */
f99c0b5c
PMF
503 result = put_subbuffer(buf);
504 if(result == -1) {
505 ERR("unknown error putting subbuffer (channel=%s)", buf->name);
506 break;
507 }
508 else if(result == PUT_SUBBUF_PUSHED) {
509 ERR("Buffer overflow (channel=%s), reader pushed. This channel will not be usable passed this point.", buf->name);
510 break;
511 }
512 else if(result == PUT_SUBBUF_DIED) {
9c904827 513 DBG("application died while putting subbuffer");
9be57e24
PMF
514 /* Skip the first subbuffer. We are not sure it is trustable
515 * because the put_subbuffer() did not complete.
516 */
517 unwrite_last_subbuffer(buf);
f99c0b5c
PMF
518 finish_consuming_dead_subbuffer(buf);
519 break;
520 }
c970a26f
PMF
521 else if(result == PUT_SUBBUF_DONE) {
522 /* Done with this subbuffer */
523 /* FIXME: add a case where this branch is used? Upon
524 * normal trace termination, at put_subbuf time, a
525 * special last-subbuffer code could be returned by
526 * the listener.
527 */
528 break;
529 }
f99c0b5c
PMF
530 else if(result == PUT_SUBBUF_OK) {
531 }
532 }
533
534 DBG("thread for buffer %s is stopping", buf->name);
535
536 /* FIXME: destroy, unalloc... */
537
538 pthread_cleanup_pop(1);
539
540 return 0;
541}
542
f99c0b5c
PMF
543struct consumer_thread_args {
544 pid_t pid;
545 const char *bufname;
546};
547
548void *consumer_thread(void *arg)
549{
550 struct buffer_info *buf = (struct buffer_info *) arg;
551 struct consumer_thread_args *args = (struct consumer_thread_args *) arg;
f05eefd8
PMF
552 int result;
553 sigset_t sigset;
f99c0b5c
PMF
554
555 DBG("GOT ARGS: pid %d bufname %s", args->pid, args->bufname);
556
f05eefd8
PMF
557 /* Block signals that should be handled by the main thread. */
558 result = sigemptyset(&sigset);
559 if(result == -1) {
560 PERROR("sigemptyset");
561 goto end;
562 }
563 result = sigaddset(&sigset, SIGTERM);
564 if(result == -1) {
565 PERROR("sigaddset");
566 goto end;
567 }
568 result = sigaddset(&sigset, SIGINT);
569 if(result == -1) {
570 PERROR("sigaddset");
571 goto end;
572 }
573 result = sigprocmask(SIG_BLOCK, &sigset, NULL);
574 if(result == -1) {
575 PERROR("sigprocmask");
576 goto end;
577 }
578
f99c0b5c
PMF
579 buf = connect_buffer(args->pid, args->bufname);
580 if(buf == NULL) {
581 ERR("failed to connect to buffer");
582 goto end;
583 }
584
585 consumer_loop(buf);
586
7fc9284b 587 free((void *)args->bufname);
750f9da4 588 destroy_buffer(buf);
f99c0b5c
PMF
589
590 end:
f99c0b5c
PMF
591 free(args);
592 return NULL;
593}
594
595int start_consuming_buffer(pid_t pid, const char *bufname)
596{
597 pthread_t thr;
598 struct consumer_thread_args *args;
750f9da4 599 int result;
f99c0b5c
PMF
600
601 DBG("beginning of start_consuming_buffer: args: pid %d bufname %s", pid, bufname);
602
603 args = (struct consumer_thread_args *) malloc(sizeof(struct consumer_thread_args));
604
605 args->pid = pid;
606 args->bufname = strdup(bufname);
607 DBG("beginning2 of start_consuming_buffer: args: pid %d bufname %s", args->pid, args->bufname);
608
750f9da4
PMF
609 result = pthread_create(&thr, NULL, consumer_thread, args);
610 if(result == -1) {
611 ERR("pthread_create failed");
612 return -1;
613 }
614 result = pthread_detach(thr);
615 if(result == -1) {
616 ERR("pthread_detach failed");
617 return -1;
618 }
f99c0b5c 619 DBG("end of start_consuming_buffer: args: pid %d bufname %s", args->pid, args->bufname);
3a7b90de
PMF
620
621 return 0;
622}
623
cd226f25
PMF
624void usage(void)
625{
626 fprintf(stderr, "Usage:\nustd OPTIONS\n\nOptions:\n"
627 "\t-h\t\tDisplay this usage.\n"
628 "\t-o DIR\t\tSpecify the directory where to output the traces.\n"
bce2937a
PMF
629 "\t-s PATH\t\tSpecify the path to use for the daemon socket.\n"
630 "\t-d\t\tStart as a daemon.\n"
631 "\t--pidfile FILE\tWrite the PID in this file (when using -d).\n");
cd226f25
PMF
632}
633
634int parse_args(int argc, char **argv)
635{
636 int c;
637
638 while (1) {
639 int option_index = 0;
640 static struct option long_options[] = {
bce2937a 641 {"pidfile", 1, 0, 'p'},
cd226f25
PMF
642 {"help", 0, 0, 'h'},
643 {"version", 0, 0, 'V'},
644 {0, 0, 0, 0}
645 };
646
bce2937a 647 c = getopt_long(argc, argv, "hs:o:d", long_options, &option_index);
cd226f25
PMF
648 if (c == -1)
649 break;
650
651 switch (c) {
652 case 0:
653 printf("option %s", long_options[option_index].name);
654 if (optarg)
655 printf(" with arg %s", optarg);
656 printf("\n");
657 break;
658 case 's':
659 sock_path = optarg;
660 break;
661 case 'o':
662 trace_path = optarg;
663 if(!is_directory(trace_path)) {
664 ERR("Not a valid directory. (%s)", trace_path);
665 return -1;
666 }
667 break;
bce2937a
PMF
668 case 'd':
669 daemon_mode = 1;
670 break;
2730a7d6
PMF
671 case 'p':
672 pidfile = strdup(optarg);
673 break;
cd226f25
PMF
674 case 'h':
675 usage();
676 exit(0);
677 case 'V':
678 printf("Version 0.0\n");
679 break;
680
681 default:
682 /* unknown option or other error; error is
683 printed by getopt, just return */
684 return -1;
685 }
686 }
687
688 return 0;
689}
690
3158b808
PMF
691void sigterm_handler(int sig)
692{
693 terminate_req = 1;
694}
695
2b3c64a4
PMF
696static int write_pidfile(const char *file_name, pid_t pid)
697{
698 FILE *pidfp;
699
5d72e651 700 pidfp = fopen(file_name, "w");
2b3c64a4
PMF
701 if(!pidfp) {
702 PERROR("fopen (%s)", pidfile);
703 WARN("killing child process");
704 return -1;
705 }
706
707 fprintf(pidfp, "%d\n", pid);
708
709 fclose(pidfp);
710
711 return 0;
712}
713
bce2937a 714int start_ustd(int fd)
3796af9b
PMF
715{
716 struct ustcomm_ustd ustd;
717 int result;
a3cdd4a7 718 sigset_t sigset;
3158b808 719 struct sigaction sa;
f05eefd8 720 int timeout = -1;
3158b808
PMF
721
722 result = sigemptyset(&sigset);
723 if(result == -1) {
4d70f833 724 PERROR("sigemptyset");
3158b808
PMF
725 return 1;
726 }
727 sa.sa_handler = sigterm_handler;
728 sa.sa_mask = sigset;
f05eefd8 729 sa.sa_flags = 0;
3158b808
PMF
730 result = sigaction(SIGTERM, &sa, NULL);
731 if(result == -1) {
732 PERROR("sigaction");
733 return 1;
734 }
2a79ceeb
PMF
735 result = sigaction(SIGINT, &sa, NULL);
736 if(result == -1) {
737 PERROR("sigaction");
738 return 1;
739 }
3796af9b 740
cd226f25 741 result = ustcomm_init_ustd(&ustd, sock_path);
3796af9b
PMF
742 if(result == -1) {
743 ERR("failed to initialize socket");
744 return 1;
745 }
746
3158b808 747 /* setup handler for SIGPIPE */
a3cdd4a7
PMF
748 result = sigemptyset(&sigset);
749 if(result == -1) {
4d70f833 750 PERROR("sigemptyset");
a3cdd4a7
PMF
751 return 1;
752 }
753 result = sigaddset(&sigset, SIGPIPE);
754 if(result == -1) {
4d70f833 755 PERROR("sigaddset");
a3cdd4a7
PMF
756 return 1;
757 }
758 result = sigprocmask(SIG_BLOCK, &sigset, NULL);
759 if(result == -1) {
4d70f833 760 PERROR("sigprocmask");
a3cdd4a7
PMF
761 return 1;
762 }
763
2b3c64a4
PMF
764 /* Write pidfile */
765 if(pidfile) {
766 result = write_pidfile(pidfile, getpid());
767 if(result == -1) {
768 ERR("failed to write pidfile");
769 return 1;
770 }
771 }
772
bce2937a
PMF
773 /* Notify parent that we are successfully started. */
774 if(fd != -1) {
775 /* write any one character */
776 result = write(fd, "!", 1);
777 if(result == -1) {
778 PERROR("write");
779 return -1;
780 }
781 if(result != 1) {
782 ERR("Problem sending confirmation of daemon start to parent");
783 return -1;
784 }
785 result = close(fd);
786 if(result == -1) {
787 PERROR("close");
788 }
789 }
790
688760ef 791 /* app loop */
3796af9b
PMF
792 for(;;) {
793 char *recvbuf;
794
3a7b90de 795 /* check for requests on our public socket */
f05eefd8
PMF
796 result = ustcomm_ustd_recv_message(&ustd, &recvbuf, NULL, timeout);
797 if(result == -1 && errno == EINTR) {
798 /* Caught signal */
799 printf("Caught signal\n");
800 }
801 else if(result == -1) {
688760ef 802 ERR("error in ustcomm_ustd_recv_message");
f99c0b5c 803 goto loop_end;
688760ef 804 }
f05eefd8 805 else if(result > 0) {
688760ef
PMF
806 if(!strncmp(recvbuf, "collect", 7)) {
807 pid_t pid;
808 char *bufname;
809 int result;
3796af9b 810
688760ef
PMF
811 result = sscanf(recvbuf, "%*s %d %50as", &pid, &bufname);
812 if(result != 2) {
f99c0b5c
PMF
813 ERR("parsing error: %s", recvbuf);
814 goto free_bufname;
688760ef 815 }
3796af9b 816
f99c0b5c 817 result = start_consuming_buffer(pid, bufname);
688760ef
PMF
818 if(result < 0) {
819 ERR("error in add_buffer");
f99c0b5c 820 goto free_bufname;
688760ef 821 }
f99c0b5c
PMF
822
823 free_bufname:
824 free(bufname);
3796af9b 825 }
2a79ceeb
PMF
826 else {
827 WARN("unknown command: %s", recvbuf);
828 }
3796af9b 829
688760ef 830 free(recvbuf);
3796af9b 831 }
3158b808 832
f99c0b5c
PMF
833 loop_end:
834
3158b808
PMF
835 if(terminate_req) {
836 pthread_mutex_lock(&active_buffers_mutex);
837 if(active_buffers == 0) {
838 pthread_mutex_unlock(&active_buffers_mutex);
839 break;
840 }
841 pthread_mutex_unlock(&active_buffers_mutex);
f05eefd8 842 timeout = 100;
3158b808 843 }
3796af9b
PMF
844 }
845
2a79ceeb
PMF
846 ustcomm_fini_ustd(&ustd);
847
3796af9b
PMF
848 return 0;
849}
bce2937a
PMF
850
851int start_ustd_daemon()
852{
853 int result;
854 int fd[2];
2730a7d6 855 pid_t child_pid;
bce2937a
PMF
856
857 result = pipe(fd);
858
2730a7d6 859 result = child_pid = fork();
bce2937a
PMF
860 if(result == -1) {
861 PERROR("fork");
862 return -1;
863 }
864 else if(result == 0) {
865 return start_ustd(fd[1]);
866 }
867 else {
868 char buf;
2730a7d6 869
bce2937a
PMF
870 result = read(fd[0], &buf, 1);
871 if(result == -1) {
872 PERROR("read");
873 return -1;
874 }
875 if(result != 1) {
876 ERR("did not receive valid confirmation that the daemon is started");
877 return -1;
878 }
879
880 result = close(fd[0]);
881 if(result == -1) {
882 PERROR("close");
883 }
884
885 DBG("The daemon is now successfully started");
886 }
887
888 /* Wait for confirmation that the server is ready. */
889
890
891 return 0;
892}
893
894int main(int argc, char **argv)
895{
896 int result;
897
898 result = parse_args(argc, argv);
899 if(result == -1) {
900 exit(1);
901 }
902
903 if(daemon_mode) {
904 result = start_ustd_daemon();
905 }
906 else {
907 result = start_ustd(-1);
908 }
909
910 return result;
911}
This page took 0.070797 seconds and 4 git commands to generate.