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