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