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