1 /* Copyright (C) 2009 Pierre-Marc Fournier, Philippe Proulx-Barrette
2 * Copyright (C) 2011 Ericsson AB
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.
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.
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
29 #include "ust/ustctl.h"
32 static int do_cmd(int sock
,
33 const struct ustcomm_header
*req_header
,
35 struct ustcomm_header
*res_header
,
38 int result
, saved_errno
= 0;
41 recv_buf
= zmalloc(USTCOMM_BUFFER_SIZE
);
47 result
= ustcomm_req(sock
, req_header
, req_data
, res_header
, recv_buf
);
49 saved_errno
= -res_header
->result
;
50 if (res_header
->size
== 0 || saved_errno
> 0) {
60 ERR("ustcomm req failed");
62 saved_errno
= ENOTCONN
;
64 saved_errno
= -result
;
78 int ustctl_connect_pid(pid_t pid
)
82 if (ustcomm_connect_app(pid
, &sock
)) {
83 ERR("could not connect to PID %u", (unsigned int) pid
);
91 static void get_pids_in_dir(DIR *dir
, pid_t
**pid_list
,
92 unsigned int *pid_list_size
)
94 struct dirent
*dirent
;
95 unsigned int read_pid
;
97 while ((dirent
= readdir(dir
))) {
98 if (!strcmp(dirent
->d_name
, ".") ||
99 !strcmp(dirent
->d_name
, "..") ||
100 !strcmp(dirent
->d_name
, "ust-consumer") ||
101 dirent
->d_type
== DT_DIR
) {
106 sscanf(dirent
->d_name
, "%u", &read_pid
);
108 (*pid_list
)[*pid_list_size
- 1] = read_pid
;
109 /* FIXME: Here we previously called pid_is_online, which
110 * always returned 1, now I replaced it with just 1.
111 * We need to figure out an intelligent way of solving
112 * this, maybe connect-disconnect.
116 *pid_list
= realloc(*pid_list
,
117 *pid_list_size
* sizeof(pid_t
));
121 (*pid_list
)[*pid_list_size
- 1] = 0; /* Array end */
124 static pid_t
*get_pids_non_root(void)
128 unsigned int pid_list_size
= 1;
129 pid_t
*pid_list
= NULL
;
131 dir_name
= ustcomm_user_sock_dir();
136 dir
= opendir(dir_name
);
141 pid_list
= malloc(pid_list_size
* sizeof(pid_t
));
146 get_pids_in_dir(dir
, &pid_list
, &pid_list_size
);
148 if (pid_list
[0] == 0) {
164 static pid_t
*get_pids_root(void)
168 unsigned int pid_list_size
= 1;
169 pid_t
*pid_list
= NULL
;
170 struct dirent
*dirent
;
172 tmp_dir
= opendir(USER_TMP_DIR
);
177 pid_list
= malloc(pid_list_size
* sizeof(pid_t
));
182 while ((dirent
= readdir(tmp_dir
))) {
183 /* Compare the dir to check for the USER_SOCK_DIR_BASE prefix */
184 if (!strncmp(dirent
->d_name
, USER_SOCK_DIR_BASE
,
185 strlen(USER_SOCK_DIR_BASE
))) {
187 if (asprintf(&dir_name
, USER_TMP_DIR
"/%s", dirent
->d_name
) < 0) {
191 dir
= opendir(dir_name
);
199 get_pids_in_dir(dir
, &pid_list
, &pid_list_size
);
211 pid_t
*ustctl_get_online_pids(void)
214 return get_pids_non_root();
216 return get_pids_root();
221 * Sets marker state (USTCTL_MS_ON or USTCTL_MS_OFF).
223 * @param mn Marker name
224 * @param state Marker's new state
225 * @param pid Traced process ID
226 * @return 0 if successful, or errors {USTCTL_ERR_GEN, USTCTL_ERR_ARG}
228 int ustctl_set_marker_state(int sock
, const char *trace
, const char *channel
,
229 const char *marker
, int state
)
231 struct ustcomm_header req_header
, res_header
;
232 struct ustcomm_marker_info marker_inf
;
235 result
= ustcomm_pack_marker_info(&req_header
,
245 req_header
.command
= state
? ENABLE_MARKER
: DISABLE_MARKER
;
247 return do_cmd(sock
, &req_header
, (char *)&marker_inf
,
252 * Set subbuffer size.
254 * @param channel_size Channel name and size
255 * @param pid Traced process ID
256 * @return 0 if successful, or error
258 int ustctl_set_subbuf_size(int sock
, const char *trace
, const char *channel
,
259 unsigned int subbuf_size
)
261 struct ustcomm_header req_header
, res_header
;
262 struct ustcomm_channel_info ch_inf
;
265 result
= ustcomm_pack_channel_info(&req_header
,
274 req_header
.command
= SET_SUBBUF_SIZE
;
275 ch_inf
.subbuf_size
= subbuf_size
;
277 return do_cmd(sock
, &req_header
, (char *)&ch_inf
,
284 * @param channel_num Channel name and num
285 * @param pid Traced process ID
286 * @return 0 if successful, or error
288 int ustctl_set_subbuf_num(int sock
, const char *trace
, const char *channel
,
291 struct ustcomm_header req_header
, res_header
;
292 struct ustcomm_channel_info ch_inf
;
295 result
= ustcomm_pack_channel_info(&req_header
,
304 req_header
.command
= SET_SUBBUF_NUM
;
305 ch_inf
.subbuf_num
= num
;
307 return do_cmd(sock
, &req_header
, (char *)&ch_inf
,
313 static int ustctl_get_subbuf_num_size(int sock
, const char *trace
, const char *channel
,
316 struct ustcomm_header req_header
, res_header
;
317 struct ustcomm_channel_info ch_inf
, *ch_inf_res
;
321 result
= ustcomm_pack_channel_info(&req_header
,
330 req_header
.command
= GET_SUBBUF_NUM_SIZE
;
332 result
= do_cmd(sock
, &req_header
, (char *)&ch_inf
,
333 &res_header
, (char **)&ch_inf_res
);
338 *num
= ch_inf_res
->subbuf_num
;
339 *size
= ch_inf_res
->subbuf_size
;
349 * @param channel Channel name
350 * @param pid Traced process ID
351 * @return subbuf cnf if successful, or error
353 int ustctl_get_subbuf_num(int sock
, const char *trace
, const char *channel
)
355 int num
, size
, result
;
357 result
= ustctl_get_subbuf_num_size(sock
, trace
, channel
,
368 * Get subbuffer size.
370 * @param channel Channel name
371 * @param pid Traced process ID
372 * @return subbuf size if successful, or error
374 int ustctl_get_subbuf_size(int sock
, const char *trace
, const char *channel
)
376 int num
, size
, result
;
378 result
= ustctl_get_subbuf_num_size(sock
, trace
, channel
,
388 static int do_trace_cmd(int sock
, const char *trace
, int command
)
390 struct ustcomm_header req_header
, res_header
;
391 struct ustcomm_single_field trace_inf
;
394 result
= ustcomm_pack_single_field(&req_header
,
402 req_header
.command
= command
;
404 return do_cmd(sock
, &req_header
, (char *)&trace_inf
, &res_header
, NULL
);
408 * Destroys an UST trace according to a PID.
410 * @param pid Traced process ID
411 * @return 0 if successful, or error USTCTL_ERR_GEN
413 int ustctl_destroy_trace(int sock
, const char *trace
)
415 return do_trace_cmd(sock
, trace
, DESTROY_TRACE
);
419 * Starts an UST trace (and setups it) according to a PID.
421 * @param pid Traced process ID
422 * @return 0 if successful, or error USTCTL_ERR_GEN
424 int ustctl_setup_and_start(int sock
, const char *trace
)
426 return do_trace_cmd(sock
, trace
, START
);
430 * Creates an UST trace according to a PID.
432 * @param pid Traced process ID
433 * @return 0 if successful, or error USTCTL_ERR_GEN
435 int ustctl_create_trace(int sock
, const char *trace
)
437 return do_trace_cmd(sock
, trace
, CREATE_TRACE
);
441 * Starts an UST trace according to a PID.
443 * @param pid Traced process ID
444 * @return 0 if successful, or error USTCTL_ERR_GEN
446 int ustctl_start_trace(int sock
, const char *trace
)
448 return do_trace_cmd(sock
, trace
, START_TRACE
);
452 * Alloc an UST trace according to a PID.
454 * @param pid Traced process ID
455 * @return 0 if successful, or error USTCTL_ERR_GEN
457 int ustctl_alloc_trace(int sock
, const char *trace
)
459 return do_trace_cmd(sock
, trace
, ALLOC_TRACE
);
463 int ustctl_force_switch(int sock
, const char *trace
)
465 return do_trace_cmd(sock
, trace
, FORCE_SUBBUF_SWITCH
);
469 * Stops an UST trace according to a PID.
471 * @param pid Traced process ID
472 * @return 0 if successful, or error USTCTL_ERR_GEN
474 int ustctl_stop_trace(int sock
, const char *trace
)
476 return do_trace_cmd(sock
, trace
, STOP_TRACE
);
480 * Counts newlines ('\n') in a string.
482 * @param str String to search in
483 * @return Total newlines count
485 unsigned int ustctl_count_nl(const char *str
)
487 unsigned int i
= 0, tot
= 0;
489 while (str
[i
] != '\0') {
490 if (str
[i
] == '\n') {
500 * Frees a CMSF array.
502 * @param cmsf CMSF array to free
503 * @return 0 if successful, or error USTCTL_ERR_ARG
505 int ustctl_free_cmsf(struct marker_status
*cmsf
)
508 return USTCTL_ERR_ARG
;
512 while (cmsf
[i
].channel
!= NULL
) {
513 free(cmsf
[i
].channel
);
514 free(cmsf
[i
].marker
);
524 * Gets channel/marker/state/format string for a given PID.
526 * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller
527 * frees with `ustctl_free_cmsf')
528 * @param pid Targeted PID
529 * @return 0 if successful, or -1 on error
531 int ustctl_get_cmsf(int sock
, struct marker_status
**cmsf
)
533 struct ustcomm_header req_header
, res_header
;
534 char *big_str
= NULL
;
536 struct marker_status
*tmp_cmsf
= NULL
;
537 unsigned int i
= 0, cmsf_ind
= 0;
543 req_header
.command
= LIST_MARKERS
;
546 result
= ustcomm_send(sock
, &req_header
, NULL
);
548 PERROR("error while requesting markers list");
552 result
= ustcomm_recv_alloc(sock
, &res_header
, &big_str
);
554 ERR("error while receiving markers list");
558 tmp_cmsf
= (struct marker_status
*) zmalloc(sizeof(struct marker_status
) *
559 (ustctl_count_nl(big_str
) + 1));
560 if (tmp_cmsf
== NULL
) {
561 ERR("Failed to allocate CMSF array");
565 /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */
566 while (big_str
[i
] != '\0') {
569 sscanf(big_str
+ i
, "marker: %a[^/]/%a[^ ] %c %a[^\n]",
570 &tmp_cmsf
[cmsf_ind
].channel
,
571 &tmp_cmsf
[cmsf_ind
].marker
,
573 &tmp_cmsf
[cmsf_ind
].fs
);
574 tmp_cmsf
[cmsf_ind
].state
= (state
== USTCTL_MS_CHR_ON
?
575 USTCTL_MS_ON
: USTCTL_MS_OFF
); /* Marker state */
577 while (big_str
[i
] != '\n') {
578 ++i
; /* Go to next '\n' */
580 ++i
; /* Skip current pointed '\n' */
583 tmp_cmsf
[cmsf_ind
].channel
= NULL
;
584 tmp_cmsf
[cmsf_ind
].marker
= NULL
;
585 tmp_cmsf
[cmsf_ind
].fs
= NULL
;
596 * @param tes TES array to free
597 * @return 0 if successful, or error USTCTL_ERR_ARG
599 int ustctl_free_tes(struct trace_event_status
*tes
)
602 return USTCTL_ERR_ARG
;
606 while (tes
[i
].name
!= NULL
) {
616 * Gets trace_events string for a given PID.
618 * @param tes Pointer to TES array to be filled (callee allocates, caller
619 * frees with `ustctl_free_tes')
620 * @param pid Targeted PID
621 * @return 0 if successful, or -1 on error
623 int ustctl_get_tes(int sock
, struct trace_event_status
**tes
)
625 struct ustcomm_header req_header
, res_header
;
626 char *big_str
= NULL
;
628 struct trace_event_status
*tmp_tes
= NULL
;
629 unsigned int i
= 0, tes_ind
= 0;
635 req_header
.command
= LIST_TRACE_EVENTS
;
638 result
= ustcomm_send(sock
, &req_header
, NULL
);
640 ERR("error while requesting trace_event list");
644 result
= ustcomm_recv_alloc(sock
, &res_header
, &big_str
);
646 ERR("error while receiving markers list");
650 tmp_tes
= (struct trace_event_status
*)
651 zmalloc(sizeof(struct trace_event_status
) *
652 (ustctl_count_nl(big_str
) + 1));
653 if (tmp_tes
== NULL
) {
654 ERR("Failed to allocate TES array");
658 /* Parse received reply string (format: "[name]"): */
659 while (big_str
[i
] != '\0') {
660 sscanf(big_str
+ i
, "trace_event: %a[^\n]",
661 &tmp_tes
[tes_ind
].name
);
662 while (big_str
[i
] != '\n') {
663 ++i
; /* Go to next '\n' */
665 ++i
; /* Skip current pointed '\n' */
668 tmp_tes
[tes_ind
].name
= NULL
;
679 * @param sock_path Sock path
680 * @param pid Traced process ID
681 * @return 0 if successful, or error
683 int ustctl_set_sock_path(int sock
, const char *sock_path
)
686 struct ustcomm_header req_header
, res_header
;
687 struct ustcomm_single_field sock_path_msg
;
689 result
= ustcomm_pack_single_field(&req_header
,
697 req_header
.command
= SET_SOCK_PATH
;
699 return do_cmd(sock
, &req_header
, (char *)&sock_path_msg
,
706 * @param sock_path Pointer to where the sock path will be returned
707 * @param pid Traced process ID
708 * @return 0 if successful, or error
710 int ustctl_get_sock_path(int sock
, char **sock_path
)
713 struct ustcomm_header req_header
, res_header
;
714 struct ustcomm_single_field
*sock_path_msg
;
716 req_header
.command
= GET_SOCK_PATH
;
719 result
= do_cmd(sock
, &req_header
, NULL
, &res_header
,
720 (char **)&sock_path_msg
);
725 result
= ustcomm_unpack_single_field(sock_path_msg
);
730 *sock_path
= strdup(sock_path_msg
->field
);