+struct {
+ enum ipmi_bootdev ipmi_type;
+ enum device_type device_type;
+} device_type_map[] = {
+ { IPMI_BOOTDEV_NETWORK, DEVICE_TYPE_NETWORK },
+ { IPMI_BOOTDEV_DISK, DEVICE_TYPE_DISK },
+ { IPMI_BOOTDEV_CDROM, DEVICE_TYPE_OPTICAL },
+};
+
+static bool ipmi_device_type_matches(enum ipmi_bootdev ipmi_type,
+ enum device_type device_type)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(device_type_map); i++) {
+ if (device_type_map[i].device_type == device_type)
+ return device_type_map[i].ipmi_type == ipmi_type;
+ }
+
+ return false;
+}
+
+static bool priority_matches(struct boot_priority *prio,
+ struct discover_boot_option *opt)
+{
+ return prio->type == opt->device->device->type ||
+ prio->type == DEVICE_TYPE_ANY;
+}
+
+/*
+ * We have different priorities to resolve conflicts between boot options that
+ * report to be the default for their device. This function assigns a priority
+ * for these options.
+ */
+static enum default_priority default_option_priority(
+ struct discover_boot_option *opt)
+{
+ const struct config *config;
+ const char *dev_str;
+ unsigned int i;
+
+ config = config_get();
+
+ /* We give highest priority to IPMI-configured boot options. If
+ * we have an IPMI bootdev configuration set, then we don't allow
+ * any other defaults */
+ if (config->ipmi_bootdev) {
+ bool ipmi_match = ipmi_device_type_matches(config->ipmi_bootdev,
+ opt->device->device->type);
+ if (ipmi_match)
+ return DEFAULT_PRIORITY_REMOTE;
+
+ pb_debug("handler: disabled default priority due to "
+ "non-matching IPMI type %x\n",
+ config->ipmi_bootdev);
+ return DEFAULT_PRIORITY_DISABLED;
+ }
+
+ /* Next, allow matching by device UUID. If we have one set but it
+ * doesn't match, disallow the default entirely */
+ dev_str = config->boot_device;
+ if (dev_str && dev_str[0]) {
+ if (!strcmp(opt->device->uuid, dev_str))
+ return DEFAULT_PRIORITY_LOCAL_UUID;
+
+ pb_debug("handler: disabled default priority due to "
+ "non-matching UUID\n");
+ return DEFAULT_PRIORITY_DISABLED;
+ }
+
+ /* Lastly, use the local priorities */
+ for (i = 0; i < config->n_boot_priorities; i++) {
+ struct boot_priority *prio = &config->boot_priorities[i];
+ if (priority_matches(prio, opt))
+ return DEFAULT_PRIORITY_LOCAL_FIRST + prio->priority;
+ }
+
+ return DEFAULT_PRIORITY_DISABLED;
+}
+