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