Add discover user event
[petitboot] / discover / user-event.c
1 /*
2  *  Copyright (C) 2009 Sony Computer Entertainment Inc.
3  *  Copyright 2009 Sony Corp.
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; version 2 of the License.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #if defined(HAVE_CONFIG_H)
20 #include "config.h"
21 #endif
22
23 #define _GNU_SOURCE
24 #include <assert.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <sys/socket.h>
28 #include <sys/types.h>
29 #include <sys/un.h>
30
31 #include <log/log.h>
32 #include <talloc/talloc.h>
33 #include <waiter/waiter.h>
34
35 #include "device-handler.h"
36 #include "event.h"
37 #include "user-event.h"
38
39
40 struct user_event {
41         struct device_handler *handler;
42         int socket;
43 };
44
45 static void user_event_print_event(struct event __attribute__((unused)) *event)
46 {
47         const char *action, *params[] = {
48                 "name", "image", "args",
49                 NULL,
50         };
51         int i;
52
53         action = event->action == EVENT_ACTION_ADD ? "add" : "remove";
54
55         pb_log("user_event %s event:\n", action);
56         pb_log("\tdevice: %s\n", event->device);
57
58         for (i = 0; params[i]; i++)
59                 pb_log("\t%-12s => %s\n",
60                                 params[i], event_get_param(event, params[i]));
61 }
62
63 static void user_event_handle_message(struct user_event *uev, char *buf,
64         int len)
65 {
66         int result;
67         struct event *event;
68
69         event = talloc(uev, struct event);
70         event->type = EVENT_TYPE_USER;
71
72         result = event_parse_ad_message(event, buf, len);
73
74         if (result)
75                 return;
76
77         user_event_print_event(event);
78         device_handler_event(uev->handler, event);
79         talloc_free(event);
80
81         return;
82 }
83
84 static int user_event_process(void *arg)
85 {
86         struct user_event *uev = arg;
87         char buf[PBOOT_USER_EVENT_SIZE];
88         int len;
89
90         len = recvfrom(uev->socket, buf, sizeof(buf), 0, NULL, NULL);
91
92         if (len < 0) {
93                 pb_log("%s: socket read failed: %s", __func__, strerror(errno));
94                 return 0;
95         }
96
97         if (len == 0) {
98                 pb_log("%s: empty", __func__);
99                 return 0;
100         }
101
102         pb_log("%s: %u bytes\n", __func__, len);
103
104         user_event_handle_message(uev, buf, len);
105
106         return 0;
107 }
108
109 static int user_event_destructor(void *arg)
110 {
111         struct user_event *uev = arg;
112
113         pb_log("%s\n", __func__);
114
115         if (uev->socket >= 0)
116                 close(uev->socket);
117
118         return 0;
119 }
120
121 struct user_event *user_event_init(struct device_handler *handler)
122 {
123         struct sockaddr_un addr;
124         struct user_event *uev;
125
126         unlink(PBOOT_USER_EVENT_SOCKET);
127
128         uev = talloc(NULL, struct user_event);
129
130         uev->handler = handler;
131
132         uev->socket = socket(AF_UNIX, SOCK_DGRAM, 0);
133         if (uev->socket < 0) {
134                 pb_log("%s: Error creating event handler socket: %s\n",
135                         __func__, strerror(errno));
136                 goto out_err;
137         }
138
139         talloc_set_destructor(uev, user_event_destructor);
140
141         memset(&addr, 0, sizeof(addr));
142         addr.sun_family = AF_UNIX;
143         strcpy(addr.sun_path, PBOOT_USER_EVENT_SOCKET);
144
145         if (bind(uev->socket, (struct sockaddr *)&addr, sizeof(addr))) {
146                 pb_log("Error binding event handler socket: %s\n",
147                         strerror(errno));
148         }
149
150         waiter_register(uev->socket, WAIT_IN, user_event_process, uev);
151
152         pb_log("%s: waiting on %s\n", __func__, PBOOT_USER_EVENT_SOCKET);
153
154         return uev;
155
156 out_err:
157         talloc_free(uev);
158         return NULL;
159 }
160
161 /**
162  * user_event_trigger - Trigger known user events
163  *
164  * SIGUSR1 causes udhcpc to renew the current lease or obtain a new lease.
165  */
166
167 void user_event_trigger(struct user_event __attribute__((unused)) *uev)
168 {
169         /* FIXME: todo */
170 }
171
172 void user_event_destroy(struct user_event *uev)
173 {
174         talloc_free(uev);
175 }