header missing
[lttv.git] / ltt / branches / poly / libltt / libltt.c
1 /* libltt
2 *
3 * Linux Trace Toolkit Netlink Control Library
4 *
5 * Controls the ltt-control kernel module through a netlink socket.
6 *
7 * Heavily inspired from libipq.c (iptables) made by
8 * James Morris <jmorris@intercode.com.au>
9 *
10 * Copyright 2005 -
11 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
12 *
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 */
25
26 #include <libltt/libltt.h>
27 #include <errno.h>
28 #include <stdio.h>
29
30
31 /* Private interface */
32
33 enum {
34 LTTCTL_ERR_NONE = 0,
35 LTTCTL_ERR_IMPL,
36 LTTCTL_ERR_HANDLE,
37 LTTCTL_ERR_SOCKET,
38 LTTCTL_ERR_BIND,
39 LTTCTL_ERR_BUFFER,
40 LTTCTL_ERR_RECV,
41 LTTCTL_ERR_NLEOF,
42 LTTCTL_ERR_ADDRLEN,
43 LTTCTL_ERR_STRUNC,
44 LTTCTL_ERR_RTRUNC,
45 LTTCTL_ERR_NLRECV,
46 LTTCTL_ERR_SEND,
47 LTTCTL_ERR_SUPP,
48 LTTCTL_ERR_RECVBUF,
49 LTTCTL_ERR_TIMEOUT,
50 LTTCTL_ERR_PROTOCOL
51 };
52 #define LTTCTL_MAXERR LTTCTL_ERR_PROTOCOL
53
54
55 struct lttctl_errmap_t {
56 int errcode;
57 char *message;
58 } lttctl_errmap[] = {
59 { LTTCTL_ERR_NONE, "Unknown error" },
60 { LTTCTL_ERR_IMPL, "Implementation error" },
61 { LTTCTL_ERR_HANDLE, "Unable to create netlink handle" },
62 { LTTCTL_ERR_SOCKET, "Unable to create netlink socket" },
63 { LTTCTL_ERR_BIND, "Unable to bind netlink socket" },
64 { LTTCTL_ERR_BUFFER, "Unable to allocate buffer" },
65 { LTTCTL_ERR_RECV, "Failed to receive netlink message" },
66 { LTTCTL_ERR_NLEOF, "Received EOF on netlink socket" },
67 { LTTCTL_ERR_ADDRLEN, "Invalid peer address length" },
68 { LTTCTL_ERR_STRUNC, "Sent message truncated" },
69 { LTTCTL_ERR_RTRUNC, "Received message truncated" },
70 { LTTCTL_ERR_NLRECV, "Received error from netlink" },
71 { LTTCTL_ERR_SEND, "Failed to send netlink message" },
72 { LTTCTL_ERR_SUPP, "Operation not supported" },
73 { LTTCTL_ERR_RECVBUF, "Receive buffer size invalid" },
74 { LTTCTL_ERR_TIMEOUT, "Timeout"},
75 { LTTCTL_ERR_PROTOCOL, "Invalid protocol specified" }
76 };
77
78 static int lttctl_errno = LTTCTL_ERR_NONE;
79
80
81 static ssize_t lttctl_netlink_sendto(const struct lttctl_handle *h,
82 const void *msg, size_t len);
83
84 static ssize_t lttctl_netlink_recvfrom(const struct lttctl_handle *h,
85 unsigned char *buf, size_t len,
86 int timeout);
87
88 static ssize_t lttctl_netlink_sendmsg(const struct lttctl_handle *h,
89 const struct msghdr *msg,
90 unsigned int flags);
91
92 static char *lttctl_strerror(int errcode);
93
94 void lttctl_perror(const char *s);
95
96 static ssize_t lttctl_netlink_sendto(const struct lttctl_handle *h,
97 const void *msg, size_t len)
98 {
99 int status = sendto(h->fd, msg, len, 0,
100 (struct sockaddr *)&h->peer, sizeof(h->peer));
101 if (status < 0)
102 lttctl_errno = LTTCTL_ERR_SEND;
103
104 return status;
105 }
106
107 static ssize_t lttctl_netlink_sendmsg(const struct lttctl_handle *h,
108 const struct msghdr *msg,
109 unsigned int flags)
110 {
111 int status = sendmsg(h->fd, msg, flags);
112 if (status < 0)
113 lttctl_errno = LTTCTL_ERR_SEND;
114 return status;
115 }
116
117 static ssize_t lttctl_netlink_recvfrom(const struct lttctl_handle *h,
118 unsigned char *buf, size_t len,
119 int timeout)
120 {
121 int addrlen, status;
122 struct nlmsghdr *nlh;
123
124 if (len < sizeof(struct nlmsghdr)) {
125 lttctl_errno = LTTCTL_ERR_RECVBUF;
126 lttctl_perror("Netlink recvfrom");
127 return -1;
128 }
129 addrlen = sizeof(h->peer);
130
131 if (timeout != 0) {
132 int ret;
133 struct timeval tv;
134 fd_set read_fds;
135
136 if (timeout < 0) {
137 /* non-block non-timeout */
138 tv.tv_sec = 0;
139 tv.tv_usec = 0;
140 } else {
141 tv.tv_sec = timeout / 1000000;
142 tv.tv_usec = timeout % 1000000;
143 }
144
145 FD_ZERO(&read_fds);
146 FD_SET(h->fd, &read_fds);
147 ret = select(h->fd+1, &read_fds, NULL, NULL, &tv);
148 if (ret < 0) {
149 if (errno == EINTR) {
150 printf("eintr\n");
151 return 0;
152 } else {
153 lttctl_errno = LTTCTL_ERR_RECV;
154 lttctl_perror("Netlink recvfrom");
155 return -1;
156 }
157 }
158 if (!FD_ISSET(h->fd, &read_fds)) {
159 lttctl_errno = LTTCTL_ERR_TIMEOUT;
160 printf("timeout\n");
161 return 0;
162 }
163 }
164 status = recvfrom(h->fd, buf, len, 0,
165 (struct sockaddr *)&h->peer, &addrlen);
166
167 if (status < 0) {
168 lttctl_errno = LTTCTL_ERR_RECV;
169 lttctl_perror("Netlink recvfrom");
170 return status;
171 }
172 if (addrlen != sizeof(h->peer)) {
173 lttctl_errno = LTTCTL_ERR_RECV;
174 lttctl_perror("Netlink recvfrom");
175 return -1;
176 }
177 if (h->peer.nl_pid != 0) {
178 lttctl_errno = LTTCTL_ERR_RECV;
179 lttctl_perror("Netlink recvfrom");
180 return -1;
181 }
182 if (status == 0) {
183 lttctl_errno = LTTCTL_ERR_NLEOF;
184 lttctl_perror("Netlink recvfrom");
185 return -1;
186 }
187 nlh = (struct nlmsghdr *)buf;
188 if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > status) {
189 lttctl_errno = LTTCTL_ERR_RTRUNC;
190 lttctl_perror("Netlink recvfrom");
191 return -1;
192 }
193
194
195 return status;
196 }
197
198
199 static char *lttctl_strerror(int errcode)
200 {
201 if (errcode < 0 || errcode > LTTCTL_MAXERR)
202 errcode = LTTCTL_ERR_IMPL;
203 return lttctl_errmap[errcode].message;
204 }
205
206
207 char *lttctl_errstr(void)
208 {
209 return lttctl_strerror(lttctl_errno);
210 }
211
212 void lttctl_perror(const char *s)
213 {
214 if (s)
215 fputs(s, stderr);
216 else
217 fputs("ERROR", stderr);
218 if (lttctl_errno)
219 fprintf(stderr, ": %s", lttctl_errstr());
220 if (errno)
221 fprintf(stderr, ": %s", strerror(errno));
222 fputc('\n', stderr);
223 }
224
225 /* public interface */
226
227 /*
228 * Create and initialise an lttctl handle.
229 */
230 struct lttctl_handle *lttctl_create_handle(void)
231 {
232 int status;
233 struct lttctl_handle *h;
234
235 h = (struct lttctl_handle *)malloc(sizeof(struct lttctl_handle));
236 if (h == NULL) {
237 lttctl_errno = LTTCTL_ERR_HANDLE;
238 lttctl_perror("Create handle");
239 goto alloc_error;
240 }
241
242 memset(h, 0, sizeof(struct lttctl_handle));
243
244 h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_LTT);
245
246 if (h->fd == -1) {
247 lttctl_errno = LTTCTL_ERR_SOCKET;
248 lttctl_perror("Create handle");
249 goto socket_error;
250 }
251 memset(&h->local, 0, sizeof(struct sockaddr_nl));
252 h->local.nl_family = AF_NETLINK;
253 h->local.nl_pid = getpid();
254 h->local.nl_groups = 0;
255 status = bind(h->fd, (struct sockaddr *)&h->local, sizeof(h->local));
256 if (status == -1) {
257 lttctl_errno = LTTCTL_ERR_BIND;
258 lttctl_perror("Create handle");
259 goto bind_error;
260 }
261 memset(&h->peer, 0, sizeof(struct sockaddr_nl));
262 h->peer.nl_family = AF_NETLINK;
263 h->peer.nl_pid = 0;
264 h->peer.nl_groups = 0;
265 return h;
266
267 /* Error condition */
268 bind_error:
269 socket_error:
270 close(h->fd);
271 alloc_error:
272 free(h);
273 return NULL;
274 }
275
276 /*
277 * No error condition is checked here at this stage, but it may happen
278 * if/when reliable messaging is implemented.
279 */
280 int lttctl_destroy_handle(struct lttctl_handle *h)
281 {
282 if (h) {
283 close(h->fd);
284 free(h);
285 }
286 return 0;
287 }
288
289
290 int lttctl_create_trace(const struct lttctl_handle *h,
291 char *name, enum trace_mode mode)
292 {
293 int err;
294
295 struct {
296 struct nlmsghdr nlh;
297 lttctl_peer_msg_t msg;
298 } req;
299 struct {
300 struct nlmsghdr nlh;
301 struct nlmsgerr nlerr;
302 lttctl_peer_msg_t msg;
303 } ack;
304
305 memset(&req, 0, sizeof(req));
306 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
307 req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
308 req.nlh.nlmsg_type = LTTCTLM_CONTROL;
309 req.nlh.nlmsg_pid = h->local.nl_pid;
310 req.nlh.nlmsg_seq = 0;
311
312 strncpy(req.msg.trace_name, name, NAME_MAX);
313 req.msg.op = OP_CREATE;
314 req.msg.args.mode = mode;
315
316 err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
317 if(err < 0) goto senderr;
318
319 err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0);
320 if(err < 0) goto senderr;
321
322 err = ack.nlerr.error;
323 if(err != 0) {
324 errno = err;
325 lttctl_perror("Create Trace Error");
326 return -1;
327 }
328
329 return 0;
330
331 senderr:
332 lttctl_perror("Create Trace Error");
333 return err;
334 }
335
336 int lttctl_destroy_trace(const struct lttctl_handle *h,
337 char *name)
338 {
339 struct {
340 struct nlmsghdr nlh;
341 lttctl_peer_msg_t msg;
342 } req;
343 struct {
344 struct nlmsghdr nlh;
345 struct nlmsgerr nlerr;
346 lttctl_peer_msg_t msg;
347 } ack;
348 int err;
349
350 memset(&req, 0, sizeof(req));
351 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
352 req.nlh.nlmsg_flags = NLM_F_REQUEST;
353 req.nlh.nlmsg_type = LTTCTLM_CONTROL;
354 req.nlh.nlmsg_pid = h->local.nl_pid;
355
356 strncpy(req.msg.trace_name, name, NAME_MAX);
357 req.msg.op = OP_DESTROY;
358
359 err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
360 if(err < 0) goto senderr;
361
362 err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0);
363 if(err < 0) goto senderr;
364
365 err = ack.nlerr.error;
366 if(err != 0) {
367 errno = err;
368 lttctl_perror("Destroy Trace Channels Error");
369 return -1;
370 }
371
372 return 0;
373
374 senderr:
375 lttctl_perror("Destroy Trace Channels Error");
376 return err;
377
378 }
379
380 int lttctl_start(const struct lttctl_handle *h,
381 char *name)
382 {
383 struct {
384 struct nlmsghdr nlh;
385 lttctl_peer_msg_t msg;
386 } req;
387 struct {
388 struct nlmsghdr nlh;
389 struct nlmsgerr nlerr;
390 lttctl_peer_msg_t msg;
391 } ack;
392
393 int err;
394
395 memset(&req, 0, sizeof(req));
396 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
397 req.nlh.nlmsg_flags = NLM_F_REQUEST;
398 req.nlh.nlmsg_type = LTTCTLM_CONTROL;
399 req.nlh.nlmsg_pid = h->local.nl_pid;
400
401 strncpy(req.msg.trace_name, name, NAME_MAX);
402 req.msg.op = OP_START;
403
404 err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
405 if(err < 0) goto senderr;
406
407 err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0);
408 if(err < 0) goto senderr;
409
410 err = ack.nlerr.error;
411 if(err != 0) {
412 errno = err;
413 lttctl_perror("Start Trace Error");
414 return -1;
415 }
416
417 return 0;
418
419 senderr:
420 lttctl_perror("Start Trace Error");
421 return err;
422
423 }
424
425 int lttctl_stop(const struct lttctl_handle *h,
426 char *name)
427 {
428 struct {
429 struct nlmsghdr nlh;
430 lttctl_peer_msg_t msg;
431 } req;
432 struct {
433 struct nlmsghdr nlh;
434 struct nlmsgerr nlerr;
435 lttctl_peer_msg_t msg;
436 } ack;
437 int err;
438
439 memset(&req, 0, sizeof(req));
440 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
441 req.nlh.nlmsg_flags = NLM_F_REQUEST;
442 req.nlh.nlmsg_type = LTTCTLM_CONTROL;
443 req.nlh.nlmsg_pid = h->local.nl_pid;
444
445 strncpy(req.msg.trace_name, name, NAME_MAX);
446 req.msg.op = OP_STOP;
447
448 err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
449 if(err < 0) goto senderr;
450
451 err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0);
452 if(err < 0) goto senderr;
453
454 err = ack.nlerr.error;
455 if(err != 0) {
456 errno = err;
457 lttctl_perror("Stop Trace Error");
458 return -1;
459 }
460
461 return 0;
462
463 senderr:
464 lttctl_perror("Stop Trace Error");
465 return err;
466 }
This page took 0.038539 seconds and 4 git commands to generate.