3 * Linux Trace Toolkit Daemon
5 * This is a simple daemon that reads a few relay+debugfs channels and save
8 * CPU hot-plugging is supported using inotify.
10 * Copyright 2009-2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
43 #include <liblttd/liblttd.h>
45 struct lttd_channel_data
{
49 struct liblttd_instance
*instance
;
50 static char path_trace
[PATH_MAX
];
51 static char *end_path_trace
;
52 static int path_trace_len
= 0;
53 static char *trace_name
= NULL
;
54 static char *channel_name
= NULL
;
55 static int daemon_mode
= 0;
56 static int append_mode
= 0;
57 static unsigned long num_threads
= 1;
58 static int dump_flight_only
= 0;
59 static int dump_normal_only
= 0;
60 static int verbose_mode
= 0;
62 static __thread
int thread_pipe
[2];
64 #define printf_verbose(fmt, args...) \
67 printf(fmt, ##args); \
72 * -t directory Directory name of the trace to write to. Will be created.
73 * -c directory Root directory of the debugfs trace channels.
74 * -d Run in background (daemon).
75 * -a Trace append mode.
76 * -s Send SIGUSR1 to parent when ready for IO.
78 void show_arguments(void)
80 printf("Please use the following arguments :\n");
82 printf("-t directory Directory name of the trace to write to.\n"
83 " It will be created.\n");
84 printf("-c directory Root directory of the debugfs trace channels.\n");
85 printf("-d Run in background (daemon).\n");
86 printf("-a Append to an possibly existing trace.\n");
87 printf("-N Number of threads to start.\n");
88 printf("-f Dump only flight recorder channels.\n");
89 printf("-n Dump only normal channels.\n");
90 printf("-v Verbose mode.\n");
97 * Parses the command line arguments.
99 * Returns 1 if the arguments were correct, but doesn't ask for program
100 * continuation. Returns -1 if the arguments are incorrect, or 0 if OK.
102 int parse_arguments(int argc
, char **argv
)
108 if(strcmp(argv
[1], "-h") == 0) {
115 switch(argv
[argn
][0]) {
117 switch(argv
[argn
][1]) {
120 trace_name
= argv
[argn
+1];
126 channel_name
= argv
[argn
+1];
138 num_threads
= strtoul(argv
[argn
+1], NULL
, 0);
143 dump_flight_only
= 1;
146 dump_normal_only
= 1;
152 printf("Invalid argument '%s'.\n", argv
[argn
]);
158 printf("Invalid argument '%s'.\n", argv
[argn
]);
165 if(trace_name
== NULL
) {
166 printf("Please specify a trace name.\n");
171 if(channel_name
== NULL
) {
172 printf("Please specify a channel name.\n");
182 printf("Linux Trace Toolkit Trace Daemon " VERSION
"\n");
184 printf("Reading from debugfs directory : %s\n", channel_name
);
185 printf("Writing to trace directory : %s\n", trace_name
);
190 /* signal handling */
192 static void handler(int signo
)
194 printf("Signal %d received : exiting cleanly\n", signo
);
195 liblttd_stop_instance(instance
);
198 int lttd_on_open_channel(struct liblttd_callbacks
*data
, struct fd_pair
*pair
, char *relative_channel_path
)
202 struct stat stat_buf
;
203 struct lttd_channel_data
*channel_data
;
205 pair
->user_data
= malloc(sizeof(struct lttd_channel_data
));
206 channel_data
= pair
->user_data
;
208 strncpy(end_path_trace
, relative_channel_path
, PATH_MAX
- path_trace_len
);
209 printf_verbose("Creating trace file %s\n", path_trace
);
211 ret
= stat(path_trace
, &stat_buf
);
214 printf_verbose("Appending to file %s as requested\n",
217 channel_data
->trace
= open(path_trace
, O_WRONLY
, S_IRWXU
|S_IRWXG
|S_IRWXO
);
218 if(channel_data
->trace
== -1) {
223 ret
= lseek(channel_data
->trace
, 0, SEEK_END
);
227 close(channel_data
->trace
);
231 printf("File %s exists, cannot open. Try append mode.\n", path_trace
);
236 if(errno
== ENOENT
) {
237 channel_data
->trace
= open(path_trace
, O_WRONLY
|O_CREAT
|O_EXCL
, S_IRWXU
|S_IRWXG
|S_IRWXO
);
238 if(channel_data
->trace
== -1) {
251 int lttd_on_close_channel(struct liblttd_callbacks
*data
, struct fd_pair
*pair
)
254 ret
= close(((struct lttd_channel_data
*)(pair
->user_data
))->trace
);
255 free(pair
->user_data
);
259 int lttd_on_new_channels_folder(struct liblttd_callbacks
*data
, char *relative_folder_path
)
264 strncpy(end_path_trace
, relative_folder_path
, PATH_MAX
- path_trace_len
);
265 printf_verbose("Creating trace subdirectory %s\n", path_trace
);
267 ret
= mkdir(path_trace
, S_IRWXU
|S_IRWXG
|S_IRWXO
);
269 if(errno
!= EEXIST
) {
280 int lttd_on_read_subbuffer(struct liblttd_callbacks
*data
, struct fd_pair
*pair
, unsigned int len
)
286 printf_verbose("splice chan to pipe offset %lu\n",
287 (unsigned long)offset
);
288 ret
= splice(pair
->channel
, &offset
, thread_pipe
[1], NULL
,
289 len
, SPLICE_F_MOVE
| SPLICE_F_MORE
);
290 printf_verbose("splice chan to pipe ret %ld\n", ret
);
292 perror("Error in relay splice");
295 ret
= splice(thread_pipe
[0], NULL
,
296 ((struct lttd_channel_data
*)(pair
->user_data
))->trace
,
297 NULL
, ret
, SPLICE_F_MOVE
| SPLICE_F_MORE
);
298 printf_verbose("splice pipe to file %ld\n", ret
);
300 perror("Error in file splice");
310 int lttd_on_new_thread(struct liblttd_callbacks
*data
, unsigned long thread_num
)
313 ret
= pipe(thread_pipe
);
315 perror("Error creating pipe");
321 int lttd_on_close_thread(struct liblttd_callbacks
*data
, unsigned long thread_num
)
323 close(thread_pipe
[0]); /* close read end */
324 close(thread_pipe
[1]); /* close write end */
328 int main(int argc
, char ** argv
)
331 struct sigaction act
;
333 struct liblttd_callbacks callbacks
= {
334 lttd_on_open_channel
,
335 lttd_on_close_channel
,
336 lttd_on_new_channels_folder
,
337 lttd_on_read_subbuffer
,
340 lttd_on_close_thread
,
344 ret
= parse_arguments(argc
, argv
);
346 if(ret
!= 0) show_arguments();
347 if(ret
< 0) return EINVAL
;
348 if(ret
> 0) return 0;
352 /* Connect the signal handlers */
353 act
.sa_handler
= handler
;
355 sigemptyset(&(act
.sa_mask
));
356 sigaddset(&(act
.sa_mask
), SIGTERM
);
357 sigaddset(&(act
.sa_mask
), SIGQUIT
);
358 sigaddset(&(act
.sa_mask
), SIGINT
);
359 sigaction(SIGTERM
, &act
, NULL
);
360 sigaction(SIGQUIT
, &act
, NULL
);
361 sigaction(SIGINT
, &act
, NULL
);
367 perror("An error occured while daemonizing.");
371 strncpy(path_trace
, trace_name
, PATH_MAX
-1);
372 path_trace_len
= strlen(path_trace
);
373 end_path_trace
= path_trace
+ path_trace_len
;
375 instance
= liblttd_new_instance(&callbacks
, channel_name
, num_threads
,
376 dump_flight_only
, dump_normal_only
, verbose_mode
);
378 perror("An error occured while creating the liblttd instance");
382 liblttd_start_instance(instance
);