} device_type_map[] = {
{ IPMI_BOOTDEV_NETWORK, DEVICE_TYPE_NETWORK },
{ IPMI_BOOTDEV_DISK, DEVICE_TYPE_DISK },
+ { IPMI_BOOTDEV_DISK, DEVICE_TYPE_USB },
{ IPMI_BOOTDEV_CDROM, DEVICE_TYPE_OPTICAL },
};
status = talloc_zero(handler, struct boot_status);
status->type = BOOT_STATUS_INFO;
- status->message = talloc_asprintf(status, "Processing %s device %s",
+ /*
+ * TRANSLATORS: this string will be passed the type and identifier
+ * of the device. For example, the first parameter could be "Disk",
+ * (which will be translated accordingly) and the second a Linux device
+ * identifier like 'sda1' (which will not be translated)
+ */
+ status->message = talloc_asprintf(status, _("Processing %s device %s"),
device_type_display_name(dev->device->type),
dev->device->id);
boot_status(handler, status);
device_handler_discover_context_commit(handler, ctx);
out:
- status->message = talloc_asprintf(status,"Processing %s complete\n",
+ /*
+ * TRANSLATORS: the format specifier in this string is a Linux
+ * device identifier, like 'sda1'
+ */
+ status->message = talloc_asprintf(status,_("Processing %s complete"),
dev->device->id);
boot_status(handler, status);
status = talloc_zero(handler, struct boot_status);
status->type = BOOT_STATUS_INFO;
- status->message = talloc_asprintf(status, "Processing dhcp event on %s",
+ /*
+ * TRANSLATORS: this format specifier will be the name of a network
+ * device, like 'eth0'.
+ */
+ status->message = talloc_asprintf(status, _("Processing dhcp event on %s"),
dev->device->id);
boot_status(handler, status);
device_handler_discover_context_commit(handler, ctx);
- status->message = talloc_asprintf(status,"Processing %s complete\n",
+ /*
+ * TRANSLATORS: this format specifier will be the name of a network
+ * device, like 'eth0'.
+ */
+ status->message = talloc_asprintf(status,_("Processing %s complete"),
dev->device->id);
boot_status(handler, status);
status = talloc_zero(handler, struct boot_status);
status->type = BOOT_STATUS_INFO;
- status->message = talloc_asprintf(status, "Processing user config");
+ status->message = talloc_asprintf(status, _("Processing user config"));
boot_status(handler, status);
/* create our context */
device_handler_discover_context_commit(handler, ctx);
status->message = talloc_asprintf(status,
- "Processing user config complete");
+ _("Processing user config complete"));
boot_status(handler, status);
talloc_free(status);
rc = process_run_sync(p);
- if (rc) {
+ if (rc || p->exit_status) {
/* ip has complained for some reason; most likely
* there is no route to the host - bail out */
- pb_debug("%s: No route to %s\n",__func__,url->host);
+ pb_debug("%s: `ip` returns non-zero exit status\n", __func__);
+ pb_debug("ip buf: %s\n", p->stdout_buf);
+ process_release(p);
return NULL;
}
return dev;
}
-
void device_handler_process_url(struct device_handler *handler,
- const char *url)
+ const char *url, const char *mac, const char *ip)
{
struct discover_context *ctx;
struct discover_device *dev;
event->type = EVENT_TYPE_USER;
event->action = EVENT_ACTION_CONF;
- event->params = talloc_array(event, struct param, 1);
- param = &event->params[0];
- param->name = talloc_strdup(event, "pxeconffile");
- param->value = talloc_strdup(event, url);
- event->n_params = 1;
+ if (url[strlen(url) - 1] == '/') {
+ event->params = talloc_array(event, struct param, 3);
+ param = &event->params[0];
+ param->name = talloc_strdup(event, "pxepathprefix");
+ param->value = talloc_strdup(event, url);
+ param = &event->params[1];
+ param->name = talloc_strdup(event, "mac");
+ param->value = talloc_strdup(event, mac);
+ param = &event->params[2];
+ param->name = talloc_strdup(event, "ip");
+ param->value = talloc_strdup(event, ip);
+ event->n_params = 3;
+ } else {
+ event->params = talloc_array(event, struct param, 1);
+ param = &event->params[0];
+ param->name = talloc_strdup(event, "pxeconffile");
+ param->value = talloc_strdup(event, url);
+ event->n_params = 1;
+ }
pb_url = pb_url_parse(event, event->params->value);
if (!pb_url || !pb_url->host) {
handler->dry_run);
}
-static const char *fs_parameters(unsigned int rw_flags, const char *fstype)
+static inline const char *get_device_path(struct discover_device *dev)
{
- if ((rw_flags | MS_RDONLY) != MS_RDONLY)
- return "";
-
- /* Avoid writing back to the disk on journaled filesystems */
- if (!strncmp(fstype, "ext4", strlen("ext4")))
- return "norecovery";
- if (!strncmp(fstype, "xfs", strlen("xfs")))
- return "norecovery";
-
- return "";
+ return dev->ramdisk ? dev->ramdisk->snapshot : dev->device_path;
}
-static inline const char *get_device_path(struct discover_device *dev)
+static char *check_subvols(struct discover_device *dev)
{
- return dev->ramdisk ? dev->ramdisk->snapshot : dev->device_path;
+ const char *fstype = discover_device_get_param(dev, "ID_FS_TYPE");
+ struct stat sb;
+ char *path;
+ int rc;
+
+ if (strncmp(fstype, "btrfs", strlen("btrfs")))
+ return dev->mount_path;
+
+ /* On btrfs a device's root may be under a subvolume path */
+ path = join_paths(dev, dev->mount_path, "@");
+ rc = stat(path, &sb);
+ if (!rc && S_ISDIR(sb.st_mode)) {
+ pb_debug("Using '%s' for btrfs root path\n", path);
+ return path;
+ }
+
+ talloc_free(path);
+ return dev->mount_path;
}
static bool check_existing_mount(struct discover_device *dev)
if (mntstat.st_rdev == devstat.st_rdev) {
dev->mount_path = talloc_strdup(dev, mnt->mnt_dir);
+ dev->root_path = check_subvols(dev);
dev->mounted_rw = !!hasmntopt(mnt, "rw");
dev->mounted = true;
dev->unmount = false;
return mnt != NULL;
}
+/*
+ * Attempt to mount a filesystem safely, while handling certain filesytem-
+ * specific options
+ */
+static int try_mount(const char *device_path, const char *mount_path,
+ const char *fstype, unsigned long flags,
+ bool have_snapshot)
+{
+ const char *fs, *safe_opts;
+ int rc;
+
+ /* Mount ext3 as ext4 instead so 'norecovery' can be used */
+ if (strncmp(fstype, "ext3", strlen("ext3")) == 0) {
+ pb_debug("Mounting ext3 filesystem as ext4\n");
+ fs = "ext4";
+ } else
+ fs = fstype;
+
+ if (strncmp(fs, "xfs", strlen("xfs")) == 0 ||
+ strncmp(fs, "ext4", strlen("ext4")) == 0)
+ safe_opts = "norecovery";
+ else
+ safe_opts = NULL;
+
+ errno = 0;
+ /* If no snapshot is available don't attempt recovery */
+ if (!have_snapshot)
+ return mount(device_path, mount_path, fs, flags, safe_opts);
+
+ rc = mount(device_path, mount_path, fs, flags, NULL);
+
+ if (!rc)
+ return rc;
+
+ /* Mounting failed; some filesystems will fail to mount if a recovery
+ * journal exists (eg. cross-endian XFS), so try again with norecovery
+ * where that option is available.
+ * If mounting read-write just return the error as norecovery is not a
+ * valid option */
+ if ((flags & MS_RDONLY) != MS_RDONLY || !safe_opts)
+ return rc;
+
+ errno = 0;
+ return mount(device_path, mount_path, fs, flags, safe_opts);
+}
+
static int mount_device(struct discover_device *dev)
{
const char *fstype, *device_path;
if (!fstype)
return 0;
- /* ext3 treats the norecovery option as an error, so mount the device
- * as an ext4 filesystem instead */
- if (!strncmp(fstype, "ext3", strlen("ext3"))) {
- pb_debug("Mounting ext3 filesystem as ext4\n");
- fstype = talloc_asprintf(dev, "ext4");
- }
-
dev->mount_path = join_paths(dev, mount_base(),
dev->device_path);
device_path = get_device_path(dev);
pb_log("mounting device %s read-only\n", dev->device_path);
- errno = 0;
- rc = mount(device_path, dev->mount_path, fstype,
- MS_RDONLY | MS_SILENT,
- fs_parameters(MS_RDONLY, fstype));
+ rc = try_mount(device_path, dev->mount_path, fstype,
+ MS_RDONLY | MS_SILENT, dev->ramdisk);
+
if (!rc) {
dev->mounted = true;
dev->mounted_rw = false;
dev->unmount = true;
+ dev->root_path = check_subvols(dev);
return 0;
}
talloc_free(dev->mount_path);
dev->mount_path = NULL;
+ dev->root_path = NULL;
return 0;
}
return -1;
}
- rc = mount(device_path, dev->mount_path, fstype,
- MS_SILENT,
- fs_parameters(MS_REMOUNT, fstype));
+ rc = try_mount(device_path, dev->mount_path, fstype,
+ MS_SILENT, dev->ramdisk);
if (rc)
goto mount_ro;
mount_ro:
pb_log("Unable to remount device %s read-write: %s\n",
device_path, strerror(errno));
- if (mount(device_path, dev->mount_path, fstype,
- MS_RDONLY | MS_SILENT,
- fs_parameters(MS_RDONLY, fstype)))
+ rc = try_mount(device_path, dev->mount_path, fstype,
+ MS_RDONLY | MS_SILENT, dev->ramdisk);
+ if (rc)
pb_log("Unable to recover mount for %s: %s\n",
device_path, strerror(errno));
return -1;
void device_release_write(struct discover_device *dev, bool release)
{
const char *fstype, *device_path;
- int rc = 0;
if (!release)
return;
device_path = get_device_path(dev);
}
- mount(device_path, dev->mount_path, fstype,
- MS_RDONLY | MS_SILENT,
- fs_parameters(MS_RDONLY, fstype));
- if (rc)
+ if (try_mount(device_path, dev->mount_path, fstype,
+ MS_RDONLY | MS_SILENT, dev->ramdisk))
pb_log("Failed to remount %s read-only: %s\n",
device_path, strerror(errno));
else