]> git.neil.brown.name Git - susman.git/blob - wakealarm.c
wakealarmd: cope with delta between system time and RTC time.
[susman.git] / wakealarm.c
1
2 /*
3  * Library code to allow libevent app to register for a wake alarm
4  * and register with wakealarmd to keep suspend at bay for the time.
5  *
6  * Copyright (C) 2011 Neil Brown <neilb@suse.de>
7  *
8  *    This program is free software; you can redistribute it and/or modify
9  *    it under the terms of the GNU General Public License as published by
10  *    the Free Software Foundation; either version 2 of the License, or
11  *    (at your option) any later version.
12  *
13  *    This program is distributed in the hope that it will be useful,
14  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *    GNU General Public License for more details.
17  *
18  *    You should have received a copy of the GNU General Public License along
19  *    with this program; if not, write to the Free Software Foundation, Inc.,
20  *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include <stdlib.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <stdio.h>
27 #include <event.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include "libsus.h"
31
32 struct han {
33         struct event    ev;
34         int             sock;
35         int             disable;
36         void            (*fn)(int,short,void*);
37         void            *data;
38 };
39
40 static void alarm_clock(int fd, short ev, void *data)
41 {
42         char buf[20];
43         int n;
44         struct han *h = data;
45
46         n = read(fd, buf, sizeof(buf)-1);
47         if (n < 0 && errno == EAGAIN)
48                 return;
49         if (n <= 0 ||
50             strncmp(buf, "Now", 3) == 0) {
51                 h->fn(-1, ev, h->data);
52                 wakealarm_destroy(&h->ev);
53         }
54         /* Some other message, keep waiting */
55 }
56
57 struct event *wakealarm_set(time_t when, void(*fn)(int, short, void*),
58                             void *data)
59 {
60         struct sockaddr_un addr;
61         struct han *h = malloc(sizeof(*h));
62         char buf[20];
63
64         if (!h)
65                 return NULL;
66
67         h->fn = fn;
68         h->data = data;
69         h->disable = suspend_open();
70         h->sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
71         if (h->sock < 0 || h->disable < 0)
72                 goto abort;
73
74         addr.sun_family = AF_UNIX;
75         strcpy(addr.sun_path, "/run/suspend/wakealarm");
76         if (connect(h->sock, (struct sockaddr*)&addr, sizeof(addr)) != 0)
77                 goto abort;
78
79         fcntl(h->sock, F_SETFL, fcntl(h->sock, F_GETFL, 0) | O_NONBLOCK);
80         sprintf(buf, "%lld\n", (long long)when);
81         write(h->sock, buf, strlen(buf));
82
83         event_set(&h->ev, h->sock, EV_READ|EV_PERSIST, alarm_clock, h);
84         event_add(&h->ev, NULL);
85
86         return &h->ev;
87
88 abort:
89         suspend_close(h->disable);
90         if (h->sock >= 0)
91                 close(h->sock);
92         free(h);
93         return NULL;
94 }
95
96 void wakealarm_destroy(struct event *ev)
97 {
98         struct han *h = (struct han *)ev;
99         event_del(&h->ev);
100         close(h->sock);
101         suspend_close(h->disable);
102         free(h);
103 }