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
= zmalloc(pad_size
);
154 result
= patient_write(buf_local
->file_fd
, tmp
, pad_size
);
156 ERR("Error writing to buffer file");
164 int on_open_buffer(struct libustd_callbacks
*data
, struct buffer_info
*buf
)
169 struct buffer_info_local
*buf_local
=
170 zmalloc(sizeof(struct buffer_info_local
));
173 ERR("could not allocate buffer_info_local struct");
177 buf
->user_data
= buf_local
;
179 /* open file for output */
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.
185 result
= create_dir_if_needed(USTD_DEFAULT_TRACE_PATH
);
187 ERR("could not create directory %s", USTD_DEFAULT_TRACE_PATH
);
191 trace_path
= USTD_DEFAULT_TRACE_PATH
;
194 asprintf(&tmp
, "%s/%u_%lld", trace_path
, buf
->pid
, buf
->pidunique
);
195 result
= create_dir_if_needed(tmp
);
197 ERR("could not create directory %s", tmp
);
203 asprintf(&tmp
, "%s/%u_%lld/%s", trace_path
, buf
->pid
, buf
->pidunique
, buf
->name
);
204 result
= fd
= open(tmp
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_EXCL
, 00600);
207 ERR("failed opening trace file %s", tmp
);
210 buf_local
->file_fd
= fd
;
216 int on_close_buffer(struct libustd_callbacks
*data
, struct buffer_info
*buf
)
218 struct buffer_info_local
*buf_local
= buf
->user_data
;
219 int result
= close(buf_local
->file_fd
);
227 int on_put_error(struct libustd_callbacks
*data
, struct buffer_info
*buf
)
229 unwrite_last_subbuffer(buf
);
232 struct libustd_callbacks
*new_callbacks()
234 struct libustd_callbacks
*callbacks
=
235 zmalloc(sizeof(struct libustd_callbacks
));
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
;
253 int is_directory(const char *dir
)
258 result
= stat(dir
, &st
);
264 if(!S_ISDIR(st
.st_mode
)) {
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"
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");
281 int parse_args(int argc
, char **argv
)
286 int option_index
= 0;
287 static struct option long_options
[] = {
288 {"pidfile", 1, 0, 'p'},
290 {"version", 0, 0, 'V'},
294 c
= getopt_long(argc
, argv
, "hs:o:d", long_options
, &option_index
);
300 printf("option %s", long_options
[option_index
].name
);
302 printf(" with arg %s", optarg
);
310 if(!is_directory(trace_path
)) {
311 ERR("Not a valid directory. (%s)", trace_path
);
319 pidfile
= strdup(optarg
);
325 printf("Version 0.0\n");
329 /* unknown option or other error; error is
330 printed by getopt, just return */
338 void sigterm_handler(int sig
)
340 libustd_stop_instance(instance
, 0);
343 int start_ustd(int fd
)
349 struct libustd_callbacks
*callbacks
= new_callbacks();
351 PERROR("new_callbacks");
355 result
= sigemptyset(&sigset
);
357 PERROR("sigemptyset");
360 sa
.sa_handler
= sigterm_handler
;
363 result
= sigaction(SIGTERM
, &sa
, NULL
);
368 result
= sigaction(SIGINT
, &sa
, NULL
);
374 instance
= libustd_new_instance(callbacks
, sock_path
);
376 ERR("failed to create libustd instance");
380 result
= libustd_init_instance(instance
);
382 ERR("failed to initialize libustd instance");
386 /* setup handler for SIGPIPE */
387 result
= sigemptyset(&sigset
);
389 PERROR("sigemptyset");
392 result
= sigaddset(&sigset
, SIGPIPE
);
397 result
= sigprocmask(SIG_BLOCK
, &sigset
, NULL
);
399 PERROR("sigprocmask");
405 result
= write_pidfile(pidfile
, getpid());
407 ERR("failed to write pidfile");
412 /* Notify parent that we are successfully started. */
414 /* write any one character */
415 result
= write(fd
, "!", 1);
421 ERR("Problem sending confirmation of daemon start to parent");
430 libustd_start_instance(instance
);
437 int start_ustd_daemon()
445 result
= child_pid
= fork();
450 else if(result
== 0) {
451 return start_ustd(fd
[1]);
456 result
= read(fd
[0], &buf
, 1);
462 ERR("did not receive valid confirmation that the daemon is started");
466 result
= close(fd
[0]);
471 DBG("The daemon is now successfully started");
474 /* Wait for confirmation that the server is ready. */
480 int main(int argc
, char **argv
)
484 result
= parse_args(argc
, argv
);
490 result
= start_ustd_daemon();
493 result
= start_ustd(-1);