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