10 #include <talloc/talloc.h>
11 #include <list/list.h>
13 #include <types/types.h>
14 #include <system/system.h>
16 #include "device-handler.h"
17 #include "discover-server.h"
23 struct device_handler {
24 struct discover_server *server;
26 struct device **devices;
27 unsigned int n_devices;
33 * device_handler_add - Add a device to the handler device array.
36 static void device_handler_add(struct device_handler *handler,
37 struct device *device)
40 handler->devices = talloc_realloc(handler, handler->devices,
41 struct device *, handler->n_devices);
42 handler->devices[handler->n_devices - 1] = device;
46 * device_handler_remove - Remove a device from the handler device array.
49 static void device_handler_remove(struct device_handler *handler,
50 struct device *device)
54 for (i = 0; i < handler->n_devices; i++)
55 if (handler->devices[i] == device)
58 if (i == handler->n_devices) {
59 assert(0 && "unknown device");
64 memmove(&handler->devices[i], &handler->devices[i + 1],
65 (handler->n_devices - i) * sizeof(handler->devices[0]));
66 handler->devices = talloc_realloc(handler, handler->devices,
67 struct device *, handler->n_devices);
71 * device_handler_find - Find a handler device by id.
74 static struct device *device_handler_find(struct device_handler *handler,
81 for (i = 0; i < handler->n_devices; i++)
82 if (handler->devices[i]->id
83 && streq(handler->devices[i]->id, id))
84 return handler->devices[i];
86 pb_log("%s: unknown device: %s\n", __func__, id);
91 * device_handler_get_device_count - Get the count of current handler devices.
94 int device_handler_get_device_count(const struct device_handler *handler)
96 return handler->n_devices;
100 * device_handler_get_device - Get a handler device by index.
103 const struct device *device_handler_get_device(
104 const struct device_handler *handler, unsigned int index)
106 if (index >= handler->n_devices) {
107 assert(0 && "bad index");
111 return handler->devices[index];
114 static void setup_device_links(struct discover_context *ctx)
121 .dir = "disk/by-uuid"
124 .env = "ID_FS_LABEL",
125 .dir = "disk/by-label"
132 for (link = links; link->env; link++) {
133 char *enc, *dir, *path;
136 value = event_get_param(ctx->event, link->env);
137 if (!value || !*value)
140 enc = encode_label(ctx, value);
141 dir = join_paths(ctx, mount_base(), link->dir);
142 path = join_paths(ctx, dir, value);
144 if (!pb_mkdir_recursive(dir)) {
146 if (symlink(ctx->mount_path, path)) {
147 pb_log("symlink(%s,%s): %s\n",
148 ctx->mount_path, path,
152 int i = ctx->n_links++;
153 ctx->links = talloc_realloc(ctx,
156 ctx->links[i] = path;
166 static void remove_device_links(struct discover_context *ctx)
170 for (i = 0; i < ctx->n_links; i++)
171 unlink(ctx->links[i]);
174 static int mount_device(struct discover_context *ctx)
176 const char *mountpoint;
179 if (!ctx->mount_path) {
180 mountpoint = mountpoint_for_device(ctx->device_path);
181 ctx->mount_path = talloc_strdup(ctx, mountpoint);
184 if (pb_mkdir_recursive(ctx->mount_path))
185 pb_log("couldn't create mount directory %s: %s\n",
186 ctx->mount_path, strerror(errno));
188 argv[0] = pb_system_apps.mount;
189 argv[1] = ctx->device_path;
190 argv[2] = ctx->mount_path;
195 if (pb_run_cmd(argv, 1, 0)) {
197 /* Retry mount without ro option. */
199 argv[0] = pb_system_apps.mount;
200 argv[1] = ctx->device_path;
201 argv[2] = ctx->mount_path;
204 if (pb_run_cmd(argv, 1, 0))
208 setup_device_links(ctx);
212 pb_rmdir_recursive(mount_base(), ctx->mount_path);
216 static int umount_device(struct discover_context *ctx)
221 remove_device_links(ctx);
225 pb_log("%s: fork failed: %s\n", __func__, strerror(errno));
230 execl(pb_system_apps.umount, pb_system_apps.umount,
231 ctx->mount_path, NULL);
235 if (waitpid(pid, &status, 0) == -1) {
236 pb_log("%s: waitpid failed: %s\n", __func__,
241 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
244 pb_rmdir_recursive(mount_base(), ctx->mount_path);
249 static struct discover_context *find_context(struct device_handler *handler,
252 struct discover_context *ctx;
254 list_for_each_entry(&handler->contexts, ctx, list) {
255 if (!strcmp(ctx->id, id))
262 static int destroy_context(void *arg)
264 struct discover_context *ctx = arg;
266 list_remove(&ctx->list);
272 static int handle_add_udev_event(struct device_handler *handler,
275 struct discover_context *ctx;
279 /* create our context */
280 ctx = talloc(handler, struct discover_context);
282 ctx->mount_path = NULL;
286 ctx->id = talloc_strdup(ctx, event->device);
288 devname = event_get_param(ctx->event, "DEVNAME");
290 ctx->device_path = talloc_strdup(ctx, devname);
292 rc = mount_device(ctx);
298 list_add(&handler->contexts, &ctx->list);
299 talloc_set_destructor(ctx, destroy_context);
301 /* set up the top-level device */
302 ctx->device = talloc_zero(ctx, struct device);
303 ctx->device->id = talloc_strdup(ctx->device, ctx->id);
304 list_init(&ctx->device->boot_options);
306 /* run the parsers */
307 iterate_parsers(ctx);
309 /* add device to handler device array */
310 device_handler_add(handler, ctx->device);
312 discover_server_notify_add(handler->server, ctx->device);
317 static int handle_remove_udev_event(struct device_handler *handler,
320 struct discover_context *ctx;
322 ctx = find_context(handler, event->device);
326 discover_server_notify_remove(handler->server, ctx->device);
328 /* remove device from handler device array */
329 device_handler_remove(handler, ctx->device);
336 static int handle_add_user_event(struct device_handler *handler,
339 struct device *device;
341 assert(event->device);
343 device = talloc_zero(handler, struct device);
348 device->id = talloc_strdup(device, event->device);
349 list_init(&device->boot_options);
351 parse_user_event(device, event);
353 discover_server_notify_add(handler->server, device);
355 /* add device to handler device array */
356 device_handler_add(handler, device);
365 static int handle_remove_user_event(struct device_handler *handler,
368 struct device *device = device_handler_find(handler, event->device);
373 discover_server_notify_remove(handler->server, device);
375 /* remove device from handler device array */
376 device_handler_remove(handler, device);
382 typedef int (*event_handler)(struct device_handler *, struct event *);
384 static event_handler handlers[EVENT_TYPE_MAX][EVENT_ACTION_MAX] = {
385 [EVENT_TYPE_UDEV] = {
386 [EVENT_ACTION_ADD] = handle_add_udev_event,
387 [EVENT_ACTION_REMOVE] = handle_remove_udev_event,
389 [EVENT_TYPE_USER] = {
390 [EVENT_ACTION_ADD] = handle_add_user_event,
391 [EVENT_ACTION_REMOVE] = handle_remove_user_event,
395 int device_handler_event(struct device_handler *handler,
398 if (event->type >= EVENT_TYPE_MAX ||
399 event->action >= EVENT_ACTION_MAX ||
400 !handlers[event->type][event->action]) {
401 pb_log("%s unknown type/action: %d/%d\n", __func__,
402 event->type, event->action);
406 return handlers[event->type][event->action](handler, event);
409 struct device_handler *device_handler_init(struct discover_server *server)
411 struct device_handler *handler;
413 handler = talloc(NULL, struct device_handler);
414 handler->devices = NULL;
415 handler->n_devices = 0;
416 handler->server = server;
418 list_init(&handler->contexts);
420 /* set up our mount point base */
421 pb_mkdir_recursive(mount_base());
428 void device_handler_destroy(struct device_handler *handler)
430 talloc_free(handler);