3 * lsused - Linux SUSpend Event monitoring Daemon
5 * apps and services can send fds to this daemon.
6 * We will not allow suspend to happen if any fd is readable.
7 * A client should also notice that it is readable, take a
8 * shared lock on the suspend/disabled file and then read the event.
10 * The client opens connects on a unix domain socket to
11 * /var/run/suspend/registration
12 * It sets 'W' with some fds attached to be watched.
13 * On notification if any fds are readable we send by 'S' to say
14 * Suspend Soon and wait for 'R' to say 'Ready'.
15 * We don't bother checking the fds again until the next suspend
19 * Copyright (C) 2011 Neil Brown <neilb@suse.de>
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License along
32 * with this program; if not, write to the Free Software Foundation, Inc.,
33 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
39 #include <sys/socket.h>
48 int sent; /* 'S' has been sent */
49 int suspending; /* ... 'R' hasn't been received yet */
55 int waiting; /* Number of replies waiting for */
56 struct handle *handles; /* linked list of handles */
57 struct pollfd *fds; /* for 'poll' */
58 struct handle **hans; /* aligned with fds */
59 int nfds; /* number of active 'fds' */
60 int fdsize; /* allocated size of fds array */
61 void *sus; /* handle from suspend_watch */
64 static void del_fd(struct state *state, int i)
66 state->fds[i] = state->fds[state->nfds - 1];
67 state->hans[i] = state->hans[state->nfds - 1];
71 static void add_fd(struct state *state, struct handle *han,
75 if (state->nfds >= state->fdsize) {
76 /*need to make bigger */
80 state->fds = realloc(state->fds,
81 need * sizeof(struct pollfd));
82 state->hans = realloc(state->hans,
83 need * sizeof(struct handle *));
86 state->fds[n].fd = fd;
87 state->fds[n].events = events;
91 static void add_han(struct handle *han, struct state *state)
94 han->next = state->handles;
98 static void del_han(struct handle *han)
100 struct state *state = han->state;
101 struct handle **hanp = &state->handles;
105 /* First remove the fds; */
106 for (i = 0; i < state->nfds ; i++)
107 if (state->hans[i] == han) {
112 /* Then remove the han */
113 for (h = *hanp; h; hanp = &h->next, h = *hanp) {
121 static void do_read(int fd, short ev, void *data)
123 struct handle *han = data;
137 msg.msg_control = mbuf;
138 msg.msg_controllen = sizeof(mbuf);
141 if (recvmsg(fd, &msg, MSG_CMSG_CLOEXEC|MSG_DONTWAIT) < 0
147 for (cm = CMSG_FIRSTHDR(&msg);
149 cm = CMSG_NXTHDR(&msg, cm))
150 if (cm->cmsg_level == SOL_SOCKET &&
151 cm->cmsg_type == SCM_RIGHTS) {
152 int *fdptr = (int*)CMSG_DATA(cm);
153 int n = (cm->cmsg_len -
154 CMSG_ALIGN(sizeof(struct cmsghdr)))
157 for (i = 0; i < n; i++)
158 add_fd(han->state, han, fdptr[i],
165 if (han->suspending) {
167 han->state->waiting--;
168 if (han->state->waiting == 0)
169 suspend_ok(han->state->sus);
180 static void do_accept(int fd, short ev, void *data)
182 struct state *state = data;
184 int newfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
188 han = malloc(sizeof(*han));
197 event_set(&han->ev, newfd, EV_READ | EV_PERSIST, do_read, han);
198 event_add(&han->ev, NULL);
199 write(newfd, "A", 1);
202 static int do_suspend(void *data)
204 struct state *state = data;
209 n = poll(state->fds, state->nfds, 0);
211 /* nothing happening */
213 for (han = state->handles ; han ; han = han->next)
216 for (i = 0; i < state->nfds; i++)
217 if (state->fds[i].revents) {
218 han = state->hans[i];
222 write(EVENT_FD(&han->ev), "S", 1);
227 return (state->waiting == 0);
230 static void did_resume(void *data)
232 struct state *state = data;
235 for (han = state->handles ; han ; han = han->next)
237 write(EVENT_FD(&han->ev), "A", 1);
240 main(int argc, char *argv[])
242 struct sockaddr_un addr;
247 memset(&state, 0, sizeof(state));
249 s = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
250 addr.sun_family = AF_UNIX;
251 strcpy(addr.sun_path, "/var/run/suspend/registration");
252 unlink("/var/run/suspend/registration");
253 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
256 /* Incase someone is waiting for us... */
261 state.sus = suspend_watch(do_suspend, did_resume, &state);
262 event_set(&ev, s, EV_READ | EV_PERSIST, do_accept, &state);
263 event_add(&ev, NULL);