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