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