1 /* Copyright (C) 2009 Pierre-Marc Fournier
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.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
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
21 #include <sys/types.h>
39 char *trace_path
=NULL
;
43 struct libustd_instance
*instance
;
45 struct buffer_info_local
{
48 /* the offset we must truncate to, to unput the last subbuffer */
49 off_t previous_offset
;
52 static int write_pidfile(const char *file_name
, pid_t pid
)
56 pidfp
= fopen(file_name
, "w");
58 PERROR("fopen (%s)", file_name
);
59 WARN("killing child process");
63 fprintf(pidfp
, "%d\n", pid
);
70 int create_dir_if_needed(char *dir
)
73 result
= mkdir(dir
, 0777);
84 int unwrite_last_subbuffer(struct buffer_info
*buf
)
87 struct buffer_info_local
*buf_local
= buf
->user_data
;
89 result
= ftruncate(buf_local
->file_fd
, buf_local
->previous_offset
);
95 result
= lseek(buf_local
->file_fd
, buf_local
->previous_offset
, SEEK_SET
);
96 if(result
== (int)(off_t
)-1) {
104 int write_current_subbuffer(struct buffer_info
*buf
)
107 struct buffer_info_local
*buf_local
= buf
->user_data
;
109 void *subbuf_mem
= buf
->mem
+ (buf
->consumed_old
& (buf
->n_subbufs
* buf
->subbuf_size
-1));
111 size_t cur_sb_size
= subbuffer_data_size(subbuf_mem
);
113 off_t cur_offset
= lseek(buf_local
->file_fd
, 0, SEEK_CUR
);
114 if(cur_offset
== (off_t
)-1) {
119 buf_local
->previous_offset
= cur_offset
;
120 DBG("previous_offset: %ld", cur_offset
);
122 result
= patient_write(buf_local
->file_fd
, subbuf_mem
, cur_sb_size
);
131 int on_read_subbuffer(struct libustd_callbacks
*data
, struct buffer_info
*buf
)
133 return write_current_subbuffer(buf
);
136 int on_read_partial_subbuffer(struct libustd_callbacks
*data
, struct buffer_info
*buf
,
137 long subbuf_index
, unsigned long valid_length
)
139 struct buffer_info_local
*buf_local
= buf
->user_data
;
142 unsigned long pad_size
;
144 result
= patient_write(buf_local
->file_fd
, buf
->mem
+ subbuf_index
* buf
->subbuf_size
, valid_length
);
146 ERR("Error writing to buffer file");
150 /* pad with empty bytes */
151 pad_size
= PAGE_ALIGN(valid_length
)-valid_length
;
153 tmp
= malloc(pad_size
);
154 memset(tmp
, 0, pad_size
);
155 result
= patient_write(buf_local
->file_fd
, tmp
, pad_size
);
157 ERR("Error writing to buffer file");
165 int on_open_buffer(struct libustd_callbacks
*data
, struct buffer_info
*buf
)
170 struct buffer_info_local
*buf_local
=
171 malloc(sizeof(struct buffer_info_local
));
174 ERR("could not allocate buffer_info_local struct");
178 buf
->user_data
= buf_local
;
180 /* open file for output */
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.
186 result
= create_dir_if_needed(USTD_DEFAULT_TRACE_PATH
);
188 ERR("could not create directory %s", USTD_DEFAULT_TRACE_PATH
);
192 trace_path
= USTD_DEFAULT_TRACE_PATH
;
195 asprintf(&tmp
, "%s/%u_%lld", trace_path
, buf
->pid
, buf
->pidunique
);
196 result
= create_dir_if_needed(tmp
);
198 ERR("could not create directory %s", tmp
);
204 asprintf(&tmp
, "%s/%u_%lld/%s", trace_path
, buf
->pid
, buf
->pidunique
, buf
->name
);
205 result
= fd
= open(tmp
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_EXCL
, 00600);
208 ERR("failed opening trace file %s", tmp
);
211 buf_local
->file_fd
= fd
;
217 int on_close_buffer(struct libustd_callbacks
*data
, struct buffer_info
*buf
)
219 struct buffer_info_local
*buf_local
= buf
->user_data
;
220 int result
= close(buf_local
->file_fd
);
228 int on_put_error(struct libustd_callbacks
*data
, struct buffer_info
*buf
)
230 unwrite_last_subbuffer(buf
);
233 struct libustd_callbacks
*new_callbacks()
235 struct libustd_callbacks
*callbacks
=
236 malloc(sizeof(struct libustd_callbacks
));
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
;
254 int is_directory(const char *dir
)
259 result
= stat(dir
, &st
);
265 if(!S_ISDIR(st
.st_mode
)) {
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"
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");
282 int parse_args(int argc
, char **argv
)
287 int option_index
= 0;
288 static struct option long_options
[] = {
289 {"pidfile", 1, 0, 'p'},
291 {"version", 0, 0, 'V'},
295 c
= getopt_long(argc
, argv
, "hs:o:d", long_options
, &option_index
);
301 printf("option %s", long_options
[option_index
].name
);
303 printf(" with arg %s", optarg
);
311 if(!is_directory(trace_path
)) {
312 ERR("Not a valid directory. (%s)", trace_path
);
320 pidfile
= strdup(optarg
);
326 printf("Version 0.0\n");
330 /* unknown option or other error; error is
331 printed by getopt, just return */
339 void sigterm_handler(int sig
)
341 libustd_stop_instance(instance
, 0);
344 int start_ustd(int fd
)
350 struct libustd_callbacks
*callbacks
= new_callbacks();
352 PERROR("new_callbacks");
356 result
= sigemptyset(&sigset
);
358 PERROR("sigemptyset");
361 sa
.sa_handler
= sigterm_handler
;
364 result
= sigaction(SIGTERM
, &sa
, NULL
);
369 result
= sigaction(SIGINT
, &sa
, NULL
);
375 instance
= libustd_new_instance(callbacks
, sock_path
);
377 ERR("failed to create libustd instance");
381 result
= libustd_init_instance(instance
);
383 ERR("failed to initialize libustd instance");
387 /* setup handler for SIGPIPE */
388 result
= sigemptyset(&sigset
);
390 PERROR("sigemptyset");
393 result
= sigaddset(&sigset
, SIGPIPE
);
398 result
= sigprocmask(SIG_BLOCK
, &sigset
, NULL
);
400 PERROR("sigprocmask");
406 result
= write_pidfile(pidfile
, getpid());
408 ERR("failed to write pidfile");
413 /* Notify parent that we are successfully started. */
415 /* write any one character */
416 result
= write(fd
, "!", 1);
422 ERR("Problem sending confirmation of daemon start to parent");
431 libustd_start_instance(instance
);
438 int start_ustd_daemon()
446 result
= child_pid
= fork();
451 else if(result
== 0) {
452 return start_ustd(fd
[1]);
457 result
= read(fd
[0], &buf
, 1);
463 ERR("did not receive valid confirmation that the daemon is started");
467 result
= close(fd
[0]);
472 DBG("The daemon is now successfully started");
475 /* Wait for confirmation that the server is ready. */
481 int main(int argc
, char **argv
)
485 result
= parse_args(argc
, argv
);
491 result
= start_ustd_daemon();
494 result
= start_ustd(-1);