]> git.ozlabs.org Git - petitboot/blob - discover/device-handler.c
ui/ncurses: Add support for 'add-url' action
[petitboot] / discover / device-handler.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <stdbool.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <mntent.h>
8 #include <sys/stat.h>
9 #include <sys/wait.h>
10 #include <sys/mount.h>
11
12 #include <talloc/talloc.h>
13 #include <list/list.h>
14 #include <log/log.h>
15 #include <types/types.h>
16 #include <system/system.h>
17 #include <process/process.h>
18 #include <url/url.h>
19 #include <i18n/i18n.h>
20
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <netdb.h>
24 #include <arpa/inet.h>
25
26 #include "device-handler.h"
27 #include "discover-server.h"
28 #include "user-event.h"
29 #include "platform.h"
30 #include "event.h"
31 #include "parser.h"
32 #include "resource.h"
33 #include "paths.h"
34 #include "sysinfo.h"
35 #include "boot.h"
36 #include "udev.h"
37 #include "network.h"
38
39 struct device_handler {
40         struct discover_server  *server;
41         int                     dry_run;
42
43         struct pb_udev          *udev;
44         struct network          *network;
45         struct user_event       *user_event;
46
47         struct discover_device  **devices;
48         unsigned int            n_devices;
49
50         struct waitset          *waitset;
51         struct waiter           *timeout_waiter;
52         bool                    autoboot_enabled;
53         unsigned int            sec_to_boot;
54
55         struct discover_boot_option *default_boot_option;
56         struct list             unresolved_boot_options;
57
58         struct boot_task        *pending_boot;
59         bool                    pending_boot_is_default;
60 };
61
62 static int mount_device(struct discover_device *dev);
63 static int umount_device(struct discover_device *dev);
64
65 static int device_handler_init_sources(struct device_handler *handler);
66 static void device_handler_reinit_sources(struct device_handler *handler);
67
68 static void device_handler_update_lang(const char *lang);
69
70 void discover_context_add_boot_option(struct discover_context *ctx,
71                 struct discover_boot_option *boot_option)
72 {
73         boot_option->source = ctx->parser;
74         list_add_tail(&ctx->boot_options, &boot_option->list);
75         talloc_steal(ctx, boot_option);
76 }
77
78 /**
79  * device_handler_get_device_count - Get the count of current handler devices.
80  */
81
82 int device_handler_get_device_count(const struct device_handler *handler)
83 {
84         return handler->n_devices;
85 }
86
87 /**
88  * device_handler_get_device - Get a handler device by index.
89  */
90
91 const struct discover_device *device_handler_get_device(
92         const struct device_handler *handler, unsigned int index)
93 {
94         if (index >= handler->n_devices) {
95                 assert(0 && "bad index");
96                 return NULL;
97         }
98
99         return handler->devices[index];
100 }
101
102 struct discover_boot_option *discover_boot_option_create(
103                 struct discover_context *ctx,
104                 struct discover_device *device)
105 {
106         struct discover_boot_option *opt;
107
108         opt = talloc_zero(ctx, struct discover_boot_option);
109         opt->option = talloc_zero(opt, struct boot_option);
110         opt->device = device;
111
112         return opt;
113 }
114
115 static int device_match_uuid(struct discover_device *dev, const char *uuid)
116 {
117         return dev->uuid && !strcmp(dev->uuid, uuid);
118 }
119
120 static int device_match_label(struct discover_device *dev, const char *label)
121 {
122         return dev->label && !strcmp(dev->label, label);
123 }
124
125 static int device_match_id(struct discover_device *dev, const char *id)
126 {
127         return !strcmp(dev->device->id, id);
128 }
129
130 static int device_match_serial(struct discover_device *dev, const char *serial)
131 {
132         const char *val = discover_device_get_param(dev, "ID_SERIAL");
133         return val && !strcmp(val, serial);
134 }
135
136 static struct discover_device *device_lookup(
137                 struct device_handler *device_handler,
138                 int (match_fn)(struct discover_device *, const char *),
139                 const char *str)
140 {
141         struct discover_device *dev;
142         unsigned int i;
143
144         if (!str)
145                 return NULL;
146
147         for (i = 0; i < device_handler->n_devices; i++) {
148                 dev = device_handler->devices[i];
149
150                 if (match_fn(dev, str))
151                         return dev;
152         }
153
154         return NULL;
155 }
156
157 struct discover_device *device_lookup_by_name(struct device_handler *handler,
158                 const char *name)
159 {
160         if (!strncmp(name, "/dev/", strlen("/dev/")))
161                 name += strlen("/dev/");
162
163         return device_lookup_by_id(handler, name);
164 }
165
166 struct discover_device *device_lookup_by_uuid(
167                 struct device_handler *device_handler,
168                 const char *uuid)
169 {
170         return device_lookup(device_handler, device_match_uuid, uuid);
171 }
172
173 struct discover_device *device_lookup_by_label(
174                 struct device_handler *device_handler,
175                 const char *label)
176 {
177         return device_lookup(device_handler, device_match_label, label);
178 }
179
180 struct discover_device *device_lookup_by_id(
181                 struct device_handler *device_handler,
182                 const char *id)
183 {
184         return device_lookup(device_handler, device_match_id, id);
185 }
186
187 struct discover_device *device_lookup_by_serial(
188                 struct device_handler *device_handler,
189                 const char *serial)
190 {
191         return device_lookup(device_handler, device_match_serial, serial);
192 }
193
194 void device_handler_destroy(struct device_handler *handler)
195 {
196         talloc_free(handler);
197 }
198
199 static int destroy_device(void *arg)
200 {
201         struct discover_device *dev = arg;
202
203         umount_device(dev);
204
205         return 0;
206 }
207
208 struct discover_device *discover_device_create(struct device_handler *handler,
209                 const char *id)
210 {
211         struct discover_device *dev;
212
213         dev = device_lookup_by_id(handler, id);
214         if (dev)
215                 return dev;
216
217         dev = talloc_zero(handler, struct discover_device);
218         dev->device = talloc_zero(dev, struct device);
219         dev->device->id = talloc_strdup(dev->device, id);
220         list_init(&dev->params);
221         list_init(&dev->boot_options);
222
223         talloc_set_destructor(dev, destroy_device);
224
225         return dev;
226 }
227
228 struct discover_device_param {
229         char                    *name;
230         char                    *value;
231         struct list_item        list;
232 };
233
234 void discover_device_set_param(struct discover_device *device,
235                 const char *name, const char *value)
236 {
237         struct discover_device_param *param;
238         bool found = false;
239
240         list_for_each_entry(&device->params, param, list) {
241                 if (!strcmp(param->name, name)) {
242                         found = true;
243                         break;
244                 }
245         }
246
247         if (!found) {
248                 if (!value)
249                         return;
250                 param = talloc(device, struct discover_device_param);
251                 param->name = talloc_strdup(param, name);
252                 list_add(&device->params, &param->list);
253         } else {
254                 if (!value) {
255                         list_remove(&param->list);
256                         talloc_free(param);
257                         return;
258                 }
259                 talloc_free(param->value);
260         }
261
262         param->value = talloc_strdup(param, value);
263 }
264
265 const char *discover_device_get_param(struct discover_device *device,
266                 const char *name)
267 {
268         struct discover_device_param *param;
269
270         list_for_each_entry(&device->params, param, list) {
271                 if (!strcmp(param->name, name))
272                         return param->value;
273         }
274         return NULL;
275 }
276
277 struct device_handler *device_handler_init(struct discover_server *server,
278                 struct waitset *waitset, int dry_run)
279 {
280         struct device_handler *handler;
281         int rc;
282
283         handler = talloc_zero(NULL, struct device_handler);
284         handler->server = server;
285         handler->waitset = waitset;
286         handler->dry_run = dry_run;
287         handler->autoboot_enabled = config_get()->autoboot_enabled;
288
289         list_init(&handler->unresolved_boot_options);
290
291         /* set up our mount point base */
292         pb_mkdir_recursive(mount_base());
293
294         parser_init();
295
296         if (config_get()->safe_mode)
297                 return handler;
298
299         rc = device_handler_init_sources(handler);
300         if (rc) {
301                 talloc_free(handler);
302                 return NULL;
303         }
304
305         return handler;
306 }
307
308 void device_handler_reinit(struct device_handler *handler)
309 {
310         struct discover_boot_option *opt, *tmp;
311         unsigned int i;
312
313         device_handler_cancel_default(handler);
314
315         /* free unresolved boot options */
316         list_for_each_entry_safe(&handler->unresolved_boot_options,
317                         opt, tmp, list)
318                 talloc_free(opt);
319         list_init(&handler->unresolved_boot_options);
320
321         /* drop all devices */
322         for (i = 0; i < handler->n_devices; i++)
323                 discover_server_notify_device_remove(handler->server,
324                                 handler->devices[i]->device);
325
326         talloc_free(handler->devices);
327         handler->devices = NULL;
328         handler->n_devices = 0;
329
330         device_handler_reinit_sources(handler);
331 }
332
333 void device_handler_remove(struct device_handler *handler,
334                 struct discover_device *device)
335 {
336         struct discover_boot_option *opt, *tmp;
337         unsigned int i;
338
339         for (i = 0; i < handler->n_devices; i++)
340                 if (handler->devices[i] == device)
341                         break;
342
343         if (i == handler->n_devices) {
344                 talloc_free(device);
345                 return;
346         }
347
348         /* Free any unresolved options, as they're currently allocated
349          * against the handler */
350         list_for_each_entry_safe(&handler->unresolved_boot_options,
351                         opt, tmp, list) {
352                 if (opt->device != device)
353                         continue;
354                 list_remove(&opt->list);
355                 talloc_free(opt);
356         }
357
358         /* if this is a network device, we have to unregister it from the
359          * network code */
360         if (device->device->type == DEVICE_TYPE_NETWORK)
361                 network_unregister_device(handler->network, device);
362
363         handler->n_devices--;
364         memmove(&handler->devices[i], &handler->devices[i + 1],
365                 (handler->n_devices - i) * sizeof(handler->devices[0]));
366         handler->devices = talloc_realloc(handler, handler->devices,
367                 struct discover_device *, handler->n_devices);
368
369         if (device->notified)
370                 discover_server_notify_device_remove(handler->server,
371                                                         device->device);
372
373         talloc_free(device);
374 }
375
376 static void boot_status(void *arg, struct boot_status *status)
377 {
378         struct device_handler *handler = arg;
379
380         discover_server_notify_boot_status(handler->server, status);
381 }
382
383 static void countdown_status(struct device_handler *handler,
384                 struct discover_boot_option *opt, unsigned int sec)
385 {
386         struct boot_status status;
387
388         status.type = BOOT_STATUS_INFO;
389         status.progress = -1;
390         status.detail = NULL;
391         status.message = talloc_asprintf(handler,
392                         _("Booting in %d sec: %s"), sec, opt->option->name);
393
394         discover_server_notify_boot_status(handler->server, &status);
395
396         talloc_free(status.message);
397 }
398
399 static int default_timeout(void *arg)
400 {
401         struct device_handler *handler = arg;
402         struct discover_boot_option *opt;
403
404         if (!handler->default_boot_option)
405                 return 0;
406
407         if (handler->pending_boot)
408                 return 0;
409
410         opt = handler->default_boot_option;
411
412         if (handler->sec_to_boot) {
413                 countdown_status(handler, opt, handler->sec_to_boot);
414                 handler->sec_to_boot--;
415                 handler->timeout_waiter = waiter_register_timeout(
416                                                 handler->waitset, 1000,
417                                                 default_timeout, handler);
418                 return 0;
419         }
420
421         handler->timeout_waiter = NULL;
422
423         pb_log("Timeout expired, booting default option %s\n", opt->option->id);
424
425         handler->pending_boot = boot(handler, handler->default_boot_option,
426                         NULL, handler->dry_run, boot_status, handler);
427         handler->pending_boot_is_default = true;
428         return 0;
429 }
430
431 static bool priority_match(struct boot_priority *prio,
432                 struct discover_boot_option *opt)
433 {
434         return prio->type == opt->device->device->type ||
435                 prio->type == DEVICE_TYPE_ANY;
436 }
437
438 static int default_option_priority(struct discover_boot_option *opt)
439 {
440         const struct config *config;
441         struct boot_priority *prio;
442         unsigned int i;
443
444         config = config_get();
445
446         for (i = 0; i < config->n_boot_priorities; i++) {
447                 prio = &config->boot_priorities[i];
448                 if (priority_match(prio, opt))
449                         return prio->priority;
450         }
451
452         return 0;
453 }
454
455 static bool device_allows_default(struct discover_device *dev)
456 {
457         const char *dev_str;
458
459         dev_str = config_get()->boot_device;
460
461         if (!dev_str || !strlen(dev_str))
462                 return true;
463
464         /* default devices are specified by UUIDs at present */
465         if (strcmp(dev->uuid, dev_str))
466                 return false;
467
468         return true;
469 }
470
471 static void set_default(struct device_handler *handler,
472                 struct discover_boot_option *opt)
473 {
474         int new_prio;
475
476         if (!handler->autoboot_enabled)
477                 return;
478
479         /* do we allow default-booting from this device? */
480         if (!device_allows_default(opt->device))
481                 return;
482
483         new_prio = default_option_priority(opt);
484
485         /* A negative priority indicates that we don't want to boot this device
486          * by default */
487         if (new_prio < 0)
488                 return;
489
490         /* Resolve any conflicts: if we have a new default option, it only
491          * replaces the current if it has a higher priority. */
492         if (handler->default_boot_option) {
493                 int cur_prio;
494
495                 cur_prio = default_option_priority(
496                                         handler->default_boot_option);
497
498                 if (new_prio > cur_prio) {
499                         handler->default_boot_option = opt;
500                         /* extend the timeout a little, so the user sees some
501                          * indication of the change */
502                         handler->sec_to_boot += 2;
503                 }
504
505                 return;
506         }
507
508         handler->sec_to_boot = config_get()->autoboot_timeout_sec;
509         handler->default_boot_option = opt;
510
511         pb_log("Boot option %s set as default, timeout %u sec.\n",
512                opt->option->id, handler->sec_to_boot);
513
514         default_timeout(handler);
515 }
516
517 static bool resource_is_resolved(struct resource *res)
518 {
519         return !res || res->resolved;
520 }
521
522 /* We only use this in an assert, which will disappear if we're compiling
523  * with NDEBUG, so we need the 'used' attribute for these builds */
524 static bool __attribute__((used)) boot_option_is_resolved(
525                 struct discover_boot_option *opt)
526 {
527         return resource_is_resolved(opt->boot_image) &&
528                 resource_is_resolved(opt->initrd) &&
529                 resource_is_resolved(opt->dtb) &&
530                 resource_is_resolved(opt->icon);
531 }
532
533 static bool resource_resolve(struct resource *res, const char *name,
534                 struct discover_boot_option *opt,
535                 struct device_handler *handler)
536 {
537         struct parser *parser = opt->source;
538
539         if (resource_is_resolved(res))
540                 return true;
541
542         pb_debug("Attempting to resolve resource %s->%s with parser %s\n",
543                         opt->option->id, name, parser->name);
544         parser->resolve_resource(handler, res);
545
546         return res->resolved;
547 }
548
549 static bool boot_option_resolve(struct discover_boot_option *opt,
550                 struct device_handler *handler)
551 {
552         return resource_resolve(opt->boot_image, "boot_image", opt, handler) &&
553                 resource_resolve(opt->initrd, "initrd", opt, handler) &&
554                 resource_resolve(opt->dtb, "dtb", opt, handler) &&
555                 resource_resolve(opt->icon, "icon", opt, handler);
556 }
557
558 static void boot_option_finalise(struct device_handler *handler,
559                 struct discover_boot_option *opt)
560 {
561         assert(boot_option_is_resolved(opt));
562
563         /* check that the parsers haven't set any of the final data */
564         assert(!opt->option->boot_image_file);
565         assert(!opt->option->initrd_file);
566         assert(!opt->option->dtb_file);
567         assert(!opt->option->icon_file);
568         assert(!opt->option->device_id);
569
570         if (opt->boot_image)
571                 opt->option->boot_image_file = opt->boot_image->url->full;
572         if (opt->initrd)
573                 opt->option->initrd_file = opt->initrd->url->full;
574         if (opt->dtb)
575                 opt->option->dtb_file = opt->dtb->url->full;
576         if (opt->icon)
577                 opt->option->icon_file = opt->icon->url->full;
578
579         opt->option->device_id = opt->device->device->id;
580
581         if (opt->option->is_default)
582                 set_default(handler, opt);
583 }
584
585 static void notify_boot_option(struct device_handler *handler,
586                 struct discover_boot_option *opt)
587 {
588         struct discover_device *dev = opt->device;
589
590         if (!dev->notified)
591                 discover_server_notify_device_add(handler->server,
592                                                   opt->device->device);
593         dev->notified = true;
594         discover_server_notify_boot_option_add(handler->server, opt->option);
595 }
596
597 static void process_boot_option_queue(struct device_handler *handler)
598 {
599         struct discover_boot_option *opt, *tmp;
600
601         list_for_each_entry_safe(&handler->unresolved_boot_options,
602                         opt, tmp, list) {
603
604                 pb_debug("queue: attempting resolution for %s\n",
605                                 opt->option->id);
606
607                 if (!boot_option_resolve(opt, handler))
608                         continue;
609
610                 pb_debug("\tresolved!\n");
611
612                 list_remove(&opt->list);
613                 list_add_tail(&opt->device->boot_options, &opt->list);
614                 talloc_steal(opt->device, opt);
615                 boot_option_finalise(handler, opt);
616                 notify_boot_option(handler, opt);
617         }
618 }
619
620 struct discover_context *device_handler_discover_context_create(
621                 struct device_handler *handler,
622                 struct discover_device *device)
623 {
624         struct discover_context *ctx;
625
626         ctx = talloc_zero(handler, struct discover_context);
627         ctx->device = device;
628         list_init(&ctx->boot_options);
629
630         return ctx;
631 }
632
633 /**
634  * context_commit - Commit a temporary discovery context to the handler,
635  * and notify the clients about any new options / devices
636  */
637 void device_handler_discover_context_commit(struct device_handler *handler,
638                 struct discover_context *ctx)
639 {
640         struct discover_device *dev = ctx->device;
641         struct discover_boot_option *opt, *tmp;
642
643         if (!device_lookup_by_id(handler, dev->device->id))
644                 device_handler_add_device(handler, dev);
645
646         /* move boot options from the context to the device */
647         list_for_each_entry_safe(&ctx->boot_options, opt, tmp, list) {
648                 list_remove(&opt->list);
649
650                 if (boot_option_resolve(opt, handler)) {
651                         pb_log("boot option %s is resolved, "
652                                         "sending to clients\n",
653                                         opt->option->id);
654                         list_add_tail(&dev->boot_options, &opt->list);
655                         talloc_steal(dev, opt);
656                         boot_option_finalise(handler, opt);
657                         notify_boot_option(handler, opt);
658                 } else {
659                         if (!opt->source->resolve_resource) {
660                                 pb_log("parser %s gave us an unresolved "
661                                         "resource (%s), but no way to "
662                                         "resolve it\n",
663                                         opt->source->name, opt->option->id);
664                                 talloc_free(opt);
665                         } else {
666                                 pb_log("boot option %s is unresolved, "
667                                                 "adding to queue\n",
668                                                 opt->option->id);
669                                 list_add(&handler->unresolved_boot_options,
670                                                 &opt->list);
671                                 talloc_steal(handler, opt);
672                         }
673                 }
674         }
675 }
676
677 void device_handler_add_device(struct device_handler *handler,
678                 struct discover_device *device)
679 {
680         handler->n_devices++;
681         handler->devices = talloc_realloc(handler, handler->devices,
682                                 struct discover_device *, handler->n_devices);
683         handler->devices[handler->n_devices - 1] = device;
684
685         if (device->device->type == DEVICE_TYPE_NETWORK)
686                 network_register_device(handler->network, device);
687 }
688
689 /* Start discovery on a hotplugged device. The device will be in our devices
690  * array, but has only just been initialised by the hotplug source.
691  */
692 int device_handler_discover(struct device_handler *handler,
693                 struct discover_device *dev)
694 {
695         struct discover_context *ctx;
696         int rc;
697
698         process_boot_option_queue(handler);
699
700         /* create our context */
701         ctx = device_handler_discover_context_create(handler, dev);
702
703         rc = mount_device(dev);
704         if (rc)
705                 goto out;
706
707         /* add this device to our system info */
708         system_info_register_blockdev(dev->device->id, dev->uuid,
709                         dev->mount_path);
710
711         /* run the parsers. This will populate the ctx's boot_option list. */
712         iterate_parsers(ctx);
713
714         /* add discovered stuff to the handler */
715         device_handler_discover_context_commit(handler, ctx);
716
717 out:
718         talloc_free(ctx);
719
720         return 0;
721 }
722
723 /* Incoming dhcp event */
724 int device_handler_dhcp(struct device_handler *handler,
725                 struct discover_device *dev, struct event *event)
726 {
727         struct discover_context *ctx;
728
729         /* create our context */
730         ctx = device_handler_discover_context_create(handler, dev);
731         ctx->event = event;
732
733         iterate_parsers(ctx);
734
735         device_handler_discover_context_commit(handler, ctx);
736
737         talloc_free(ctx);
738
739         return 0;
740 }
741
742 /* incoming conf event */
743 int device_handler_conf(struct device_handler *handler,
744                 struct discover_device *dev, struct pb_url *url)
745 {
746         struct discover_context *ctx;
747
748         /* create our context */
749         ctx = device_handler_discover_context_create(handler, dev);
750         ctx->conf_url = url;
751
752         iterate_parsers(ctx);
753
754         device_handler_discover_context_commit(handler, ctx);
755
756         talloc_free(ctx);
757
758         return 0;
759 }
760
761 static struct discover_boot_option *find_boot_option_by_id(
762                 struct device_handler *handler, const char *id)
763 {
764         unsigned int i;
765
766         for (i = 0; i < handler->n_devices; i++) {
767                 struct discover_device *dev = handler->devices[i];
768                 struct discover_boot_option *opt;
769
770                 list_for_each_entry(&dev->boot_options, opt, list)
771                         if (!strcmp(opt->option->id, id))
772                                 return opt;
773         }
774
775         return NULL;
776 }
777
778 void device_handler_boot(struct device_handler *handler,
779                 struct boot_command *cmd)
780 {
781         struct discover_boot_option *opt = NULL;
782
783         if (cmd->option_id && strlen(cmd->option_id))
784                 opt = find_boot_option_by_id(handler, cmd->option_id);
785
786         if (handler->pending_boot)
787                 boot_cancel(handler->pending_boot);
788         handler->pending_boot = boot(handler, opt, cmd, handler->dry_run,
789                         boot_status, handler);
790         handler->pending_boot_is_default = false;
791 }
792
793 void device_handler_cancel_default(struct device_handler *handler)
794 {
795         struct boot_status status;
796
797         if (handler->timeout_waiter)
798                 waiter_remove(handler->timeout_waiter);
799
800         handler->timeout_waiter = NULL;
801         handler->autoboot_enabled = false;
802
803         /* we only send status if we had a default boot option queued */
804         if (!handler->default_boot_option)
805                 return;
806
807         pb_log("Cancelling default boot option\n");
808
809         if (handler->pending_boot && handler->pending_boot_is_default) {
810                 boot_cancel(handler->pending_boot);
811                 handler->pending_boot = NULL;
812                 handler->pending_boot_is_default = false;
813         }
814
815         handler->default_boot_option = NULL;
816
817         status.type = BOOT_STATUS_INFO;
818         status.progress = -1;
819         status.detail = NULL;
820         status.message = _("Default boot cancelled");
821
822         discover_server_notify_boot_status(handler->server, &status);
823 }
824
825 void device_handler_update_config(struct device_handler *handler,
826                 struct config *config)
827 {
828         int rc;
829
830         rc = config_set(config);
831         if (rc)
832                 return;
833
834         discover_server_notify_config(handler->server, config);
835         device_handler_update_lang(config->lang);
836         device_handler_reinit(handler);
837 }
838
839 static char *device_from_addr(void *ctx, struct pb_url *url)
840 {
841         char *ipaddr, *buf, *tok, *dev = NULL;
842         const char *delim = " ";
843         struct sockaddr_in *ip;
844         struct sockaddr_in si;
845         struct addrinfo *res;
846         struct process *p;
847         int rc;
848
849         /* Note: IPv4 only */
850         rc = inet_pton(AF_INET, url->host, &(si.sin_addr));
851         if (rc > 0) {
852                 ipaddr = url->host;
853         } else {
854                 /* need to turn hostname into a valid IP */
855                 rc = getaddrinfo(url->host, NULL, NULL, &res);
856                 if (rc) {
857                         pb_debug("%s: Invalid URL\n",__func__);
858                         return NULL;
859                 }
860                 ipaddr = talloc_array(ctx,char,INET_ADDRSTRLEN);
861                 ip = (struct sockaddr_in *) res->ai_addr;
862                 inet_ntop(AF_INET, &(ip->sin_addr), ipaddr, INET_ADDRSTRLEN);
863                 freeaddrinfo(res);
864         }
865
866         const char *argv[] = {
867                 pb_system_apps.ip,
868                 "route", "show", "to", "match",
869                 ipaddr,
870                 NULL
871         };
872
873         p = process_create(ctx);
874
875         p->path = pb_system_apps.ip;
876         p->argv = argv;
877         p->keep_stdout = true;
878
879         rc = process_run_sync(p);
880
881         if (rc) {
882                 /* ip has complained for some reason; most likely
883                  * there is no route to the host - bail out */
884                 pb_debug("%s: No route to %s\n",__func__,url->host);
885                 return NULL;
886         }
887
888         buf = p->stdout_buf;
889         /* If a route is found, ip-route output will be of the form
890          * "... dev DEVNAME ... " */
891         tok = strtok(buf, delim);
892         while (tok) {
893                 if (!strcmp(tok, "dev")) {
894                         tok = strtok(NULL, delim);
895                         dev = talloc_strdup(ctx, tok);
896                         break;
897                 }
898                 tok = strtok(NULL, delim);
899         }
900
901         process_release(p);
902         if (dev)
903                 pb_debug("%s: Found interface '%s'\n", __func__,dev);
904         return dev;
905 }
906
907
908 void device_handler_process_url(struct device_handler *handler,
909                 const char *url)
910 {
911         struct discover_context *ctx;
912         struct discover_device *dev;
913         struct boot_status *status;
914         struct pb_url *pb_url;
915         struct event *event;
916         struct param *param;
917
918         status = talloc(handler, struct boot_status);
919
920         status->type = BOOT_STATUS_ERROR;
921         status->progress = 0;
922         status->detail = talloc_asprintf(status,
923                         _("Received config URL %s"), url);
924
925         event = talloc(handler, struct event);
926         event->type = EVENT_TYPE_USER;
927         event->action = EVENT_ACTION_CONF;
928
929         event->params = talloc_array(event, struct param, 1);
930         param = &event->params[0];
931         param->name = talloc_strdup(event, "pxeconffile");
932         param->value = talloc_strdup(event, url);
933         event->n_params = 1;
934
935         pb_url = pb_url_parse(event, event->params->value);
936         if (!pb_url || !pb_url->host) {
937                 status->message = talloc_asprintf(handler,
938                                         _("Invalid config URL!"));
939                 goto msg;
940         }
941
942         event->device = device_from_addr(event, pb_url);
943         if (!event->device) {
944                 status->message = talloc_asprintf(status,
945                                         _("Unable to route to host %s"),
946                                         pb_url->host);
947                 goto msg;
948         }
949
950         dev = discover_device_create(handler, event->device);
951         ctx = device_handler_discover_context_create(handler, dev);
952         ctx->event = event;
953
954         iterate_parsers(ctx);
955
956         device_handler_discover_context_commit(handler, ctx);
957
958         talloc_free(ctx);
959
960         status->type = BOOT_STATUS_INFO;
961         status->message = talloc_asprintf(status, _("Config file %s parsed"),
962                                         pb_url->file);
963 msg:
964         boot_status(handler, status);
965         talloc_free(status);
966 }
967
968 #ifndef PETITBOOT_TEST
969
970 static void device_handler_update_lang(const char *lang)
971 {
972         const char *cur_lang;
973
974         if (!lang)
975                 return;
976
977         cur_lang = setlocale(LC_ALL, NULL);
978         if (cur_lang && !strcmp(cur_lang, lang))
979                 return;
980
981         setlocale(LC_ALL, lang);
982 }
983
984 static int device_handler_init_sources(struct device_handler *handler)
985 {
986         /* init our device sources: udev, network and user events */
987         handler->udev = udev_init(handler, handler->waitset);
988         if (!handler->udev)
989                 return -1;
990
991         handler->network = network_init(handler, handler->waitset,
992                         handler->dry_run);
993         if (!handler->network)
994                 return -1;
995
996         handler->user_event = user_event_init(handler, handler->waitset);
997         if (!handler->user_event)
998                 return -1;
999
1000         return 0;
1001 }
1002
1003 static void device_handler_reinit_sources(struct device_handler *handler)
1004 {
1005         /* if we haven't initialised sources previously (becuase we started in
1006          * safe mode), then init once here. */
1007         if (!(handler->udev || handler->network || handler->user_event)) {
1008                 device_handler_init_sources(handler);
1009                 return;
1010         }
1011
1012         udev_reinit(handler->udev);
1013
1014         network_shutdown(handler->network);
1015         handler->network = network_init(handler, handler->waitset,
1016                         handler->dry_run);
1017 }
1018
1019 static bool check_existing_mount(struct discover_device *dev)
1020 {
1021         struct stat devstat, mntstat;
1022         struct mntent *mnt;
1023         FILE *fp;
1024         int rc;
1025
1026         rc = stat(dev->device_path, &devstat);
1027         if (rc) {
1028                 pb_debug("%s: stat failed: %s\n", __func__, strerror(errno));
1029                 return false;
1030         }
1031
1032         if (!S_ISBLK(devstat.st_mode)) {
1033                 pb_debug("%s: %s isn't a block device?\n", __func__,
1034                                 dev->device_path);
1035                 return false;
1036         }
1037
1038         fp = fopen("/proc/self/mounts", "r");
1039
1040         for (;;) {
1041                 mnt = getmntent(fp);
1042                 if (!mnt)
1043                         break;
1044
1045                 if (!mnt->mnt_fsname || mnt->mnt_fsname[0] != '/')
1046                         continue;
1047
1048                 rc = stat(mnt->mnt_fsname, &mntstat);
1049                 if (rc)
1050                         continue;
1051
1052                 if (!S_ISBLK(mntstat.st_mode))
1053                         continue;
1054
1055                 if (mntstat.st_rdev == devstat.st_rdev) {
1056                         dev->mount_path = talloc_strdup(dev, mnt->mnt_dir);
1057                         dev->mounted_rw = !!hasmntopt(mnt, "rw");
1058                         dev->mounted = true;
1059                         dev->unmount = false;
1060
1061                         pb_debug("%s: %s is already mounted (r%c) at %s\n",
1062                                         __func__, dev->device_path,
1063                                         dev->mounted_rw ? 'w' : 'o',
1064                                         mnt->mnt_dir);
1065                         break;
1066                 }
1067         }
1068
1069         fclose(fp);
1070
1071         return mnt != NULL;
1072 }
1073
1074 static int mount_device(struct discover_device *dev)
1075 {
1076         const char *fstype;
1077         int rc;
1078
1079         if (!dev->device_path)
1080                 return -1;
1081
1082         if (dev->mounted)
1083                 return 0;
1084
1085         if (check_existing_mount(dev))
1086                 return 0;
1087
1088         fstype = discover_device_get_param(dev, "ID_FS_TYPE");
1089         if (!fstype)
1090                 return 0;
1091
1092         dev->mount_path = join_paths(dev, mount_base(),
1093                                         dev->device_path);
1094
1095         if (pb_mkdir_recursive(dev->mount_path)) {
1096                 pb_log("couldn't create mount directory %s: %s\n",
1097                                 dev->mount_path, strerror(errno));
1098                 goto err_free;
1099         }
1100
1101         pb_log("mounting device %s read-only\n", dev->device_path);
1102         errno = 0;
1103         rc = mount(dev->device_path, dev->mount_path, fstype,
1104                         MS_RDONLY | MS_SILENT, "");
1105         if (!rc) {
1106                 dev->mounted = true;
1107                 dev->mounted_rw = false;
1108                 dev->unmount = true;
1109                 return 0;
1110         }
1111
1112         pb_log("couldn't mount device %s: mount failed: %s\n",
1113                         dev->device_path, strerror(errno));
1114
1115         pb_rmdir_recursive(mount_base(), dev->mount_path);
1116 err_free:
1117         talloc_free(dev->mount_path);
1118         dev->mount_path = NULL;
1119         return -1;
1120 }
1121
1122 static int umount_device(struct discover_device *dev)
1123 {
1124         int rc;
1125
1126         if (!dev->mounted || !dev->unmount)
1127                 return 0;
1128
1129         pb_log("unmounting device %s\n", dev->device_path);
1130         rc = umount(dev->mount_path);
1131         if (rc)
1132                 return -1;
1133
1134         dev->mounted = false;
1135
1136         pb_rmdir_recursive(mount_base(), dev->mount_path);
1137
1138         talloc_free(dev->mount_path);
1139         dev->mount_path = NULL;
1140
1141         return 0;
1142 }
1143
1144 int device_request_write(struct discover_device *dev, bool *release)
1145 {
1146         int rc;
1147
1148         *release = false;
1149
1150         if (!dev->mounted)
1151                 return -1;
1152
1153         if (dev->mounted_rw)
1154                 return 0;
1155
1156         pb_log("remounting device %s read-write\n", dev->device_path);
1157         rc = mount(dev->device_path, dev->mount_path, "",
1158                         MS_REMOUNT | MS_SILENT, "");
1159         if (rc)
1160                 return -1;
1161
1162         dev->mounted_rw = true;
1163         *release = true;
1164         return 0;
1165 }
1166
1167 void device_release_write(struct discover_device *dev, bool release)
1168 {
1169         if (!release)
1170                 return;
1171
1172         pb_log("remounting device %s read-only\n", dev->device_path);
1173         mount(dev->device_path, dev->mount_path, "",
1174                         MS_REMOUNT | MS_RDONLY | MS_SILENT, "");
1175         dev->mounted_rw = false;
1176 }
1177
1178 #else
1179
1180 static void device_handler_update_lang(const char *lang __attribute__((unused)))
1181 {
1182 }
1183
1184 static int device_handler_init_sources(
1185                 struct device_handler *handler __attribute__((unused)))
1186 {
1187         return 0;
1188 }
1189
1190 static void device_handler_reinit_sources(
1191                 struct device_handler *handler __attribute__((unused)))
1192 {
1193 }
1194
1195 static int umount_device(struct discover_device *dev __attribute__((unused)))
1196 {
1197         return 0;
1198 }
1199
1200 static int __attribute__((unused)) mount_device(
1201                 struct discover_device *dev __attribute__((unused)))
1202 {
1203         return 0;
1204 }
1205
1206 int device_request_write(struct discover_device *dev __attribute__((unused)),
1207                 bool *release)
1208 {
1209         *release = true;
1210         return 0;
1211 }
1212
1213 void device_release_write(struct discover_device *dev __attribute__((unused)),
1214         bool release __attribute__((unused)))
1215 {
1216 }
1217
1218 #endif
1219