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