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