update compat
[lttv.git] / ltt-control / lttctl / lttctl.c
CommitLineData
2cdb6fcb 1/* lttctl
2 *
3 * Linux Trace Toolkit Control
4 *
5 * Small program that controls LTT through libltt.
6 *
7 * Copyright 2005 -
8 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
9 */
10
4e4d11b3 11#ifdef HAVE_CONFIG_H
12#include <config.h>
13#endif
14
5cec0a15 15#include <liblttctl/lttctl.h>
5adba60f 16#include <errno.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <sys/types.h>
86a65fdb 20#include <sys/wait.h>
5adba60f 21#include <unistd.h>
22#include <signal.h>
d5fbdb60 23#include <dirent.h>
24#include <string.h>
25#include <sys/stat.h>
26
27/* Buffer for file copy : 4k seems optimal. */
2312de30 28#define BUF_SIZE 4096
2cdb6fcb 29
5adba60f 30enum trace_ctl_op {
b7f08766 31 CTL_OP_CREATE_START,
5adba60f 32 CTL_OP_CREATE,
33 CTL_OP_DESTROY,
b7f08766 34 CTL_OP_STOP_DESTROY,
5adba60f 35 CTL_OP_START,
36 CTL_OP_STOP,
37 CTL_OP_DAEMON,
129fd24a 38 CTL_OP_DESCRIPTION,
5adba60f 39 CTL_OP_NONE
40};
2cdb6fcb 41
5adba60f 42static char *trace_name = NULL;
313b3771 43static char *trace_type = "relay";
5adba60f 44static char *mode_name = NULL;
988614ed 45static unsigned subbuf_size = 0;
46static unsigned n_subbufs = 0;
45653836 47static unsigned append_trace = 0;
5adba60f 48static enum trace_mode mode = LTT_TRACE_NORMAL;
49static enum trace_ctl_op op = CTL_OP_NONE;
50static char *channel_root = NULL;
51static char *trace_root = NULL;
22acb617 52static char *num_threads = "1";
5adba60f 53
86a65fdb 54static int sigchld_received = 0;
ada84671 55
86a65fdb 56void sigchld_handler(int signo)
5adba60f 57{
58 printf("signal %d received\n", signo);
86a65fdb 59 sigchld_received = 1;
5adba60f 60}
61
62
63/* Args :
64 *
65 */
66void show_arguments(void)
67{
68 printf("Please use the following arguments :\n");
69 printf("\n");
70 printf("-n name Name of the trace.\n");
b7f08766 71 printf("-b Create trace channels and start tracing (no daemon).\n");
bc0fcb31 72 printf("-c Create trace channels.\n");
73 printf("-m mode Normal or flight recorder mode.\n");
5adba60f 74 printf(" Mode values : normal (default) or flight.\n");
75 printf("-r Destroy trace channels.\n");
b7f08766 76 printf("-R Stop tracing and destroy trace channels.\n");
5adba60f 77 printf("-s Start tracing.\n");
78 //printf(" Note : will automatically create a normal trace if "
79 // "none exists.\n");
80 printf("-q Stop tracing.\n");
81 printf("-d Create trace, spawn a lttd daemon, start tracing.\n");
d5fbdb60 82 printf(" (optionnaly, you can set LTT_DAEMON\n");
83 printf(" and the LTT_FACILITIES env. vars.)\n");
5adba60f 84 printf("-t Trace root path. (ex. /root/traces/example_trace)\n");
313b3771 85 printf("-T Type of trace (ex. relay)\n");
5adba60f 86 printf("-l LTT channels root path. (ex. /mnt/relayfs/ltt)\n");
4085af66 87 printf("-z Size of the subbuffers (will be rounded to next page size)\n");
988614ed 88 printf("-x Number of subbuffers\n");
129fd24a 89 printf("-e Get XML facilities description\n");
45653836 90 printf("-a Append to trace\n");
b8d28629 91 printf("-N Number of lttd threads\n");
5adba60f 92 printf("\n");
93}
94
95
96/* parse_arguments
97 *
98 * Parses the command line arguments.
99 *
2baf08e5 100 * Returns -1 if the arguments were correct, but doesn't ask for program
101 * continuation. Returns EINVAL if the arguments are incorrect, or 0 if OK.
5adba60f 102 */
103int parse_arguments(int argc, char **argv)
104{
105 int ret = 0;
106 int argn = 1;
107
108 if(argc == 2) {
109 if(strcmp(argv[1], "-h") == 0) {
2baf08e5 110 return -1;
5adba60f 111 }
112 }
113
114 while(argn < argc) {
115
116 switch(argv[argn][0]) {
117 case '-':
118 switch(argv[argn][1]) {
119 case 'n':
120 if(argn+1 < argc) {
121 trace_name = argv[argn+1];
122 argn++;
123 } else {
8eab4866 124 printf("Specify a trace name after -n.\n");
5adba60f 125 printf("\n");
2baf08e5 126 ret = EINVAL;
5adba60f 127 }
128
129 break;
b7f08766 130 case 'b':
131 op = CTL_OP_CREATE_START;
cd39bb61 132 break;
5adba60f 133 case 'c':
134 op = CTL_OP_CREATE;
bc0fcb31 135 break;
136 case 'm':
5adba60f 137 if(argn+1 < argc) {
138 mode_name = argv[argn+1];
139 argn++;
140 if(strcmp(mode_name, "normal") == 0)
141 mode = LTT_TRACE_NORMAL;
142 else if(strcmp(mode_name, "flight") == 0)
143 mode = LTT_TRACE_FLIGHT;
144 else {
145 printf("Invalid mode '%s'.\n", argv[argn]);
146 printf("\n");
2baf08e5 147 ret = EINVAL;
5adba60f 148 }
149 } else {
bc0fcb31 150 printf("Specify a mode after -m.\n");
5adba60f 151 printf("\n");
2baf08e5 152 ret = EINVAL;
5adba60f 153 }
154 break;
155 case 'r':
156 op = CTL_OP_DESTROY;
157 break;
b7f08766 158 case 'R':
159 op = CTL_OP_STOP_DESTROY;
160 break;
5adba60f 161 case 's':
162 op = CTL_OP_START;
163 break;
164 case 'q':
165 op = CTL_OP_STOP;
166 break;
988614ed 167 case 'z':
168 if(argn+1 < argc) {
169 subbuf_size = (unsigned)atoi(argv[argn+1]);
170 argn++;
171 } else {
172 printf("Specify a number of subbuffers after -z.\n");
173 printf("\n");
2baf08e5 174 ret = EINVAL;
988614ed 175 }
176 break;
177 case 'x':
178 if(argn+1 < argc) {
179 n_subbufs = (unsigned)atoi(argv[argn+1]);
180 argn++;
181 } else {
182 printf("Specify a subbuffer size after -x.\n");
183 printf("\n");
2baf08e5 184 ret = EINVAL;
988614ed 185 }
186 break;
5adba60f 187 case 'd':
188 op = CTL_OP_DAEMON;
189 break;
129fd24a 190 case 'e':
191 op = CTL_OP_DESCRIPTION;
192 break;
5adba60f 193 case 't':
194 if(argn+1 < argc) {
195 trace_root = argv[argn+1];
196 argn++;
197 } else {
988614ed 198 printf("Specify a trace root path after -t.\n");
5adba60f 199 printf("\n");
2baf08e5 200 ret = EINVAL;
5adba60f 201 }
202 break;
203 case 'l':
204 if(argn+1 < argc) {
205 channel_root = argv[argn+1];
206 argn++;
207 } else {
988614ed 208 printf("Specify a channel root path after -l.\n");
5adba60f 209 printf("\n");
2baf08e5 210 ret = EINVAL;
5adba60f 211 }
212 break;
45653836 213 case 'a':
214 append_trace = 1;
215 break;
22acb617 216 case 'N':
217 if(argn+1 < argc) {
218 num_threads = argv[argn+1];
219 argn++;
220 }
221 break;
313b3771 222 case 'T':
223 if(argn+1 < argc) {
224 trace_type = argv[argn+1];
225 argn++;
226 } else {
227 printf("Specify a trace type after -T.\n");
228 printf("\n");
229 ret = EINVAL;
230 }
231 break;
5adba60f 232 default:
233 printf("Invalid argument '%s'.\n", argv[argn]);
234 printf("\n");
2baf08e5 235 ret = EINVAL;
5adba60f 236 }
237 break;
238 default:
239 printf("Invalid argument '%s'.\n", argv[argn]);
240 printf("\n");
2baf08e5 241 ret = EINVAL;
5adba60f 242 }
243 argn++;
244 }
245
129fd24a 246 if(op != CTL_OP_DESCRIPTION && trace_name == NULL) {
5adba60f 247 printf("Please specify a trace name.\n");
248 printf("\n");
2baf08e5 249 ret = EINVAL;
5adba60f 250 }
251
252 if(op == CTL_OP_NONE) {
253 printf("Please specify an operation.\n");
254 printf("\n");
2baf08e5 255 ret = EINVAL;
5adba60f 256 }
257
258 if(op == CTL_OP_DAEMON) {
259 if(trace_root == NULL) {
260 printf("Please specify -t trace_root_path with the -d option.\n");
261 printf("\n");
2baf08e5 262 ret = EINVAL;
5adba60f 263 }
264 if(channel_root == NULL) {
265 printf("Please specify -l ltt_root_path with the -d option.\n");
266 printf("\n");
2baf08e5 267 ret = EINVAL;
5adba60f 268 }
269 }
270
129fd24a 271 if(op == CTL_OP_DESCRIPTION) {
272 if(trace_root == NULL) {
273 printf("Please specify -t trace_root_path with the -e option.\n");
274 printf("\n");
2baf08e5 275 ret = EINVAL;
129fd24a 276 }
277 }
278
5adba60f 279 return ret;
280}
281
282void show_info(void)
283{
284 printf("Linux Trace Toolkit Trace Control\n");
285 printf("\n");
129fd24a 286 if(trace_name != NULL) {
287 printf("Controlling trace : %s\n", trace_name);
288 printf("\n");
289 }
290}
291
292int create_eventdefs(void)
293{
294 int ret = 0;
295 char eventdefs_path[PATH_MAX];
296 char eventdefs_file[PATH_MAX];
297 char facilities_file[PATH_MAX];
298 char read_buf[BUF_SIZE];
299 struct dirent *entry;
300 char *facilities_path = getenv("LTT_FACILITIES");
301 if(facilities_path == NULL) facilities_path =
86a65fdb 302 PACKAGE_DATA_DIR "/" PACKAGE "/facilities";
129fd24a 303
304 ret = mkdir(trace_root, S_IRWXU|S_IRWXG|S_IRWXO);
305 if(ret == -1 && errno != EEXIST) {
618fbcc1 306 ret = errno;
129fd24a 307 perror("Cannot create trace_root directory");
308 printf("trace_root is %s\n", trace_root);
309 goto error;
310 }
bd55296c 311 ret = 0;
129fd24a 312
313 size_t trace_root_len = strlen(trace_root);
314 strncpy(eventdefs_path, trace_root, PATH_MAX);
315 strncat(eventdefs_path, "/eventdefs/", PATH_MAX - trace_root_len);
316 size_t eventdefs_path_len = strlen(eventdefs_path);
317 ret = mkdir(eventdefs_path, S_IRWXU|S_IRWXG|S_IRWXO);
45653836 318 if(ret == -1 && (!append_trace || errno != EEXIST)) {
2baf08e5 319 ret = errno;
618fbcc1 320 perror("Cannot create eventdefs directory");
129fd24a 321 goto error;
322 }
bd55296c 323 ret = 0;
129fd24a 324
325 DIR *facilities_dir = opendir(facilities_path);
326
86a65fdb 327 if(facilities_dir == NULL) {
328 perror("Cannot open facilities directory");
2baf08e5 329 ret = EEXIST;
86a65fdb 330 goto error;
331 }
332
129fd24a 333 while((entry = readdir(facilities_dir)) != NULL) {
334 if(entry->d_name[0] == '.') continue;
335
336 printf("Appending facility file %s\n", entry->d_name);
337 strncpy(eventdefs_file, eventdefs_path, PATH_MAX);
338 strncat(eventdefs_file, entry->d_name, PATH_MAX - eventdefs_path_len);
339 /* Append to the file */
340 FILE *dest = fopen(eventdefs_file, "a");
341 if(!dest) {
342 perror("Cannot create eventdefs file");
343 continue;
344 }
345 strncpy(facilities_file, facilities_path, PATH_MAX);
346 size_t facilities_dir_len = strlen(facilities_path);
347 strncat(facilities_file, "/", PATH_MAX - facilities_dir_len);
348 strncat(facilities_file, entry->d_name, PATH_MAX - facilities_dir_len-1);
349 FILE *src = fopen(facilities_file, "r");
350 if(!src) {
2baf08e5 351 ret = errno;
618fbcc1 352 perror("Cannot open eventdefs file for reading");
129fd24a 353 goto close_dest;
354 }
355
356 do {
357 size_t read_size, write_size;
358 read_size = fread(read_buf, sizeof(char), BUF_SIZE, src);
359 if(ferror(src)) {
2baf08e5 360 ret = errno;
618fbcc1 361 perror("Cannot read eventdefs file");
129fd24a 362 goto close_src;
363 }
364 write_size = fwrite(read_buf, sizeof(char), read_size, dest);
365 if(ferror(dest)) {
2baf08e5 366 ret = errno;
618fbcc1 367 perror("Cannot write eventdefs file");
129fd24a 368 goto close_src;
369 }
370 } while(!feof(src));
371
372 /* Add spacing between facilities */
373 fwrite("\n", 1, 1, dest);
374
375close_src:
376 fclose(src);
377close_dest:
378 fclose(dest);
379 }
380
381 closedir(facilities_dir);
382
86a65fdb 383error:
129fd24a 384 return ret;
385
5adba60f 386}
387
129fd24a 388
5adba60f 389int lttctl_daemon(struct lttctl_handle *handle, char *trace_name)
390{
391 char channel_path[PATH_MAX] = "";
392 pid_t pid;
393 int ret;
394 char *lttd_path = getenv("LTT_DAEMON");
395 struct sigaction act;
396
86a65fdb 397 if(lttd_path == NULL) lttd_path =
398 PACKAGE_BIN_DIR "/lttd";
5adba60f 399
400 strcat(channel_path, channel_root);
401 strcat(channel_path, "/");
402 strcat(channel_path, trace_name);
403
404
313b3771 405 ret = lttctl_create_trace(handle, trace_name, mode, trace_type, subbuf_size, n_subbufs);
5adba60f 406 if(ret != 0) goto create_error;
407
86a65fdb 408 act.sa_handler = sigchld_handler;
5adba60f 409 sigemptyset(&(act.sa_mask));
86a65fdb 410 sigaddset(&(act.sa_mask), SIGCHLD);
411 sigaction(SIGCHLD, &act, NULL);
ada84671 412
5adba60f 413 pid = fork();
414
415 if(pid > 0) {
86a65fdb 416 int status;
5adba60f 417 /* parent */
86a65fdb 418 while(!(sigchld_received)) pause();
419
420 waitpid(pid, &status, 0);
421 ret = 0;
422 if(WIFEXITED(status))
423 ret = WEXITSTATUS(status);
424 if(ret) goto start_error;
5adba60f 425
5adba60f 426 printf("Creating supplementary trace files\n");
129fd24a 427 ret = create_eventdefs();
428 if(ret) goto start_error;
5adba60f 429
430 } else if(pid == 0) {
431 /* child */
45653836 432 int ret;
433 if(append_trace)
434 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
22acb617 435 channel_path, "-d", "-a", "-N", num_threads, NULL);
45653836 436 else
437 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
22acb617 438 channel_path, "-d", "-N", num_threads, NULL);
5adba60f 439 if(ret) {
618fbcc1 440 ret = errno;
5adba60f 441 perror("Error in executing the lttd daemon");
618fbcc1 442 exit(ret);
5adba60f 443 }
444 } else {
445 /* error */
446 perror("Error in forking for lttd daemon");
5adba60f 447 }
448
449 ret = lttctl_start(handle, trace_name);
450 if(ret != 0) goto start_error;
451
452 return 0;
453
454 /* error handling */
455start_error:
86a65fdb 456 printf("Trace start error\n");
5adba60f 457 ret |= lttctl_destroy_trace(handle, trace_name);
458create_error:
459 return ret;
460}
461
462int main(int argc, char ** argv)
463{
464 int ret;
465 struct lttctl_handle *handle;
466
467 ret = parse_arguments(argc, argv);
468
469 if(ret != 0) show_arguments();
2baf08e5 470 if(ret == EINVAL) return EINVAL;
471 if(ret == -1) return 0;
5adba60f 472
473 show_info();
474
475 handle = lttctl_create_handle();
476
477 if(handle == NULL) return -1;
478
479 switch(op) {
b7f08766 480 case CTL_OP_CREATE_START:
313b3771 481 ret = lttctl_create_trace(handle, trace_name, mode, trace_type, subbuf_size,
b7f08766 482 n_subbufs);
483 if(!ret)
484 ret = lttctl_start(handle, trace_name);
485 break;
5adba60f 486 case CTL_OP_CREATE:
313b3771 487 ret = lttctl_create_trace(handle, trace_name, mode, trace_type, subbuf_size,
988614ed 488 n_subbufs);
24ba6df0 489 break;
5adba60f 490 case CTL_OP_DESTROY:
491 ret = lttctl_destroy_trace(handle, trace_name);
492 break;
b7f08766 493 case CTL_OP_STOP_DESTROY:
494 ret = lttctl_stop(handle, trace_name);
495 if(!ret)
496 ret = lttctl_destroy_trace(handle, trace_name);
497 break;
5adba60f 498 case CTL_OP_START:
499 ret = lttctl_start(handle, trace_name);
500 break;
501 case CTL_OP_STOP:
502 ret = lttctl_stop(handle, trace_name);
503 break;
504 case CTL_OP_DAEMON:
505 ret = lttctl_daemon(handle, trace_name);
506 break;
129fd24a 507 case CTL_OP_DESCRIPTION:
508 ret = create_eventdefs();
509 break;
5adba60f 510 case CTL_OP_NONE:
511 break;
512 }
513
514 ret |= lttctl_destroy_handle(handle);
515
516 return ret;
517}
This page took 0.054204 seconds and 4 git commands to generate.