ustd: get_subbuffer: assume prog died if trace cannot be found
[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");
468 /* FIXME: maybe drop this trace */
9be57e24 469 return -1;
02af3e60
PMF
470 }
471
472 return 0;
473}
474
f99c0b5c
PMF
475int consumer_loop(struct buffer_info *buf)
476{
477 int result;
478
479 pthread_cleanup_push(decrement_active_buffers, NULL);
480
481 for(;;) {
482 /* get the subbuffer */
483 result = get_subbuffer(buf);
484 if(result == -1) {
485 ERR("error getting subbuffer");
486 continue;
487 }
488 else if(result == GET_SUBBUF_DONE) {
489 /* this is done */
490 break;
491 }
492 else if(result == GET_SUBBUF_DIED) {
493 finish_consuming_dead_subbuffer(buf);
494 break;
495 }
496
497 /* write data to file */
02af3e60
PMF
498 write_current_subbuffer(buf);
499 /* FIXME: handle return value? */
f99c0b5c
PMF
500
501 /* put the subbuffer */
f99c0b5c
PMF
502 result = put_subbuffer(buf);
503 if(result == -1) {
504 ERR("unknown error putting subbuffer (channel=%s)", buf->name);
505 break;
506 }
507 else if(result == PUT_SUBBUF_PUSHED) {
508 ERR("Buffer overflow (channel=%s), reader pushed. This channel will not be usable passed this point.", buf->name);
509 break;
510 }
511 else if(result == PUT_SUBBUF_DIED) {
9c904827 512 DBG("application died while putting subbuffer");
9be57e24
PMF
513 /* Skip the first subbuffer. We are not sure it is trustable
514 * because the put_subbuffer() did not complete.
515 */
516 unwrite_last_subbuffer(buf);
f99c0b5c
PMF
517 finish_consuming_dead_subbuffer(buf);
518 break;
519 }
c970a26f
PMF
520 else if(result == PUT_SUBBUF_DONE) {
521 /* Done with this subbuffer */
522 /* FIXME: add a case where this branch is used? Upon
523 * normal trace termination, at put_subbuf time, a
524 * special last-subbuffer code could be returned by
525 * the listener.
526 */
527 break;
528 }
f99c0b5c
PMF
529 else if(result == PUT_SUBBUF_OK) {
530 }
531 }
532
533 DBG("thread for buffer %s is stopping", buf->name);
534
535 /* FIXME: destroy, unalloc... */
536
537 pthread_cleanup_pop(1);
538
539 return 0;
540}
541
f99c0b5c
PMF
542struct consumer_thread_args {
543 pid_t pid;
544 const char *bufname;
545};
546
547void *consumer_thread(void *arg)
548{
549 struct buffer_info *buf = (struct buffer_info *) arg;
550 struct consumer_thread_args *args = (struct consumer_thread_args *) arg;
551
552 DBG("GOT ARGS: pid %d bufname %s", args->pid, args->bufname);
553
554 buf = connect_buffer(args->pid, args->bufname);
555 if(buf == NULL) {
556 ERR("failed to connect to buffer");
557 goto end;
558 }
559
560 consumer_loop(buf);
561
7fc9284b 562 free((void *)args->bufname);
750f9da4 563 destroy_buffer(buf);
f99c0b5c
PMF
564
565 end:
f99c0b5c
PMF
566 free(args);
567 return NULL;
568}
569
570int start_consuming_buffer(pid_t pid, const char *bufname)
571{
572 pthread_t thr;
573 struct consumer_thread_args *args;
750f9da4 574 int result;
f99c0b5c
PMF
575
576 DBG("beginning of start_consuming_buffer: args: pid %d bufname %s", pid, bufname);
577
578 args = (struct consumer_thread_args *) malloc(sizeof(struct consumer_thread_args));
579
580 args->pid = pid;
581 args->bufname = strdup(bufname);
582 DBG("beginning2 of start_consuming_buffer: args: pid %d bufname %s", args->pid, args->bufname);
583
750f9da4
PMF
584 result = pthread_create(&thr, NULL, consumer_thread, args);
585 if(result == -1) {
586 ERR("pthread_create failed");
587 return -1;
588 }
589 result = pthread_detach(thr);
590 if(result == -1) {
591 ERR("pthread_detach failed");
592 return -1;
593 }
f99c0b5c 594 DBG("end of start_consuming_buffer: args: pid %d bufname %s", args->pid, args->bufname);
3a7b90de
PMF
595
596 return 0;
597}
598
cd226f25
PMF
599void usage(void)
600{
601 fprintf(stderr, "Usage:\nustd OPTIONS\n\nOptions:\n"
602 "\t-h\t\tDisplay this usage.\n"
603 "\t-o DIR\t\tSpecify the directory where to output the traces.\n"
bce2937a
PMF
604 "\t-s PATH\t\tSpecify the path to use for the daemon socket.\n"
605 "\t-d\t\tStart as a daemon.\n"
606 "\t--pidfile FILE\tWrite the PID in this file (when using -d).\n");
cd226f25
PMF
607}
608
609int parse_args(int argc, char **argv)
610{
611 int c;
612
613 while (1) {
614 int option_index = 0;
615 static struct option long_options[] = {
bce2937a 616 {"pidfile", 1, 0, 'p'},
cd226f25
PMF
617 {"help", 0, 0, 'h'},
618 {"version", 0, 0, 'V'},
619 {0, 0, 0, 0}
620 };
621
bce2937a 622 c = getopt_long(argc, argv, "hs:o:d", long_options, &option_index);
cd226f25
PMF
623 if (c == -1)
624 break;
625
626 switch (c) {
627 case 0:
628 printf("option %s", long_options[option_index].name);
629 if (optarg)
630 printf(" with arg %s", optarg);
631 printf("\n");
632 break;
633 case 's':
634 sock_path = optarg;
635 break;
636 case 'o':
637 trace_path = optarg;
638 if(!is_directory(trace_path)) {
639 ERR("Not a valid directory. (%s)", trace_path);
640 return -1;
641 }
642 break;
bce2937a
PMF
643 case 'd':
644 daemon_mode = 1;
645 break;
2730a7d6
PMF
646 case 'p':
647 pidfile = strdup(optarg);
648 break;
cd226f25
PMF
649 case 'h':
650 usage();
651 exit(0);
652 case 'V':
653 printf("Version 0.0\n");
654 break;
655
656 default:
657 /* unknown option or other error; error is
658 printed by getopt, just return */
659 return -1;
660 }
661 }
662
663 return 0;
664}
665
3158b808
PMF
666void sigterm_handler(int sig)
667{
668 terminate_req = 1;
669}
670
2b3c64a4
PMF
671static int write_pidfile(const char *file_name, pid_t pid)
672{
673 FILE *pidfp;
674
5d72e651 675 pidfp = fopen(file_name, "w");
2b3c64a4
PMF
676 if(!pidfp) {
677 PERROR("fopen (%s)", pidfile);
678 WARN("killing child process");
679 return -1;
680 }
681
682 fprintf(pidfp, "%d\n", pid);
683
684 fclose(pidfp);
685
686 return 0;
687}
688
bce2937a 689int start_ustd(int fd)
3796af9b
PMF
690{
691 struct ustcomm_ustd ustd;
692 int result;
a3cdd4a7 693 sigset_t sigset;
3158b808
PMF
694 struct sigaction sa;
695
696 result = sigemptyset(&sigset);
697 if(result == -1) {
4d70f833 698 PERROR("sigemptyset");
3158b808
PMF
699 return 1;
700 }
701 sa.sa_handler = sigterm_handler;
702 sa.sa_mask = sigset;
703 sa.sa_flags = SA_RESTART;
704 result = sigaction(SIGTERM, &sa, NULL);
705 if(result == -1) {
706 PERROR("sigaction");
707 return 1;
708 }
2a79ceeb
PMF
709 result = sigaction(SIGINT, &sa, NULL);
710 if(result == -1) {
711 PERROR("sigaction");
712 return 1;
713 }
3796af9b 714
cd226f25 715 result = ustcomm_init_ustd(&ustd, sock_path);
3796af9b
PMF
716 if(result == -1) {
717 ERR("failed to initialize socket");
718 return 1;
719 }
720
3158b808 721 /* setup handler for SIGPIPE */
a3cdd4a7
PMF
722 result = sigemptyset(&sigset);
723 if(result == -1) {
4d70f833 724 PERROR("sigemptyset");
a3cdd4a7
PMF
725 return 1;
726 }
727 result = sigaddset(&sigset, SIGPIPE);
728 if(result == -1) {
4d70f833 729 PERROR("sigaddset");
a3cdd4a7
PMF
730 return 1;
731 }
732 result = sigprocmask(SIG_BLOCK, &sigset, NULL);
733 if(result == -1) {
4d70f833 734 PERROR("sigprocmask");
a3cdd4a7
PMF
735 return 1;
736 }
737
2b3c64a4
PMF
738 /* Write pidfile */
739 if(pidfile) {
740 result = write_pidfile(pidfile, getpid());
741 if(result == -1) {
742 ERR("failed to write pidfile");
743 return 1;
744 }
745 }
746
bce2937a
PMF
747 /* Notify parent that we are successfully started. */
748 if(fd != -1) {
749 /* write any one character */
750 result = write(fd, "!", 1);
751 if(result == -1) {
752 PERROR("write");
753 return -1;
754 }
755 if(result != 1) {
756 ERR("Problem sending confirmation of daemon start to parent");
757 return -1;
758 }
759 result = close(fd);
760 if(result == -1) {
761 PERROR("close");
762 }
763 }
764
688760ef 765 /* app loop */
3796af9b
PMF
766 for(;;) {
767 char *recvbuf;
768
3a7b90de 769 /* check for requests on our public socket */
688760ef
PMF
770 result = ustcomm_ustd_recv_message(&ustd, &recvbuf, NULL, 100);
771 if(result == -1) {
772 ERR("error in ustcomm_ustd_recv_message");
f99c0b5c 773 goto loop_end;
688760ef
PMF
774 }
775 if(result > 0) {
776 if(!strncmp(recvbuf, "collect", 7)) {
777 pid_t pid;
778 char *bufname;
779 int result;
3796af9b 780
688760ef
PMF
781 result = sscanf(recvbuf, "%*s %d %50as", &pid, &bufname);
782 if(result != 2) {
f99c0b5c
PMF
783 ERR("parsing error: %s", recvbuf);
784 goto free_bufname;
688760ef 785 }
3796af9b 786
f99c0b5c 787 result = start_consuming_buffer(pid, bufname);
688760ef
PMF
788 if(result < 0) {
789 ERR("error in add_buffer");
f99c0b5c 790 goto free_bufname;
688760ef 791 }
f99c0b5c
PMF
792
793 free_bufname:
794 free(bufname);
3796af9b 795 }
2a79ceeb
PMF
796 else {
797 WARN("unknown command: %s", recvbuf);
798 }
3796af9b 799
688760ef 800 free(recvbuf);
3796af9b 801 }
3158b808 802
f99c0b5c
PMF
803 loop_end:
804
3158b808
PMF
805 if(terminate_req) {
806 pthread_mutex_lock(&active_buffers_mutex);
807 if(active_buffers == 0) {
808 pthread_mutex_unlock(&active_buffers_mutex);
809 break;
810 }
811 pthread_mutex_unlock(&active_buffers_mutex);
812 }
3796af9b
PMF
813 }
814
2a79ceeb
PMF
815 ustcomm_fini_ustd(&ustd);
816
3796af9b
PMF
817 return 0;
818}
bce2937a
PMF
819
820int start_ustd_daemon()
821{
822 int result;
823 int fd[2];
2730a7d6 824 pid_t child_pid;
bce2937a
PMF
825
826 result = pipe(fd);
827
2730a7d6 828 result = child_pid = fork();
bce2937a
PMF
829 if(result == -1) {
830 PERROR("fork");
831 return -1;
832 }
833 else if(result == 0) {
834 return start_ustd(fd[1]);
835 }
836 else {
837 char buf;
2730a7d6 838
bce2937a
PMF
839 result = read(fd[0], &buf, 1);
840 if(result == -1) {
841 PERROR("read");
842 return -1;
843 }
844 if(result != 1) {
845 ERR("did not receive valid confirmation that the daemon is started");
846 return -1;
847 }
848
849 result = close(fd[0]);
850 if(result == -1) {
851 PERROR("close");
852 }
853
854 DBG("The daemon is now successfully started");
855 }
856
857 /* Wait for confirmation that the server is ready. */
858
859
860 return 0;
861}
862
863int main(int argc, char **argv)
864{
865 int result;
866
867 result = parse_args(argc, argv);
868 if(result == -1) {
869 exit(1);
870 }
871
872 if(daemon_mode) {
873 result = start_ustd_daemon();
874 }
875 else {
876 result = start_ustd(-1);
877 }
878
879 return result;
880}
This page took 0.068461 seconds and 4 git commands to generate.