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>
ace0e68d 28#include <linux/netlink.h>
264cbffe 29#include <libltt/libltt.h>
ace0e68d 30#include <errno.h>
31#include <stdio.h>
31d2c6b0 32
33/* Private interface */
34
35enum {
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
57struct lttctl_errmap_t {
58 int errcode;
59 char *message;
60} lttctl_errmap[] = {
ace0e68d 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" }
31d2c6b0 78};
79
80static int lttctl_errno = LTTCTL_ERR_NONE;
81
82
83static ssize_t lttctl_netlink_sendto(const struct lttctl_handle *h,
84 const void *msg, size_t len);
85
86static ssize_t lttctl_netlink_recvfrom(const struct lttctl_handle *h,
87 unsigned char *buf, size_t len,
88 int timeout);
89
90static ssize_t lttctl_netlink_sendmsg(const struct lttctl_handle *h,
91 const struct msghdr *msg,
92 unsigned int flags);
93
94static char *lttctl_strerror(int errcode);
95
ace0e68d 96void lttctl_perror(const char *s);
97
31d2c6b0 98static 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;
ace0e68d 105
31d2c6b0 106 return status;
107}
108
109static 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
119static 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
ace0e68d 126 if (len < sizeof(struct nlmsghdr)) {
31d2c6b0 127 lttctl_errno = LTTCTL_ERR_RECVBUF;
ace0e68d 128 lttctl_perror("Netlink recvfrom");
31d2c6b0 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) {
ace0e68d 152 printf("eintr\n");
31d2c6b0 153 return 0;
154 } else {
ace0e68d 155 lttctl_errno = LTTCTL_ERR_RECV;
156 lttctl_perror("Netlink recvfrom");
31d2c6b0 157 return -1;
158 }
159 }
160 if (!FD_ISSET(h->fd, &read_fds)) {
ace0e68d 161 lttctl_errno = LTTCTL_ERR_TIMEOUT;
162 printf("timeout\n");
31d2c6b0 163 return 0;
164 }
165 }
166 status = recvfrom(h->fd, buf, len, 0,
167 (struct sockaddr *)&h->peer, &addrlen);
ace0e68d 168
31d2c6b0 169 if (status < 0) {
170 lttctl_errno = LTTCTL_ERR_RECV;
ace0e68d 171 lttctl_perror("Netlink recvfrom");
31d2c6b0 172 return status;
173 }
174 if (addrlen != sizeof(h->peer)) {
175 lttctl_errno = LTTCTL_ERR_RECV;
ace0e68d 176 lttctl_perror("Netlink recvfrom");
31d2c6b0 177 return -1;
178 }
179 if (h->peer.nl_pid != 0) {
180 lttctl_errno = LTTCTL_ERR_RECV;
ace0e68d 181 lttctl_perror("Netlink recvfrom");
31d2c6b0 182 return -1;
183 }
184 if (status == 0) {
185 lttctl_errno = LTTCTL_ERR_NLEOF;
ace0e68d 186 lttctl_perror("Netlink recvfrom");
31d2c6b0 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;
ace0e68d 192 lttctl_perror("Netlink recvfrom");
31d2c6b0 193 return -1;
194 }
ace0e68d 195
196
31d2c6b0 197 return status;
198}
199
200
201static 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
ace0e68d 209char *lttctl_errstr(void)
210{
211 return lttctl_strerror(lttctl_errno);
212}
213
214void 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}
31d2c6b0 226
227/* public interface */
228
229/*
230 * Create and initialise an lttctl handle.
231 */
232struct 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) {
ace0e68d 239 lttctl_errno = LTTCTL_ERR_HANDLE;
240 lttctl_perror("Create handle");
241 goto alloc_error;
31d2c6b0 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;
ace0e68d 250 lttctl_perror("Create handle");
251 goto socket_error;
31d2c6b0 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;
ace0e68d 260 lttctl_perror("Create handle");
261 goto bind_error;
31d2c6b0 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;
ace0e68d 268
269 /* Error condition */
270bind_error:
271socket_error:
272 close(h->fd);
273alloc_error:
274 free(h);
275 return NULL;
31d2c6b0 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 */
282int 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
ace0e68d 292int lttctl_create_trace(const struct lttctl_handle *h,
31d2c6b0 293 char *name, enum trace_mode mode)
294{
ace0e68d 295 int err;
296
31d2c6b0 297 struct {
298 struct nlmsghdr nlh;
299 lttctl_peer_msg_t msg;
300 } req;
ace0e68d 301 struct {
302 struct nlmsghdr nlh;
303 struct nlmsgerr nlerr;
304 lttctl_peer_msg_t msg;
305 } ack;
31d2c6b0 306
307 memset(&req, 0, sizeof(req));
ace0e68d 308 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
309 req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
31d2c6b0 310 req.nlh.nlmsg_type = LTTCTLM_CONTROL;
311 req.nlh.nlmsg_pid = h->local.nl_pid;
ace0e68d 312 req.nlh.nlmsg_seq = 0;
31d2c6b0 313
314 strncpy(req.msg.trace_name, name, NAME_MAX);
315 req.msg.op = OP_CREATE;
316 req.msg.args.mode = mode;
317
ace0e68d 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
333senderr:
334 lttctl_perror("Create Trace Error");
335 return err;
31d2c6b0 336}
337
ace0e68d 338int lttctl_destroy_trace(const struct lttctl_handle *h,
31d2c6b0 339 char *name)
340{
341 struct {
342 struct nlmsghdr nlh;
343 lttctl_peer_msg_t msg;
344 } req;
ace0e68d 345 struct {
346 struct nlmsghdr nlh;
347 struct nlmsgerr nlerr;
348 lttctl_peer_msg_t msg;
349 } ack;
350 int err;
31d2c6b0 351
352 memset(&req, 0, sizeof(req));
ace0e68d 353 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
31d2c6b0 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
ace0e68d 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
376senderr:
377 lttctl_perror("Destroy Trace Channels Error");
378 return err;
379
31d2c6b0 380}
381
ace0e68d 382int lttctl_start(const struct lttctl_handle *h,
31d2c6b0 383 char *name)
384{
385 struct {
386 struct nlmsghdr nlh;
387 lttctl_peer_msg_t msg;
388 } req;
ace0e68d 389 struct {
390 struct nlmsghdr nlh;
391 struct nlmsgerr nlerr;
392 lttctl_peer_msg_t msg;
393 } ack;
394
395 int err;
31d2c6b0 396
397 memset(&req, 0, sizeof(req));
ace0e68d 398 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
31d2c6b0 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
ace0e68d 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
421senderr:
422 lttctl_perror("Start Trace Error");
423 return err;
424
31d2c6b0 425}
426
ace0e68d 427int lttctl_stop(const struct lttctl_handle *h,
31d2c6b0 428 char *name)
429{
430 struct {
431 struct nlmsghdr nlh;
432 lttctl_peer_msg_t msg;
433 } req;
ace0e68d 434 struct {
435 struct nlmsghdr nlh;
436 struct nlmsgerr nlerr;
437 lttctl_peer_msg_t msg;
438 } ack;
439 int err;
31d2c6b0 440
441 memset(&req, 0, sizeof(req));
ace0e68d 442 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
31d2c6b0 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
ace0e68d 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
465senderr:
466 lttctl_perror("Stop Trace Error");
467 return err;
31d2c6b0 468}
This page took 0.058987 seconds and 4 git commands to generate.