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 if (asprintf(&tmp
, "%s/%u_%lld", trace_path
, buf
->pid
, buf
->pidunique
) < 0) {
195 ERR("on_open_buffer : asprintf failed (%s/%u_%lld)",
196 trace_path
, buf
->pid
, buf
->pidunique
);
199 result
= create_dir_if_needed(tmp
);
201 ERR("could not create directory %s", tmp
);
207 if (asprintf(&tmp
, "%s/%u_%lld/%s", trace_path
, buf
->pid
, buf
->pidunique
, buf
->name
) < 0) {
208 ERR("on_open_buffer : asprintf failed (%s/%u_%lld/%s)",
209 trace_path
, buf
->pid
, buf
->pidunique
, buf
->name
);
212 result
= fd
= open(tmp
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_EXCL
, 00600);
215 ERR("failed opening trace file %s", tmp
);
218 buf_local
->file_fd
= fd
;
224 int on_close_buffer(struct libustd_callbacks
*data
, struct buffer_info
*buf
)
226 struct buffer_info_local
*buf_local
= buf
->user_data
;
227 int result
= close(buf_local
->file_fd
);
235 int on_put_error(struct libustd_callbacks
*data
, struct buffer_info
*buf
)
237 unwrite_last_subbuffer(buf
);
240 struct libustd_callbacks
*new_callbacks()
242 struct libustd_callbacks
*callbacks
=
243 zmalloc(sizeof(struct libustd_callbacks
));
248 callbacks
->on_open_buffer
= on_open_buffer
;
249 callbacks
->on_close_buffer
= on_close_buffer
;
250 callbacks
->on_read_subbuffer
= on_read_subbuffer
;
251 callbacks
->on_read_partial_subbuffer
= on_read_partial_subbuffer
;
252 callbacks
->on_put_error
= on_put_error
;
253 callbacks
->on_new_thread
= NULL
;
254 callbacks
->on_close_thread
= NULL
;
255 callbacks
->on_trace_end
= NULL
;
261 int is_directory(const char *dir
)
266 result
= stat(dir
, &st
);
272 if(!S_ISDIR(st
.st_mode
)) {
281 fprintf(stderr
, "Usage:\nustd OPTIONS\n\nOptions:\n"
282 "\t-h\t\tDisplay this usage.\n"
283 "\t-o DIR\t\tSpecify the directory where to output the traces.\n"
284 "\t-s PATH\t\tSpecify the path to use for the daemon socket.\n"
285 "\t-d\t\tStart as a daemon.\n"
286 "\t--pidfile FILE\tWrite the PID in this file (when using -d).\n");
289 int parse_args(int argc
, char **argv
)
294 int option_index
= 0;
295 static struct option long_options
[] = {
296 {"pidfile", 1, 0, 'p'},
298 {"version", 0, 0, 'V'},
302 c
= getopt_long(argc
, argv
, "hs:o:d", long_options
, &option_index
);
308 printf("option %s", long_options
[option_index
].name
);
310 printf(" with arg %s", optarg
);
318 if(!is_directory(trace_path
)) {
319 ERR("Not a valid directory. (%s)", trace_path
);
327 pidfile
= strdup(optarg
);
333 printf("Version 0.0\n");
337 /* unknown option or other error; error is
338 printed by getopt, just return */
346 void sigterm_handler(int sig
)
348 libustd_stop_instance(instance
, 0);
351 int start_ustd(int fd
)
357 struct libustd_callbacks
*callbacks
= new_callbacks();
359 PERROR("new_callbacks");
363 result
= sigemptyset(&sigset
);
365 PERROR("sigemptyset");
368 sa
.sa_handler
= sigterm_handler
;
371 result
= sigaction(SIGTERM
, &sa
, NULL
);
376 result
= sigaction(SIGINT
, &sa
, NULL
);
382 instance
= libustd_new_instance(callbacks
, sock_path
);
384 ERR("failed to create libustd instance");
388 result
= libustd_init_instance(instance
);
390 ERR("failed to initialize libustd instance");
394 /* setup handler for SIGPIPE */
395 result
= sigemptyset(&sigset
);
397 PERROR("sigemptyset");
400 result
= sigaddset(&sigset
, SIGPIPE
);
405 result
= sigprocmask(SIG_BLOCK
, &sigset
, NULL
);
407 PERROR("sigprocmask");
413 result
= write_pidfile(pidfile
, getpid());
415 ERR("failed to write pidfile");
420 /* Notify parent that we are successfully started. */
422 /* write any one character */
423 result
= write(fd
, "!", 1);
429 ERR("Problem sending confirmation of daemon start to parent");
438 libustd_start_instance(instance
);
445 int start_ustd_daemon()
453 result
= child_pid
= fork();
458 else if(result
== 0) {
459 return start_ustd(fd
[1]);
464 result
= read(fd
[0], &buf
, 1);
470 ERR("did not receive valid confirmation that the daemon is started");
474 result
= close(fd
[0]);
479 DBG("The daemon is now successfully started");
482 /* Wait for confirmation that the server is ready. */
488 int main(int argc
, char **argv
)
492 result
= parse_args(argc
, argv
);
498 result
= start_ustd_daemon();
501 result
= start_ustd(-1);