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 static char path_trace
[PATH_MAX
];
50 static char *end_path_trace
;
51 static int path_trace_len
= 0;
52 static char *trace_name
= NULL
;
53 static char *channel_name
= NULL
;
54 static int daemon_mode
= 0;
55 static int append_mode
= 0;
56 static unsigned long num_threads
= 1;
57 static int dump_flight_only
= 0;
58 static int dump_normal_only
= 0;
59 static int verbose_mode
= 0;
61 static __thread
int thread_pipe
[2];
63 #define printf_verbose(fmt, args...) \
66 printf(fmt, ##args); \
71 * -t directory Directory name of the trace to write to. Will be created.
72 * -c directory Root directory of the debugfs trace channels.
73 * -d Run in background (daemon).
74 * -a Trace append mode.
75 * -s Send SIGUSR1 to parent when ready for IO.
77 void show_arguments(void)
79 printf("Please use the following arguments :\n");
81 printf("-t directory Directory name of the trace to write to.\n"
82 " It will be created.\n");
83 printf("-c directory Root directory of the debugfs trace channels.\n");
84 printf("-d Run in background (daemon).\n");
85 printf("-a Append to an possibly existing trace.\n");
86 printf("-N Number of threads to start.\n");
87 printf("-f Dump only flight recorder channels.\n");
88 printf("-n Dump only normal channels.\n");
89 printf("-v Verbose mode.\n");
96 * Parses the command line arguments.
98 * Returns 1 if the arguments were correct, but doesn't ask for program
99 * continuation. Returns -1 if the arguments are incorrect, or 0 if OK.
101 int parse_arguments(int argc
, char **argv
)
107 if(strcmp(argv
[1], "-h") == 0) {
114 switch(argv
[argn
][0]) {
116 switch(argv
[argn
][1]) {
119 trace_name
= argv
[argn
+1];
125 channel_name
= argv
[argn
+1];
137 num_threads
= strtoul(argv
[argn
+1], NULL
, 0);
142 dump_flight_only
= 1;
145 dump_normal_only
= 1;
151 printf("Invalid argument '%s'.\n", argv
[argn
]);
157 printf("Invalid argument '%s'.\n", argv
[argn
]);
164 if(trace_name
== NULL
) {
165 printf("Please specify a trace name.\n");
170 if(channel_name
== NULL
) {
171 printf("Please specify a channel name.\n");
181 printf("Linux Trace Toolkit Trace Daemon " VERSION
"\n");
183 printf("Reading from debugfs directory : %s\n", channel_name
);
184 printf("Writing to trace directory : %s\n", trace_name
);
189 /* signal handling */
191 static void handler(int signo
)
193 printf("Signal %d received : exiting cleanly\n", signo
);
197 int lttd_on_open_channel(struct liblttd_callbacks
*data
, struct fd_pair
*pair
, char *relative_channel_path
)
201 struct stat stat_buf
;
202 struct lttd_channel_data
*channel_data
;
204 pair
->user_data
= malloc(sizeof(struct lttd_channel_data
));
205 channel_data
= pair
->user_data
;
207 strncpy(end_path_trace
, relative_channel_path
, PATH_MAX
- path_trace_len
);
208 printf_verbose("Creating trace file %s\n", path_trace
);
210 ret
= stat(path_trace
, &stat_buf
);
213 printf_verbose("Appending to file %s as requested\n",
216 channel_data
->trace
= open(path_trace
, O_WRONLY
, S_IRWXU
|S_IRWXG
|S_IRWXO
);
217 if(channel_data
->trace
== -1) {
222 ret
= lseek(channel_data
->trace
, 0, SEEK_END
);
226 close(channel_data
->trace
);
230 printf("File %s exists, cannot open. Try append mode.\n", path_trace
);
235 if(errno
== ENOENT
) {
236 channel_data
->trace
= open(path_trace
, O_WRONLY
|O_CREAT
|O_EXCL
, S_IRWXU
|S_IRWXG
|S_IRWXO
);
237 if(channel_data
->trace
== -1) {
250 int lttd_on_close_channel(struct liblttd_callbacks
*data
, struct fd_pair
*pair
)
253 ret
= close(((struct lttd_channel_data
*)(pair
->user_data
))->trace
);
254 free(pair
->user_data
);
258 int lttd_on_new_channels_folder(struct liblttd_callbacks
*data
, char *relative_folder_path
)
263 strncpy(end_path_trace
, relative_folder_path
, PATH_MAX
- path_trace_len
);
264 printf_verbose("Creating trace subdirectory %s\n", path_trace
);
266 ret
= mkdir(path_trace
, S_IRWXU
|S_IRWXG
|S_IRWXO
);
268 if(errno
!= EEXIST
) {
279 int lttd_on_read_subbuffer(struct liblttd_callbacks
*data
, struct fd_pair
*pair
, unsigned int len
)
285 printf_verbose("splice chan to pipe offset %lu\n",
286 (unsigned long)offset
);
287 ret
= splice(pair
->channel
, &offset
, thread_pipe
[1], NULL
,
288 len
, SPLICE_F_MOVE
| SPLICE_F_MORE
);
289 printf_verbose("splice chan to pipe ret %ld\n", ret
);
291 perror("Error in relay splice");
294 ret
= splice(thread_pipe
[0], NULL
,
295 ((struct lttd_channel_data
*)(pair
->user_data
))->trace
,
296 NULL
, ret
, SPLICE_F_MOVE
| SPLICE_F_MORE
);
297 printf_verbose("splice pipe to file %ld\n", ret
);
299 perror("Error in file splice");
309 int on_new_thread(struct liblttd_callbacks
*data
, unsigned long thread_num
) {
311 ret
= pipe(thread_pipe
);
313 perror("Error creating pipe");
319 int on_close_thread(struct liblttd_callbacks
*data
, unsigned long thread_num
) {
320 close(thread_pipe
[0]); /* close read end */
321 close(thread_pipe
[1]); /* close write end */
325 int main(int argc
, char ** argv
)
328 struct sigaction act
;
330 struct liblttd_callbacks callbacks
= {
331 lttd_on_open_channel
,
332 lttd_on_close_channel
,
333 lttd_on_new_channels_folder
,
334 lttd_on_read_subbuffer
,
341 ret
= parse_arguments(argc
, argv
);
343 if(ret
!= 0) show_arguments();
344 if(ret
< 0) return EINVAL
;
345 if(ret
> 0) return 0;
349 /* Connect the signal handlers */
350 act
.sa_handler
= handler
;
352 sigemptyset(&(act
.sa_mask
));
353 sigaddset(&(act
.sa_mask
), SIGTERM
);
354 sigaddset(&(act
.sa_mask
), SIGQUIT
);
355 sigaddset(&(act
.sa_mask
), SIGINT
);
356 sigaction(SIGTERM
, &act
, NULL
);
357 sigaction(SIGQUIT
, &act
, NULL
);
358 sigaction(SIGINT
, &act
, NULL
);
364 perror("An error occured while daemonizing.");
369 strncpy(path_trace
, trace_name
, PATH_MAX
-1);
370 path_trace_len
= strlen(path_trace
);
371 end_path_trace
= path_trace
+ path_trace_len
;
373 liblttd_start(channel_name
, num_threads
, dump_flight_only
, dump_normal_only
,
374 verbose_mode
, &callbacks
);