X-Git-Url: https://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=discover%2Fdevice-handler.c;h=8b4046edd83e52a686a7ee0b29768a4bffb1f36f;hp=cdfee483767e449c885d0ebf3db3671040a4c78f;hb=bd6e384a0ba2c1464d9270baf829fea932b88224;hpb=f611bde3f182e9a4befb48a0160d1831708aca67 diff --git a/discover/device-handler.c b/discover/device-handler.c index cdfee48..8b4046e 100644 --- a/discover/device-handler.c +++ b/discover/device-handler.c @@ -1,9 +1,11 @@ #include #include +#include #include #include #include +#include #include #include @@ -103,6 +105,12 @@ static int device_match_id(struct discover_device *dev, const char *id) return !strcmp(dev->device->id, id); } +static int device_match_serial(struct discover_device *dev, const char *serial) +{ + const char *val = discover_device_get_param(dev, "ID_SERIAL"); + return val && !strcmp(val, serial); +} + static struct discover_device *device_lookup( struct device_handler *device_handler, int (match_fn)(struct discover_device *, const char *), @@ -154,6 +162,13 @@ struct discover_device *device_lookup_by_id( return device_lookup(device_handler, device_match_id, id); } +struct discover_device *device_lookup_by_serial( + struct device_handler *device_handler, + const char *serial) +{ + return device_lookup(device_handler, device_match_serial, serial); +} + void device_handler_destroy(struct device_handler *handler) { talloc_free(handler); @@ -327,6 +342,8 @@ static int default_timeout(void *arg) return 0; } + handler->timeout_waiter = NULL; + pb_log("Timeout expired, booting default option %s\n", opt->option->id); boot(handler, handler->default_boot_option, NULL, @@ -334,17 +351,56 @@ static int default_timeout(void *arg) return 0; } +static bool priority_match(struct boot_priority *prio, + struct discover_boot_option *opt) +{ + return prio->type == opt->device->device->type; +} + +static int default_option_priority(struct discover_boot_option *opt) +{ + const struct config *config; + struct boot_priority *prio; + int i; + + config = config_get(); + + for (i = 0; i < config->n_boot_priorities; i++) { + prio = &config->boot_priorities[i]; + if (priority_match(prio, opt)) + break; + } + + return i; +} + static void set_default(struct device_handler *handler, struct discover_boot_option *opt) { - if (handler->default_boot_option) + if (!handler->autoboot_enabled) return; - if (!handler->autoboot_enabled) + /* Resolve any conflicts: if we have a new default option, it only + * replaces the current if it has a higher priority. */ + if (handler->default_boot_option) { + int new_prio, cur_prio; + + new_prio = default_option_priority(opt); + cur_prio = default_option_priority( + handler->default_boot_option); + + if (new_prio < cur_prio) { + handler->default_boot_option = opt; + /* extend the timeout a little, so the user sees some + * indication of the change */ + handler->sec_to_boot += 2; + } + return; + } - handler->default_boot_option = opt; handler->sec_to_boot = config_get()->autoboot_timeout_sec; + handler->default_boot_option = opt; pb_log("Boot option %s set as default, timeout %u sec.\n", opt->option->id, handler->sec_to_boot); @@ -530,13 +586,16 @@ int device_handler_discover(struct device_handler *handler, struct discover_device *dev, enum conf_method method) { struct discover_context *ctx; + int rc; process_boot_option_queue(handler); /* create our context */ ctx = device_handler_discover_context_create(handler, dev); - mount_device(dev); + rc = mount_device(dev); + if (rc) + goto out; /* run the parsers. This will populate the ctx's boot_option list. */ iterate_parsers(ctx, method); @@ -544,6 +603,7 @@ int device_handler_discover(struct device_handler *handler, /* add discovered stuff to the handler */ device_handler_discover_context_commit(handler, ctx); +out: talloc_free(ctx); return 0; @@ -623,6 +683,58 @@ void device_handler_cancel_default(struct device_handler *handler) } #ifndef PETITBOOT_TEST +static bool check_existing_mount(struct discover_device *dev) +{ + struct stat devstat, mntstat; + struct mntent *mnt; + FILE *fp; + int rc; + + rc = stat(dev->device_path, &devstat); + if (rc) { + pb_debug("%s: stat failed: %s\n", __func__, strerror(errno)); + return false; + } + + if (!S_ISBLK(devstat.st_mode)) { + pb_debug("%s: %s isn't a block device?\n", __func__, + dev->device_path); + return false; + } + + fp = fopen("/proc/self/mounts", "r"); + + for (;;) { + mnt = getmntent(fp); + if (!mnt) + break; + + if (!mnt->mnt_fsname || mnt->mnt_fsname[0] != '/') + continue; + + rc = stat(mnt->mnt_fsname, &mntstat); + if (rc) + continue; + + if (!S_ISBLK(mntstat.st_mode)) + continue; + + if (mntstat.st_rdev == devstat.st_rdev) { + pb_debug("%s: %s is already mounted at %s\n" + __func__, dev->device_path, + mnt->mnt_dir); + dev->mount_path = talloc_strdup(dev, mnt->mnt_dir); + dev->mounted = true; + dev->unmount = false; + break; + } + } + + fclose(fp); + + return mnt != NULL; +} + static int mount_device(struct discover_device *dev) { int rc; @@ -630,29 +742,44 @@ static int mount_device(struct discover_device *dev) if (!dev->device_path) return -1; - if (!dev->mount_path) - dev->mount_path = join_paths(dev, mount_base(), - dev->device_path); + if (dev->mounted) + return 0; - if (pb_mkdir_recursive(dev->mount_path)) + if (check_existing_mount(dev)) + return 0; + + dev->mount_path = join_paths(dev, mount_base(), + dev->device_path); + + if (pb_mkdir_recursive(dev->mount_path)) { pb_log("couldn't create mount directory %s: %s\n", dev->mount_path, strerror(errno)); + goto err_free; + } rc = process_run_simple(dev, pb_system_apps.mount, dev->device_path, dev->mount_path, "-o", "ro", NULL); - - if (!rc) + if (!rc) { + dev->mounted = true; + dev->unmount = true; return 0; + } /* Retry mount without ro option. */ rc = process_run_simple(dev, pb_system_apps.mount, dev->device_path, dev->mount_path, NULL); - if (!rc) + if (!rc) { + dev->mounted = true; + dev->unmount = true; return 0; + } pb_rmdir_recursive(mount_base(), dev->mount_path); +err_free: + talloc_free(dev->mount_path); + dev->mount_path = NULL; return -1; } @@ -660,7 +787,7 @@ static int umount_device(struct discover_device *dev) { int status; - if (!dev->mount_path) + if (!dev->mounted || !dev->unmount) return 0; status = process_run_simple(dev, pb_system_apps.umount, @@ -669,6 +796,10 @@ static int umount_device(struct discover_device *dev) if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) return -1; + dev->mounted = false; + talloc_free(dev->mount_path); + dev->mount_path = NULL; + pb_rmdir_recursive(mount_base(), dev->mount_path); return 0;