]> git.ozlabs.org Git - petitboot/blob - discover/device-handler.c
487f2e73506221a316cd8e3b72928cccc733b167
[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         int rc;
759
760         process_boot_option_queue(handler);
761
762         /* create our context */
763         ctx = device_handler_discover_context_create(handler, dev);
764
765         rc = mount_device(dev);
766         if (rc)
767                 goto out;
768
769         /* add this device to our system info */
770         system_info_register_blockdev(dev->device->id, dev->uuid,
771                         dev->mount_path);
772
773         /* run the parsers. This will populate the ctx's boot_option list. */
774         iterate_parsers(ctx);
775
776         /* add discovered stuff to the handler */
777         device_handler_discover_context_commit(handler, ctx);
778
779 out:
780         talloc_free(ctx);
781
782         return 0;
783 }
784
785 /* Incoming dhcp event */
786 int device_handler_dhcp(struct device_handler *handler,
787                 struct discover_device *dev, struct event *event)
788 {
789         struct discover_context *ctx;
790
791         /* create our context */
792         ctx = device_handler_discover_context_create(handler, dev);
793         ctx->event = event;
794
795         iterate_parsers(ctx);
796
797         device_handler_discover_context_commit(handler, ctx);
798
799         talloc_free(ctx);
800
801         return 0;
802 }
803
804 /* incoming conf event */
805 int device_handler_conf(struct device_handler *handler,
806                 struct discover_device *dev, struct pb_url *url)
807 {
808         struct discover_context *ctx;
809
810         /* create our context */
811         ctx = device_handler_discover_context_create(handler, dev);
812         ctx->conf_url = url;
813
814         iterate_parsers(ctx);
815
816         device_handler_discover_context_commit(handler, ctx);
817
818         talloc_free(ctx);
819
820         return 0;
821 }
822
823 static struct discover_boot_option *find_boot_option_by_id(
824                 struct device_handler *handler, const char *id)
825 {
826         unsigned int i;
827
828         for (i = 0; i < handler->n_devices; i++) {
829                 struct discover_device *dev = handler->devices[i];
830                 struct discover_boot_option *opt;
831
832                 list_for_each_entry(&dev->boot_options, opt, list)
833                         if (!strcmp(opt->option->id, id))
834                                 return opt;
835         }
836
837         return NULL;
838 }
839
840 void device_handler_boot(struct device_handler *handler,
841                 struct boot_command *cmd)
842 {
843         struct discover_boot_option *opt = NULL;
844
845         if (cmd->option_id && strlen(cmd->option_id))
846                 opt = find_boot_option_by_id(handler, cmd->option_id);
847
848         if (handler->pending_boot)
849                 boot_cancel(handler->pending_boot);
850
851         platform_pre_boot();
852
853         handler->pending_boot = boot(handler, opt, cmd, handler->dry_run,
854                         boot_status, handler);
855         handler->pending_boot_is_default = false;
856 }
857
858 void device_handler_cancel_default(struct device_handler *handler)
859 {
860         struct boot_status status;
861
862         if (handler->timeout_waiter)
863                 waiter_remove(handler->timeout_waiter);
864
865         handler->timeout_waiter = NULL;
866         handler->autoboot_enabled = false;
867
868         /* we only send status if we had a default boot option queued */
869         if (!handler->default_boot_option)
870                 return;
871
872         pb_log("Cancelling default boot option\n");
873
874         if (handler->pending_boot && handler->pending_boot_is_default) {
875                 boot_cancel(handler->pending_boot);
876                 handler->pending_boot = NULL;
877                 handler->pending_boot_is_default = false;
878         }
879
880         handler->default_boot_option = NULL;
881
882         status.type = BOOT_STATUS_INFO;
883         status.progress = -1;
884         status.detail = NULL;
885         status.message = _("Default boot cancelled");
886
887         discover_server_notify_boot_status(handler->server, &status);
888 }
889
890 void device_handler_update_config(struct device_handler *handler,
891                 struct config *config)
892 {
893         int rc;
894
895         rc = config_set(config);
896         if (rc)
897                 return;
898
899         discover_server_notify_config(handler->server, config);
900         device_handler_update_lang(config->lang);
901         device_handler_reinit(handler);
902 }
903
904 static char *device_from_addr(void *ctx, struct pb_url *url)
905 {
906         char *ipaddr, *buf, *tok, *dev = NULL;
907         const char *delim = " ";
908         struct sockaddr_in *ip;
909         struct sockaddr_in si;
910         struct addrinfo *res;
911         struct process *p;
912         int rc;
913
914         /* Note: IPv4 only */
915         rc = inet_pton(AF_INET, url->host, &(si.sin_addr));
916         if (rc > 0) {
917                 ipaddr = url->host;
918         } else {
919                 /* need to turn hostname into a valid IP */
920                 rc = getaddrinfo(url->host, NULL, NULL, &res);
921                 if (rc) {
922                         pb_debug("%s: Invalid URL\n",__func__);
923                         return NULL;
924                 }
925                 ipaddr = talloc_array(ctx,char,INET_ADDRSTRLEN);
926                 ip = (struct sockaddr_in *) res->ai_addr;
927                 inet_ntop(AF_INET, &(ip->sin_addr), ipaddr, INET_ADDRSTRLEN);
928                 freeaddrinfo(res);
929         }
930
931         const char *argv[] = {
932                 pb_system_apps.ip,
933                 "route", "show", "to", "match",
934                 ipaddr,
935                 NULL
936         };
937
938         p = process_create(ctx);
939
940         p->path = pb_system_apps.ip;
941         p->argv = argv;
942         p->keep_stdout = true;
943
944         rc = process_run_sync(p);
945
946         if (rc) {
947                 /* ip has complained for some reason; most likely
948                  * there is no route to the host - bail out */
949                 pb_debug("%s: No route to %s\n",__func__,url->host);
950                 return NULL;
951         }
952
953         buf = p->stdout_buf;
954         /* If a route is found, ip-route output will be of the form
955          * "... dev DEVNAME ... " */
956         tok = strtok(buf, delim);
957         while (tok) {
958                 if (!strcmp(tok, "dev")) {
959                         tok = strtok(NULL, delim);
960                         dev = talloc_strdup(ctx, tok);
961                         break;
962                 }
963                 tok = strtok(NULL, delim);
964         }
965
966         process_release(p);
967         if (dev)
968                 pb_debug("%s: Found interface '%s'\n", __func__,dev);
969         return dev;
970 }
971
972
973 void device_handler_process_url(struct device_handler *handler,
974                 const char *url)
975 {
976         struct discover_context *ctx;
977         struct discover_device *dev;
978         struct boot_status *status;
979         struct pb_url *pb_url;
980         struct event *event;
981         struct param *param;
982
983         status = talloc(handler, struct boot_status);
984
985         status->type = BOOT_STATUS_ERROR;
986         status->progress = 0;
987         status->detail = talloc_asprintf(status,
988                         _("Received config URL %s"), url);
989
990         if (!handler->network) {
991                 status->message = talloc_asprintf(handler,
992                                         _("No network configured"));
993                 goto msg;
994         }
995
996         event = talloc(handler, struct event);
997         event->type = EVENT_TYPE_USER;
998         event->action = EVENT_ACTION_CONF;
999
1000         event->params = talloc_array(event, struct param, 1);
1001         param = &event->params[0];
1002         param->name = talloc_strdup(event, "pxeconffile");
1003         param->value = talloc_strdup(event, url);
1004         event->n_params = 1;
1005
1006         pb_url = pb_url_parse(event, event->params->value);
1007         if (!pb_url || !pb_url->host) {
1008                 status->message = talloc_asprintf(handler,
1009                                         _("Invalid config URL!"));
1010                 goto msg;
1011         }
1012
1013         event->device = device_from_addr(event, pb_url);
1014         if (!event->device) {
1015                 status->message = talloc_asprintf(status,
1016                                         _("Unable to route to host %s"),
1017                                         pb_url->host);
1018                 goto msg;
1019         }
1020
1021         dev = discover_device_create(handler, event->device);
1022         ctx = device_handler_discover_context_create(handler, dev);
1023         ctx->event = event;
1024
1025         iterate_parsers(ctx);
1026
1027         device_handler_discover_context_commit(handler, ctx);
1028
1029         talloc_free(ctx);
1030
1031         status->type = BOOT_STATUS_INFO;
1032         status->message = talloc_asprintf(status, _("Config file %s parsed"),
1033                                         pb_url->file);
1034 msg:
1035         boot_status(handler, status);
1036         talloc_free(status);
1037 }
1038
1039 #ifndef PETITBOOT_TEST
1040
1041 static void device_handler_update_lang(const char *lang)
1042 {
1043         const char *cur_lang;
1044
1045         if (!lang)
1046                 return;
1047
1048         cur_lang = setlocale(LC_ALL, NULL);
1049         if (cur_lang && !strcmp(cur_lang, lang))
1050                 return;
1051
1052         setlocale(LC_ALL, lang);
1053 }
1054
1055 static int device_handler_init_sources(struct device_handler *handler)
1056 {
1057         /* init our device sources: udev, network and user events */
1058         handler->udev = udev_init(handler, handler->waitset);
1059         if (!handler->udev)
1060                 return -1;
1061
1062         handler->network = network_init(handler, handler->waitset,
1063                         handler->dry_run);
1064         if (!handler->network)
1065                 return -1;
1066
1067         handler->user_event = user_event_init(handler, handler->waitset);
1068         if (!handler->user_event)
1069                 return -1;
1070
1071         return 0;
1072 }
1073
1074 static void device_handler_reinit_sources(struct device_handler *handler)
1075 {
1076         /* if we haven't initialised sources previously (becuase we started in
1077          * safe mode), then init once here. */
1078         if (!(handler->udev || handler->network || handler->user_event)) {
1079                 device_handler_init_sources(handler);
1080                 return;
1081         }
1082
1083         udev_reinit(handler->udev);
1084
1085         network_shutdown(handler->network);
1086         handler->network = network_init(handler, handler->waitset,
1087                         handler->dry_run);
1088 }
1089
1090 static const char *fs_parameters(unsigned int rw_flags, const char *fstype)
1091 {
1092         if ((rw_flags | MS_RDONLY) != MS_RDONLY)
1093                 return "";
1094
1095         /* Avoid writing back to the disk on journaled filesystems */
1096         if (!strncmp(fstype, "ext4", strlen("ext4")))
1097                 return "norecovery";
1098         if (!strncmp(fstype, "xfs", strlen("xfs")))
1099                 return "norecovery";
1100
1101         return "";
1102 }
1103
1104 static bool check_existing_mount(struct discover_device *dev)
1105 {
1106         struct stat devstat, mntstat;
1107         struct mntent *mnt;
1108         FILE *fp;
1109         int rc;
1110
1111         rc = stat(dev->device_path, &devstat);
1112         if (rc) {
1113                 pb_debug("%s: stat failed: %s\n", __func__, strerror(errno));
1114                 return false;
1115         }
1116
1117         if (!S_ISBLK(devstat.st_mode)) {
1118                 pb_debug("%s: %s isn't a block device?\n", __func__,
1119                                 dev->device_path);
1120                 return false;
1121         }
1122
1123         fp = fopen("/proc/self/mounts", "r");
1124
1125         for (;;) {
1126                 mnt = getmntent(fp);
1127                 if (!mnt)
1128                         break;
1129
1130                 if (!mnt->mnt_fsname || mnt->mnt_fsname[0] != '/')
1131                         continue;
1132
1133                 rc = stat(mnt->mnt_fsname, &mntstat);
1134                 if (rc)
1135                         continue;
1136
1137                 if (!S_ISBLK(mntstat.st_mode))
1138                         continue;
1139
1140                 if (mntstat.st_rdev == devstat.st_rdev) {
1141                         dev->mount_path = talloc_strdup(dev, mnt->mnt_dir);
1142                         dev->mounted_rw = !!hasmntopt(mnt, "rw");
1143                         dev->mounted = true;
1144                         dev->unmount = false;
1145
1146                         pb_debug("%s: %s is already mounted (r%c) at %s\n",
1147                                         __func__, dev->device_path,
1148                                         dev->mounted_rw ? 'w' : 'o',
1149                                         mnt->mnt_dir);
1150                         break;
1151                 }
1152         }
1153
1154         fclose(fp);
1155
1156         return mnt != NULL;
1157 }
1158
1159 static int mount_device(struct discover_device *dev)
1160 {
1161         const char *fstype;
1162         int rc;
1163
1164         if (!dev->device_path)
1165                 return -1;
1166
1167         if (dev->mounted)
1168                 return 0;
1169
1170         if (check_existing_mount(dev))
1171                 return 0;
1172
1173         fstype = discover_device_get_param(dev, "ID_FS_TYPE");
1174         if (!fstype)
1175                 return 0;
1176
1177         /* ext3 treats the norecovery option as an error, so mount the device
1178          * as an ext4 filesystem instead */
1179         if (!strncmp(fstype, "ext3", strlen("ext3"))) {
1180                 pb_debug("Mounting ext3 filesystem as ext4\n");
1181                 fstype = talloc_asprintf(dev, "ext4");
1182         }
1183
1184         dev->mount_path = join_paths(dev, mount_base(),
1185                                         dev->device_path);
1186
1187         if (pb_mkdir_recursive(dev->mount_path)) {
1188                 pb_log("couldn't create mount directory %s: %s\n",
1189                                 dev->mount_path, strerror(errno));
1190                 goto err_free;
1191         }
1192
1193         pb_log("mounting device %s read-only\n", dev->device_path);
1194         errno = 0;
1195         rc = mount(dev->device_path, dev->mount_path, fstype,
1196                         MS_RDONLY | MS_SILENT,
1197                         fs_parameters(MS_RDONLY, fstype));
1198         if (!rc) {
1199                 dev->mounted = true;
1200                 dev->mounted_rw = false;
1201                 dev->unmount = true;
1202                 return 0;
1203         }
1204
1205         pb_log("couldn't mount device %s: mount failed: %s\n",
1206                         dev->device_path, strerror(errno));
1207
1208         pb_rmdir_recursive(mount_base(), dev->mount_path);
1209 err_free:
1210         talloc_free(dev->mount_path);
1211         dev->mount_path = NULL;
1212         return -1;
1213 }
1214
1215 static int umount_device(struct discover_device *dev)
1216 {
1217         int rc;
1218
1219         if (!dev->mounted || !dev->unmount)
1220                 return 0;
1221
1222         pb_log("unmounting device %s\n", dev->device_path);
1223         rc = umount(dev->mount_path);
1224         if (rc)
1225                 return -1;
1226
1227         dev->mounted = false;
1228
1229         pb_rmdir_recursive(mount_base(), dev->mount_path);
1230
1231         talloc_free(dev->mount_path);
1232         dev->mount_path = NULL;
1233
1234         return 0;
1235 }
1236
1237 int device_request_write(struct discover_device *dev, bool *release)
1238 {
1239         const char *fstype;
1240         int rc;
1241
1242         *release = false;
1243
1244         if (!dev->mounted)
1245                 return -1;
1246
1247         if (dev->mounted_rw)
1248                 return 0;
1249
1250         fstype = discover_device_get_param(dev, "ID_FS_TYPE");
1251
1252         pb_log("remounting device %s read-write\n", dev->device_path);
1253
1254         rc = umount(dev->mount_path);
1255         if (rc) {
1256                 pb_log("Failed to unmount %s\n", dev->mount_path);
1257                 return -1;
1258         }
1259         rc = mount(dev->device_path, dev->mount_path, fstype,
1260                         MS_SILENT,
1261                         fs_parameters(MS_REMOUNT, fstype));
1262         if (rc)
1263                 goto mount_ro;
1264
1265         dev->mounted_rw = true;
1266         *release = true;
1267         return 0;
1268
1269 mount_ro:
1270         pb_log("Unable to remount device %s read-write\n", dev->device_path);
1271         rc = mount(dev->device_path, dev->mount_path, fstype,
1272                         MS_RDONLY | MS_SILENT,
1273                         fs_parameters(MS_RDONLY, fstype));
1274         if (rc)
1275                 pb_log("Unable to recover mount for %s\n", dev->device_path);
1276         return -1;
1277 }
1278
1279 void device_release_write(struct discover_device *dev, bool release)
1280 {
1281         const char *fstype;
1282
1283         if (!release)
1284                 return;
1285
1286         fstype = discover_device_get_param(dev, "ID_FS_TYPE");
1287
1288         pb_log("remounting device %s read-only\n", dev->device_path);
1289         mount(dev->device_path, dev->mount_path, "",
1290                         MS_REMOUNT | MS_RDONLY | MS_SILENT,
1291                         fs_parameters(MS_RDONLY, fstype));
1292         dev->mounted_rw = false;
1293 }
1294
1295 #else
1296
1297 static void device_handler_update_lang(const char *lang __attribute__((unused)))
1298 {
1299 }
1300
1301 static int device_handler_init_sources(
1302                 struct device_handler *handler __attribute__((unused)))
1303 {
1304         return 0;
1305 }
1306
1307 static void device_handler_reinit_sources(
1308                 struct device_handler *handler __attribute__((unused)))
1309 {
1310 }
1311
1312 static int umount_device(struct discover_device *dev __attribute__((unused)))
1313 {
1314         return 0;
1315 }
1316
1317 static int __attribute__((unused)) mount_device(
1318                 struct discover_device *dev __attribute__((unused)))
1319 {
1320         return 0;
1321 }
1322
1323 int device_request_write(struct discover_device *dev __attribute__((unused)),
1324                 bool *release)
1325 {
1326         *release = true;
1327         return 0;
1328 }
1329
1330 void device_release_write(struct discover_device *dev __attribute__((unused)),
1331         bool release __attribute__((unused)))
1332 {
1333 }
1334
1335 #endif
1336