Move the code from lttd to liblttd and adapt everything so it works
[ltt-control.git] / lttd / lttd.c
CommitLineData
617de8e1 1/* lttd
2 *
3 * Linux Trace Toolkit Daemon
4 *
c2ffa20f 5 * This is a simple daemon that reads a few relay+debugfs channels and save
6 * them in a trace.
617de8e1 7 *
31482529 8 * CPU hot-plugging is supported using inotify.
617de8e1 9 *
ed2849af
MD
10 * Copyright 2009-2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
11 *
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.
16 *
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.
21 *
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.
617de8e1 25 */
26
0bb647f5 27#ifdef HAVE_CONFIG_H
469206ed 28#include <config.h>
0bb647f5 29#endif
30
e54e1d5d 31#define _REENTRANT
0bb647f5 32#define _GNU_SOURCE
008e2515 33
617de8e1 34#include <stdio.h>
617de8e1 35#include <stdlib.h>
617de8e1 36#include <string.h>
1d483eea 37#include <signal.h>
008e2515
MSL
38#include <errno.h>
39#include <fcntl.h>
40#include <dirent.h>
41#include <sys/stat.h>
1d483eea 42
008e2515 43#include <liblttd/liblttd.h>
357915bb 44
008e2515 45struct lttd_channel_data {
617de8e1 46 int trace;
357915bb 47};
48
008e2515
MSL
49static char path_trace[PATH_MAX];
50static char *end_path_trace;
51static int path_trace_len = 0;
89565b43 52static char *trace_name = NULL;
53static char *channel_name = NULL;
54static int daemon_mode = 0;
55static int append_mode = 0;
56static unsigned long num_threads = 1;
89565b43 57static int dump_flight_only = 0;
58static int dump_normal_only = 0;
083518b7 59static int verbose_mode = 0;
60
008e2515
MSL
61static __thread int thread_pipe[2];
62
083518b7 63#define printf_verbose(fmt, args...) \
64 do { \
65 if (verbose_mode) \
66 printf(fmt, ##args); \
67 } while (0)
617de8e1 68
69/* Args :
70 *
71 * -t directory Directory name of the trace to write to. Will be created.
c2ffa20f 72 * -c directory Root directory of the debugfs trace channels.
617de8e1 73 * -d Run in background (daemon).
083518b7 74 * -a Trace append mode.
75 * -s Send SIGUSR1 to parent when ready for IO.
617de8e1 76 */
77void show_arguments(void)
78{
79 printf("Please use the following arguments :\n");
80 printf("\n");
81 printf("-t directory Directory name of the trace to write to.\n"
82 " It will be created.\n");
c2ffa20f 83 printf("-c directory Root directory of the debugfs trace channels.\n");
617de8e1 84 printf("-d Run in background (daemon).\n");
90ccaa9a 85 printf("-a Append to an possibly existing trace.\n");
5ffb77aa 86 printf("-N Number of threads to start.\n");
89565b43 87 printf("-f Dump only flight recorder channels.\n");
88 printf("-n Dump only normal channels.\n");
083518b7 89 printf("-v Verbose mode.\n");
617de8e1 90 printf("\n");
91}
92
93
94/* parse_arguments
95 *
96 * Parses the command line arguments.
97 *
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.
100 */
101int parse_arguments(int argc, char **argv)
102{
103 int ret = 0;
104 int argn = 1;
008e2515 105
617de8e1 106 if(argc == 2) {
107 if(strcmp(argv[1], "-h") == 0) {
108 return 1;
109 }
110 }
111
90ccaa9a 112 while(argn < argc) {
617de8e1 113
114 switch(argv[argn][0]) {
115 case '-':
116 switch(argv[argn][1]) {
117 case 't':
90ccaa9a 118 if(argn+1 < argc) {
119 trace_name = argv[argn+1];
120 argn++;
121 }
617de8e1 122 break;
123 case 'c':
90ccaa9a 124 if(argn+1 < argc) {
125 channel_name = argv[argn+1];
126 argn++;
127 }
617de8e1 128 break;
129 case 'd':
130 daemon_mode = 1;
131 break;
90ccaa9a 132 case 'a':
133 append_mode = 1;
134 break;
5ffb77aa 135 case 'N':
e54e1d5d 136 if(argn+1 < argc) {
137 num_threads = strtoul(argv[argn+1], NULL, 0);
138 argn++;
139 }
140 break;
89565b43 141 case 'f':
142 dump_flight_only = 1;
143 break;
144 case 'n':
145 dump_normal_only = 1;
146 break;
083518b7 147 case 'v':
148 verbose_mode = 1;
149 break;
617de8e1 150 default:
151 printf("Invalid argument '%s'.\n", argv[argn]);
152 printf("\n");
153 ret = -1;
154 }
155 break;
156 default:
157 printf("Invalid argument '%s'.\n", argv[argn]);
158 printf("\n");
159 ret = -1;
160 }
161 argn++;
162 }
008e2515 163
617de8e1 164 if(trace_name == NULL) {
165 printf("Please specify a trace name.\n");
166 printf("\n");
167 ret = -1;
168 }
008e2515 169
617de8e1 170 if(channel_name == NULL) {
171 printf("Please specify a channel name.\n");
172 printf("\n");
173 ret = -1;
174 }
008e2515 175
617de8e1 176 return ret;
177}
178
179void show_info(void)
180{
15061ecb 181 printf("Linux Trace Toolkit Trace Daemon " VERSION "\n");
617de8e1 182 printf("\n");
c2ffa20f 183 printf("Reading from debugfs directory : %s\n", channel_name);
617de8e1 184 printf("Writing to trace directory : %s\n", trace_name);
185 printf("\n");
186}
187
188
1d483eea 189/* signal handling */
190
191static void handler(int signo)
192{
193 printf("Signal %d received : exiting cleanly\n", signo);
008e2515 194 liblttd_stop();
1d483eea 195}
196
008e2515 197int lttd_on_open_channel(struct liblttd_callbacks *data, struct fd_pair *pair, char *relative_channel_path)
357915bb 198{
199 int open_ret = 0;
008e2515 200 int ret;
357915bb 201 struct stat stat_buf;
008e2515 202 struct lttd_channel_data *channel_data;
357915bb 203
008e2515
MSL
204 pair->user_data = malloc(sizeof(struct lttd_channel_data));
205 channel_data = pair->user_data;
206
207 strncpy(end_path_trace, relative_channel_path, PATH_MAX - path_trace_len);
208 printf_verbose("Creating trace file %s\n", path_trace);
357915bb 209
357915bb 210 ret = stat(path_trace, &stat_buf);
211 if(ret == 0) {
212 if(append_mode) {
083518b7 213 printf_verbose("Appending to file %s as requested\n",
214 path_trace);
357915bb 215
008e2515
MSL
216 channel_data->trace = open(path_trace, O_WRONLY, S_IRWXU|S_IRWXG|S_IRWXO);
217 if(channel_data->trace == -1) {
357915bb 218 perror(path_trace);
1ee8f63e 219 open_ret = -1;
1ee8f63e 220 goto end;
357915bb 221 }
008e2515 222 ret = lseek(channel_data->trace, 0, SEEK_END);
42e99028 223 if (ret < 0) {
224 perror(path_trace);
1ee8f63e 225 open_ret = -1;
008e2515 226 close(channel_data->trace);
1ee8f63e 227 goto end;
42e99028 228 }
357915bb 229 } else {
230 printf("File %s exists, cannot open. Try append mode.\n", path_trace);
231 open_ret = -1;
232 goto end;
233 }
234 } else {
235 if(errno == ENOENT) {
008e2515
MSL
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) {
357915bb 238 perror(path_trace);
1ee8f63e 239 open_ret = -1;
1ee8f63e 240 goto end;
357915bb 241 }
242 }
243 }
008e2515 244
357915bb 245end:
246 return open_ret;
008e2515 247
357915bb 248}
1d483eea 249
008e2515
MSL
250int lttd_on_close_channel(struct liblttd_callbacks *data, struct fd_pair *pair)
251{
252 int ret;
253 ret = close(((struct lttd_channel_data *)(pair->user_data))->trace);
254 free(pair->user_data);
255 return ret;
256}
257
258int lttd_on_new_channels_folder(struct liblttd_callbacks *data, char *relative_folder_path)
617de8e1 259{
617de8e1 260 int ret;
002f91bb 261 int open_ret = 0;
617de8e1 262
008e2515
MSL
263 strncpy(end_path_trace, relative_folder_path, PATH_MAX - path_trace_len);
264 printf_verbose("Creating trace subdirectory %s\n", path_trace);
617de8e1 265
008e2515 266 ret = mkdir(path_trace, S_IRWXU|S_IRWXG|S_IRWXO);
617de8e1 267 if(ret == -1) {
b1e3e7c7 268 if(errno != EEXIST) {
008e2515 269 perror(path_trace);
002f91bb 270 open_ret = -1;
d304b1dd 271 goto end;
90ccaa9a 272 }
617de8e1 273 }
274
d304b1dd 275end:
d304b1dd 276 return open_ret;
617de8e1 277}
278
008e2515 279int lttd_on_read_subbuffer(struct liblttd_callbacks *data, struct fd_pair *pair, unsigned int len)
1d483eea 280{
f01152ea 281 long ret;
008e2515 282 off_t offset = 0;
1d483eea 283
f01152ea 284 while (len > 0) {
4e1c69e6 285 printf_verbose("splice chan to pipe offset %lu\n",
286 (unsigned long)offset);
f01152ea 287 ret = splice(pair->channel, &offset, thread_pipe[1], NULL,
4b6ff6ef 288 len, SPLICE_F_MOVE | SPLICE_F_MORE);
083518b7 289 printf_verbose("splice chan to pipe ret %ld\n", ret);
f01152ea 290 if (ret < 0) {
291 perror("Error in relay splice");
292 goto write_error;
293 }
008e2515
MSL
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);
083518b7 297 printf_verbose("splice pipe to file %ld\n", ret);
f01152ea 298 if (ret < 0) {
299 perror("Error in file splice");
300 goto write_error;
301 }
302 len -= ret;
303 }
304
469206ed 305write_error:
e54e1d5d 306 return ret;
e54e1d5d 307}
308
008e2515 309int on_new_thread(struct liblttd_callbacks *data, unsigned long thread_num) {
90ccaa9a 310 int ret;
f01152ea 311 ret = pipe(thread_pipe);
312 if (ret < 0) {
313 perror("Error creating pipe");
008e2515 314 return ret;
f01152ea 315 }
008e2515 316 return 0;
31482529 317}
318
008e2515
MSL
319int 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 */
31482529 322 return 0;
617de8e1 323}
324
325int main(int argc, char ** argv)
326{
e54e1d5d 327 int ret = 0;
1d483eea 328 struct sigaction act;
008e2515
MSL
329
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,
335 NULL,
336 on_new_thread,
337 on_close_thread,
338 NULL
339 };
340
617de8e1 341 ret = parse_arguments(argc, argv);
342
343 if(ret != 0) show_arguments();
344 if(ret < 0) return EINVAL;
345 if(ret > 0) return 0;
346
347 show_info();
348
1d483eea 349 /* Connect the signal handlers */
350 act.sa_handler = handler;
351 act.sa_flags = 0;
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);
359
06cb3ad3 360 if(daemon_mode) {
361 ret = daemon(0, 0);
362
363 if(ret == -1) {
364 perror("An error occured while daemonizing.");
365 exit(-1);
366 }
367 }
368
008e2515
MSL
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;
617de8e1 372
008e2515
MSL
373 liblttd_start(channel_name, num_threads, dump_flight_only, dump_normal_only,
374 verbose_mode, &callbacks);
5ffb77aa 375
617de8e1 376 return ret;
377}
008e2515 378
This page took 0.04562 seconds and 4 git commands to generate.