ust-consumerd: fix exit race crashes
[ust.git] / ust-consumerd / ust-consumerd.c
CommitLineData
c39c72ee 1/* Copyright (C) 2009 Pierre-Marc Fournier
d159ac37 2 * 2010 Alexis Halle
1f8b0dff 3 *
c39c72ee
PMF
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
1f8b0dff 8 *
c39c72ee 9 * This library is distributed in the hope that it will be useful,
1f8b0dff 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
c39c72ee
PMF
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
1f8b0dff 13 *
c39c72ee
PMF
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1f8b0dff
PMF
17 */
18
3796af9b
PMF
19#define _GNU_SOURCE
20
21#include <sys/types.h>
cd226f25 22#include <sys/stat.h>
3796af9b 23#include <sys/shm.h>
688760ef
PMF
24#include <fcntl.h>
25#include <unistd.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
9dc7b7ff 35#include "ust/ustconsumer.h"
fbae86d6 36#include "../libustconsumer/lowlevel.h"
6af64c43 37#include "usterr.h"
a3cdd4a7 38
c97d4437 39char *sock_path=NULL;
cd226f25 40char *trace_path=NULL;
bce2937a 41int daemon_mode = 0;
2730a7d6 42char *pidfile = NULL;
cd226f25 43
9dc7b7ff 44struct ustconsumer_instance *instance;
688760ef 45
d159ac37
AH
46struct buffer_info_local {
47 /* output file */
48 int file_fd;
49 /* the offset we must truncate to, to unput the last subbuffer */
50 off_t previous_offset;
51};
688760ef 52
d159ac37 53static int write_pidfile(const char *file_name, pid_t pid)
688760ef 54{
d159ac37 55 FILE *pidfp;
688760ef 56
d159ac37
AH
57 pidfp = fopen(file_name, "w");
58 if(!pidfp) {
59 PERROR("fopen (%s)", file_name);
60 WARN("killing child process");
61 return -1;
688760ef
PMF
62 }
63
d159ac37 64 fprintf(pidfp, "%d\n", pid);
ab805ccd 65
d159ac37 66 fclose(pidfp);
688760ef 67
d159ac37 68 return 0;
3158b808
PMF
69}
70
72ebd39a
PMF
71int create_dir_if_needed(char *dir)
72{
73 int result;
74 result = mkdir(dir, 0777);
75 if(result == -1) {
76 if(errno != EEXIST) {
4d70f833 77 PERROR("mkdir");
72ebd39a
PMF
78 return -1;
79 }
80 }
81
82 return 0;
83}
84
d159ac37 85int unwrite_last_subbuffer(struct buffer_info *buf)
cd226f25
PMF
86{
87 int result;
d159ac37 88 struct buffer_info_local *buf_local = buf->user_data;
cd226f25 89
d159ac37 90 result = ftruncate(buf_local->file_fd, buf_local->previous_offset);
cd226f25 91 if(result == -1) {
d159ac37
AH
92 PERROR("ftruncate");
93 return -1;
cd226f25
PMF
94 }
95
d159ac37
AH
96 result = lseek(buf_local->file_fd, buf_local->previous_offset, SEEK_SET);
97 if(result == (int)(off_t)-1) {
98 PERROR("lseek");
99 return -1;
cd226f25
PMF
100 }
101
d159ac37 102 return 0;
cd226f25
PMF
103}
104
d159ac37 105int write_current_subbuffer(struct buffer_info *buf)
3a7b90de 106{
3a7b90de 107 int result;
d159ac37 108 struct buffer_info_local *buf_local = buf->user_data;
3a7b90de 109
d159ac37 110 void *subbuf_mem = buf->mem + (buf->consumed_old & (buf->n_subbufs * buf->subbuf_size-1));
3a7b90de 111
d159ac37 112 size_t cur_sb_size = subbuffer_data_size(subbuf_mem);
4e2a8808 113
d159ac37
AH
114 off_t cur_offset = lseek(buf_local->file_fd, 0, SEEK_CUR);
115 if(cur_offset == (off_t)-1) {
116 PERROR("lseek");
117 return -1;
0ed54020 118 }
ed1317e7 119
d159ac37
AH
120 buf_local->previous_offset = cur_offset;
121 DBG("previous_offset: %ld", cur_offset);
ed1317e7 122
d159ac37 123 result = patient_write(buf_local->file_fd, subbuf_mem, cur_sb_size);
a3cdd4a7 124 if(result == -1) {
d159ac37
AH
125 PERROR("write");
126 return -1;
0ed54020 127 }
3a7b90de 128
d159ac37
AH
129 return 0;
130}
3a7b90de 131
9dc7b7ff 132int on_read_subbuffer(struct ustconsumer_callbacks *data, struct buffer_info *buf)
d159ac37
AH
133{
134 return write_current_subbuffer(buf);
135}
3a7b90de 136
9dc7b7ff 137int on_read_partial_subbuffer(struct ustconsumer_callbacks *data, struct buffer_info *buf,
d159ac37
AH
138 long subbuf_index, unsigned long valid_length)
139{
140 struct buffer_info_local *buf_local = buf->user_data;
141 char *tmp;
142 int result;
143 unsigned long pad_size;
3a7b90de 144
d159ac37 145 result = patient_write(buf_local->file_fd, buf->mem + subbuf_index * buf->subbuf_size, valid_length);
0ed54020 146 if(result == -1) {
d159ac37 147 ERR("Error writing to buffer file");
fbae86d6 148 return result;
0ed54020 149 }
3a7b90de 150
d159ac37
AH
151 /* pad with empty bytes */
152 pad_size = PAGE_ALIGN(valid_length)-valid_length;
153 if(pad_size) {
7032c7d3 154 tmp = zmalloc(pad_size);
d159ac37
AH
155 result = patient_write(buf_local->file_fd, tmp, pad_size);
156 if(result == -1) {
157 ERR("Error writing to buffer file");
fbae86d6 158 return result;
d159ac37
AH
159 }
160 free(tmp);
3a7b90de 161 }
fbae86d6 162 return result;
d159ac37 163}
8cefc145 164
9dc7b7ff 165int on_open_buffer(struct ustconsumer_callbacks *data, struct buffer_info *buf)
d159ac37
AH
166{
167 char *tmp;
168 int result;
169 int fd;
170 struct buffer_info_local *buf_local =
7032c7d3 171 zmalloc(sizeof(struct buffer_info_local));
3a7b90de 172
d159ac37
AH
173 if(!buf_local) {
174 ERR("could not allocate buffer_info_local struct");
175 return 1;
a3cdd4a7 176 }
d159ac37
AH
177
178 buf->user_data = buf_local;
a3cdd4a7 179
3a7b90de 180 /* open file for output */
cd226f25
PMF
181 if(!trace_path) {
182 /* Only create the directory if using the default path, because
183 * of the risk of typo when using trace path override. We don't
184 * want to risk creating plenty of useless directories in that case.
185 */
9dc7b7ff 186 result = create_dir_if_needed(USTCONSUMER_DEFAULT_TRACE_PATH);
cd226f25 187 if(result == -1) {
9dc7b7ff 188 ERR("could not create directory %s", USTCONSUMER_DEFAULT_TRACE_PATH);
d159ac37 189 return 1;
cd226f25
PMF
190 }
191
9dc7b7ff 192 trace_path = USTCONSUMER_DEFAULT_TRACE_PATH;
72ebd39a
PMF
193 }
194
08b8805e
DG
195 if (asprintf(&tmp, "%s/%u_%lld", trace_path, buf->pid, buf->pidunique) < 0) {
196 ERR("on_open_buffer : asprintf failed (%s/%u_%lld)",
197 trace_path, buf->pid, buf->pidunique);
198 return 1;
199 }
72ebd39a
PMF
200 result = create_dir_if_needed(tmp);
201 if(result == -1) {
202 ERR("could not create directory %s", tmp);
203 free(tmp);
d159ac37 204 return 1;
72ebd39a
PMF
205 }
206 free(tmp);
207
08b8805e
DG
208 if (asprintf(&tmp, "%s/%u_%lld/%s", trace_path, buf->pid, buf->pidunique, buf->name) < 0) {
209 ERR("on_open_buffer : asprintf failed (%s/%u_%lld/%s)",
210 trace_path, buf->pid, buf->pidunique, buf->name);
211 return 1;
212 }
5343b286 213again:
ed1317e7 214 result = fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 00600);
5343b286
JW
215 if (result == -1 && errno == EINTR)
216 goto again;
217
3a7b90de
PMF
218 if(result == -1) {
219 PERROR("open");
6cb88bc0 220 ERR("failed opening trace file %s", tmp);
d159ac37 221 return 1;
3a7b90de 222 }
d159ac37 223 buf_local->file_fd = fd;
3a7b90de
PMF
224 free(tmp);
225
d159ac37 226 return 0;
f99c0b5c
PMF
227}
228
9dc7b7ff 229int on_close_buffer(struct ustconsumer_callbacks *data, struct buffer_info *buf)
750f9da4 230{
d159ac37 231 struct buffer_info_local *buf_local = buf->user_data;
5343b286
JW
232 int result;
233
234again:
235 result = close(buf_local->file_fd);
236 if (result == -1 && errno == EINTR)
237 goto again;
d159ac37 238 free(buf_local);
750f9da4
PMF
239 if(result == -1) {
240 PERROR("close");
241 }
9be57e24
PMF
242 return 0;
243}
244
9dc7b7ff 245int on_put_error(struct ustconsumer_callbacks *data, struct buffer_info *buf)
02af3e60 246{
fbae86d6 247 return unwrite_last_subbuffer(buf);
02af3e60
PMF
248}
249
9dc7b7ff 250struct ustconsumer_callbacks *new_callbacks()
f99c0b5c 251{
9dc7b7ff
NC
252 struct ustconsumer_callbacks *callbacks =
253 zmalloc(sizeof(struct ustconsumer_callbacks));
f99c0b5c 254
d159ac37
AH
255 if(!callbacks)
256 return NULL;
f99c0b5c 257
d159ac37
AH
258 callbacks->on_open_buffer = on_open_buffer;
259 callbacks->on_close_buffer = on_close_buffer;
260 callbacks->on_read_subbuffer = on_read_subbuffer;
261 callbacks->on_read_partial_subbuffer = on_read_partial_subbuffer;
262 callbacks->on_put_error = on_put_error;
263 callbacks->on_new_thread = NULL;
264 callbacks->on_close_thread = NULL;
265 callbacks->on_trace_end = NULL;
f99c0b5c 266
d159ac37 267 return callbacks;
f99c0b5c 268
f99c0b5c
PMF
269}
270
d159ac37 271int is_directory(const char *dir)
f99c0b5c 272{
f05eefd8 273 int result;
d159ac37 274 struct stat st;
f99c0b5c 275
d159ac37 276 result = stat(dir, &st);
f05eefd8 277 if(result == -1) {
d159ac37
AH
278 PERROR("stat");
279 return 0;
f99c0b5c
PMF
280 }
281
d159ac37
AH
282 if(!S_ISDIR(st.st_mode)) {
283 return 0;
750f9da4 284 }
3a7b90de 285
d159ac37 286 return 1;
3a7b90de
PMF
287}
288
cd226f25
PMF
289void usage(void)
290{
9dc7b7ff 291 fprintf(stderr, "Usage:\nust-consumerd OPTIONS\n\nOptions:\n"
cd226f25
PMF
292 "\t-h\t\tDisplay this usage.\n"
293 "\t-o DIR\t\tSpecify the directory where to output the traces.\n"
bce2937a
PMF
294 "\t-s PATH\t\tSpecify the path to use for the daemon socket.\n"
295 "\t-d\t\tStart as a daemon.\n"
296 "\t--pidfile FILE\tWrite the PID in this file (when using -d).\n");
cd226f25
PMF
297}
298
299int parse_args(int argc, char **argv)
300{
301 int c;
302
303 while (1) {
304 int option_index = 0;
305 static struct option long_options[] = {
bce2937a 306 {"pidfile", 1, 0, 'p'},
cd226f25
PMF
307 {"help", 0, 0, 'h'},
308 {"version", 0, 0, 'V'},
309 {0, 0, 0, 0}
310 };
311
bce2937a 312 c = getopt_long(argc, argv, "hs:o:d", long_options, &option_index);
cd226f25
PMF
313 if (c == -1)
314 break;
315
316 switch (c) {
317 case 0:
318 printf("option %s", long_options[option_index].name);
319 if (optarg)
320 printf(" with arg %s", optarg);
321 printf("\n");
322 break;
323 case 's':
324 sock_path = optarg;
325 break;
326 case 'o':
327 trace_path = optarg;
328 if(!is_directory(trace_path)) {
329 ERR("Not a valid directory. (%s)", trace_path);
330 return -1;
331 }
332 break;
bce2937a
PMF
333 case 'd':
334 daemon_mode = 1;
335 break;
2730a7d6
PMF
336 case 'p':
337 pidfile = strdup(optarg);
338 break;
cd226f25
PMF
339 case 'h':
340 usage();
341 exit(0);
342 case 'V':
343 printf("Version 0.0\n");
344 break;
345
346 default:
347 /* unknown option or other error; error is
348 printed by getopt, just return */
349 return -1;
350 }
351 }
352
353 return 0;
354}
355
3158b808
PMF
356void sigterm_handler(int sig)
357{
9dc7b7ff 358 ustconsumer_stop_instance(instance, 0);
2b3c64a4
PMF
359}
360
9dc7b7ff 361int start_ustconsumer(int fd)
3796af9b 362{
3796af9b 363 int result;
a3cdd4a7 364 sigset_t sigset;
3158b808
PMF
365 struct sigaction sa;
366
9dc7b7ff 367 struct ustconsumer_callbacks *callbacks = new_callbacks();
d159ac37
AH
368 if(!callbacks) {
369 PERROR("new_callbacks");
370 return 1;
371 }
372
3158b808
PMF
373 result = sigemptyset(&sigset);
374 if(result == -1) {
4d70f833 375 PERROR("sigemptyset");
3158b808
PMF
376 return 1;
377 }
378 sa.sa_handler = sigterm_handler;
379 sa.sa_mask = sigset;
f05eefd8 380 sa.sa_flags = 0;
3158b808
PMF
381 result = sigaction(SIGTERM, &sa, NULL);
382 if(result == -1) {
383 PERROR("sigaction");
384 return 1;
385 }
2a79ceeb
PMF
386 result = sigaction(SIGINT, &sa, NULL);
387 if(result == -1) {
388 PERROR("sigaction");
389 return 1;
390 }
3796af9b 391
9dc7b7ff 392 instance = ustconsumer_new_instance(callbacks, sock_path);
d159ac37 393 if(!instance) {
9dc7b7ff 394 ERR("failed to create ustconsumer instance");
d159ac37
AH
395 return 1;
396 }
397
9dc7b7ff 398 result = ustconsumer_init_instance(instance);
d159ac37 399 if(result) {
9dc7b7ff 400 ERR("failed to initialize ustconsumer instance");
3796af9b
PMF
401 return 1;
402 }
403
3158b808 404 /* setup handler for SIGPIPE */
a3cdd4a7
PMF
405 result = sigemptyset(&sigset);
406 if(result == -1) {
4d70f833 407 PERROR("sigemptyset");
a3cdd4a7
PMF
408 return 1;
409 }
410 result = sigaddset(&sigset, SIGPIPE);
411 if(result == -1) {
4d70f833 412 PERROR("sigaddset");
a3cdd4a7
PMF
413 return 1;
414 }
415 result = sigprocmask(SIG_BLOCK, &sigset, NULL);
416 if(result == -1) {
4d70f833 417 PERROR("sigprocmask");
a3cdd4a7
PMF
418 return 1;
419 }
420
2b3c64a4
PMF
421 /* Write pidfile */
422 if(pidfile) {
423 result = write_pidfile(pidfile, getpid());
424 if(result == -1) {
425 ERR("failed to write pidfile");
426 return 1;
427 }
428 }
429
bce2937a
PMF
430 /* Notify parent that we are successfully started. */
431 if(fd != -1) {
432 /* write any one character */
433 result = write(fd, "!", 1);
434 if(result == -1) {
435 PERROR("write");
436 return -1;
437 }
438 if(result != 1) {
439 ERR("Problem sending confirmation of daemon start to parent");
440 return -1;
441 }
442 result = close(fd);
443 if(result == -1) {
444 PERROR("close");
445 }
446 }
447
9dc7b7ff 448 ustconsumer_start_instance(instance);
3796af9b 449
d159ac37 450 free(callbacks);
2a79ceeb 451
3796af9b
PMF
452 return 0;
453}
bce2937a 454
9dc7b7ff 455int start_ustconsumer_daemon()
bce2937a
PMF
456{
457 int result;
458 int fd[2];
2730a7d6 459 pid_t child_pid;
bce2937a
PMF
460
461 result = pipe(fd);
462
2730a7d6 463 result = child_pid = fork();
bce2937a
PMF
464 if(result == -1) {
465 PERROR("fork");
466 return -1;
467 }
468 else if(result == 0) {
9dc7b7ff 469 return start_ustconsumer(fd[1]);
bce2937a
PMF
470 }
471 else {
472 char buf;
2730a7d6 473
bce2937a
PMF
474 result = read(fd[0], &buf, 1);
475 if(result == -1) {
476 PERROR("read");
477 return -1;
478 }
479 if(result != 1) {
480 ERR("did not receive valid confirmation that the daemon is started");
481 return -1;
482 }
483
484 result = close(fd[0]);
485 if(result == -1) {
486 PERROR("close");
487 }
488
489 DBG("The daemon is now successfully started");
490 }
491
492 /* Wait for confirmation that the server is ready. */
493
494
495 return 0;
496}
497
498int main(int argc, char **argv)
499{
500 int result;
501
502 result = parse_args(argc, argv);
503 if(result == -1) {
504 exit(1);
505 }
506
507 if(daemon_mode) {
9dc7b7ff 508 result = start_ustconsumer_daemon();
bce2937a
PMF
509 }
510 else {
9dc7b7ff 511 result = start_ustconsumer(-1);
bce2937a
PMF
512 }
513
514 return result;
515}
This page took 0.062348 seconds and 4 git commands to generate.