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 pid_t
*ustctl_get_online_pids(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
));
143 get_pids_in_dir(dir
, &pid_list
, &pid_list_size
);
145 if (pid_list
[0] == 0) {
162 * Sets marker state (USTCTL_MS_ON or USTCTL_MS_OFF).
164 * @param mn Marker name
165 * @param state Marker's new state
166 * @param pid Traced process ID
167 * @return 0 if successful, or errors {USTCTL_ERR_GEN, USTCTL_ERR_ARG}
169 int ustctl_set_marker_state(int sock
, const char *trace
, const char *channel
,
170 const char *marker
, int state
)
172 struct ustcomm_header req_header
, res_header
;
173 struct ustcomm_marker_info marker_inf
;
176 result
= ustcomm_pack_marker_info(&req_header
,
186 req_header
.command
= state
? ENABLE_MARKER
: DISABLE_MARKER
;
188 return do_cmd(sock
, &req_header
, (char *)&marker_inf
,
193 * Set subbuffer size.
195 * @param channel_size Channel name and size
196 * @param pid Traced process ID
197 * @return 0 if successful, or error
199 int ustctl_set_subbuf_size(int sock
, const char *trace
, const char *channel
,
200 unsigned int subbuf_size
)
202 struct ustcomm_header req_header
, res_header
;
203 struct ustcomm_channel_info ch_inf
;
206 result
= ustcomm_pack_channel_info(&req_header
,
215 req_header
.command
= SET_SUBBUF_SIZE
;
216 ch_inf
.subbuf_size
= subbuf_size
;
218 return do_cmd(sock
, &req_header
, (char *)&ch_inf
,
225 * @param channel_num Channel name and num
226 * @param pid Traced process ID
227 * @return 0 if successful, or error
229 int ustctl_set_subbuf_num(int sock
, const char *trace
, const char *channel
,
232 struct ustcomm_header req_header
, res_header
;
233 struct ustcomm_channel_info ch_inf
;
236 result
= ustcomm_pack_channel_info(&req_header
,
245 req_header
.command
= SET_SUBBUF_NUM
;
246 ch_inf
.subbuf_num
= num
;
248 return do_cmd(sock
, &req_header
, (char *)&ch_inf
,
254 static int ustctl_get_subbuf_num_size(int sock
, const char *trace
, const char *channel
,
257 struct ustcomm_header req_header
, res_header
;
258 struct ustcomm_channel_info ch_inf
, *ch_inf_res
;
262 result
= ustcomm_pack_channel_info(&req_header
,
271 req_header
.command
= GET_SUBBUF_NUM_SIZE
;
273 result
= do_cmd(sock
, &req_header
, (char *)&ch_inf
,
274 &res_header
, (char **)&ch_inf_res
);
279 *num
= ch_inf_res
->subbuf_num
;
280 *size
= ch_inf_res
->subbuf_size
;
290 * @param channel Channel name
291 * @param pid Traced process ID
292 * @return subbuf cnf if successful, or error
294 int ustctl_get_subbuf_num(int sock
, const char *trace
, const char *channel
)
296 int num
, size
, result
;
298 result
= ustctl_get_subbuf_num_size(sock
, trace
, channel
,
309 * Get subbuffer size.
311 * @param channel Channel name
312 * @param pid Traced process ID
313 * @return subbuf size if successful, or error
315 int ustctl_get_subbuf_size(int sock
, const char *trace
, const char *channel
)
317 int num
, size
, result
;
319 result
= ustctl_get_subbuf_num_size(sock
, trace
, channel
,
329 static int do_trace_cmd(int sock
, const char *trace
, int command
)
331 struct ustcomm_header req_header
, res_header
;
332 struct ustcomm_single_field trace_inf
;
335 result
= ustcomm_pack_single_field(&req_header
,
343 req_header
.command
= command
;
345 return do_cmd(sock
, &req_header
, (char *)&trace_inf
, &res_header
, NULL
);
349 * Destroys an UST trace according to a PID.
351 * @param pid Traced process ID
352 * @return 0 if successful, or error USTCTL_ERR_GEN
354 int ustctl_destroy_trace(int sock
, const char *trace
)
356 return do_trace_cmd(sock
, trace
, DESTROY_TRACE
);
360 * Starts an UST trace (and setups it) according to a PID.
362 * @param pid Traced process ID
363 * @return 0 if successful, or error USTCTL_ERR_GEN
365 int ustctl_setup_and_start(int sock
, const char *trace
)
367 return do_trace_cmd(sock
, trace
, START
);
371 * Creates an UST trace according to a PID.
373 * @param pid Traced process ID
374 * @return 0 if successful, or error USTCTL_ERR_GEN
376 int ustctl_create_trace(int sock
, const char *trace
)
378 return do_trace_cmd(sock
, trace
, CREATE_TRACE
);
382 * Starts an UST trace according to a PID.
384 * @param pid Traced process ID
385 * @return 0 if successful, or error USTCTL_ERR_GEN
387 int ustctl_start_trace(int sock
, const char *trace
)
389 return do_trace_cmd(sock
, trace
, START_TRACE
);
393 * Alloc an UST trace according to a PID.
395 * @param pid Traced process ID
396 * @return 0 if successful, or error USTCTL_ERR_GEN
398 int ustctl_alloc_trace(int sock
, const char *trace
)
400 return do_trace_cmd(sock
, trace
, ALLOC_TRACE
);
404 int ustctl_force_switch(int sock
, const char *trace
)
406 return do_trace_cmd(sock
, trace
, FORCE_SUBBUF_SWITCH
);
410 * Stops an UST trace according to a PID.
412 * @param pid Traced process ID
413 * @return 0 if successful, or error USTCTL_ERR_GEN
415 int ustctl_stop_trace(int sock
, const char *trace
)
417 return do_trace_cmd(sock
, trace
, STOP_TRACE
);
421 * Counts newlines ('\n') in a string.
423 * @param str String to search in
424 * @return Total newlines count
426 unsigned int ustctl_count_nl(const char *str
)
428 unsigned int i
= 0, tot
= 0;
430 while (str
[i
] != '\0') {
431 if (str
[i
] == '\n') {
441 * Frees a CMSF array.
443 * @param cmsf CMSF array to free
444 * @return 0 if successful, or error USTCTL_ERR_ARG
446 int ustctl_free_cmsf(struct marker_status
*cmsf
)
449 return USTCTL_ERR_ARG
;
453 while (cmsf
[i
].channel
!= NULL
) {
454 free(cmsf
[i
].channel
);
455 free(cmsf
[i
].marker
);
465 * Gets channel/marker/state/format string for a given PID.
467 * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller
468 * frees with `ustctl_free_cmsf')
469 * @param pid Targeted PID
470 * @return 0 if successful, or -1 on error
472 int ustctl_get_cmsf(int sock
, struct marker_status
**cmsf
)
474 struct ustcomm_header req_header
, res_header
;
475 char *big_str
= NULL
;
477 struct marker_status
*tmp_cmsf
= NULL
;
478 unsigned int i
= 0, cmsf_ind
= 0;
484 req_header
.command
= LIST_MARKERS
;
487 result
= ustcomm_send(sock
, &req_header
, NULL
);
489 PERROR("error while requesting markers list");
493 result
= ustcomm_recv_alloc(sock
, &res_header
, &big_str
);
495 ERR("error while receiving markers list");
499 tmp_cmsf
= (struct marker_status
*) zmalloc(sizeof(struct marker_status
) *
500 (ustctl_count_nl(big_str
) + 1));
501 if (tmp_cmsf
== NULL
) {
502 ERR("Failed to allocate CMSF array");
506 /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */
507 while (big_str
[i
] != '\0') {
510 sscanf(big_str
+ i
, "marker: %a[^/]/%a[^ ] %c %a[^\n]",
511 &tmp_cmsf
[cmsf_ind
].channel
,
512 &tmp_cmsf
[cmsf_ind
].marker
,
514 &tmp_cmsf
[cmsf_ind
].fs
);
515 tmp_cmsf
[cmsf_ind
].state
= (state
== USTCTL_MS_CHR_ON
?
516 USTCTL_MS_ON
: USTCTL_MS_OFF
); /* Marker state */
518 while (big_str
[i
] != '\n') {
519 ++i
; /* Go to next '\n' */
521 ++i
; /* Skip current pointed '\n' */
524 tmp_cmsf
[cmsf_ind
].channel
= NULL
;
525 tmp_cmsf
[cmsf_ind
].marker
= NULL
;
526 tmp_cmsf
[cmsf_ind
].fs
= NULL
;
537 * @param tes TES array to free
538 * @return 0 if successful, or error USTCTL_ERR_ARG
540 int ustctl_free_tes(struct trace_event_status
*tes
)
543 return USTCTL_ERR_ARG
;
547 while (tes
[i
].name
!= NULL
) {
557 * Gets trace_events string for a given PID.
559 * @param tes Pointer to TES array to be filled (callee allocates, caller
560 * frees with `ustctl_free_tes')
561 * @param pid Targeted PID
562 * @return 0 if successful, or -1 on error
564 int ustctl_get_tes(int sock
, struct trace_event_status
**tes
)
566 struct ustcomm_header req_header
, res_header
;
567 char *big_str
= NULL
;
569 struct trace_event_status
*tmp_tes
= NULL
;
570 unsigned int i
= 0, tes_ind
= 0;
576 req_header
.command
= LIST_TRACE_EVENTS
;
579 result
= ustcomm_send(sock
, &req_header
, NULL
);
581 ERR("error while requesting trace_event list");
585 result
= ustcomm_recv_alloc(sock
, &res_header
, &big_str
);
587 ERR("error while receiving markers list");
591 tmp_tes
= (struct trace_event_status
*)
592 zmalloc(sizeof(struct trace_event_status
) *
593 (ustctl_count_nl(big_str
) + 1));
594 if (tmp_tes
== NULL
) {
595 ERR("Failed to allocate TES array");
599 /* Parse received reply string (format: "[name]"): */
600 while (big_str
[i
] != '\0') {
601 sscanf(big_str
+ i
, "trace_event: %a[^\n]",
602 &tmp_tes
[tes_ind
].name
);
603 while (big_str
[i
] != '\n') {
604 ++i
; /* Go to next '\n' */
606 ++i
; /* Skip current pointed '\n' */
609 tmp_tes
[tes_ind
].name
= NULL
;
620 * @param sock_path Sock path
621 * @param pid Traced process ID
622 * @return 0 if successful, or error
624 int ustctl_set_sock_path(int sock
, const char *sock_path
)
627 struct ustcomm_header req_header
, res_header
;
628 struct ustcomm_single_field sock_path_msg
;
630 result
= ustcomm_pack_single_field(&req_header
,
638 req_header
.command
= SET_SOCK_PATH
;
640 return do_cmd(sock
, &req_header
, (char *)&sock_path_msg
,
647 * @param sock_path Pointer to where the sock path will be returned
648 * @param pid Traced process ID
649 * @return 0 if successful, or error
651 int ustctl_get_sock_path(int sock
, char **sock_path
)
654 struct ustcomm_header req_header
, res_header
;
655 struct ustcomm_single_field
*sock_path_msg
;
657 req_header
.command
= GET_SOCK_PATH
;
660 result
= do_cmd(sock
, &req_header
, NULL
, &res_header
,
661 (char **)&sock_path_msg
);
666 result
= ustcomm_unpack_single_field(sock_path_msg
);
671 *sock_path
= strdup(sock_path_msg
->field
);