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