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