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