9845c5c600c81e5a7136550235b0e5697f99c098
[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 <libltt/libltt.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 #include <signal.h>
22 #include <dirent.h>
23 #include <string.h>
24 #include <sys/stat.h>
25
26 /* Buffer for file copy : 4k seems optimal. */
27 #define BUF_SIZE 4194304
28
29 enum trace_ctl_op {
30 CTL_OP_CREATE,
31 CTL_OP_DESTROY,
32 CTL_OP_START,
33 CTL_OP_STOP,
34 CTL_OP_DAEMON,
35 CTL_OP_DESCRIPTION,
36 CTL_OP_NONE
37 };
38
39 static char *trace_name = NULL;
40 static char *mode_name = NULL;
41 static unsigned subbuf_size = 0;
42 static unsigned n_subbufs = 0;
43 static enum trace_mode mode = LTT_TRACE_NORMAL;
44 static enum trace_ctl_op op = CTL_OP_NONE;
45 static char *channel_root = NULL;
46 static char *trace_root = NULL;
47
48 static int sigio_received = 0;
49
50 void handler(int signo)
51 {
52 printf("signal %d received\n", signo);
53 sigio_received = 1;
54 }
55
56
57 /* Args :
58 *
59 */
60 void show_arguments(void)
61 {
62 printf("Please use the following arguments :\n");
63 printf("\n");
64 printf("-n name Name of the trace.\n");
65 printf("-c mode Create trace channels in mode normal or flight recorder.\n");
66 printf(" Mode values : normal (default) or flight.\n");
67 printf("-r 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("-l LTT channels root path. (ex. /mnt/relayfs/ltt)\n");
77 printf("-z Size of the subbuffers (will be rounded to next page size)\n");
78 printf("-x Number of subbuffers\n");
79 printf("-e Get XML facilities description\n");
80 printf("\n");
81 }
82
83
84 /* parse_arguments
85 *
86 * Parses the command line arguments.
87 *
88 * Returns 1 if the arguments were correct, but doesn't ask for program
89 * continuation. Returns -1 if the arguments are incorrect, or 0 if OK.
90 */
91 int parse_arguments(int argc, char **argv)
92 {
93 int ret = 0;
94 int argn = 1;
95
96 if(argc == 2) {
97 if(strcmp(argv[1], "-h") == 0) {
98 return 1;
99 }
100 }
101
102 while(argn < argc) {
103
104 switch(argv[argn][0]) {
105 case '-':
106 switch(argv[argn][1]) {
107 case 'n':
108 if(argn+1 < argc) {
109 trace_name = argv[argn+1];
110 argn++;
111 } else {
112 printf("Specify a trace name after -n.\n", argv[argn]);
113 printf("\n");
114 ret = -1;
115 }
116
117 break;
118 case 'c':
119 op = CTL_OP_CREATE;
120 if(argn+1 < argc) {
121 mode_name = argv[argn+1];
122 argn++;
123 if(strcmp(mode_name, "normal") == 0)
124 mode = LTT_TRACE_NORMAL;
125 else if(strcmp(mode_name, "flight") == 0)
126 mode = LTT_TRACE_FLIGHT;
127 else {
128 printf("Invalid mode '%s'.\n", argv[argn]);
129 printf("\n");
130 ret = -1;
131 }
132 } else {
133 printf("Specify a mode after -c.\n");
134 printf("\n");
135 ret = -1;
136 }
137 break;
138 case 'r':
139 op = CTL_OP_DESTROY;
140 break;
141 case 's':
142 op = CTL_OP_START;
143 break;
144 case 'q':
145 op = CTL_OP_STOP;
146 break;
147 case 'z':
148 if(argn+1 < argc) {
149 subbuf_size = (unsigned)atoi(argv[argn+1]);
150 argn++;
151 } else {
152 printf("Specify a number of subbuffers after -z.\n");
153 printf("\n");
154 ret = -1;
155 }
156 break;
157 case 'x':
158 if(argn+1 < argc) {
159 n_subbufs = (unsigned)atoi(argv[argn+1]);
160 argn++;
161 } else {
162 printf("Specify a subbuffer size after -x.\n");
163 printf("\n");
164 ret = -1;
165 }
166 break;
167 case 'd':
168 op = CTL_OP_DAEMON;
169 break;
170 case 'e':
171 op = CTL_OP_DESCRIPTION;
172 break;
173 case 't':
174 if(argn+1 < argc) {
175 trace_root = argv[argn+1];
176 argn++;
177 } else {
178 printf("Specify a trace root path after -t.\n");
179 printf("\n");
180 ret = -1;
181 }
182 break;
183 case 'l':
184 if(argn+1 < argc) {
185 channel_root = argv[argn+1];
186 argn++;
187 } else {
188 printf("Specify a channel root path after -l.\n");
189 printf("\n");
190 ret = -1;
191 }
192 break;
193 default:
194 printf("Invalid argument '%s'.\n", argv[argn]);
195 printf("\n");
196 ret = -1;
197 }
198 break;
199 default:
200 printf("Invalid argument '%s'.\n", argv[argn]);
201 printf("\n");
202 ret = -1;
203 }
204 argn++;
205 }
206
207 if(op != CTL_OP_DESCRIPTION && trace_name == NULL) {
208 printf("Please specify a trace name.\n");
209 printf("\n");
210 ret = -1;
211 }
212
213 if(op == CTL_OP_NONE) {
214 printf("Please specify an operation.\n");
215 printf("\n");
216 ret = -1;
217 }
218
219 if(op == CTL_OP_DAEMON) {
220 if(trace_root == NULL) {
221 printf("Please specify -t trace_root_path with the -d option.\n");
222 printf("\n");
223 ret = -1;
224 }
225 if(channel_root == NULL) {
226 printf("Please specify -l ltt_root_path with the -d option.\n");
227 printf("\n");
228 ret = -1;
229 }
230 }
231
232 if(op == CTL_OP_DESCRIPTION) {
233 if(trace_root == NULL) {
234 printf("Please specify -t trace_root_path with the -e option.\n");
235 printf("\n");
236 ret = -1;
237 }
238 }
239
240 return ret;
241 }
242
243 void show_info(void)
244 {
245 printf("Linux Trace Toolkit Trace Control\n");
246 printf("\n");
247 if(trace_name != NULL) {
248 printf("Controlling trace : %s\n", trace_name);
249 printf("\n");
250 }
251 }
252
253 int create_eventdefs(void)
254 {
255 int ret = 0;
256 char eventdefs_path[PATH_MAX];
257 char eventdefs_file[PATH_MAX];
258 char facilities_file[PATH_MAX];
259 char read_buf[BUF_SIZE];
260 struct dirent *entry;
261 char *facilities_path = getenv("LTT_FACILITIES");
262 if(facilities_path == NULL) facilities_path =
263 "/usr/share/LinuxTraceToolkitViewer/facilities";
264
265 ret = mkdir(trace_root, S_IRWXU|S_IRWXG|S_IRWXO);
266 if(ret == -1 && errno != EEXIST) {
267 perror("Cannot create trace_root directory");
268 printf("trace_root is %s\n", trace_root);
269 goto error;
270 }
271 ret = 0;
272
273 size_t trace_root_len = strlen(trace_root);
274 strncpy(eventdefs_path, trace_root, PATH_MAX);
275 strncat(eventdefs_path, "/eventdefs/", PATH_MAX - trace_root_len);
276 size_t eventdefs_path_len = strlen(eventdefs_path);
277 ret = mkdir(eventdefs_path, S_IRWXU|S_IRWXG|S_IRWXO);
278 if(ret == -1 && errno != EEXIST) {
279 perror("Cannot create eventdefs directory");
280 goto error;
281 }
282 ret = 0;
283
284 DIR *facilities_dir = opendir(facilities_path);
285
286 while((entry = readdir(facilities_dir)) != NULL) {
287 if(entry->d_name[0] == '.') continue;
288
289 printf("Appending facility file %s\n", entry->d_name);
290 strncpy(eventdefs_file, eventdefs_path, PATH_MAX);
291 strncat(eventdefs_file, entry->d_name, PATH_MAX - eventdefs_path_len);
292 /* Append to the file */
293 FILE *dest = fopen(eventdefs_file, "a");
294 if(!dest) {
295 perror("Cannot create eventdefs file");
296 continue;
297 }
298 strncpy(facilities_file, facilities_path, PATH_MAX);
299 size_t facilities_dir_len = strlen(facilities_path);
300 strncat(facilities_file, "/", PATH_MAX - facilities_dir_len);
301 strncat(facilities_file, entry->d_name, PATH_MAX - facilities_dir_len-1);
302 FILE *src = fopen(facilities_file, "r");
303 if(!src) {
304 perror("Cannot open eventdefs file for reading");
305 goto close_dest;
306 }
307
308 do {
309 size_t read_size, write_size;
310 read_size = fread(read_buf, sizeof(char), BUF_SIZE, src);
311 if(ferror(src)) {
312 perror("Cannot read eventdefs file");
313 goto close_src;
314 }
315 write_size = fwrite(read_buf, sizeof(char), read_size, dest);
316 if(ferror(dest)) {
317 perror("Cannot write eventdefs file");
318 goto close_src;
319 }
320 } while(!feof(src));
321
322 /* Add spacing between facilities */
323 fwrite("\n", 1, 1, dest);
324
325 close_src:
326 fclose(src);
327 close_dest:
328 fclose(dest);
329 }
330
331 closedir(facilities_dir);
332
333 error:
334 return ret;
335
336 }
337
338
339 int lttctl_daemon(struct lttctl_handle *handle, char *trace_name)
340 {
341 char channel_path[PATH_MAX] = "";
342 pid_t pid;
343 int ret;
344 char *lttd_path = getenv("LTT_DAEMON");
345 struct sigaction act;
346
347 if(lttd_path == NULL) lttd_path = "lttd";
348
349 strcat(channel_path, channel_root);
350 strcat(channel_path, "/");
351 strcat(channel_path, trace_name);
352
353
354 ret = lttctl_create_trace(handle, trace_name, mode, subbuf_size, n_subbufs);
355 if(ret != 0) goto create_error;
356
357 act.sa_handler = handler;
358 sigemptyset(&(act.sa_mask));
359 sigaddset(&(act.sa_mask), SIGIO);
360 sigaction(SIGIO, &act, NULL);
361
362 sigio_received = 0;
363
364 pid = fork();
365
366 if(pid > 0) {
367 /* parent */
368 while(!sigio_received) pause();
369
370 /* Now the trace is created, go on and create the supplementary files... */
371
372 printf("Creating supplementary trace files\n");
373 ret = create_eventdefs();
374 if(ret) goto start_error;
375
376 } else if(pid == 0) {
377 /* child */
378 int ret =
379 execlp(lttd_path, lttd_path, "-t", trace_root, "-c", channel_path, "-s", NULL);
380 if(ret) {
381 perror("Error in executing the lttd daemon");
382 exit(-1);
383 }
384 } else {
385 /* error */
386 perror("Error in forking for lttd daemon");
387
388 }
389
390 ret = lttctl_start(handle, trace_name);
391 if(ret != 0) goto start_error;
392
393 return 0;
394
395 /* error handling */
396 start_error:
397 ret |= lttctl_destroy_trace(handle, trace_name);
398 create_error:
399 return ret;
400 }
401
402 int main(int argc, char ** argv)
403 {
404 int ret;
405 struct lttctl_handle *handle;
406
407 ret = parse_arguments(argc, argv);
408
409 if(ret != 0) show_arguments();
410 if(ret < 0) return EINVAL;
411 if(ret > 0) return 0;
412
413 show_info();
414
415 handle = lttctl_create_handle();
416
417 if(handle == NULL) return -1;
418
419 switch(op) {
420 case CTL_OP_CREATE:
421 ret = lttctl_create_trace(handle, trace_name, mode, subbuf_size,
422 n_subbufs);
423 break;
424 case CTL_OP_DESTROY:
425 ret = lttctl_destroy_trace(handle, trace_name);
426 break;
427 case CTL_OP_START:
428 ret = lttctl_start(handle, trace_name);
429 break;
430 case CTL_OP_STOP:
431 ret = lttctl_stop(handle, trace_name);
432 break;
433 case CTL_OP_DAEMON:
434 ret = lttctl_daemon(handle, trace_name);
435 break;
436 case CTL_OP_DESCRIPTION:
437 ret = create_eventdefs();
438 break;
439 case CTL_OP_NONE:
440 break;
441 }
442
443 ret |= lttctl_destroy_handle(handle);
444
445 return ret;
446 }
This page took 0.037123 seconds and 3 git commands to generate.