Fix asprintf and scanf ignoring return value
[ust.git] / libustcmd / ustcmd.c
1 /* Copyright (C) 2009 Pierre-Marc Fournier, Philippe Proulx-Barrette
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 #define _GNU_SOURCE
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <getopt.h>
22 #include <stdlib.h>
23 #include <fcntl.h>
24 #include <string.h>
25 #include <dirent.h>
26
27 #include "ustcomm.h"
28 #include "ust/ustcmd.h"
29 #include "usterr.h"
30
31 pid_t *ustcmd_get_online_pids(void)
32 {
33 struct dirent *dirent;
34 DIR *dir;
35 unsigned int ret_size = 1 * sizeof(pid_t), i = 0;
36
37 dir = opendir(SOCK_DIR);
38 if (!dir) {
39 return NULL;
40 }
41
42 pid_t *ret = (pid_t *) malloc(ret_size);
43
44 while ((dirent = readdir(dir))) {
45 if (!strcmp(dirent->d_name, ".") ||
46 !strcmp(dirent->d_name, "..")) {
47
48 continue;
49 }
50
51 if (dirent->d_type != DT_DIR &&
52 !!strcmp(dirent->d_name, "ustd")) {
53
54 sscanf(dirent->d_name, "%u", (unsigned int *) &ret[i]);
55 if (pid_is_online(ret[i])) {
56 ret_size += sizeof(pid_t);
57 ret = (pid_t *) realloc(ret, ret_size);
58 ++i;
59 }
60 }
61 }
62
63 ret[i] = 0; /* Array end */
64
65 if (ret[0] == 0) {
66 /* No PID at all */
67 free(ret);
68 return NULL;
69 }
70
71 closedir(dir);
72 return ret;
73 }
74
75 /**
76 * Sets marker state (USTCMD_MS_ON or USTCMD_MS_OFF).
77 *
78 * @param mn Marker name
79 * @param state Marker's new state
80 * @param pid Traced process ID
81 * @return 0 if successful, or errors {USTCMD_ERR_GEN, USTCMD_ERR_ARG}
82 */
83 int ustcmd_set_marker_state(const char *mn, int state, pid_t pid)
84 {
85 char *cmd_str [] = {"disable_marker", "enable_marker"};
86 char *cmd;
87 int result;
88
89 if (mn == NULL) {
90 return USTCMD_ERR_ARG;
91 }
92
93 if (asprintf(&cmd, "%s %s", cmd_str[state], mn) < 0) {
94 ERR("ustcmd_set_marker_state : asprintf failed (%s %s)",
95 cmd_str[state], mn);
96 return USTCMD_ERR_GEN;
97 }
98
99 result = ustcmd_send_cmd(cmd, pid, NULL);
100 if (result) {
101 free(cmd);
102 return USTCMD_ERR_GEN;
103 }
104
105 free(cmd);
106 return 0;
107 }
108
109 /**
110 * Set subbuffer size.
111 *
112 * @param channel_size Channel name and size
113 * @param pid Traced process ID
114 * @return 0 if successful, or error
115 */
116 int ustcmd_set_subbuf_size(const char *channel_size, pid_t pid)
117 {
118 char *cmd;
119 int result;
120
121 if (asprintf(&cmd, "%s %s", "set_subbuf_size", channel_size) < 0) {
122 ERR("ustcmd_set_subbuf_size : asprintf failed (set_subbuf_size %s)",
123 channel_size);
124 return -1;
125 }
126
127 result = ustcmd_send_cmd(cmd, pid, NULL);
128 if (result != 1) {
129 free(cmd);
130 return 1;
131 }
132
133 free(cmd);
134 return 0;
135 }
136
137 /**
138 * Set subbuffer num.
139 *
140 * @param channel_num Channel name and num
141 * @param pid Traced process ID
142 * @return 0 if successful, or error
143 */
144 int ustcmd_set_subbuf_num(const char *channel_size, pid_t pid)
145 {
146 char *cmd;
147 int result;
148
149 if (asprintf(&cmd, "%s %s", "set_subbuf_num", channel_size) < 0) {
150 ERR("ustcmd_set_subbuf_num : asprintf failed (set_subbuf_num %s",
151 channel_size);
152 return -1;
153 }
154
155 result = ustcmd_send_cmd(cmd, pid, NULL);
156 if (result != 1) {
157 free(cmd);
158 return 1;
159 }
160
161 free(cmd);
162 return 0;
163 }
164
165 /**
166 * Get subbuffer size.
167 *
168 * @param channel Channel name
169 * @param pid Traced process ID
170 * @return subbuf size if successful, or error
171 */
172 int ustcmd_get_subbuf_size(const char *channel, pid_t pid)
173 {
174 char *cmd, *reply;
175 int result;
176
177 /* format: channel_cpu */
178 if (asprintf(&cmd, "%s %s_0", "get_subbuf_size", channel) < 0) {
179 ERR("ustcmd_get_subbuf_size : asprintf failed (get_subbuf_size, %s_0",
180 channel);
181 return -1;
182 }
183
184 result = ustcmd_send_cmd(cmd, pid, &reply);
185 if (result) {
186 free(cmd);
187 free(reply);
188 return -1;
189 }
190
191 result = atoi(reply);
192 free(cmd);
193 free(reply);
194 return result;
195 }
196
197 /**
198 * Get subbuffer num.
199 *
200 * @param channel Channel name
201 * @param pid Traced process ID
202 * @return subbuf cnf if successful, or error
203 */
204 int ustcmd_get_subbuf_num(const char *channel, pid_t pid)
205 {
206 char *cmd, *reply;
207 int result;
208
209 /* format: channel_cpu */
210 if (asprintf(&cmd, "%s %s_0", "get_n_subbufs", channel) < 0) {
211 ERR("ustcmd_get_subbuf_num : asprintf failed (get_n_subbufs, %s_0",
212 channel);
213 return -1;
214 }
215
216 result = ustcmd_send_cmd(cmd, pid, &reply);
217 if (result) {
218 free(cmd);
219 free(reply);
220 return -1;
221 }
222
223 result = atoi(reply);
224 free(cmd);
225 free(reply);
226 return result;
227 }
228
229 /**
230 * Destroys an UST trace according to a PID.
231 *
232 * @param pid Traced process ID
233 * @return 0 if successful, or error USTCMD_ERR_GEN
234 */
235 int ustcmd_destroy_trace(pid_t pid)
236 {
237 int result;
238
239 result = ustcmd_send_cmd("trace_destroy", pid, NULL);
240 if (result != 1) {
241 return USTCMD_ERR_GEN;
242 }
243
244 return 0;
245 }
246
247 /**
248 * Starts an UST trace (and setups it) according to a PID.
249 *
250 * @param pid Traced process ID
251 * @return 0 if successful, or error USTCMD_ERR_GEN
252 */
253 int ustcmd_setup_and_start(pid_t pid)
254 {
255 int result;
256
257 result = ustcmd_send_cmd("start", pid, NULL);
258 if (result != 1) {
259 return USTCMD_ERR_GEN;
260 }
261
262 return 0;
263 }
264
265 /**
266 * Creates an UST trace according to a PID.
267 *
268 * @param pid Traced process ID
269 * @return 0 if successful, or error USTCMD_ERR_GEN
270 */
271 int ustcmd_create_trace(pid_t pid)
272 {
273 int result;
274
275 result = ustcmd_send_cmd("trace_create", pid, NULL);
276 if (result != 1) {
277 return USTCMD_ERR_GEN;
278 }
279
280 return 0;
281 }
282
283 /**
284 * Starts an UST trace according to a PID.
285 *
286 * @param pid Traced process ID
287 * @return 0 if successful, or error USTCMD_ERR_GEN
288 */
289 int ustcmd_start_trace(pid_t pid)
290 {
291 int result;
292
293 result = ustcmd_send_cmd("trace_start", pid, NULL);
294 if (result != 1) {
295 return USTCMD_ERR_GEN;
296 }
297
298 return 0;
299 }
300
301 /**
302 * Alloc an UST trace according to a PID.
303 *
304 * @param pid Traced process ID
305 * @return 0 if successful, or error USTCMD_ERR_GEN
306 */
307 int ustcmd_alloc_trace(pid_t pid)
308 {
309 int result;
310
311 result = ustcmd_send_cmd("trace_alloc", pid, NULL);
312 if (result != 1) {
313 return USTCMD_ERR_GEN;
314 }
315
316 return 0;
317 }
318
319 /**
320 * Stops an UST trace according to a PID.
321 *
322 * @param pid Traced process ID
323 * @return 0 if successful, or error USTCMD_ERR_GEN
324 */
325 int ustcmd_stop_trace(pid_t pid)
326 {
327 int result;
328
329 result = ustcmd_send_cmd("trace_stop", pid, NULL);
330 if (result != 1) {
331 return USTCMD_ERR_GEN;
332 }
333
334 return 0;
335 }
336
337 /**
338 * Counts newlines ('\n') in a string.
339 *
340 * @param str String to search in
341 * @return Total newlines count
342 */
343 unsigned int ustcmd_count_nl(const char *str)
344 {
345 unsigned int i = 0, tot = 0;
346
347 while (str[i] != '\0') {
348 if (str[i] == '\n') {
349 ++tot;
350 }
351 ++i;
352 }
353
354 return tot;
355 }
356
357 /**
358 * Frees a CMSF array.
359 *
360 * @param cmsf CMSF array to free
361 * @return 0 if successful, or error USTCMD_ERR_ARG
362 */
363 int ustcmd_free_cmsf(struct marker_status *cmsf)
364 {
365 if (cmsf == NULL) {
366 return USTCMD_ERR_ARG;
367 }
368
369 unsigned int i = 0;
370 while (cmsf[i].channel != NULL) {
371 free(cmsf[i].channel);
372 free(cmsf[i].marker);
373 free(cmsf[i].fs);
374 ++i;
375 }
376 free(cmsf);
377
378 return 0;
379 }
380
381 /**
382 * Gets channel/marker/state/format string for a given PID.
383 *
384 * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller
385 * frees with `ustcmd_free_cmsf')
386 * @param pid Targeted PID
387 * @return 0 if successful, or -1 on error
388 */
389 int ustcmd_get_cmsf(struct marker_status **cmsf, const pid_t pid)
390 {
391 char *big_str = NULL;
392 int result;
393 struct marker_status *tmp_cmsf = NULL;
394 unsigned int i = 0, cmsf_ind = 0;
395
396 if (cmsf == NULL) {
397 return -1;
398 }
399 result = ustcmd_send_cmd("list_markers", pid, &big_str);
400 if (result != 1) {
401 return -1;
402 }
403
404 if (result != 1) {
405 ERR("error while getting markers list");
406 return -1;
407 }
408
409 tmp_cmsf = (struct marker_status *) malloc(sizeof(struct marker_status) *
410 (ustcmd_count_nl(big_str) + 1));
411 if (tmp_cmsf == NULL) {
412 return -1;
413 }
414
415 /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */
416 while (big_str[i] != '\0') {
417 char state;
418
419 sscanf(big_str + i, "marker: %a[^/]/%a[^ ] %c %a[^\n]",
420 &tmp_cmsf[cmsf_ind].channel,
421 &tmp_cmsf[cmsf_ind].marker,
422 &state,
423 &tmp_cmsf[cmsf_ind].fs);
424 tmp_cmsf[cmsf_ind].state = (state == USTCMD_MS_CHR_ON ?
425 USTCMD_MS_ON : USTCMD_MS_OFF); /* Marker state */
426
427 while (big_str[i] != '\n') {
428 ++i; /* Go to next '\n' */
429 }
430 ++i; /* Skip current pointed '\n' */
431 ++cmsf_ind;
432 }
433 tmp_cmsf[cmsf_ind].channel = NULL;
434 tmp_cmsf[cmsf_ind].marker = NULL;
435 tmp_cmsf[cmsf_ind].fs = NULL;
436
437 *cmsf = tmp_cmsf;
438
439 free(big_str);
440 return 0;
441 }
442
443 /**
444 * Set socket path
445 *
446 * @param sock_path Socket path
447 * @param pid Traced process ID
448 * @return 0 if successful, or error
449 */
450 int ustcmd_set_sock_path(const char *sock_path, pid_t pid)
451 {
452 char *cmd;
453 int result;
454
455 if (asprintf(&cmd, "%s %s", "set_sock_path", sock_path) < 0) {
456 ERR("ustcmd_set_sock_path : asprintf failed (set_sock_path, %s",
457 sock_path);
458 return -1;
459 }
460
461 result = ustcmd_send_cmd(cmd, pid, NULL);
462 if (result != 1) {
463 free(cmd);
464 return USTCMD_ERR_GEN;
465 }
466
467 free(cmd);
468 return 0;
469 }
470
471 /**
472 * Get socket path
473 *
474 * @param sock_path Pointer to where the socket path will be returned
475 * @param pid Traced process ID
476 * @return 0 if successful, or error
477 */
478 int ustcmd_get_sock_path(char **sock_path, pid_t pid)
479 {
480 char *cmd, *reply;
481 int result;
482
483 if (asprintf(&cmd, "%s", "get_sock_path") < 0) {
484 ERR("ustcmd_get_sock_path : asprintf failed");
485 return USTCMD_ERR_GEN;
486 }
487
488 result = ustcmd_send_cmd(cmd, pid, &reply);
489 if (result != 1) {
490 free(cmd);
491 free(reply);
492 return USTCMD_ERR_GEN;
493 }
494
495 free(cmd);
496 *sock_path = reply;
497 return 0;
498 }
499
500 int ustcmd_force_switch(pid_t pid)
501 {
502 int result;
503
504 result = ustcmd_send_cmd("force_switch", pid, NULL);
505 if (result != 1) {
506 return USTCMD_ERR_GEN;
507 }
508
509 return 0;
510 }
511
512 /**
513 * Sends a given command to a traceable process
514 *
515 * @param cmd Null-terminated command to send
516 * @param pid Targeted PID
517 * @param reply Pointer to string to be filled with a reply string (must
518 * be NULL if no reply is needed for the given command).
519 * @return -1 if successful, 0 on EOT, 1 on success
520 */
521
522 int ustcmd_send_cmd(const char *cmd, const pid_t pid, char **reply)
523 {
524 struct ustcomm_connection conn;
525 int retval;
526
527 if (ustcomm_connect_app(pid, &conn)) {
528 ERR("could not connect to PID %u", (unsigned int) pid);
529 return -1;
530 }
531
532 retval = ustcomm_send_request(&conn, cmd, reply);
533
534 ustcomm_close_app(&conn);
535
536 return retval;
537 }
This page took 0.040063 seconds and 4 git commands to generate.