fix destruction to free all memory
[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 "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 asprintf(&cmd, "%s %s", cmd_str[state], mn);
94
95 result = ustcmd_send_cmd(cmd, pid, NULL);
96 if (result) {
97 free(cmd);
98 return USTCMD_ERR_GEN;
99 }
100
101 free(cmd);
102 return 0;
103 }
104
105 /**
106 * Set subbuffer size.
107 *
108 * @param channel_size Channel name and size
109 * @param pid Traced process ID
110 * @return 0 if successful, or error
111 */
112 int ustcmd_set_subbuf_size(const char *channel_size, pid_t pid)
113 {
114 char *cmd;
115 int result;
116
117 asprintf(&cmd, "%s %s", "set_subbuf_size", channel_size);
118
119 result = ustcmd_send_cmd(cmd, pid, NULL);
120 if (result != 1) {
121 free(cmd);
122 return 1;
123 }
124
125 free(cmd);
126 return 0;
127 }
128
129 /**
130 * Set subbuffer num.
131 *
132 * @param channel_num Channel name and num
133 * @param pid Traced process ID
134 * @return 0 if successful, or error
135 */
136 int ustcmd_set_subbuf_num(const char *channel_size, pid_t pid)
137 {
138 char *cmd;
139 int result;
140
141 asprintf(&cmd, "%s %s", "set_subbuf_num", channel_size);
142
143 result = ustcmd_send_cmd(cmd, pid, NULL);
144 if (result != 1) {
145 free(cmd);
146 return 1;
147 }
148
149 free(cmd);
150 return 0;
151 }
152
153
154 /**
155 * Destroys an UST trace according to a PID.
156 *
157 * @param pid Traced process ID
158 * @return 0 if successful, or error USTCMD_ERR_GEN
159 */
160 int ustcmd_destroy_trace(pid_t pid)
161 {
162 int result;
163
164 result = ustcmd_send_cmd("trace_destroy", pid, NULL);
165 if (result != 1) {
166 return USTCMD_ERR_GEN;
167 }
168
169 return 0;
170 }
171
172 /**
173 * Starts an UST trace (and setups it) according to a PID.
174 *
175 * @param pid Traced process ID
176 * @return 0 if successful, or error USTCMD_ERR_GEN
177 */
178 int ustcmd_setup_and_start(pid_t pid)
179 {
180 int result;
181
182 result = ustcmd_send_cmd("start", pid, NULL);
183 if (result != 1) {
184 return USTCMD_ERR_GEN;
185 }
186
187 return 0;
188 }
189
190 /**
191 * Creates an UST trace according to a PID.
192 *
193 * @param pid Traced process ID
194 * @return 0 if successful, or error USTCMD_ERR_GEN
195 */
196 int ustcmd_create_trace(pid_t pid)
197 {
198 int result;
199
200 result = ustcmd_send_cmd("trace_create", pid, NULL);
201 if (result != 1) {
202 return USTCMD_ERR_GEN;
203 }
204
205 return 0;
206 }
207
208 /**
209 * Starts an UST trace according to a PID.
210 *
211 * @param pid Traced process ID
212 * @return 0 if successful, or error USTCMD_ERR_GEN
213 */
214 int ustcmd_start_trace(pid_t pid)
215 {
216 int result;
217
218 result = ustcmd_send_cmd("trace_start", pid, NULL);
219 if (result != 1) {
220 return USTCMD_ERR_GEN;
221 }
222
223 return 0;
224 }
225
226 /**
227 * Alloc an UST trace according to a PID.
228 *
229 * @param pid Traced process ID
230 * @return 0 if successful, or error USTCMD_ERR_GEN
231 */
232 int ustcmd_alloc_trace(pid_t pid)
233 {
234 int result;
235
236 result = ustcmd_send_cmd("trace_alloc", pid, NULL);
237 if (result != 1) {
238 return USTCMD_ERR_GEN;
239 }
240
241 return 0;
242 }
243
244 /**
245 * Stops an UST trace according to a PID.
246 *
247 * @param pid Traced process ID
248 * @return 0 if successful, or error USTCMD_ERR_GEN
249 */
250 int ustcmd_stop_trace(pid_t pid)
251 {
252 int result;
253
254 result = ustcmd_send_cmd("trace_stop", pid, NULL);
255 if (result != 1) {
256 return USTCMD_ERR_GEN;
257 }
258
259 return 0;
260 }
261
262 /**
263 * Counts newlines ('\n') in a string.
264 *
265 * @param str String to search in
266 * @return Total newlines count
267 */
268 unsigned int ustcmd_count_nl(const char *str)
269 {
270 unsigned int i = 0, tot = 0;
271
272 while (str[i] != '\0') {
273 if (str[i] == '\n') {
274 ++tot;
275 }
276 ++i;
277 }
278
279 return tot;
280 }
281
282 /**
283 * Frees a CMSF array.
284 *
285 * @param cmsf CMSF array to free
286 * @return 0 if successful, or error USTCMD_ERR_ARG
287 */
288 int ustcmd_free_cmsf(struct marker_status *cmsf)
289 {
290 if (cmsf == NULL) {
291 return USTCMD_ERR_ARG;
292 }
293
294 unsigned int i = 0;
295 while (cmsf[i].channel != NULL) {
296 free(cmsf[i].channel);
297 free(cmsf[i].marker);
298 free(cmsf[i].fs);
299 ++i;
300 }
301 free(cmsf);
302
303 return 0;
304 }
305
306 /**
307 * Gets channel/marker/state/format string for a given PID.
308 *
309 * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller
310 * frees with `ustcmd_free_cmsf')
311 * @param pid Targeted PID
312 * @return 0 if successful, or -1 on error
313 */
314 int ustcmd_get_cmsf(struct marker_status **cmsf, const pid_t pid)
315 {
316 char *big_str = NULL;
317 int result;
318 struct marker_status *tmp_cmsf = NULL;
319 unsigned int i = 0, cmsf_ind = 0;
320
321 if (cmsf == NULL) {
322 return -1;
323 }
324 result = ustcmd_send_cmd("list_markers", pid, &big_str);
325 if (result != 1) {
326 return -1;
327 }
328
329 if (result != 1) {
330 ERR("error while getting markers list");
331 return -1;
332 }
333
334 tmp_cmsf = (struct marker_status *) malloc(sizeof(struct marker_status) *
335 (ustcmd_count_nl(big_str) + 1));
336 if (tmp_cmsf == NULL) {
337 return -1;
338 }
339
340 /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */
341 while (big_str[i] != '\0') {
342 char state;
343
344 sscanf(big_str + i, "marker: %a[^/]/%a[^ ] %c %a[^\n]",
345 &tmp_cmsf[cmsf_ind].channel,
346 &tmp_cmsf[cmsf_ind].marker,
347 &state,
348 &tmp_cmsf[cmsf_ind].fs);
349 tmp_cmsf[cmsf_ind].state = (state == USTCMD_MS_CHR_ON ?
350 USTCMD_MS_ON : USTCMD_MS_OFF); /* Marker state */
351
352 while (big_str[i] != '\n') {
353 ++i; /* Go to next '\n' */
354 }
355 ++i; /* Skip current pointed '\n' */
356 ++cmsf_ind;
357 }
358 tmp_cmsf[cmsf_ind].channel = NULL;
359 tmp_cmsf[cmsf_ind].marker = NULL;
360 tmp_cmsf[cmsf_ind].fs = NULL;
361
362 *cmsf = tmp_cmsf;
363
364 free(big_str);
365 return 0;
366 }
367
368 /**
369 * Sends a given command to a traceable process
370 *
371 * @param cmd Null-terminated command to send
372 * @param pid Targeted PID
373 * @param reply Pointer to string to be filled with a reply string (must
374 * be NULL if no reply is needed for the given command).
375 * @return -1 if successful, 0 on EOT, 1 on success
376 */
377
378 int ustcmd_send_cmd(const char *cmd, const pid_t pid, char **reply)
379 {
380 struct ustcomm_connection conn;
381 int retval;
382
383 if (ustcomm_connect_app(pid, &conn)) {
384 ERR("could not connect to PID %u", (unsigned int) pid);
385 return -1;
386 }
387
388 retval = ustcomm_send_request(&conn, cmd, reply);
389
390 ustcomm_close_app(&conn);
391
392 return retval;
393 }
This page took 0.035886 seconds and 4 git commands to generate.