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