trace control work in progress
[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
5adba60f 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>
d5fbdb60 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
2cdb6fcb 28
5adba60f 29enum trace_ctl_op {
30 CTL_OP_CREATE,
31 CTL_OP_DESTROY,
32 CTL_OP_START,
33 CTL_OP_STOP,
34 CTL_OP_DAEMON,
129fd24a 35 CTL_OP_DESCRIPTION,
5adba60f 36 CTL_OP_NONE
37};
2cdb6fcb 38
5adba60f 39static char *trace_name = NULL;
40static char *mode_name = NULL;
988614ed 41static unsigned subbuf_size = 0;
42static unsigned n_subbufs = 0;
5adba60f 43static enum trace_mode mode = LTT_TRACE_NORMAL;
44static enum trace_ctl_op op = CTL_OP_NONE;
45static char *channel_root = NULL;
46static char *trace_root = NULL;
47
ada84671 48static int sigio_received = 0;
49
5adba60f 50void handler(int signo)
51{
52 printf("signal %d received\n", signo);
ada84671 53 sigio_received = 1;
5adba60f 54}
55
56
57/* Args :
58 *
59 */
60void 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");
d5fbdb60 73 printf(" (optionnaly, you can set LTT_DAEMON\n");
74 printf(" and the LTT_FACILITIES env. vars.)\n");
5adba60f 75 printf("-t Trace root path. (ex. /root/traces/example_trace)\n");
76 printf("-l LTT channels root path. (ex. /mnt/relayfs/ltt)\n");
4085af66 77 printf("-z Size of the subbuffers (will be rounded to next page size)\n");
988614ed 78 printf("-x Number of subbuffers\n");
129fd24a 79 printf("-e Get XML facilities description\n");
5adba60f 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 */
91int 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 {
988614ed 133 printf("Specify a mode after -c.\n");
5adba60f 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;
988614ed 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;
5adba60f 167 case 'd':
168 op = CTL_OP_DAEMON;
169 break;
129fd24a 170 case 'e':
171 op = CTL_OP_DESCRIPTION;
172 break;
5adba60f 173 case 't':
174 if(argn+1 < argc) {
175 trace_root = argv[argn+1];
176 argn++;
177 } else {
988614ed 178 printf("Specify a trace root path after -t.\n");
5adba60f 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 {
988614ed 188 printf("Specify a channel root path after -l.\n");
5adba60f 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
129fd24a 207 if(op != CTL_OP_DESCRIPTION && trace_name == NULL) {
5adba60f 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
129fd24a 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
5adba60f 240 return ret;
241}
242
243void show_info(void)
244{
245 printf("Linux Trace Toolkit Trace Control\n");
246 printf("\n");
129fd24a 247 if(trace_name != NULL) {
248 printf("Controlling trace : %s\n", trace_name);
249 printf("\n");
250 }
251}
252
253int 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 }
bd55296c 271 ret = 0;
129fd24a 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 }
bd55296c 282 ret = 0;
129fd24a 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
325close_src:
326 fclose(src);
327close_dest:
328 fclose(dest);
329 }
330
331 closedir(facilities_dir);
332
333 error:
334 return ret;
335
5adba60f 336}
337
129fd24a 338
5adba60f 339int 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
988614ed 354 ret = lttctl_create_trace(handle, trace_name, mode, subbuf_size, n_subbufs);
5adba60f 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
ada84671 362 sigio_received = 0;
363
5adba60f 364 pid = fork();
365
366 if(pid > 0) {
5adba60f 367 /* parent */
ada84671 368 while(!sigio_received) pause();
5adba60f 369
370 /* Now the trace is created, go on and create the supplementary files... */
d5fbdb60 371
5adba60f 372 printf("Creating supplementary trace files\n");
129fd24a 373 ret = create_eventdefs();
374 if(ret) goto start_error;
5adba60f 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 */
396start_error:
397 ret |= lttctl_destroy_trace(handle, trace_name);
398create_error:
399 return ret;
400}
401
402int 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:
988614ed 421 ret = lttctl_create_trace(handle, trace_name, mode, subbuf_size,
422 n_subbufs);
24ba6df0 423 break;
5adba60f 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;
129fd24a 436 case CTL_OP_DESCRIPTION:
437 ret = create_eventdefs();
438 break;
5adba60f 439 case CTL_OP_NONE:
440 break;
441 }
442
443 ret |= lttctl_destroy_handle(handle);
444
445 return ret;
446}
This page took 0.041561 seconds and 4 git commands to generate.