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