Update version to 0.16
[ust.git] / libustctl / libustctl.c
1 /* Copyright (C) 2009 Pierre-Marc Fournier, Philippe Proulx-Barrette
2 * Copyright (C) 2011 Ericsson AB
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #define _GNU_SOURCE
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <getopt.h>
23 #include <stdlib.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <dirent.h>
27
28 #include "ustcomm.h"
29 #include "ust/ustctl.h"
30 #include "usterr.h"
31
32 static int do_cmd(int sock,
33 const struct ustcomm_header *req_header,
34 const char *req_data,
35 struct ustcomm_header *res_header,
36 char **res_data)
37 {
38 int result, saved_errno = 0;
39 char *recv_buf;
40
41 recv_buf = zmalloc(USTCOMM_BUFFER_SIZE);
42 if (!recv_buf) {
43 saved_errno = ENOMEM;
44 goto out;
45 }
46
47 result = ustcomm_req(sock, req_header, req_data, res_header, recv_buf);
48 if (result > 0) {
49 saved_errno = -res_header->result;
50 if (res_header->size == 0 || saved_errno > 0) {
51 free(recv_buf);
52 } else {
53 if (res_data) {
54 *res_data = recv_buf;
55 } else {
56 free(recv_buf);
57 }
58 }
59 } else {
60 ERR("ustcomm req failed");
61 if (result == 0) {
62 saved_errno = ENOTCONN;
63 } else {
64 saved_errno = -result;
65 }
66 free(recv_buf);
67 }
68
69 out:
70 errno = saved_errno;
71 if (errno) {
72 return -1;
73 }
74
75 return 0;
76 }
77
78 int ustctl_connect_pid(pid_t pid)
79 {
80 int sock;
81
82 if (ustcomm_connect_app(pid, &sock)) {
83 ERR("could not connect to PID %u", (unsigned int) pid);
84 errno = ENOTCONN;
85 return -1;
86 }
87
88 return sock;
89 }
90
91 static int realloc_pid_list(pid_t **pid_list, unsigned int *pid_list_size)
92 {
93 pid_t *new_pid_list;
94 unsigned int new_pid_list_size = 2 * *pid_list_size;
95
96 new_pid_list = realloc(*pid_list,
97 new_pid_list_size * sizeof(pid_t));
98 if (!*new_pid_list) {
99 return -1;
100 }
101
102 *pid_list = new_pid_list;
103 *pid_list_size = new_pid_list_size;
104
105 return 0;
106 }
107
108 static int get_pids_in_dir(DIR *dir, pid_t **pid_list,
109 unsigned int *pid_list_index,
110 unsigned int *pid_list_size)
111 {
112 struct dirent *dirent;
113 pid_t read_pid;
114
115 while ((dirent = readdir(dir))) {
116 if (!strcmp(dirent->d_name, ".") ||
117 !strcmp(dirent->d_name, "..") ||
118 !strcmp(dirent->d_name, "ust-consumer") ||
119 dirent->d_type == DT_DIR) {
120
121 continue;
122 }
123
124 if (ustcomm_is_socket_live(dirent->d_name, &read_pid)) {
125
126 (*pid_list)[(*pid_list_index)++] = (long) read_pid;
127
128 if (*pid_list_index == *pid_list_size) {
129 if (realloc_pid_list(pid_list, pid_list_size)) {
130 return -1;
131 }
132 }
133 }
134 }
135
136 (*pid_list)[*pid_list_index] = 0; /* Array end */
137
138 return 0;
139 }
140
141 static pid_t *get_pids_non_root(void)
142 {
143 char *dir_name;
144 DIR *dir;
145 unsigned int pid_list_index = 0, pid_list_size = 1;
146 pid_t *pid_list = NULL;
147
148 dir_name = ustcomm_user_sock_dir();
149 if (!dir_name) {
150 return NULL;
151 }
152
153 dir = opendir(dir_name);
154 if (!dir) {
155 goto free_dir_name;
156 }
157
158 pid_list = malloc(pid_list_size * sizeof(pid_t));
159 if (!pid_list) {
160 goto close_dir;
161 }
162
163 if (get_pids_in_dir(dir, &pid_list, &pid_list_index, &pid_list_size)) {
164 /* if any errors are encountered, force freeing of the list */
165 pid_list[0] = 0;
166 }
167
168 close_dir:
169 closedir(dir);
170
171 free_dir_name:
172 free(dir_name);
173
174 return pid_list;
175 }
176
177 static pid_t *get_pids_root(void)
178 {
179 char *dir_name;
180 DIR *tmp_dir, *dir;
181 unsigned int pid_list_index = 0, pid_list_size = 1;
182 pid_t *pid_list = NULL;
183 struct dirent *dirent;
184 int result;
185
186 tmp_dir = opendir(USER_TMP_DIR);
187 if (!tmp_dir) {
188 return NULL;
189 }
190
191 pid_list = malloc(pid_list_size * sizeof(pid_t));
192 if (!pid_list) {
193 goto close_tmp_dir;
194 }
195
196 while ((dirent = readdir(tmp_dir))) {
197 /* Compare the dir to check for the USER_SOCK_DIR_BASE prefix */
198 if (!strncmp(dirent->d_name, USER_SOCK_DIR_BASE,
199 strlen(USER_SOCK_DIR_BASE))) {
200
201 if (asprintf(&dir_name, USER_TMP_DIR "/%s",
202 dirent->d_name) < 0) {
203 goto close_tmp_dir;
204 }
205
206 dir = opendir(dir_name);
207
208 free(dir_name);
209
210 if (!dir) {
211 continue;
212 }
213
214 result = get_pids_in_dir(dir, &pid_list, &pid_list_index,
215 &pid_list_size);
216
217 closedir(dir);
218
219 if (result) {
220 /*
221 * if any errors are encountered,
222 * force freeing of the list
223 */
224 pid_list[0] = 0;
225 break;
226 }
227 }
228 }
229
230 close_tmp_dir:
231 closedir(tmp_dir);
232
233 return pid_list;
234 }
235
236 pid_t *ustctl_get_online_pids(void)
237 {
238 pid_t *pid_list;
239
240 if (geteuid()) {
241 pid_list = get_pids_non_root();
242 } else {
243 pid_list = get_pids_root();
244 }
245
246 if (pid_list && pid_list[0] == 0) {
247 /* No PID at all */
248 free(pid_list);
249 pid_list = NULL;
250 }
251
252 return pid_list;
253 }
254
255 /**
256 * Sets ust_marker state (USTCTL_MS_ON or USTCTL_MS_OFF).
257 *
258 * @param mn Marker name
259 * @param state Marker's new state
260 * @param pid Traced process ID
261 * @return 0 if successful, or errors {USTCTL_ERR_GEN, USTCTL_ERR_ARG}
262 */
263 int ustctl_set_ust_marker_state(int sock, const char *trace, const char *channel,
264 const char *ust_marker, int state)
265 {
266 struct ustcomm_header req_header, res_header;
267 struct ustcomm_ust_marker_info ust_marker_inf;
268 int result;
269
270 result = ustcomm_pack_ust_marker_info(&req_header,
271 &ust_marker_inf,
272 trace,
273 channel,
274 ust_marker);
275 if (result < 0) {
276 errno = -result;
277 return -1;
278 }
279
280 req_header.command = state ? ENABLE_MARKER : DISABLE_MARKER;
281
282 return do_cmd(sock, &req_header, (char *)&ust_marker_inf,
283 &res_header, NULL);
284 }
285
286 /**
287 * Set subbuffer size.
288 *
289 * @param channel_size Channel name and size
290 * @param pid Traced process ID
291 * @return 0 if successful, or error
292 */
293 int ustctl_set_subbuf_size(int sock, const char *trace, const char *channel,
294 unsigned int subbuf_size)
295 {
296 struct ustcomm_header req_header, res_header;
297 struct ustcomm_channel_info ch_inf;
298 int result;
299
300 result = ustcomm_pack_channel_info(&req_header,
301 &ch_inf,
302 trace,
303 channel);
304 if (result < 0) {
305 errno = -result;
306 return -1;
307 }
308
309 req_header.command = SET_SUBBUF_SIZE;
310 ch_inf.subbuf_size = subbuf_size;
311
312 return do_cmd(sock, &req_header, (char *)&ch_inf,
313 &res_header, NULL);
314 }
315
316 /**
317 * Set subbuffer num.
318 *
319 * @param channel_num Channel name and num
320 * @param pid Traced process ID
321 * @return 0 if successful, or error
322 */
323 int ustctl_set_subbuf_num(int sock, const char *trace, const char *channel,
324 unsigned int num)
325 {
326 struct ustcomm_header req_header, res_header;
327 struct ustcomm_channel_info ch_inf;
328 int result;
329
330 result = ustcomm_pack_channel_info(&req_header,
331 &ch_inf,
332 trace,
333 channel);
334 if (result < 0) {
335 errno = -result;
336 return -1;
337 }
338
339 req_header.command = SET_SUBBUF_NUM;
340 ch_inf.subbuf_num = num;
341
342 return do_cmd(sock, &req_header, (char *)&ch_inf,
343 &res_header, NULL);
344
345 }
346
347
348 static int ustctl_get_subbuf_num_size(int sock, const char *trace, const char *channel,
349 int *num, int *size)
350 {
351 struct ustcomm_header req_header, res_header;
352 struct ustcomm_channel_info ch_inf, *ch_inf_res;
353 int result;
354
355
356 result = ustcomm_pack_channel_info(&req_header,
357 &ch_inf,
358 trace,
359 channel);
360 if (result < 0) {
361 errno = -result;
362 return -1;
363 }
364
365 req_header.command = GET_SUBBUF_NUM_SIZE;
366
367 result = do_cmd(sock, &req_header, (char *)&ch_inf,
368 &res_header, (char **)&ch_inf_res);
369 if (result < 0) {
370 return -1;
371 }
372
373 *num = ch_inf_res->subbuf_num;
374 *size = ch_inf_res->subbuf_size;
375
376 free(ch_inf_res);
377
378 return 0;
379 }
380
381 /**
382 * Get subbuffer num.
383 *
384 * @param channel Channel name
385 * @param pid Traced process ID
386 * @return subbuf cnf if successful, or error
387 */
388 int ustctl_get_subbuf_num(int sock, const char *trace, const char *channel)
389 {
390 int num, size, result;
391
392 result = ustctl_get_subbuf_num_size(sock, trace, channel,
393 &num, &size);
394 if (result < 0) {
395 errno = -result;
396 return -1;
397 }
398
399 return num;
400 }
401
402 /**
403 * Get subbuffer size.
404 *
405 * @param channel Channel name
406 * @param pid Traced process ID
407 * @return subbuf size if successful, or error
408 */
409 int ustctl_get_subbuf_size(int sock, const char *trace, const char *channel)
410 {
411 int num, size, result;
412
413 result = ustctl_get_subbuf_num_size(sock, trace, channel,
414 &num, &size);
415 if (result < 0) {
416 errno = -result;
417 return -1;
418 }
419
420 return size;
421 }
422
423 static int do_trace_cmd(int sock, const char *trace, int command)
424 {
425 struct ustcomm_header req_header, res_header;
426 struct ustcomm_single_field trace_inf;
427 int result;
428
429 result = ustcomm_pack_single_field(&req_header,
430 &trace_inf,
431 trace);
432 if (result < 0) {
433 errno = -result;
434 return -1;
435 }
436
437 req_header.command = command;
438
439 return do_cmd(sock, &req_header, (char *)&trace_inf, &res_header, NULL);
440 }
441
442 /**
443 * Destroys an UST trace according to a PID.
444 *
445 * @param pid Traced process ID
446 * @return 0 if successful, or error USTCTL_ERR_GEN
447 */
448 int ustctl_destroy_trace(int sock, const char *trace)
449 {
450 return do_trace_cmd(sock, trace, DESTROY_TRACE);
451 }
452
453 /**
454 * Starts an UST trace (and setups it) according to a PID.
455 *
456 * @param pid Traced process ID
457 * @return 0 if successful, or error USTCTL_ERR_GEN
458 */
459 int ustctl_setup_and_start(int sock, const char *trace)
460 {
461 return do_trace_cmd(sock, trace, START);
462 }
463
464 /**
465 * Creates an UST trace according to a PID.
466 *
467 * @param pid Traced process ID
468 * @return 0 if successful, or error USTCTL_ERR_GEN
469 */
470 int ustctl_create_trace(int sock, const char *trace)
471 {
472 return do_trace_cmd(sock, trace, CREATE_TRACE);
473 }
474
475 /**
476 * Starts an UST trace according to a PID.
477 *
478 * @param pid Traced process ID
479 * @return 0 if successful, or error USTCTL_ERR_GEN
480 */
481 int ustctl_start_trace(int sock, const char *trace)
482 {
483 return do_trace_cmd(sock, trace, START_TRACE);
484 }
485
486 /**
487 * Alloc an UST trace according to a PID.
488 *
489 * @param pid Traced process ID
490 * @return 0 if successful, or error USTCTL_ERR_GEN
491 */
492 int ustctl_alloc_trace(int sock, const char *trace)
493 {
494 return do_trace_cmd(sock, trace, ALLOC_TRACE);
495 }
496
497
498 int ustctl_force_switch(int sock, const char *trace)
499 {
500 return do_trace_cmd(sock, trace, FORCE_SUBBUF_SWITCH);
501 }
502
503 /**
504 * Stops an UST trace according to a PID.
505 *
506 * @param pid Traced process ID
507 * @return 0 if successful, or error USTCTL_ERR_GEN
508 */
509 int ustctl_stop_trace(int sock, const char *trace)
510 {
511 return do_trace_cmd(sock, trace, STOP_TRACE);
512 }
513
514 /**
515 * Counts newlines ('\n') in a string.
516 *
517 * @param str String to search in
518 * @return Total newlines count
519 */
520 unsigned int ustctl_count_nl(const char *str)
521 {
522 unsigned int i = 0, tot = 0;
523
524 while (str[i] != '\0') {
525 if (str[i] == '\n') {
526 ++tot;
527 }
528 ++i;
529 }
530
531 return tot;
532 }
533
534 /**
535 * Frees a CMSF array.
536 *
537 * @param cmsf CMSF array to free
538 * @return 0 if successful, or error USTCTL_ERR_ARG
539 */
540 int ustctl_free_cmsf(struct ust_marker_status *cmsf)
541 {
542 if (cmsf == NULL) {
543 return USTCTL_ERR_ARG;
544 }
545
546 unsigned int i = 0;
547 while (cmsf[i].channel != NULL) {
548 free(cmsf[i].channel);
549 free(cmsf[i].ust_marker);
550 free(cmsf[i].fs);
551 ++i;
552 }
553 free(cmsf);
554
555 return 0;
556 }
557
558 /**
559 * Gets channel/ust_marker/state/format string for a given PID.
560 *
561 * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller
562 * frees with `ustctl_free_cmsf')
563 * @param pid Targeted PID
564 * @return 0 if successful, or -1 on error
565 */
566 int ustctl_get_cmsf(int sock, struct ust_marker_status **cmsf)
567 {
568 struct ustcomm_header req_header, res_header;
569 char *big_str = NULL;
570 int result;
571 struct ust_marker_status *tmp_cmsf = NULL;
572 unsigned int i = 0, cmsf_ind = 0;
573
574 if (cmsf == NULL) {
575 return -1;
576 }
577
578 req_header.command = LIST_MARKERS;
579 req_header.size = 0;
580
581 result = ustcomm_send(sock, &req_header, NULL);
582 if (result <= 0) {
583 PERROR("error while requesting ust_marker list");
584 return -1;
585 }
586
587 result = ustcomm_recv_alloc(sock, &res_header, &big_str);
588 if (result <= 0) {
589 ERR("error while receiving ust_marker list");
590 return -1;
591 }
592
593 tmp_cmsf = (struct ust_marker_status *) zmalloc(sizeof(struct ust_marker_status) *
594 (ustctl_count_nl(big_str) + 1));
595 if (tmp_cmsf == NULL) {
596 ERR("Failed to allocate CMSF array");
597 return -1;
598 }
599
600 /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */
601 while (big_str[i] != '\0') {
602 char state;
603
604 sscanf(big_str + i, "ust_marker: %a[^/]/%a[^ ] %c %a[^\n]",
605 &tmp_cmsf[cmsf_ind].channel,
606 &tmp_cmsf[cmsf_ind].ust_marker,
607 &state,
608 &tmp_cmsf[cmsf_ind].fs);
609 tmp_cmsf[cmsf_ind].state = (state == USTCTL_MS_CHR_ON ?
610 USTCTL_MS_ON : USTCTL_MS_OFF); /* Marker state */
611
612 while (big_str[i] != '\n') {
613 ++i; /* Go to next '\n' */
614 }
615 ++i; /* Skip current pointed '\n' */
616 ++cmsf_ind;
617 }
618 tmp_cmsf[cmsf_ind].channel = NULL;
619 tmp_cmsf[cmsf_ind].ust_marker = NULL;
620 tmp_cmsf[cmsf_ind].fs = NULL;
621
622 *cmsf = tmp_cmsf;
623
624 free(big_str);
625 return 0;
626 }
627
628 /**
629 * Frees a TES array.
630 *
631 * @param tes TES array to free
632 * @return 0 if successful, or error USTCTL_ERR_ARG
633 */
634 int ustctl_free_tes(struct trace_event_status *tes)
635 {
636 if (tes == NULL) {
637 return USTCTL_ERR_ARG;
638 }
639
640 unsigned int i = 0;
641 while (tes[i].name != NULL) {
642 free(tes[i].name);
643 ++i;
644 }
645 free(tes);
646
647 return 0;
648 }
649
650 /**
651 * Gets trace_events string for a given PID.
652 *
653 * @param tes Pointer to TES array to be filled (callee allocates, caller
654 * frees with `ustctl_free_tes')
655 * @param pid Targeted PID
656 * @return 0 if successful, or -1 on error
657 */
658 int ustctl_get_tes(int sock, struct trace_event_status **tes)
659 {
660 struct ustcomm_header req_header, res_header;
661 char *big_str = NULL;
662 int result;
663 struct trace_event_status *tmp_tes = NULL;
664 unsigned int i = 0, tes_ind = 0;
665
666 if (tes == NULL) {
667 return -1;
668 }
669
670 req_header.command = LIST_TRACE_EVENTS;
671 req_header.size = 0;
672
673 result = ustcomm_send(sock, &req_header, NULL);
674 if (result != 1) {
675 ERR("error while requesting trace_event list");
676 return -1;
677 }
678
679 result = ustcomm_recv_alloc(sock, &res_header, &big_str);
680 if (result != 1) {
681 ERR("error while receiving ust_marker list");
682 return -1;
683 }
684
685 tmp_tes = (struct trace_event_status *)
686 zmalloc(sizeof(struct trace_event_status) *
687 (ustctl_count_nl(big_str) + 1));
688 if (tmp_tes == NULL) {
689 ERR("Failed to allocate TES array");
690 return -1;
691 }
692
693 /* Parse received reply string (format: "[name]"): */
694 while (big_str[i] != '\0') {
695 sscanf(big_str + i, "trace_event: %a[^\n]",
696 &tmp_tes[tes_ind].name);
697 while (big_str[i] != '\n') {
698 ++i; /* Go to next '\n' */
699 }
700 ++i; /* Skip current pointed '\n' */
701 ++tes_ind;
702 }
703 tmp_tes[tes_ind].name = NULL;
704
705 *tes = tmp_tes;
706
707 free(big_str);
708 return 0;
709 }
710
711 /**
712 * Set sock path
713 *
714 * @param sock_path Sock path
715 * @param pid Traced process ID
716 * @return 0 if successful, or error
717 */
718 int ustctl_set_sock_path(int sock, const char *sock_path)
719 {
720 int result;
721 struct ustcomm_header req_header, res_header;
722 struct ustcomm_single_field sock_path_msg;
723
724 result = ustcomm_pack_single_field(&req_header,
725 &sock_path_msg,
726 sock_path);
727 if (result < 0) {
728 errno = -result;
729 return -1;
730 }
731
732 req_header.command = SET_SOCK_PATH;
733
734 return do_cmd(sock, &req_header, (char *)&sock_path_msg,
735 &res_header, NULL);
736 }
737
738 /**
739 * Get sock path
740 *
741 * @param sock_path Pointer to where the sock path will be returned
742 * @param pid Traced process ID
743 * @return 0 if successful, or error
744 */
745 int ustctl_get_sock_path(int sock, char **sock_path)
746 {
747 int result;
748 struct ustcomm_header req_header, res_header;
749 struct ustcomm_single_field *sock_path_msg;
750
751 req_header.command = GET_SOCK_PATH;
752 req_header.size = 0;
753
754 result = do_cmd(sock, &req_header, NULL, &res_header,
755 (char **)&sock_path_msg);
756 if (result < 0) {
757 return -1;
758 }
759
760 result = ustcomm_unpack_single_field(sock_path_msg);
761 if (result < 0) {
762 return result;
763 }
764
765 *sock_path = strdup(sock_path_msg->field);
766
767 free(sock_path_msg);
768
769 return 0;
770 }
This page took 0.042926 seconds and 4 git commands to generate.