3 * Use libevent to watch for suspends and take action.
4 * The calling program must already have a libevent loop running.
5 * One or two callbacks are registered with suspend_watch.
6 * The first is required and gets called just before suspend.
7 * It must return promptly but may call suspend_block first.
8 * The second is options and will get called after resume.
11 * Copyright (C) 2011 Neil Brown <neilb@suse.de>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
37 int (*will_suspend)(void *data);
38 void (*did_resume)(void *data);
45 static void checkdir(int efd, short ev, void *vp)
56 if (han->nextfd >= 0) {
57 /*suspended - maybe not any more */
62 /* back from resume */
64 han->fd = han->nextfd;
67 han->did_resume(han->data);
68 /* Fall through incase suspend has started again */
71 /* not suspended yet */
72 if (fstat(han->fd, &stb) == 0
77 /* We need to move on now. */
78 fd = open("/run/suspend/watching-next", O_RDONLY|O_CLOEXEC);
81 rv = han->will_suspend(han->data);
86 int suspend_ok(void *v)
89 flock(han->fd, LOCK_UN);
93 void *suspend_watch(int (*will_suspend)(void *data),
94 void (*did_resume)(void *data),
97 struct cb *han = malloc(sizeof(*han));
104 han->will_suspend = will_suspend;
105 han->did_resume = did_resume;
108 signal_set(&han->ev, SIGIO, checkdir, han);
109 signal_add(&han->ev, NULL);
110 han->dirfd = open("/run/suspend", O_RDONLY|O_CLOEXEC);
113 fcntl(han->dirfd, F_NOTIFY, DN_MODIFY | DN_MULTISHOT);
115 fd = open("/run/suspend/watching", O_RDONLY|O_CLOEXEC);
119 /* OK, he won't suspend until I say OK. */
123 signal_del(&han->ev);
131 void suspend_unwatch(void *v)
136 signal_del(&han->ev);
139 if (han->nextfd >= 0)