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