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>
35 #include "ust/ustconsumer.h"
36 #include "../libustconsumer/lowlevel.h"
40 char *trace_path
=NULL
;
44 struct ustconsumer_instance
*instance
;
46 struct buffer_info_local
{
49 /* the offset we must truncate to, to unput the last subbuffer */
50 off_t previous_offset
;
53 static int write_pidfile(const char *file_name
, pid_t pid
)
57 pidfp
= fopen(file_name
, "w");
59 PERROR("fopen (%s)", file_name
);
60 WARN("killing child process");
64 fprintf(pidfp
, "%d\n", pid
);
71 int create_dir_if_needed(char *dir
)
74 result
= mkdir(dir
, 0777);
85 int unwrite_last_subbuffer(struct buffer_info
*buf
)
88 struct buffer_info_local
*buf_local
= buf
->user_data
;
90 result
= ftruncate(buf_local
->file_fd
, buf_local
->previous_offset
);
96 result
= lseek(buf_local
->file_fd
, buf_local
->previous_offset
, SEEK_SET
);
97 if(result
== (int)(off_t
)-1) {
105 int write_current_subbuffer(struct buffer_info
*buf
)
108 struct buffer_info_local
*buf_local
= buf
->user_data
;
110 void *subbuf_mem
= buf
->mem
+ (buf
->consumed_old
& (buf
->n_subbufs
* buf
->subbuf_size
-1));
112 size_t cur_sb_size
= subbuffer_data_size(subbuf_mem
);
114 off_t cur_offset
= lseek(buf_local
->file_fd
, 0, SEEK_CUR
);
115 if(cur_offset
== (off_t
)-1) {
120 buf_local
->previous_offset
= cur_offset
;
121 DBG("previous_offset: %ld", cur_offset
);
123 result
= patient_write(buf_local
->file_fd
, subbuf_mem
, cur_sb_size
);
132 int on_read_subbuffer(struct ustconsumer_callbacks
*data
, struct buffer_info
*buf
)
134 return write_current_subbuffer(buf
);
137 int on_read_partial_subbuffer(struct ustconsumer_callbacks
*data
, struct buffer_info
*buf
,
138 long subbuf_index
, unsigned long valid_length
)
140 struct buffer_info_local
*buf_local
= buf
->user_data
;
143 unsigned long pad_size
;
145 result
= patient_write(buf_local
->file_fd
, buf
->mem
+ subbuf_index
* buf
->subbuf_size
, valid_length
);
147 ERR("Error writing to buffer file");
151 /* pad with empty bytes */
152 pad_size
= PAGE_ALIGN(valid_length
)-valid_length
;
154 tmp
= zmalloc(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 ustconsumer_callbacks
*data
, struct buffer_info
*buf
)
170 struct buffer_info_local
*buf_local
=
171 zmalloc(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(USTCONSUMER_DEFAULT_TRACE_PATH
);
188 ERR("could not create directory %s", USTCONSUMER_DEFAULT_TRACE_PATH
);
192 trace_path
= USTCONSUMER_DEFAULT_TRACE_PATH
;
195 if (asprintf(&tmp
, "%s/%u_%lld", trace_path
, buf
->pid
, buf
->pidunique
) < 0) {
196 ERR("on_open_buffer : asprintf failed (%s/%u_%lld)",
197 trace_path
, buf
->pid
, buf
->pidunique
);
200 result
= create_dir_if_needed(tmp
);
202 ERR("could not create directory %s", tmp
);
208 if (asprintf(&tmp
, "%s/%u_%lld/%s", trace_path
, buf
->pid
, buf
->pidunique
, buf
->name
) < 0) {
209 ERR("on_open_buffer : asprintf failed (%s/%u_%lld/%s)",
210 trace_path
, buf
->pid
, buf
->pidunique
, buf
->name
);
213 result
= fd
= open(tmp
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_EXCL
, 00600);
216 ERR("failed opening trace file %s", tmp
);
219 buf_local
->file_fd
= fd
;
225 int on_close_buffer(struct ustconsumer_callbacks
*data
, struct buffer_info
*buf
)
227 struct buffer_info_local
*buf_local
= buf
->user_data
;
228 int result
= close(buf_local
->file_fd
);
236 int on_put_error(struct ustconsumer_callbacks
*data
, struct buffer_info
*buf
)
238 return unwrite_last_subbuffer(buf
);
241 struct ustconsumer_callbacks
*new_callbacks()
243 struct ustconsumer_callbacks
*callbacks
=
244 zmalloc(sizeof(struct ustconsumer_callbacks
));
249 callbacks
->on_open_buffer
= on_open_buffer
;
250 callbacks
->on_close_buffer
= on_close_buffer
;
251 callbacks
->on_read_subbuffer
= on_read_subbuffer
;
252 callbacks
->on_read_partial_subbuffer
= on_read_partial_subbuffer
;
253 callbacks
->on_put_error
= on_put_error
;
254 callbacks
->on_new_thread
= NULL
;
255 callbacks
->on_close_thread
= NULL
;
256 callbacks
->on_trace_end
= NULL
;
262 int is_directory(const char *dir
)
267 result
= stat(dir
, &st
);
273 if(!S_ISDIR(st
.st_mode
)) {
282 fprintf(stderr
, "Usage:\nust-consumerd OPTIONS\n\nOptions:\n"
283 "\t-h\t\tDisplay this usage.\n"
284 "\t-o DIR\t\tSpecify the directory where to output the traces.\n"
285 "\t-s PATH\t\tSpecify the path to use for the daemon socket.\n"
286 "\t-d\t\tStart as a daemon.\n"
287 "\t--pidfile FILE\tWrite the PID in this file (when using -d).\n");
290 int parse_args(int argc
, char **argv
)
295 int option_index
= 0;
296 static struct option long_options
[] = {
297 {"pidfile", 1, 0, 'p'},
299 {"version", 0, 0, 'V'},
303 c
= getopt_long(argc
, argv
, "hs:o:d", long_options
, &option_index
);
309 printf("option %s", long_options
[option_index
].name
);
311 printf(" with arg %s", optarg
);
319 if(!is_directory(trace_path
)) {
320 ERR("Not a valid directory. (%s)", trace_path
);
328 pidfile
= strdup(optarg
);
334 printf("Version 0.0\n");
338 /* unknown option or other error; error is
339 printed by getopt, just return */
347 void sigterm_handler(int sig
)
349 ustconsumer_stop_instance(instance
, 0);
352 int start_ustconsumer(int fd
)
358 struct ustconsumer_callbacks
*callbacks
= new_callbacks();
360 PERROR("new_callbacks");
364 result
= sigemptyset(&sigset
);
366 PERROR("sigemptyset");
369 sa
.sa_handler
= sigterm_handler
;
372 result
= sigaction(SIGTERM
, &sa
, NULL
);
377 result
= sigaction(SIGINT
, &sa
, NULL
);
383 instance
= ustconsumer_new_instance(callbacks
, sock_path
);
385 ERR("failed to create ustconsumer instance");
389 result
= ustconsumer_init_instance(instance
);
391 ERR("failed to initialize ustconsumer instance");
395 /* setup handler for SIGPIPE */
396 result
= sigemptyset(&sigset
);
398 PERROR("sigemptyset");
401 result
= sigaddset(&sigset
, SIGPIPE
);
406 result
= sigprocmask(SIG_BLOCK
, &sigset
, NULL
);
408 PERROR("sigprocmask");
414 result
= write_pidfile(pidfile
, getpid());
416 ERR("failed to write pidfile");
421 /* Notify parent that we are successfully started. */
423 /* write any one character */
424 result
= write(fd
, "!", 1);
430 ERR("Problem sending confirmation of daemon start to parent");
439 ustconsumer_start_instance(instance
);
446 int start_ustconsumer_daemon()
454 result
= child_pid
= fork();
459 else if(result
== 0) {
460 return start_ustconsumer(fd
[1]);
465 result
= read(fd
[0], &buf
, 1);
471 ERR("did not receive valid confirmation that the daemon is started");
475 result
= close(fd
[0]);
480 DBG("The daemon is now successfully started");
483 /* Wait for confirmation that the server is ready. */
489 int main(int argc
, char **argv
)
493 result
= parse_args(argc
, argv
);
499 result
= start_ustconsumer_daemon();
502 result
= start_ustconsumer(-1);