add regex support for marker names
[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
28 #include "ustcomm.h"
29 #include "ustcmd.h"
30
31 #define _GNU_SOURCE
32
33 pid_t* ustcmd_get_online_pids(void) {
34 struct dirent* dirent;
35 DIR* dir;
36 unsigned int ret_size = 1 * sizeof(pid_t), i = 0;
37
38 dir = opendir(SOCK_DIR);
39 if (!dir) {
40 return NULL;
41 }
42
43 pid_t* ret = (pid_t*) malloc(ret_size);
44
45 while (dirent = readdir(dir)) {
46 if (!strcmp(dirent->d_name, ".") ||
47 !strcmp(dirent->d_name, "..")) {
48
49 continue;
50 }
51
52 if (dirent->d_type != DT_DIR &&
53 !!strcmp(dirent->d_name, "ustd")) {
54
55 sscanf(dirent->d_name, "%u", (unsigned int*) &ret[i]);
56 if (pid_is_online(ret[i])) {
57 ret_size += sizeof(pid_t);
58 ret = (pid_t*) realloc(ret, ret_size);
59 ++i;
60 }
61 }
62 }
63
64 ret[i] = 0; /* Array end */
65
66 if (ret[0] == 0) { /* 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_shoot(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 * Destroys an UST trace according to a PID.
107 *
108 * @param pid Traced process ID
109 * @return 0 if successful, or error USTCMD_ERR_GEN
110 */
111 int ustcmd_destroy_trace(pid_t pid) {
112 int tres;
113
114 if (tres = ustcmd_shoot("destroy", pid, NULL)) {
115 return USTCMD_ERR_GEN;
116 }
117
118 return 0;
119 }
120
121 /**
122 * Starts an UST trace (and setups it) according to a PID.
123 *
124 * @param pid Traced process ID
125 * @return 0 if successful, or error USTCMD_ERR_GEN
126 */
127 int ustcmd_setup_and_start(pid_t pid) {
128 int tres;
129
130 if (tres = ustcmd_shoot("start", pid, NULL)) {
131 return USTCMD_ERR_GEN;
132 }
133
134 return 0;
135 }
136
137 /**
138 * Starts an UST trace according to a PID.
139 *
140 * @param pid Traced process ID
141 * @return 0 if successful, or error USTCMD_ERR_GEN
142 */
143 int ustcmd_start_trace(pid_t pid) {
144 int tres;
145
146 if (tres = ustcmd_shoot("trace_start", pid, NULL)) {
147 return USTCMD_ERR_GEN;
148 }
149
150 return 0;
151 }
152
153 /**
154 * Stops an UST trace according to a PID.
155 *
156 * @param pid Traced process ID
157 * @return 0 if successful, or error USTCMD_ERR_GEN
158 */
159 int ustcmd_stop_trace(pid_t pid) {
160 int tres;
161
162 if (tres = ustcmd_shoot("trace_stop", pid, NULL)) {
163 return USTCMD_ERR_GEN;
164 }
165
166 return 0;
167 }
168
169 /**
170 * Counts newlines ('\n') in a string.
171 *
172 * @param str String to search in
173 * @return Total newlines count
174 */
175 unsigned int ustcmd_count_nl(const char* str) {
176 unsigned int i = 0, tot = 0;
177
178 while (str[i] != '\0') {
179 if (str[i] == '\n') {
180 ++tot;
181 }
182 ++i;
183 }
184
185 return tot;
186 }
187
188 /**
189 * Frees a CMSF array.
190 *
191 * @param cmsf CMSF array to free
192 * @return 0 if successful, or error USTCMD_ERR_ARG
193 */
194 int ustcmd_free_cmsf(struct USTcmd_cmsf* cmsf) {
195 if (cmsf == NULL) {
196 return USTCMD_ERR_ARG;
197 }
198
199 unsigned int i = 0;
200 while (cmsf[i].channel != NULL) {
201 free(cmsf[i].channel);
202 free(cmsf[i].marker);
203 free(cmsf[i].fs);
204 ++i;
205 }
206 free(cmsf);
207
208 return 0;
209 }
210
211 /**
212 * Gets channel/marker/state/format string for a given PID.
213 *
214 * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller
215 * frees with `ustcmd_free_cmsf')
216 * @param pid Targeted PID
217 * @return 0 if successful, or errors {USTCMD_ERR_ARG, USTCMD_ERR_GEN}
218 */
219 int ustcmd_get_cmsf(struct USTcmd_cmsf** cmsf, const pid_t pid) {
220 char* big_str = NULL;
221 int result;
222 struct USTcmd_cmsf* tmp_cmsf = NULL;
223 unsigned int i = 0, cmsf_ind = 0;
224
225 if (cmsf == NULL) {
226 return USTCMD_ERR_ARG;
227 }
228 result = ustcmd_shoot("list_markers", pid, &big_str);
229 if (result) {
230 return USTCMD_ERR_GEN;
231 }
232
233 if (big_str == NULL) {
234 fprintf(stderr, "ustcmd: error while getting markers list\n");
235 return USTCMD_ERR_GEN;
236 }
237
238 tmp_cmsf = (struct USTcmd_cmsf*) malloc(sizeof(struct USTcmd_cmsf) *
239 (ustcmd_count_nl(big_str) + 1));
240 if (tmp_cmsf == NULL) {
241 return USTCMD_ERR_GEN;
242 }
243
244 /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */
245 while (big_str[i] != '\0') {
246 char state;
247
248 sscanf(big_str + i, "%a[^/]/%a[^ ] %c %a[^\n]",
249 &tmp_cmsf[cmsf_ind].channel,
250 &tmp_cmsf[cmsf_ind].marker,
251 &state,
252 &tmp_cmsf[cmsf_ind].fs);
253 tmp_cmsf[cmsf_ind].state = (state == USTCMD_MS_CHR_ON ?
254 USTCMD_MS_ON : USTCMD_MS_OFF); /* Marker state */
255
256 while (big_str[i] != '\n') {
257 ++i; /* Go to next '\n' */
258 }
259 ++i; /* Skip current pointed '\n' */
260 ++cmsf_ind;
261 }
262 tmp_cmsf[cmsf_ind].channel = NULL;
263 tmp_cmsf[cmsf_ind].marker = NULL;
264 tmp_cmsf[cmsf_ind].fs = NULL;
265
266 *cmsf = tmp_cmsf;
267
268 free(big_str);
269 return 0;
270 }
271
272 /**
273 * Shoots a given command using ustcomm.
274 *
275 * @param cmd Null-terminated command to shoot
276 * @param pid Targeted PID
277 * @param reply Pointer to string to be filled with a reply string (must
278 * be NULL if no reply is needed for the given command).
279 * @return 0 if successful, or errors {USTCMD_ERR_ARG, USTCMD_ERR_CONN}
280 */
281 int ustcmd_shoot(const char* cmd, const pid_t pid, char** reply) {
282 if (cmd == NULL) {
283 return USTCMD_ERR_ARG;
284 }
285
286 if (ustcomm_connect_app(pid, &conn)) {
287 fprintf(stderr, "ustcmd_shoot: could not connect to PID %u\n",
288 (unsigned int) pid);
289 return USTCMD_ERR_CONN;
290 }
291
292 ustcomm_send_request(&conn, cmd, reply);
293
294 return 0;
295 }
This page took 0.03668 seconds and 5 git commands to generate.