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