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