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