Commit | Line | Data |
---|---|---|
ed2849af MD |
1 | /* |
2 | * liblttctl | |
2727692a | 3 | * |
ed2849af | 4 | * Linux Trace Toolkit Control Library |
2727692a | 5 | * |
c928825d | 6 | * Controls the ltt-control kernel module through debugfs. |
2727692a | 7 | * |
ed2849af | 8 | * Copyright (c) 2005-2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
2727692a | 9 | * |
ed2849af MD |
10 | * This library is free software; you can redistribute it and/or |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
2727692a | 14 | * |
ed2849af | 15 | * This library is distributed in the hope that it will be useful, |
2727692a | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
ed2849af MD |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | * Lesser General Public License for more details. | |
c928825d | 19 | * |
ed2849af MD |
20 | * You should have received a copy of the GNU Lesser General Public |
21 | * License along with this library; if not, write to the Free Software | |
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
2727692a | 23 | */ |
24 | ||
25 | #ifdef HAVE_CONFIG_H | |
26 | #include <config.h> | |
27 | #endif | |
28 | ||
29 | #include <liblttctl/lttctl.h> | |
30 | #include <errno.h> | |
31 | #include <stdio.h> | |
2727692a | 32 | #include <string.h> |
c928825d | 33 | #include <dirent.h> |
34 | #include <limits.h> | |
35 | #include <fcntl.h> | |
36 | #include <stdlib.h> | |
2727692a | 37 | |
c928825d | 38 | #define MAX_CHANNEL (256) |
2727692a | 39 | |
c928825d | 40 | static char debugfsmntdir[PATH_MAX]; |
2727692a | 41 | |
c928825d | 42 | static int initdebugfsmntdir(void) |
2727692a | 43 | { |
354b34fd | 44 | return getdebugfsmntdir(debugfsmntdir); |
45 | } | |
2727692a | 46 | |
354b34fd | 47 | /* |
48 | * This function must called posterior to initdebugfsmntdir(), | |
49 | * because it need to use debugfsmntdir[] which is inited in initdebugfsmntdir() | |
50 | */ | |
51 | static int initmodule(void) | |
52 | { | |
53 | char controldirname[PATH_MAX]; | |
54 | DIR *dir; | |
55 | int tryload_done = 0; | |
56 | ||
57 | sprintf(controldirname, "%s/ltt/control/", debugfsmntdir); | |
58 | ||
59 | check_again: | |
60 | /* | |
61 | * Check ltt control's debugfs dir | |
62 | * | |
63 | * We don't check is ltt-trace-control module exist, because it maybe | |
64 | * compiled into kernel. | |
65 | */ | |
66 | dir = opendir(controldirname); | |
67 | if (dir) { | |
68 | closedir(dir); | |
69 | return 0; | |
c928825d | 70 | } |
2727692a | 71 | |
354b34fd | 72 | if (!tryload_done) { |
73 | system("modprobe ltt-trace-control"); | |
74 | tryload_done = 1; | |
75 | goto check_again; | |
2727692a | 76 | } |
354b34fd | 77 | |
78 | return -ENOENT; | |
c928825d | 79 | } |
80 | ||
81 | int lttctl_init(void) | |
82 | { | |
83 | int ret; | |
354b34fd | 84 | |
c928825d | 85 | |
86 | ret = initdebugfsmntdir(); | |
87 | if (ret) { | |
354b34fd | 88 | fprintf(stderr, "Get debugfs mount point failed\n"); |
4015ea80 | 89 | return ret; |
2727692a | 90 | } |
2727692a | 91 | |
354b34fd | 92 | ret = initmodule(); |
93 | if (ret) { | |
94 | fprintf(stderr, "Control module seems not work\n"); | |
4015ea80 | 95 | return ret; |
c928825d | 96 | } |
2727692a | 97 | |
c928825d | 98 | return 0; |
99 | } | |
2727692a | 100 | |
c928825d | 101 | int lttctl_destroy(void) |
2727692a | 102 | { |
c928825d | 103 | return 0; |
2727692a | 104 | } |
105 | ||
c928825d | 106 | static int lttctl_sendop(const char *fname, const char *op) |
2727692a | 107 | { |
c928825d | 108 | int fd; |
109 | ||
110 | if (!fname) { | |
111 | fprintf(stderr, "%s: args invalid\n", __func__); | |
112 | return 1; | |
113 | } | |
114 | ||
115 | fd = open(fname, O_WRONLY); | |
116 | if (fd == -1) { | |
117 | fprintf(stderr, "%s: open %s failed: %s\n", __func__, fname, | |
118 | strerror(errno)); | |
119 | return errno; | |
120 | } | |
121 | ||
122 | if (write(fd, op, strlen(op)) == -1) { | |
4015ea80 | 123 | int ret = errno; |
c928825d | 124 | fprintf(stderr, "%s: write %s to %s failed: %s\n", __func__, op, |
125 | fname, strerror(errno)); | |
126 | close(fd); | |
4015ea80 | 127 | return ret; |
c928825d | 128 | } |
2727692a | 129 | |
c928825d | 130 | close(fd); |
131 | ||
132 | return 0; | |
133 | } | |
2727692a | 134 | |
135 | /* | |
c928825d | 136 | * check is trace exist(check debugfsmntdir too) |
137 | * expect: | |
138 | * 0: expect that trace not exist | |
139 | * !0: expect that trace exist | |
140 | * | |
141 | * ret: | |
142 | * 0: check pass | |
4015ea80 | 143 | * -(EEXIST | ENOENT): check failed |
c928825d | 144 | * -ERRNO: error happened (no check) |
2727692a | 145 | */ |
c928825d | 146 | static int lttctl_check_trace(const char *name, int expect) |
2727692a | 147 | { |
c928825d | 148 | char tracedirname[PATH_MAX]; |
149 | DIR *dir; | |
150 | int exist; | |
2727692a | 151 | |
c928825d | 152 | if (!name) { |
153 | fprintf(stderr, "%s: args invalid\n", __func__); | |
154 | return -EINVAL; | |
2727692a | 155 | } |
c928825d | 156 | |
157 | if (!debugfsmntdir[0]) { | |
158 | fprintf(stderr, "%s: debugfsmntdir not valid\n", __func__); | |
159 | return -EINVAL; | |
160 | } | |
161 | ||
162 | sprintf(tracedirname, "%s/ltt/control/%s", debugfsmntdir, name); | |
163 | ||
164 | dir = opendir(tracedirname); | |
165 | if (dir) { | |
166 | exist = 1; | |
22acd9c7 | 167 | closedir(dir); |
c928825d | 168 | } else { |
169 | if (errno != ENOENT) { | |
170 | fprintf(stderr, "%s: %s\n", __func__, strerror(errno)); | |
171 | return -EINVAL; | |
172 | } | |
173 | exist = 0; | |
174 | } | |
175 | ||
c928825d | 176 | if (!expect != !exist) { |
177 | if (exist) | |
4015ea80 | 178 | { |
c928825d | 179 | fprintf(stderr, "Trace %s already exist\n", name); |
4015ea80 | 180 | return -EEXIST; |
181 | } | |
c928825d | 182 | else |
4015ea80 | 183 | { |
c928825d | 184 | fprintf(stderr, "Trace %s not exist\n", name); |
4015ea80 | 185 | return -ENOENT; |
186 | } | |
187 | ||
c928825d | 188 | } |
189 | ||
190 | return 0; | |
2727692a | 191 | } |
192 | ||
193 | /* | |
c928825d | 194 | * get channel list of a trace |
195 | * don't include metadata channel when metadata is 0 | |
196 | * | |
197 | * return number of channel on success | |
198 | * return negative number on fail | |
199 | * Caller must free channellist. | |
2727692a | 200 | */ |
c928825d | 201 | static int lttctl_get_channellist(const char *tracename, |
202 | char ***channellist, int metadata) | |
2727692a | 203 | { |
c928825d | 204 | char tracedirname[PATH_MAX]; |
205 | struct dirent *dirent; | |
206 | DIR *dir; | |
207 | char **list = NULL, **old_list; | |
208 | int nr_chan = 0; | |
209 | ||
210 | sprintf(tracedirname, "%s/ltt/control/%s/channel", debugfsmntdir, | |
211 | tracename); | |
212 | ||
213 | dir = opendir(tracedirname); | |
214 | if (!dir) { | |
215 | nr_chan = -ENOENT; | |
216 | goto error; | |
217 | } | |
218 | ||
219 | for (;;) { | |
220 | dirent = readdir(dir); | |
221 | if (!dirent) | |
222 | break; | |
223 | if (!strcmp(dirent->d_name, ".") | |
224 | || !strcmp(dirent->d_name, "..")) | |
225 | continue; | |
226 | if (!metadata && !strcmp(dirent->d_name, "metadata")) | |
227 | continue; | |
228 | old_list = list; | |
229 | list = malloc(sizeof(char *) * ++nr_chan); | |
230 | memcpy(list, old_list, sizeof(*list) * (nr_chan - 1)); | |
231 | free(old_list); | |
232 | list[nr_chan - 1] = strdup(dirent->d_name); | |
233 | } | |
234 | ||
235 | closedir(dir); | |
236 | ||
237 | *channellist = list; | |
238 | return nr_chan; | |
239 | error: | |
240 | free(list); | |
241 | *channellist = NULL; | |
242 | return nr_chan; | |
243 | } | |
244 | ||
4015ea80 | 245 | static void lttctl_free_channellist(char **channellist, int n_channel) |
246 | { | |
247 | int i = 0; | |
248 | for(; i < n_channel; ++i) | |
249 | free(channellist[i]); | |
250 | free(channellist); | |
251 | } | |
252 | ||
c928825d | 253 | int lttctl_setup_trace(const char *name) |
254 | { | |
255 | int ret; | |
256 | char ctlfname[PATH_MAX]; | |
257 | ||
258 | if (!name) { | |
259 | fprintf(stderr, "%s: args invalid\n", __func__); | |
260 | ret = -EINVAL; | |
261 | goto arg_error; | |
262 | } | |
263 | ||
264 | ret = lttctl_check_trace(name, 0); | |
265 | if (ret) | |
266 | goto arg_error; | |
267 | ||
268 | sprintf(ctlfname, "%s/ltt/setup_trace", debugfsmntdir); | |
269 | ||
270 | ret = lttctl_sendop(ctlfname, name); | |
271 | if (ret) { | |
272 | fprintf(stderr, "Setup trace failed\n"); | |
273 | goto op_err; | |
2727692a | 274 | } |
c928825d | 275 | |
2727692a | 276 | return 0; |
c928825d | 277 | |
278 | op_err: | |
279 | arg_error: | |
280 | return ret; | |
2727692a | 281 | } |
282 | ||
c928825d | 283 | int lttctl_destroy_trace(const char *name) |
284 | { | |
285 | int ret; | |
286 | char ctlfname[PATH_MAX]; | |
287 | ||
288 | if (!name) { | |
289 | fprintf(stderr, "%s: args invalid\n", __func__); | |
290 | ret = -EINVAL; | |
291 | goto arg_error; | |
292 | } | |
293 | ||
294 | ret = lttctl_check_trace(name, 1); | |
295 | if (ret) | |
296 | goto arg_error; | |
297 | ||
298 | sprintf(ctlfname, "%s/ltt/destroy_trace", debugfsmntdir); | |
299 | ||
300 | ret = lttctl_sendop(ctlfname, name); | |
301 | if (ret) { | |
302 | fprintf(stderr, "Destroy trace failed\n"); | |
303 | goto op_err; | |
304 | } | |
305 | ||
306 | return 0; | |
307 | ||
308 | op_err: | |
309 | arg_error: | |
310 | return ret; | |
311 | } | |
2727692a | 312 | |
c928825d | 313 | int lttctl_alloc_trace(const char *name) |
2727692a | 314 | { |
c928825d | 315 | int ret; |
316 | char ctlfname[PATH_MAX]; | |
317 | ||
318 | if (!name) { | |
319 | fprintf(stderr, "%s: args invalid\n", __func__); | |
320 | ret = -EINVAL; | |
321 | goto arg_error; | |
322 | } | |
323 | ||
324 | ret = lttctl_check_trace(name, 1); | |
325 | if (ret) | |
326 | goto arg_error; | |
327 | ||
328 | sprintf(ctlfname, "%s/ltt/control/%s/alloc", debugfsmntdir, name); | |
329 | ||
330 | ret = lttctl_sendop(ctlfname, "1"); | |
331 | if (ret) { | |
332 | fprintf(stderr, "Allocate trace failed\n"); | |
333 | goto op_err; | |
334 | } | |
335 | ||
336 | return 0; | |
337 | ||
338 | op_err: | |
339 | arg_error: | |
340 | return ret; | |
341 | } | |
342 | ||
343 | int lttctl_start(const char *name) | |
344 | { | |
345 | int ret; | |
346 | char ctlfname[PATH_MAX]; | |
347 | ||
348 | if (!name) { | |
349 | fprintf(stderr, "%s: args invalid\n", __func__); | |
350 | ret = -EINVAL; | |
351 | goto arg_error; | |
352 | } | |
353 | ||
354 | ret = lttctl_check_trace(name, 1); | |
355 | if (ret) | |
356 | goto arg_error; | |
357 | ||
358 | sprintf(ctlfname, "%s/ltt/control/%s/enabled", debugfsmntdir, name); | |
359 | ||
360 | ret = lttctl_sendop(ctlfname, "1"); | |
361 | if (ret) { | |
362 | fprintf(stderr, "Start trace failed\n"); | |
363 | goto op_err; | |
2727692a | 364 | } |
365 | ||
366 | return 0; | |
367 | ||
c928825d | 368 | op_err: |
369 | arg_error: | |
370 | return ret; | |
2727692a | 371 | } |
372 | ||
c928825d | 373 | int lttctl_pause(const char *name) |
2727692a | 374 | { |
c928825d | 375 | int ret; |
376 | char ctlfname[PATH_MAX]; | |
377 | ||
378 | if (!name) { | |
379 | fprintf(stderr, "%s: args invalid\n", __func__); | |
380 | ret = -EINVAL; | |
381 | goto arg_error; | |
382 | } | |
383 | ||
384 | ret = lttctl_check_trace(name, 1); | |
385 | if (ret) | |
386 | goto arg_error; | |
387 | ||
388 | sprintf(ctlfname, "%s/ltt/control/%s/enabled", debugfsmntdir, name); | |
389 | ||
390 | ret = lttctl_sendop(ctlfname, "0"); | |
391 | if (ret) { | |
392 | fprintf(stderr, "Pause trace failed\n"); | |
393 | goto op_err; | |
2727692a | 394 | } |
395 | ||
396 | return 0; | |
397 | ||
c928825d | 398 | op_err: |
399 | arg_error: | |
400 | return ret; | |
401 | } | |
402 | ||
403 | int lttctl_set_trans(const char *name, const char *trans) | |
404 | { | |
405 | int ret; | |
406 | char ctlfname[PATH_MAX]; | |
407 | ||
408 | if (!name) { | |
409 | fprintf(stderr, "%s: args invalid\n", __func__); | |
410 | ret = -EINVAL; | |
411 | goto arg_error; | |
412 | } | |
413 | ||
414 | ret = lttctl_check_trace(name, 1); | |
415 | if (ret) | |
416 | goto arg_error; | |
417 | ||
418 | sprintf(ctlfname, "%s/ltt/control/%s/trans", debugfsmntdir, name); | |
2727692a | 419 | |
c928825d | 420 | ret = lttctl_sendop(ctlfname, trans); |
421 | if (ret) { | |
422 | fprintf(stderr, "Set transport failed\n"); | |
423 | goto op_err; | |
424 | } | |
425 | ||
426 | return 0; | |
427 | ||
428 | op_err: | |
429 | arg_error: | |
430 | return ret; | |
2727692a | 431 | } |
432 | ||
c928825d | 433 | static int __lttctl_set_channel_enable(const char *name, const char *channel, |
434 | int enable) | |
2727692a | 435 | { |
c928825d | 436 | int ret; |
437 | char ctlfname[PATH_MAX]; | |
2727692a | 438 | |
c928825d | 439 | sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/enable", debugfsmntdir, |
440 | name, channel); | |
2727692a | 441 | |
c928825d | 442 | ret = lttctl_sendop(ctlfname, enable ? "1" : "0"); |
443 | if (ret) | |
444 | fprintf(stderr, "Set channel's enable mode failed\n"); | |
2727692a | 445 | |
c928825d | 446 | return ret; |
447 | } | |
341bb0dd | 448 | |
c928825d | 449 | int lttctl_set_channel_enable(const char *name, const char *channel, |
450 | int enable) | |
451 | { | |
452 | int ret; | |
4015ea80 | 453 | char **channellist; |
454 | int n_channel; | |
2727692a | 455 | |
c928825d | 456 | if (!name || !channel) { |
457 | fprintf(stderr, "%s: args invalid\n", __func__); | |
458 | ret = -EINVAL; | |
459 | goto arg_error; | |
460 | } | |
2727692a | 461 | |
c928825d | 462 | ret = lttctl_check_trace(name, 1); |
463 | if (ret) | |
464 | goto arg_error; | |
465 | ||
466 | if (strcmp(channel, "all")) { | |
467 | ret = __lttctl_set_channel_enable(name, channel, enable); | |
468 | if (ret) | |
469 | goto op_err; | |
470 | } else { | |
c928825d | 471 | /* Don't allow set enable state for metadata channel */ |
472 | n_channel = lttctl_get_channellist(name, &channellist, 0); | |
473 | if (n_channel < 0) { | |
474 | fprintf(stderr, "%s: lttctl_get_channellist failed\n", | |
475 | __func__); | |
476 | ret = -ENOENT; | |
477 | goto op_err; | |
478 | } | |
2727692a | 479 | |
c928825d | 480 | for (; n_channel > 0; n_channel--) { |
481 | ret = __lttctl_set_channel_enable(name, | |
482 | channellist[n_channel - 1], enable); | |
483 | if (ret) | |
4015ea80 | 484 | goto op_err_clean; |
c928825d | 485 | } |
4015ea80 | 486 | lttctl_free_channellist(channellist, n_channel); |
2727692a | 487 | } |
488 | ||
489 | return 0; | |
490 | ||
4015ea80 | 491 | op_err_clean: |
492 | lttctl_free_channellist(channellist, n_channel); | |
c928825d | 493 | op_err: |
494 | arg_error: | |
495 | return ret; | |
496 | } | |
497 | ||
498 | static int __lttctl_set_channel_overwrite(const char *name, const char *channel, | |
499 | int overwrite) | |
500 | { | |
501 | int ret; | |
502 | char ctlfname[PATH_MAX]; | |
503 | ||
504 | sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/overwrite", | |
505 | debugfsmntdir, name, channel); | |
506 | ||
507 | ret = lttctl_sendop(ctlfname, overwrite ? "1" : "0"); | |
508 | if (ret) | |
509 | fprintf(stderr, "Set channel's overwrite mode failed\n"); | |
510 | ||
511 | return ret; | |
512 | } | |
513 | int lttctl_set_channel_overwrite(const char *name, const char *channel, | |
514 | int overwrite) | |
515 | { | |
516 | int ret; | |
4015ea80 | 517 | char **channellist; |
518 | int n_channel; | |
c928825d | 519 | |
520 | if (!name || !channel) { | |
521 | fprintf(stderr, "%s: args invalid\n", __func__); | |
522 | ret = -EINVAL; | |
523 | goto arg_error; | |
524 | } | |
525 | ||
526 | ret = lttctl_check_trace(name, 1); | |
527 | if (ret) | |
528 | goto arg_error; | |
529 | ||
530 | if (strcmp(channel, "all")) { | |
531 | ret = __lttctl_set_channel_overwrite(name, channel, overwrite); | |
532 | if (ret) | |
533 | goto op_err; | |
534 | } else { | |
c928825d | 535 | /* Don't allow set overwrite for metadata channel */ |
536 | n_channel = lttctl_get_channellist(name, &channellist, 0); | |
537 | if (n_channel < 0) { | |
538 | fprintf(stderr, "%s: lttctl_get_channellist failed\n", | |
539 | __func__); | |
540 | ret = -ENOENT; | |
541 | goto op_err; | |
542 | } | |
543 | ||
544 | for (; n_channel > 0; n_channel--) { | |
545 | ret = __lttctl_set_channel_overwrite(name, | |
546 | channellist[n_channel - 1], overwrite); | |
547 | if (ret) | |
4015ea80 | 548 | goto op_err_clean; |
c928825d | 549 | } |
4015ea80 | 550 | lttctl_free_channellist(channellist, n_channel); |
c928825d | 551 | } |
552 | ||
553 | return 0; | |
2727692a | 554 | |
4015ea80 | 555 | op_err_clean: |
556 | lttctl_free_channellist(channellist, n_channel); | |
c928825d | 557 | op_err: |
558 | arg_error: | |
559 | return ret; | |
2727692a | 560 | } |
561 | ||
c928825d | 562 | static int __lttctl_set_channel_subbuf_num(const char *name, |
563 | const char *channel, unsigned subbuf_num) | |
564 | { | |
565 | int ret; | |
566 | char ctlfname[PATH_MAX]; | |
567 | char opstr[32]; | |
568 | ||
569 | sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/subbuf_num", | |
570 | debugfsmntdir, name, channel); | |
571 | ||
572 | sprintf(opstr, "%u", subbuf_num); | |
573 | ||
574 | ret = lttctl_sendop(ctlfname, opstr); | |
575 | if (ret) | |
576 | fprintf(stderr, "Set channel's subbuf number failed\n"); | |
577 | ||
578 | return ret; | |
579 | } | |
580 | int lttctl_set_channel_subbuf_num(const char *name, const char *channel, | |
581 | unsigned subbuf_num) | |
2727692a | 582 | { |
c928825d | 583 | int ret; |
4015ea80 | 584 | char **channellist; |
585 | int n_channel; | |
c928825d | 586 | |
587 | if (!name || !channel) { | |
588 | fprintf(stderr, "%s: args invalid\n", __func__); | |
589 | ret = -EINVAL; | |
590 | goto arg_error; | |
591 | } | |
592 | ||
593 | ret = lttctl_check_trace(name, 1); | |
594 | if (ret) | |
595 | goto arg_error; | |
596 | ||
597 | if (strcmp(channel, "all")) { | |
598 | ret = __lttctl_set_channel_subbuf_num(name, channel, | |
599 | subbuf_num); | |
600 | if (ret) | |
601 | goto op_err; | |
602 | } else { | |
c928825d | 603 | /* allow set subbuf_num for metadata channel */ |
604 | n_channel = lttctl_get_channellist(name, &channellist, 1); | |
605 | if (n_channel < 0) { | |
606 | fprintf(stderr, "%s: lttctl_get_channellist failed\n", | |
607 | __func__); | |
608 | ret = -ENOENT; | |
609 | goto op_err; | |
610 | } | |
611 | ||
612 | for (; n_channel > 0; n_channel--) { | |
613 | ret = __lttctl_set_channel_subbuf_num(name, | |
614 | channellist[n_channel - 1], subbuf_num); | |
615 | if (ret) | |
4015ea80 | 616 | goto op_err_clean; |
c928825d | 617 | } |
4015ea80 | 618 | lttctl_free_channellist(channellist, n_channel); |
2727692a | 619 | } |
620 | ||
621 | return 0; | |
622 | ||
4015ea80 | 623 | op_err_clean: |
624 | lttctl_free_channellist(channellist, n_channel); | |
c928825d | 625 | op_err: |
626 | arg_error: | |
627 | return ret; | |
628 | } | |
629 | ||
630 | static int __lttctl_set_channel_subbuf_size(const char *name, | |
631 | const char *channel, unsigned subbuf_size) | |
632 | { | |
633 | int ret; | |
634 | char ctlfname[PATH_MAX]; | |
635 | char opstr[32]; | |
636 | ||
637 | sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/subbuf_size", | |
638 | debugfsmntdir, name, channel); | |
639 | ||
640 | sprintf(opstr, "%u", subbuf_size); | |
641 | ||
642 | ret = lttctl_sendop(ctlfname, opstr); | |
643 | if (ret) | |
644 | fprintf(stderr, "Set channel's subbuf size failed\n"); | |
341bb0dd | 645 | return ret; |
2727692a | 646 | } |
8d5607b4 | 647 | |
c928825d | 648 | int lttctl_set_channel_subbuf_size(const char *name, const char *channel, |
649 | unsigned subbuf_size) | |
650 | { | |
651 | int ret; | |
4015ea80 | 652 | char **channellist; |
653 | int n_channel; | |
2727692a | 654 | |
c928825d | 655 | if (!name || !channel) { |
656 | fprintf(stderr, "%s: args invalid\n", __func__); | |
657 | ret = -EINVAL; | |
658 | goto arg_error; | |
659 | } | |
660 | ||
661 | ret = lttctl_check_trace(name, 1); | |
662 | if (ret) | |
663 | goto arg_error; | |
664 | ||
665 | if (strcmp(channel, "all")) { | |
666 | ret = __lttctl_set_channel_subbuf_size(name, channel, | |
667 | subbuf_size); | |
668 | if (ret) | |
669 | goto op_err; | |
670 | } else { | |
c928825d | 671 | /* allow set subbuf_size for metadata channel */ |
672 | n_channel = lttctl_get_channellist(name, &channellist, 1); | |
673 | if (n_channel < 0) { | |
674 | fprintf(stderr, "%s: lttctl_get_channellist failed\n", | |
675 | __func__); | |
676 | ret = -ENOENT; | |
677 | goto op_err; | |
678 | } | |
679 | ||
680 | for (; n_channel > 0; n_channel--) { | |
681 | ret = __lttctl_set_channel_subbuf_size(name, | |
682 | channellist[n_channel - 1], subbuf_size); | |
683 | if (ret) | |
4015ea80 | 684 | goto op_err_clean; |
c928825d | 685 | } |
4015ea80 | 686 | lttctl_free_channellist(channellist, n_channel); |
c928825d | 687 | } |
688 | ||
689 | return 0; | |
690 | ||
4015ea80 | 691 | op_err_clean: |
692 | lttctl_free_channellist(channellist, n_channel); | |
c928825d | 693 | op_err: |
694 | arg_error: | |
695 | return ret; | |
696 | } | |
354b34fd | 697 | |
8d5607b4 MD |
698 | static int __lttctl_set_channel_switch_timer(const char *name, |
699 | const char *channel, unsigned switch_timer) | |
700 | { | |
701 | int ret; | |
702 | char ctlfname[PATH_MAX]; | |
703 | char opstr[32]; | |
704 | ||
705 | sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/switch_timer", | |
706 | debugfsmntdir, name, channel); | |
707 | ||
708 | sprintf(opstr, "%u", switch_timer); | |
709 | ||
710 | ret = lttctl_sendop(ctlfname, opstr); | |
711 | if (ret) | |
712 | fprintf(stderr, "Set channel's switch timer failed\n"); | |
341bb0dd | 713 | return ret; |
8d5607b4 MD |
714 | } |
715 | ||
716 | int lttctl_set_channel_switch_timer(const char *name, const char *channel, | |
717 | unsigned switch_timer) | |
718 | { | |
719 | int ret; | |
720 | char **channellist; | |
721 | int n_channel; | |
722 | ||
723 | if (!name || !channel) { | |
724 | fprintf(stderr, "%s: args invalid\n", __func__); | |
725 | ret = -EINVAL; | |
726 | goto arg_error; | |
727 | } | |
728 | ||
729 | ret = lttctl_check_trace(name, 1); | |
730 | if (ret) | |
731 | goto arg_error; | |
732 | ||
733 | if (strcmp(channel, "all")) { | |
734 | ret = __lttctl_set_channel_subbuf_size(name, channel, | |
735 | switch_timer); | |
736 | if (ret) | |
737 | goto op_err; | |
738 | } else { | |
739 | /* allow set subbuf_size for metadata channel */ | |
740 | n_channel = lttctl_get_channellist(name, &channellist, 1); | |
741 | if (n_channel < 0) { | |
742 | fprintf(stderr, "%s: lttctl_get_channellist failed\n", | |
743 | __func__); | |
744 | ret = -ENOENT; | |
745 | goto op_err; | |
746 | } | |
747 | ||
748 | for (; n_channel > 0; n_channel--) { | |
749 | ret = __lttctl_set_channel_switch_timer(name, | |
750 | channellist[n_channel - 1], switch_timer); | |
751 | if (ret) | |
752 | goto op_err_clean; | |
753 | } | |
754 | lttctl_free_channellist(channellist, n_channel); | |
755 | } | |
756 | ||
757 | return 0; | |
758 | ||
759 | op_err_clean: | |
760 | lttctl_free_channellist(channellist, n_channel); | |
761 | op_err: | |
762 | arg_error: | |
763 | return ret; | |
764 | } | |
765 | ||
354b34fd | 766 | int getdebugfsmntdir(char *mntdir) |
767 | { | |
768 | char mnt_dir[PATH_MAX]; | |
769 | char mnt_type[PATH_MAX]; | |
770 | int trymount_done = 0; | |
771 | ||
772 | FILE *fp = fopen("/proc/mounts", "r"); | |
773 | if (!fp) | |
774 | return -EINVAL; | |
775 | ||
776 | find_again: | |
777 | while (1) { | |
778 | if (fscanf(fp, "%*s %s %s %*s %*s %*s", mnt_dir, mnt_type) <= 0) | |
779 | break; | |
780 | ||
781 | if (!strcmp(mnt_type, "debugfs")) { | |
782 | strcpy(mntdir, mnt_dir); | |
783 | return 0; | |
784 | } | |
785 | } | |
786 | ||
787 | if (!trymount_done) { | |
788 | mount("debugfs", "/sys/kernel/debug/", "debugfs", 0, NULL); | |
789 | trymount_done = 1; | |
790 | goto find_again; | |
791 | } | |
792 | ||
793 | return -ENOENT; | |
794 | } |