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