UST-wide warning fixes/bugfixes
[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 }
ed1317e7 213 result = fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 00600);
3a7b90de
PMF
214 if(result == -1) {
215 PERROR("open");
6cb88bc0 216 ERR("failed opening trace file %s", tmp);
d159ac37 217 return 1;
3a7b90de 218 }
d159ac37 219 buf_local->file_fd = fd;
3a7b90de
PMF
220 free(tmp);
221
d159ac37 222 return 0;
f99c0b5c
PMF
223}
224
9dc7b7ff 225int on_close_buffer(struct ustconsumer_callbacks *data, struct buffer_info *buf)
750f9da4 226{
d159ac37
AH
227 struct buffer_info_local *buf_local = buf->user_data;
228 int result = close(buf_local->file_fd);
229 free(buf_local);
750f9da4
PMF
230 if(result == -1) {
231 PERROR("close");
232 }
9be57e24
PMF
233 return 0;
234}
235
9dc7b7ff 236int on_put_error(struct ustconsumer_callbacks *data, struct buffer_info *buf)
02af3e60 237{
fbae86d6 238 return unwrite_last_subbuffer(buf);
02af3e60
PMF
239}
240
9dc7b7ff 241struct ustconsumer_callbacks *new_callbacks()
f99c0b5c 242{
9dc7b7ff
NC
243 struct ustconsumer_callbacks *callbacks =
244 zmalloc(sizeof(struct ustconsumer_callbacks));
f99c0b5c 245
d159ac37
AH
246 if(!callbacks)
247 return NULL;
f99c0b5c 248
d159ac37
AH
249 callbacks->on_open_buffer = on_open_buffer;
250 callbacks->on_close_buffer = on_close_buffer;
251 callbacks->on_read_subbuffer = on_read_subbuffer;
252 callbacks->on_read_partial_subbuffer = on_read_partial_subbuffer;
253 callbacks->on_put_error = on_put_error;
254 callbacks->on_new_thread = NULL;
255 callbacks->on_close_thread = NULL;
256 callbacks->on_trace_end = NULL;
f99c0b5c 257
d159ac37 258 return callbacks;
f99c0b5c 259
f99c0b5c
PMF
260}
261
d159ac37 262int is_directory(const char *dir)
f99c0b5c 263{
f05eefd8 264 int result;
d159ac37 265 struct stat st;
f99c0b5c 266
d159ac37 267 result = stat(dir, &st);
f05eefd8 268 if(result == -1) {
d159ac37
AH
269 PERROR("stat");
270 return 0;
f99c0b5c
PMF
271 }
272
d159ac37
AH
273 if(!S_ISDIR(st.st_mode)) {
274 return 0;
750f9da4 275 }
3a7b90de 276
d159ac37 277 return 1;
3a7b90de
PMF
278}
279
cd226f25
PMF
280void usage(void)
281{
9dc7b7ff 282 fprintf(stderr, "Usage:\nust-consumerd OPTIONS\n\nOptions:\n"
cd226f25
PMF
283 "\t-h\t\tDisplay this usage.\n"
284 "\t-o DIR\t\tSpecify the directory where to output the traces.\n"
bce2937a
PMF
285 "\t-s PATH\t\tSpecify the path to use for the daemon socket.\n"
286 "\t-d\t\tStart as a daemon.\n"
287 "\t--pidfile FILE\tWrite the PID in this file (when using -d).\n");
cd226f25
PMF
288}
289
290int parse_args(int argc, char **argv)
291{
292 int c;
293
294 while (1) {
295 int option_index = 0;
296 static struct option long_options[] = {
bce2937a 297 {"pidfile", 1, 0, 'p'},
cd226f25
PMF
298 {"help", 0, 0, 'h'},
299 {"version", 0, 0, 'V'},
300 {0, 0, 0, 0}
301 };
302
bce2937a 303 c = getopt_long(argc, argv, "hs:o:d", long_options, &option_index);
cd226f25
PMF
304 if (c == -1)
305 break;
306
307 switch (c) {
308 case 0:
309 printf("option %s", long_options[option_index].name);
310 if (optarg)
311 printf(" with arg %s", optarg);
312 printf("\n");
313 break;
314 case 's':
315 sock_path = optarg;
316 break;
317 case 'o':
318 trace_path = optarg;
319 if(!is_directory(trace_path)) {
320 ERR("Not a valid directory. (%s)", trace_path);
321 return -1;
322 }
323 break;
bce2937a
PMF
324 case 'd':
325 daemon_mode = 1;
326 break;
2730a7d6
PMF
327 case 'p':
328 pidfile = strdup(optarg);
329 break;
cd226f25
PMF
330 case 'h':
331 usage();
332 exit(0);
333 case 'V':
334 printf("Version 0.0\n");
335 break;
336
337 default:
338 /* unknown option or other error; error is
339 printed by getopt, just return */
340 return -1;
341 }
342 }
343
344 return 0;
345}
346
3158b808
PMF
347void sigterm_handler(int sig)
348{
9dc7b7ff 349 ustconsumer_stop_instance(instance, 0);
2b3c64a4
PMF
350}
351
9dc7b7ff 352int start_ustconsumer(int fd)
3796af9b 353{
3796af9b 354 int result;
a3cdd4a7 355 sigset_t sigset;
3158b808
PMF
356 struct sigaction sa;
357
9dc7b7ff 358 struct ustconsumer_callbacks *callbacks = new_callbacks();
d159ac37
AH
359 if(!callbacks) {
360 PERROR("new_callbacks");
361 return 1;
362 }
363
3158b808
PMF
364 result = sigemptyset(&sigset);
365 if(result == -1) {
4d70f833 366 PERROR("sigemptyset");
3158b808
PMF
367 return 1;
368 }
369 sa.sa_handler = sigterm_handler;
370 sa.sa_mask = sigset;
f05eefd8 371 sa.sa_flags = 0;
3158b808
PMF
372 result = sigaction(SIGTERM, &sa, NULL);
373 if(result == -1) {
374 PERROR("sigaction");
375 return 1;
376 }
2a79ceeb
PMF
377 result = sigaction(SIGINT, &sa, NULL);
378 if(result == -1) {
379 PERROR("sigaction");
380 return 1;
381 }
3796af9b 382
9dc7b7ff 383 instance = ustconsumer_new_instance(callbacks, sock_path);
d159ac37 384 if(!instance) {
9dc7b7ff 385 ERR("failed to create ustconsumer instance");
d159ac37
AH
386 return 1;
387 }
388
9dc7b7ff 389 result = ustconsumer_init_instance(instance);
d159ac37 390 if(result) {
9dc7b7ff 391 ERR("failed to initialize ustconsumer instance");
3796af9b
PMF
392 return 1;
393 }
394
3158b808 395 /* setup handler for SIGPIPE */
a3cdd4a7
PMF
396 result = sigemptyset(&sigset);
397 if(result == -1) {
4d70f833 398 PERROR("sigemptyset");
a3cdd4a7
PMF
399 return 1;
400 }
401 result = sigaddset(&sigset, SIGPIPE);
402 if(result == -1) {
4d70f833 403 PERROR("sigaddset");
a3cdd4a7
PMF
404 return 1;
405 }
406 result = sigprocmask(SIG_BLOCK, &sigset, NULL);
407 if(result == -1) {
4d70f833 408 PERROR("sigprocmask");
a3cdd4a7
PMF
409 return 1;
410 }
411
2b3c64a4
PMF
412 /* Write pidfile */
413 if(pidfile) {
414 result = write_pidfile(pidfile, getpid());
415 if(result == -1) {
416 ERR("failed to write pidfile");
417 return 1;
418 }
419 }
420
bce2937a
PMF
421 /* Notify parent that we are successfully started. */
422 if(fd != -1) {
423 /* write any one character */
424 result = write(fd, "!", 1);
425 if(result == -1) {
426 PERROR("write");
427 return -1;
428 }
429 if(result != 1) {
430 ERR("Problem sending confirmation of daemon start to parent");
431 return -1;
432 }
433 result = close(fd);
434 if(result == -1) {
435 PERROR("close");
436 }
437 }
438
9dc7b7ff 439 ustconsumer_start_instance(instance);
3796af9b 440
d159ac37 441 free(callbacks);
2a79ceeb 442
3796af9b
PMF
443 return 0;
444}
bce2937a 445
9dc7b7ff 446int start_ustconsumer_daemon()
bce2937a
PMF
447{
448 int result;
449 int fd[2];
2730a7d6 450 pid_t child_pid;
bce2937a
PMF
451
452 result = pipe(fd);
453
2730a7d6 454 result = child_pid = fork();
bce2937a
PMF
455 if(result == -1) {
456 PERROR("fork");
457 return -1;
458 }
459 else if(result == 0) {
9dc7b7ff 460 return start_ustconsumer(fd[1]);
bce2937a
PMF
461 }
462 else {
463 char buf;
2730a7d6 464
bce2937a
PMF
465 result = read(fd[0], &buf, 1);
466 if(result == -1) {
467 PERROR("read");
468 return -1;
469 }
470 if(result != 1) {
471 ERR("did not receive valid confirmation that the daemon is started");
472 return -1;
473 }
474
475 result = close(fd[0]);
476 if(result == -1) {
477 PERROR("close");
478 }
479
480 DBG("The daemon is now successfully started");
481 }
482
483 /* Wait for confirmation that the server is ready. */
484
485
486 return 0;
487}
488
489int main(int argc, char **argv)
490{
491 int result;
492
493 result = parse_args(argc, argv);
494 if(result == -1) {
495 exit(1);
496 }
497
498 if(daemon_mode) {
9dc7b7ff 499 result = start_ustconsumer_daemon();
bce2937a
PMF
500 }
501 else {
9dc7b7ff 502 result = start_ustconsumer(-1);
bce2937a
PMF
503 }
504
505 return result;
506}
This page took 0.059935 seconds and 4 git commands to generate.