/******************************************************************************* * Copyright (c) 2013 Linaro * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Linaro *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include enum type_t { TYPE_SYSFS, TYPE_NETLINK, }; static int sysfs_handle_open(char *name) { char sysfs[256] = "/sys/devices/virtual/xt_idletimer/timers/"; char buffer[256]; int r, rd; strcat(sysfs, name); r = open(sysfs, O_RDONLY); if (r < 0) return r; rd = read(r, buffer, sizeof(buffer)); return r; } static int netlink_socket_open(struct sockaddr_nl *s_nladdr) { int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); bind(fd, (struct sockaddr*)s_nladdr, sizeof(*s_nladdr)); return fd; } static int do_wait(char *nick, enum type_t type, int seconds) { struct pollfd pfd; int r; short exp; struct sockaddr_nl s_nladdr; static char buffer[256]; char *ptr; pfd.revents = 0; if (type == TYPE_SYSFS) { pfd.fd = sysfs_handle_open(nick); pfd.events = POLLPRI | POLLERR; exp = POLLPRI | POLLERR; } if (type == TYPE_NETLINK) { memset(&s_nladdr, 0 ,sizeof(s_nladdr)); s_nladdr.nl_family = AF_NETLINK ; s_nladdr.nl_pid = getpid(); s_nladdr.nl_groups = 0xffffffff; pfd.fd = netlink_socket_open(&s_nladdr); pfd.events = POLLIN; exp = POLLIN; } r = poll(&pfd, 1, seconds * 1000); if (r <= 0) return r; if (type == TYPE_NETLINK) { struct msghdr msg; struct iovec iov[2]; struct nlmsghdr nlh; iov[0].iov_base = (void *)&nlh; iov[0].iov_len = sizeof(nlh); iov[1].iov_base = (void *)buffer; iov[1].iov_len = sizeof(buffer); msg.msg_name = &s_nladdr; msg.msg_namelen = sizeof(s_nladdr); msg.msg_iov = iov; msg.msg_iovlen = sizeof(iov)/sizeof(iov[0]); memset(buffer, 0, sizeof(buffer)); r = recvmsg(pfd.fd, &msg, 0); } else { lseek(pfd.fd, 0, SEEK_SET); r = read(pfd.fd, buffer, sizeof(buffer)); } if (r < 0) return r; for (ptr = buffer; ptr - buffer < r; ptr = ptr + strlen(ptr) + 1) { if (strlen(ptr) == 0) continue; printf("%s\n", ptr); } close(pfd.fd); return 1; } int main(int argc, char *argv[]) { int c, r, opti; int timeout_sec = 10; struct option lopt[] = { { "timeout", required_argument, NULL, 't' }, { "sysfs", required_argument, NULL, 's' }, { "netlink", no_argument, NULL, 'n' }, { NULL, 0, NULL, 0 }, }; char *shopt = "ts:n"; char *nick = NULL; enum type_t type; while ((c = getopt_long(argc, argv, shopt, lopt, &opti)) != -1 ) { switch (c) { case 't': timeout_sec = atoi(optarg); break; case 's': case 'n': if (!nick) { if (optarg) { nick = strdup(optarg); } else { nick = (char*)0xffffffff; } type = (c == 's' ? TYPE_SYSFS : TYPE_NETLINK); } else { printf("sysfs and netlink could not be used at the same time\n"); exit(1); } break; default: printf("Hmmm, c = 0x%x (%c)\n", c, isprint(c) ? c : '*'); break; } } if (!nick) { printf("Sorry, you have to provide one of --sysfs=ARG or --netlink\n"); return EINVAL; } r = do_wait(nick, type, timeout_sec); if (r < 0) { perror("do_wait"); return r; } else if (r == 0) { printf("No data within %d seconds\n", timeout_sec); return 1; } printf("OK\n"); return 0; }