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