Initial import
[lttng-tools.git] / liblttngctl / liblttngctl.c
1 /* Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version 2
6 * of the License, or (at your option) any later version.
7 *
8 * This program 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
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 *
17 */
18
19 #define _GNU_SOURCE
20 #include <errno.h>
21 #include <grp.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include <lttng/liblttngctl.h>
28
29 #include "liblttsessiondcomm.h"
30 #include "lttngerr.h"
31
32 /* Socket to session daemon for communication */
33 static int sessiond_socket;
34 static char sessiond_sock_path[PATH_MAX];
35
36 /* Communication structure to ltt-sessiond */
37 static struct lttcomm_lttng_msg llm;
38 static struct lttcomm_session_msg lsm;
39
40 /* Prototypes */
41 static int check_tracing_group(const char *grp_name);
42 static int ask_sessiond(void);
43 static int set_session_daemon_path(void);
44 static void reset_data_struct(void);
45
46 int lttng_connect_sessiond(void);
47 int lttng_create_session(const char *name, char *session_id);
48 int lttng_check_session_daemon(void);
49
50 /* Variables */
51 static char *tracing_group;
52 static int connected;
53
54 /*
55 * ask_sessiond
56 *
57 * Send lttcomm_session_msg to the daemon and wait
58 * for the reply. Data replied will be put in llm
59 *
60 * On success, return 0
61 * On error, return error code
62 */
63 static int ask_sessiond(void)
64 {
65 int ret;
66
67 if (!connected) {
68 ret = -ECONNREFUSED;
69 goto error;
70 }
71
72 ret = lttcomm_send_unix_sock(sessiond_socket, &lsm, sizeof(lsm));
73 if (ret < 0) {
74 goto error;
75 }
76
77 ret = lttcomm_recv_unix_sock(sessiond_socket, &llm, sizeof(llm));
78 if (ret < 0) {
79 goto error;
80 }
81
82 /* Check return code */
83 if (llm.ret_code != LTTCOMM_OK) {
84 ret = -llm.ret_code;
85 goto error;
86 }
87
88 return 0;
89
90 error:
91 return ret;
92 }
93
94 /*
95 * lttng_get_readable_code
96 *
97 * Return a human readable string of code
98 */
99 const char *lttng_get_readable_code(int code)
100 {
101 if (code > -LTTCOMM_OK) {
102 return "Ended with errors";
103 }
104
105 return lttcomm_get_readable_code(code);
106 }
107
108 /*
109 * lttng_create_session
110 *
111 * Create a tracing session using "name" to the session daemon.
112 * If no name is given, the auto session creation is set and
113 * the daemon will take care of finding a name.
114 *
115 * On success, return 0 and session_id point to the uuid str.
116 * On error, negative value is returned.
117 */
118 int lttng_create_session(const char *name, char *session_id)
119 {
120 int ret;
121
122 lsm.cmd_type = LTTNG_CREATE_SESSION;
123 if (name == NULL) {
124 lsm.u.create_session.auto_session = 1;
125 } else {
126 strncpy(lsm.session_name, name, strlen(name));
127 lsm.u.create_session.auto_session = 0;
128 }
129
130 /* Ask the session daemon */
131 ret = ask_sessiond();
132 if (ret < 0) {
133 goto end;
134 }
135
136 /* Unparse session ID */
137 uuid_unparse(llm.session_id, session_id);
138
139 end:
140 reset_data_struct();
141
142 return ret;
143 }
144
145 /*
146 * lttng_ust_list_apps
147 *
148 * Ask the session daemon for all UST traceable
149 * applications.
150 *
151 * Return the size of pids.
152 */
153 size_t lttng_ust_list_apps(pid_t **pids)
154 {
155 int ret;
156
157 lsm.cmd_type = UST_LIST_APPS;
158
159 ret = ask_sessiond();
160 if (ret < 0) {
161 goto error;
162 }
163
164 *pids = llm.u.list_apps.pids;
165
166 return llm.u.list_apps.size;
167
168 error:
169 return ret;
170 }
171
172 /*
173 * lttng_connect_sessiond
174 *
175 * Connect to the LTTng session daemon.
176 * On success, return 0
177 * On error, return a negative value
178 */
179 int lttng_connect_sessiond(void)
180 {
181 int ret;
182
183 ret = set_session_daemon_path();
184 if (ret < 0) {
185 return ret;
186 }
187
188 /* Connect to the sesssion daemon */
189 ret = lttcomm_connect_unix_sock(sessiond_sock_path);
190 if (ret < 0) {
191 return ret;
192 }
193
194 sessiond_socket = ret;
195 connected = 1;
196
197 return 0;
198 }
199
200 /*
201 * lttng_set_tracing_group
202 *
203 * Set tracing group variable with name. This function
204 * allocate memory pointed by tracing_group.
205 */
206 int lttng_set_tracing_group(const char *name)
207 {
208 if (asprintf(&tracing_group, "%s", name) < 0) {
209 return -ENOMEM;
210 }
211
212 return 0;
213 }
214
215 /*
216 * lttng_check_session_daemon
217 *
218 * Return 0 if a sesssion daemon is available
219 * else return -1
220 */
221 int lttng_check_session_daemon(void)
222 {
223 int ret;
224
225 ret = set_session_daemon_path();
226 if (ret < 0) {
227 return ret;
228 }
229
230 /* If socket exist, we consider the daemon started */
231 ret = access(sessiond_sock_path, F_OK);
232 if (ret < 0) {
233 return ret;
234 }
235
236 return 0;
237 }
238
239 /*
240 * reset_data_struct
241 *
242 * Reset session daemon structures.
243 */
244 static void reset_data_struct(void)
245 {
246 memset(&lsm, 0, sizeof(lsm));
247 memset(&llm, 0, sizeof(llm));
248 }
249
250 /*
251 * set_session_daemon_path
252 *
253 * Set sessiond socket path by putting it in
254 * the global sessiond_sock_path variable.
255 */
256 static int set_session_daemon_path(void)
257 {
258 int ret;
259
260 /* Are we in the tracing group ? */
261 ret = check_tracing_group(tracing_group);
262 if (ret < 0) {
263 if (sprintf(sessiond_sock_path, DEFAULT_HOME_CLIENT_UNIX_SOCK,
264 getenv("HOME")) < 0) {
265 return -ENOMEM;
266 }
267 } else {
268 strncpy(sessiond_sock_path, DEFAULT_GLOBAL_CLIENT_UNIX_SOCK,
269 sizeof(DEFAULT_GLOBAL_CLIENT_UNIX_SOCK));
270 }
271
272 return 0;
273 }
274
275 /*
276 * check_tracing_group
277 *
278 * Check if the specified group name exist.
279 * If yes, 0, else -1
280 */
281 static int check_tracing_group(const char *grp_name)
282 {
283 struct group *grp_tracing; /* no free(). See getgrnam(3) */
284 gid_t *grp_list;
285 int grp_list_size, grp_id, i;
286 int ret = -1;
287
288 /* Get GID of group 'tracing' */
289 grp_tracing = getgrnam(grp_name);
290 if (grp_tracing == NULL) {
291 /* NULL means not found also. getgrnam(3) */
292 if (errno != 0) {
293 perror("getgrnam");
294 }
295 goto end;
296 }
297
298 /* Get number of supplementary group IDs */
299 grp_list_size = getgroups(0, NULL);
300 if (grp_list_size < 0) {
301 perror("getgroups");
302 goto end;
303 }
304
305 /* Alloc group list of the right size */
306 grp_list = malloc(grp_list_size * sizeof(gid_t));
307 grp_id = getgroups(grp_list_size, grp_list);
308 if (grp_id < -1) {
309 perror("getgroups");
310 goto free_list;
311 }
312
313 for (i = 0; i < grp_list_size; i++) {
314 if (grp_list[i] == grp_tracing->gr_gid) {
315 ret = 0;
316 break;
317 }
318 }
319
320 free_list:
321 free(grp_list);
322
323 end:
324 return ret;
325 }
326
327 /*
328 * lib constructor
329 */
330 static void __attribute__((constructor)) init()
331 {
332 /* Set default session group */
333 lttng_set_tracing_group(DEFAULT_TRACING_GROUP);
334 }
This page took 0.035669 seconds and 5 git commands to generate.