From: Samuel Mendoza-Jonas Date: Fri, 11 Sep 2015 05:56:18 +0000 (+1000) Subject: Merge branch 'pb-plugin' into master X-Git-Tag: v1.0.0~49 X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=commitdiff_plain;h=5acb43464206348b7cced9508852fdd2989aea58;hp=d6f3931ec79f9c9cbcf9daef1f1d0957cb07ffa5 Merge branch 'pb-plugin' into master Signed-off-by: Samuel Mendoza-Jonas --- diff --git a/discover/Makefile.am b/discover/Makefile.am index 7808110..1672035 100644 --- a/discover/Makefile.am +++ b/discover/Makefile.am @@ -24,6 +24,8 @@ discover_pb_discover_SOURCES = \ discover/device-handler.h \ discover/discover-server.c \ discover/discover-server.h \ + discover/devmapper.c \ + discover/devmapper.h \ discover/event.c \ discover/event.h \ discover/params.c \ @@ -58,6 +60,10 @@ discover_pb_discover_LDADD = \ $(core_lib) \ $(UDEV_LIBS) +discover_pb_discover_LDFLAGS = \ + $(AM_LDFLAGS) \ + -ldevmapper + discover_pb_discover_CPPFLAGS = \ $(AM_CPPFLAGS) \ -DLOCAL_STATE_DIR='"$(localstatedir)"' \ diff --git a/discover/device-handler.c b/discover/device-handler.c index 64095f1..4e25e07 100644 --- a/discover/device-handler.c +++ b/discover/device-handler.c @@ -26,6 +26,7 @@ #include "device-handler.h" #include "discover-server.h" +#include "devmapper.h" #include "user-event.h" #include "platform.h" #include "event.h" @@ -56,6 +57,9 @@ struct device_handler { struct discover_device **devices; unsigned int n_devices; + struct ramdisk_device **ramdisks; + unsigned int n_ramdisks; + struct waitset *waitset; struct waiter *timeout_waiter; bool autoboot_enabled; @@ -319,6 +323,7 @@ struct device_handler *device_handler_init(struct discover_server *server, void device_handler_reinit(struct device_handler *handler) { struct discover_boot_option *opt, *tmp; + struct ramdisk_device *ramdisk; unsigned int i; device_handler_cancel_default(handler); @@ -330,13 +335,20 @@ void device_handler_reinit(struct device_handler *handler) list_init(&handler->unresolved_boot_options); /* drop all devices */ - for (i = 0; i < handler->n_devices; i++) + for (i = 0; i < handler->n_devices; i++) { discover_server_notify_device_remove(handler->server, handler->devices[i]->device); + ramdisk = handler->devices[i]->ramdisk; + talloc_free(handler->devices[i]); + talloc_free(ramdisk); + } talloc_free(handler->devices); handler->devices = NULL; handler->n_devices = 0; + talloc_free(handler->ramdisks); + handler->ramdisks = NULL; + handler->n_ramdisks = 0; device_handler_reinit_sources(handler); } @@ -445,6 +457,7 @@ struct { } 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 }, }; @@ -748,6 +761,95 @@ void device_handler_add_device(struct device_handler *handler, network_register_device(handler->network, device); } +void device_handler_add_ramdisk(struct device_handler *handler, + const char *path) +{ + struct ramdisk_device *dev; + unsigned int i; + + if (!path) + return; + + for (i = 0; i < handler->n_ramdisks; i++) + if (!strcmp(handler->ramdisks[i]->path, path)) + return; + + dev = talloc_zero(handler, struct ramdisk_device); + if (!dev) { + pb_log("Failed to allocate memory to track %s\n", path); + return; + } + + dev->path = talloc_strdup(handler, path); + + handler->ramdisks = talloc_realloc(handler, handler->ramdisks, + struct ramdisk_device *, + handler->n_ramdisks + 1); + if (!handler->ramdisks) { + pb_log("Failed to reallocate memory" + "- ramdisk tracking inconsistent!\n"); + return; + } + + handler->ramdisks[i] = dev; + i = handler->n_ramdisks++; +} + +struct ramdisk_device *device_handler_get_ramdisk( + struct device_handler *handler) +{ + unsigned int i; + char *name; + dev_t id; + + /* Check if free ramdisk exists */ + for (i = 0; i < handler->n_ramdisks; i++) + if (!handler->ramdisks[i]->snapshot && + !handler->ramdisks[i]->origin && + !handler->ramdisks[i]->base) + return handler->ramdisks[i]; + + /* Otherwise create a new one */ + name = talloc_asprintf(handler, "/dev/ram%d", + handler->n_ramdisks); + if (!name) { + pb_debug("Failed to allocate memory to name /dev/ram%d", + handler->n_ramdisks); + return NULL; + } + + id = makedev(1, handler->n_ramdisks); + if (mknod(name, S_IFBLK, id)) { + if (errno == EEXIST) { + /* We haven't yet received updates for existing + * ramdisks - add and use this one */ + pb_debug("Using untracked ramdisk %s\n", name); + } else { + pb_log("Failed to create new ramdisk %s: %s\n", + name, strerror(errno)); + return NULL; + } + } + device_handler_add_ramdisk(handler, name); + talloc_free(name); + + return handler->ramdisks[i]; +} + +void device_handler_release_ramdisk(struct discover_device *device) +{ + struct ramdisk_device *ramdisk = device->ramdisk; + + talloc_free(ramdisk->snapshot); + talloc_free(ramdisk->origin); + talloc_free(ramdisk->base); + + ramdisk->snapshot = ramdisk->origin = ramdisk->base = NULL; + ramdisk->sectors = 0; + + device->ramdisk = NULL; +} + /* Start discovery on a hotplugged device. The device will be in our devices * array, but has only just been initialised by the hotplug source. */ @@ -1123,28 +1225,46 @@ static void device_handler_reinit_sources(struct device_handler *handler) handler->dry_run); } -static const char *fs_parameters(unsigned int rw_flags, const char *fstype) +static const char *fs_parameters(struct discover_device *dev, + unsigned int rw_flags) { + const char *fstype = discover_device_get_param(dev, "ID_FS_TYPE"); + + /* XFS journals are not cross-endian compatible; don't try recovery + * even if we have a snapshot */ + if (!strncmp(fstype, "xfs", strlen("xfs"))) + return "norecovery"; + + /* If we have a snapshot available allow touching the filesystem */ + if (dev->ramdisk) + return ""; + if ((rw_flags | MS_RDONLY) != MS_RDONLY) return ""; - /* Avoid writing back to the disk on journaled filesystems */ + /* Avoid writes due to journal replay if we don't have a snapshot */ if (!strncmp(fstype, "ext4", strlen("ext4"))) return "norecovery"; - if (!strncmp(fstype, "xfs", strlen("xfs"))) - return "norecovery"; return ""; } +static inline const char *get_device_path(struct discover_device *dev) +{ + return dev->ramdisk ? dev->ramdisk->snapshot : dev->device_path; +} + static bool check_existing_mount(struct discover_device *dev) { struct stat devstat, mntstat; + const char *device_path; struct mntent *mnt; FILE *fp; int rc; - rc = stat(dev->device_path, &devstat); + device_path = get_device_path(dev); + + rc = stat(device_path, &devstat); if (rc) { pb_debug("%s: stat failed: %s\n", __func__, strerror(errno)); return false; @@ -1194,7 +1314,7 @@ static bool check_existing_mount(struct discover_device *dev) static int mount_device(struct discover_device *dev) { - const char *fstype; + const char *fstype, *device_path; int rc; if (!dev->device_path) @@ -1226,11 +1346,13 @@ static int mount_device(struct discover_device *dev) goto err_free; } + device_path = get_device_path(dev); + pb_log("mounting device %s read-only\n", dev->device_path); errno = 0; - rc = mount(dev->device_path, dev->mount_path, fstype, + rc = mount(device_path, dev->mount_path, fstype, MS_RDONLY | MS_SILENT, - fs_parameters(MS_RDONLY, fstype)); + fs_parameters(dev, MS_RDONLY)); if (!rc) { dev->mounted = true; dev->mounted_rw = false; @@ -1239,7 +1361,10 @@ static int mount_device(struct discover_device *dev) } pb_log("couldn't mount device %s: mount failed: %s\n", - dev->device_path, strerror(errno)); + device_path, strerror(errno)); + + /* If mount fails clean up any snapshot */ + devmapper_destroy_snapshot(dev); pb_rmdir_recursive(mount_base(), dev->mount_path); err_free: @@ -1250,17 +1375,21 @@ err_free: static int umount_device(struct discover_device *dev) { + const char *device_path; int rc; if (!dev->mounted || !dev->unmount) return 0; - pb_log("unmounting device %s\n", dev->device_path); + device_path = get_device_path(dev); + + pb_log("unmounting device %s\n", device_path); rc = umount(dev->mount_path); if (rc) return -1; dev->mounted = false; + devmapper_destroy_snapshot(dev); pb_rmdir_recursive(mount_base(), dev->mount_path); @@ -1272,11 +1401,16 @@ static int umount_device(struct discover_device *dev) int device_request_write(struct discover_device *dev, bool *release) { - const char *fstype; + const char *fstype, *device_path; + const struct config *config; int rc; *release = false; + config = config_get(); + if (!config->allow_writes) + return -1; + if (!dev->mounted) return -1; @@ -1285,16 +1419,20 @@ int device_request_write(struct discover_device *dev, bool *release) fstype = discover_device_get_param(dev, "ID_FS_TYPE"); - pb_log("remounting device %s read-write\n", dev->device_path); + device_path = get_device_path(dev); + + pb_log("remounting device %s read-write\n", device_path); rc = umount(dev->mount_path); if (rc) { - pb_log("Failed to unmount %s\n", dev->mount_path); + pb_log("Failed to unmount %s: %s\n", + dev->mount_path, strerror(errno)); return -1; } - rc = mount(dev->device_path, dev->mount_path, fstype, + + rc = mount(device_path, dev->mount_path, fstype, MS_SILENT, - fs_parameters(MS_REMOUNT, fstype)); + fs_parameters(dev, MS_REMOUNT)); if (rc) goto mount_ro; @@ -1303,29 +1441,50 @@ int device_request_write(struct discover_device *dev, bool *release) return 0; mount_ro: - pb_log("Unable to remount device %s read-write\n", dev->device_path); - rc = mount(dev->device_path, dev->mount_path, fstype, + 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)); - if (rc) - pb_log("Unable to recover mount for %s\n", dev->device_path); + fs_parameters(dev, MS_RDONLY))) + 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; + const char *fstype, *device_path; + int rc = 0; if (!release) return; + device_path = get_device_path(dev); + fstype = discover_device_get_param(dev, "ID_FS_TYPE"); - pb_log("remounting device %s read-only\n", dev->device_path); - mount(dev->device_path, dev->mount_path, "", - MS_REMOUNT | MS_RDONLY | MS_SILENT, - fs_parameters(MS_RDONLY, fstype)); - dev->mounted_rw = false; + pb_log("remounting device %s read-only\n", device_path); + + if (umount(dev->mount_path)) { + pb_log("Failed to unmount %s\n", dev->mount_path); + return; + } + dev->mounted_rw = dev->mounted = false; + + if (dev->ramdisk) { + devmapper_merge_snapshot(dev); + /* device_path becomes stale after merge */ + device_path = get_device_path(dev); + } + + mount(device_path, dev->mount_path, fstype, + MS_RDONLY | MS_SILENT, + fs_parameters(dev, MS_RDONLY)); + if (rc) + pb_log("Failed to remount %s read-only: %s\n", + device_path, strerror(errno)); + else + dev->mounted = true; } #else diff --git a/discover/device-handler.h b/discover/device-handler.h index b592c46..5877733 100644 --- a/discover/device-handler.h +++ b/discover/device-handler.h @@ -26,6 +26,7 @@ struct discover_device { char *mount_path; const char *device_path; + struct ramdisk_device *ramdisk; bool mounted; bool mounted_rw; bool unmount; @@ -59,6 +60,14 @@ struct discover_context { void *test_data; }; +struct ramdisk_device { + const char *path; + char *snapshot; + char *origin; + char *base; + unsigned int sectors; +}; + struct device_handler *device_handler_init(struct discover_server *server, struct waitset *waitset, int dry_run); @@ -72,6 +81,11 @@ struct discover_device *discover_device_create(struct device_handler *handler, const char *id); void device_handler_add_device(struct device_handler *handler, struct discover_device *device); +void device_handler_add_ramdisk(struct device_handler *handler, + const char *path); +struct ramdisk_device *device_handler_get_ramdisk( + struct device_handler *handler); +void device_handler_release_ramdisk(struct discover_device *device); int device_handler_discover(struct device_handler *handler, struct discover_device *dev); int device_handler_dhcp(struct device_handler *handler, diff --git a/discover/devmapper.c b/discover/devmapper.c new file mode 100644 index 0000000..e2ef0b5 --- /dev/null +++ b/discover/devmapper.c @@ -0,0 +1,553 @@ +#include +#include +#include +#include +#include + +#include "libdevmapper.h" +#include "devmapper.h" +#include "platform.h" + +#define MERGE_INTERVAL_US 200000 + +struct target { + long unsigned int start_sector; + long unsigned int end_sector; + char *ttype; + char *params; +}; + +/* Return the number of sectors on a block device. Zero represents an error */ +static unsigned int get_block_sectors(struct discover_device *device) +{ + const char *tmp; + long unsigned int sectors; + + tmp = discover_device_get_param(device, "ID_PART_ENTRY_SIZE"); + if (!tmp) { + pb_debug("Could not retrieve ID_PART_ENTRY_SIZE for %s\n", + device->device_path); + return 0; + } + + errno = 0; + sectors = strtoul(tmp, NULL, 0); + if (errno) { + pb_debug("Error reading sector count for %s: %s\n", + device->device_path, strerror(errno)); + sectors = 0; + } + + return sectors; +} + +/* + * The system's libdm may or may not have udev sync support. Tell libdm + * to manage the creation of device nodes itself rather than waiting on udev + * to do it + */ +static inline int set_cookie(struct dm_task *task, uint32_t *cookie) +{ + uint16_t udev_rules = 0; + *cookie = 0; + + dm_udev_set_sync_support(0); + udev_rules |= DM_UDEV_DISABLE_DM_RULES_FLAG | + DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG; + + return dm_task_set_cookie(task, cookie, udev_rules); +} + +static bool snapshot_merge_complete(const char *dm_name) +{ + long long unsigned int sectors, meta_sectors; + char *params = NULL, *target_type = NULL; + uint64_t start, length; + struct dm_task *task; + bool result = true; + int n; + + task = dm_task_create(DM_DEVICE_STATUS); + if (!task) { + pb_log("%s: Error creating task\n", __func__); + return result; + } + + if (!dm_task_set_name(task, dm_name)) { + pb_log("No dm-device named '%s'\n", dm_name); + goto out; + } + + if (!dm_task_run(task)) { + pb_log("Unable to retrieve status for '%s'\n", dm_name); + goto out; + } + + dm_get_next_target(task, NULL, &start, &length, &target_type, ¶ms); + + if (!params) { + pb_log("Unable to retrieve params for '%s'\n", dm_name); + goto out; + } + + if (!strncmp(params, "Invalid", strlen("Invalid"))) { + pb_log("dm-device %s has become invalid\n", dm_name); + goto out; + } + + /* Merge is complete when metadata sectors are the only sectors + * allocated - see Documentation/device-mapper/snapshot.txt */ + n = sscanf(params, "%llu/%*u %llu", §ors, &meta_sectors); + if (n != 2) { + pb_log("%s unexpected status: '%s'\n", dm_name, params); + goto out; + } + result = sectors == meta_sectors; + + pb_debug("%s merging; %llu sectors, %llu metadata sectors\n", + dm_name, sectors, meta_sectors); + +out: + /* In case of error or an invalid snapshot return true so callers will + * move on and catch the error */ + dm_task_destroy(task); + return result; +} + +/* Resume or suspend dm device */ +static int set_device_active(const char *dm_name, bool active) +{ + struct dm_task *task; + uint32_t cookie; + int rc = -1; + + if (active) + task = dm_task_create(DM_DEVICE_RESUME); + else + task = dm_task_create(DM_DEVICE_SUSPEND); + + if (!task) { + pb_log("%s: Could not create dm_task\n", __func__); + return rc; + } + + if (!dm_task_set_name(task, dm_name)) { + pb_log("No dm-device named '%s'\n", dm_name); + goto out; + } + + if (!set_cookie(task, &cookie)) + goto out; + + if (!dm_task_run(task)) { + pb_log("Unable to %s device '%s'\n", + active ? "resume" : "suspend", dm_name); + goto out; + } + + rc = 0; + + /* Wait for /dev/mapper/ entries to be updated */ + dm_udev_wait(cookie); + +out: + dm_task_destroy(task); + return rc; +} + +/* Run a DM_DEVICE_CREATE task with provided table (ttype and params) */ +static int run_create_task(const char *dm_name, const struct target *target) +{ + struct dm_task *task; + uint32_t cookie; + + pb_debug("%s: %lu %lu '%s' '%s'\n", __func__, + target->start_sector, target->end_sector, + target->ttype, target->params); + + task = dm_task_create(DM_DEVICE_CREATE); + if (!task) { + pb_log("Error creating new dm-task\n"); + return -1; + } + + if (!dm_task_set_name(task, dm_name)) + return -1; + + if (!dm_task_add_target(task, target->start_sector, target->end_sector, + target->ttype, target->params)) + return -1; + + if (!dm_task_set_add_node(task, DM_ADD_NODE_ON_CREATE)) + return -1; + + if (!set_cookie(task, &cookie)) + return -1; + + if (!dm_task_run(task)) { + pb_log("Error executing dm-task\n"); + return -1; + } + + /* Wait for /dev/mapper/ entry to appear */ + dm_udev_wait(cookie); + + dm_task_destroy(task); + return 0; +} + +static int create_base(struct discover_device *device) +{ + struct target target; + char *name = NULL; + int rc = -1; + + if (!device->ramdisk) + return rc; + + target.start_sector = 0; + target.end_sector = device->ramdisk->sectors; + + target.ttype = talloc_asprintf(device, "linear"); + target.params = talloc_asprintf(device, "%s 0", device->device_path); + if (!target.ttype || !target.params) { + pb_log("Failed to allocate map parameters\n"); + goto out; + } + + name = talloc_asprintf(device, "%s-base", device->device->id); + if (!name || run_create_task(name, &target)) + goto out; + + device->ramdisk->base = talloc_asprintf(device, "/dev/mapper/%s-base", + device->device->id); + if (!device->ramdisk->base) { + pb_log("Failed to track new device /dev/mapper/%s-base\n", + device->device->id); + goto out; + } + + rc = 0; + +out: + talloc_free(name); + talloc_free(target.params); + talloc_free(target.ttype); + return rc; +} + +static int create_origin(struct discover_device *device) +{ + struct target target; + char *name = NULL; + int rc = -1; + + if (!device->ramdisk || !device->ramdisk->base) + return -1; + + target.start_sector = 0; + target.end_sector = device->ramdisk->sectors; + + target.ttype = talloc_asprintf(device, "snapshot-origin"); + target.params = talloc_asprintf(device, "%s", device->ramdisk->base); + if (!target.ttype || !target.params) { + pb_log("Failed to allocate map parameters\n"); + goto out; + } + + name = talloc_asprintf(device, "%s-origin", device->device->id); + if (!name || run_create_task(name, &target)) + goto out; + + device->ramdisk->origin = talloc_asprintf(device, + "/dev/mapper/%s-origin", + device->device->id); + if (!device->ramdisk->origin) { + pb_log("Failed to track new device /dev/mapper/%s-origin\n", + device->device->id); + goto out; + } + + rc = 0; + +out: + talloc_free(name); + talloc_free(target.params); + talloc_free(target.ttype); + return rc; +} + +static int create_snapshot(struct discover_device *device) +{ + struct target target; + int rc = -1; + + if (!device->ramdisk || !device->ramdisk->base || + !device->ramdisk->origin) + return -1; + + target.start_sector = 0; + target.end_sector = device->ramdisk->sectors; + + target.ttype = talloc_asprintf(device, "snapshot"); + target.params = talloc_asprintf(device, "%s %s P 8", + device->ramdisk->base, device->ramdisk->path); + if (!target.ttype || !target.params) { + pb_log("Failed to allocate snapshot parameters\n"); + goto out; + } + + if (run_create_task(device->device->id, &target)) + goto out; + + device->ramdisk->snapshot = talloc_asprintf(device, "/dev/mapper/%s", + device->device->id); + if (!device->ramdisk->snapshot) { + pb_log("Failed to track new device /dev/mapper/%s\n", + device->device->id); + goto out; + } + + rc = 0; + +out: + talloc_free(target.params); + talloc_free(target.ttype); + return rc; +} + +int devmapper_init_snapshot(struct device_handler *handler, + struct discover_device *device) +{ + struct ramdisk_device *ramdisk; + + if (config_get()->disable_snapshots) + return 0; + + ramdisk = device_handler_get_ramdisk(handler); + if (!ramdisk) { + pb_log("No ramdisk available for snapshot %s\n", + device->device->id); + return -1; + } + + ramdisk->sectors = get_block_sectors(device); + if (!ramdisk->sectors) { + pb_log("Error retreiving sectors for %s\n", + device->device->id); + return -1; + } + + device->ramdisk = ramdisk; + + /* Create linear map */ + if (create_base(device)) { + pb_log("Error creating linear base\n"); + goto err; + } + + /* Create snapshot-origin */ + if (create_origin(device)) { + pb_log("Error creating snapshot-origin\n"); + goto err; + } + + if (set_device_active(device->ramdisk->origin, false)) { + pb_log("Failed to suspend origin\n"); + goto err; + } + + /* Create snapshot */ + if (create_snapshot(device)) { + pb_log("Error creating snapshot\n"); + goto err; + } + + if (set_device_active(device->ramdisk->origin, true)) { + pb_log("Failed to resume origin\n"); + goto err; + } + + pb_log("Snapshot successfully created for %s\n", device->device->id); + + return 0; + +err: + pb_log("Error creating snapshot devices for %s\n", device->device->id); + devmapper_destroy_snapshot(device); + return -1; +} + +/* Destroy specific dm device */ +static int destroy_device(const char *dm_name) +{ + struct dm_task *task; + uint32_t cookie; + int rc = -1; + + task = dm_task_create(DM_DEVICE_REMOVE); + if (!task) { + pb_log("%s: could not create dm_task\n", __func__); + return -1; + } + + if (!dm_task_set_name(task, dm_name)) { + pb_log("No dm device named '%s'\n", dm_name); + goto out; + } + + if (!set_cookie(task, &cookie)) + goto out; + + if (!dm_task_run(task)) { + pb_log("Unable to remove device '%s'\n", dm_name); + goto out; + } + + rc = 0; + + /* Wait for /dev/mapper/ entries to be removed */ + dm_udev_wait(cookie); + +out: + dm_task_destroy(task); + return rc; +} + +/* Destroy all dm devices related to a discover_device's snapshot */ +int devmapper_destroy_snapshot(struct discover_device *device) +{ + int rc = -1; + + if (!device->ramdisk) + return 0; + + if (device->mounted) { + pb_log("Can not remove snapshot: %s is mounted\n", + device->device->id); + return -1; + } + + /* Clean up dm devices in order */ + if (device->ramdisk->snapshot) + if (destroy_device(device->ramdisk->snapshot)) + goto out; + + if (device->ramdisk->origin) + if (destroy_device(device->ramdisk->origin)) + goto out; + + if (device->ramdisk->base) + if (destroy_device(device->ramdisk->base)) + goto out; + + rc = 0; +out: + if (rc) + pb_log("Warning: %s snapshot not cleanly removed\n", + device->device->id); + device_handler_release_ramdisk(device); + return rc; +} + +static int reload_snapshot(struct discover_device *device, bool merge) +{ + struct target target; + struct dm_task *task; + int rc = -1; + + target.start_sector = 0; + target.end_sector = device->ramdisk->sectors; + + if (merge) { + target.ttype = talloc_asprintf(device, "snapshot-merge"); + target.params = talloc_asprintf(device, "%s %s P 8", + device->ramdisk->base, device->ramdisk->path); + } else { + target.ttype = talloc_asprintf(device, "snapshot-origin"); + target.params = talloc_asprintf(device, "%s", + device->ramdisk->base); + } + if (!target.ttype || !target.params) { + pb_log("%s: failed to allocate parameters\n", __func__); + goto err1; + } + + task = dm_task_create(DM_DEVICE_RELOAD); + if (!task) { + pb_log("%s: Error creating task\n", __func__); + goto err1; + } + + if (!dm_task_set_name(task, device->ramdisk->origin)) { + pb_log("No dm-device named '%s'\n", device->ramdisk->origin); + goto err2; + } + + if (!dm_task_add_target(task, target.start_sector, target.end_sector, + target.ttype, target.params)) { + pb_log("%s: Failed to set target\n", __func__); + goto err2; + } + + if (!dm_task_run(task)) { + pb_log("Failed to reload %s\n", device->ramdisk->origin); + goto err2; + } + + rc = 0; +err2: + dm_task_destroy(task); +err1: + talloc_free(target.ttype); + talloc_free(target.params); + return rc; +} + +int devmapper_merge_snapshot(struct discover_device *device) +{ + if (device->mounted) { + pb_log("%s: %s still mounted\n", __func__, device->device->id); + return -1; + } + + /* Suspend origin device */ + if (set_device_active(device->ramdisk->origin, false)) { + pb_log("%s: failed to suspend %s\n", + __func__, device->ramdisk->origin); + return -1; + } + + /* Destroy snapshot */ + if (destroy_device(device->ramdisk->snapshot)) { + /* The state of the snapshot is unknown, but try to + * resume to allow the snapshot to be remounted */ + set_device_active(device->ramdisk->origin, true); + return -1; + } + talloc_free(device->ramdisk->snapshot); + device->ramdisk->snapshot = NULL; + + /* Reload origin device for merging */ + reload_snapshot(device, true); + + /* Resume origin device */ + set_device_active(device->ramdisk->origin, true); + + /* Block until merge complete */ + while (!snapshot_merge_complete(device->ramdisk->origin)) + usleep(MERGE_INTERVAL_US); + + /* Suspend origin device */ + set_device_active(device->ramdisk->origin, false); + + /* Reload origin device */ + reload_snapshot(device, false); + + /* Re-create snapshot */ + if (create_snapshot(device)) + return -1; + + /* Resume origin device */ + return set_device_active(device->ramdisk->origin, true); +} diff --git a/discover/devmapper.h b/discover/devmapper.h new file mode 100644 index 0000000..ae8196c --- /dev/null +++ b/discover/devmapper.h @@ -0,0 +1,11 @@ +#ifndef _DEVMAPPER_H +#define _DEVMAPPER_H + +#include "device-handler.h" + +int devmapper_init_snapshot(struct device_handler *handler, + struct discover_device *device); +int devmapper_destroy_snapshot(struct discover_device *device); +int devmapper_merge_snapshot(struct discover_device *device); + +#endif /* _DEVMAPPER_H */ diff --git a/discover/platform-powerpc.c b/discover/platform-powerpc.c index 2b3b043..d45cced 100644 --- a/discover/platform-powerpc.c +++ b/discover/platform-powerpc.c @@ -53,6 +53,8 @@ static const char *known_params[] = { "petitboot,bootdevs", "petitboot,language", "petitboot,debug?", + "petitboot,write?", + "petitboot,snapshots?", NULL, }; @@ -548,6 +550,14 @@ static void populate_config(struct platform_powerpc *platform, val = get_param(platform, "petitboot,debug?"); config->debug = val && !strcmp(val, "true"); } + + val = get_param(platform, "petitboot,write?"); + if (val) + config->allow_writes = !strcmp(val, "true"); + + val = get_param(platform, "petitboot,snapshots?"); + if (val) + config->disable_snapshots = !strcmp(val, "false"); } static char *iface_config_str(void *ctx, struct interface_config *config) @@ -707,6 +717,12 @@ static int update_config(struct platform_powerpc *platform, val = config->lang ?: ""; update_string_config(platform, "petitboot,language", val); + if (config->allow_writes == defaults->allow_writes) + val = ""; + else + val = config->allow_writes ? "true" : "false"; + update_string_config(platform, "petitboot,write?", val); + update_network_config(platform, config); update_bootdev_config(platform, config); diff --git a/discover/platform.c b/discover/platform.c index 74e2a82..a6bd74c 100644 --- a/discover/platform.c +++ b/discover/platform.c @@ -35,6 +35,9 @@ static void dump_config(struct config *config) if (config->safe_mode) pb_log(" safe mode: active\n"); + if (config->disable_snapshots) + pb_log(" dm-snapshots disabled\n"); + for (i = 0; i < config->network.n_interfaces; i++) { struct interface_config *ifconf = config->network.interfaces[i]; @@ -108,6 +111,8 @@ void config_set_defaults(struct config *config) config->network.n_dns_servers = 0; config->safe_mode = false; config->lang = NULL; + config->allow_writes = true; + config->disable_snapshots = false; config->n_autoboot_opts = 2; config->autoboot_opts = talloc_array(config, struct autoboot_option, diff --git a/discover/udev.c b/discover/udev.c index 6ccb8d4..6cc718e 100644 --- a/discover/udev.c +++ b/discover/udev.c @@ -25,6 +25,7 @@ #include "pb-discover.h" #include "device-handler.h" #include "cdrom.h" +#include "devmapper.h" /* We set a default monitor buffer size, as we may not process monitor * events while performing device discvoery. systemd uses a 128M buffer, so @@ -73,13 +74,21 @@ static int udev_handle_block_add(struct pb_udev *udev, struct udev_device *dev, const char *name) { struct discover_device *ddev; + unsigned int i = 0; const char *typestr; const char *uuid; const char *path; const char *node; const char *prop; const char *type; - bool cdrom; + const char *devname; + const char *ignored_types[] = { + "linux_raid_member", + "swap", + "LVM2_member", + NULL, + }; + bool cdrom, usb; typestr = udev_device_get_devtype(dev); if (!typestr) { @@ -94,12 +103,16 @@ static int udev_handle_block_add(struct pb_udev *udev, struct udev_device *dev, node = udev_device_get_devnode(dev); path = udev_device_get_devpath(dev); - if (path && (strstr(path, "virtual/block/loop") - || strstr(path, "virtual/block/ram"))) { + if (path && strstr(path, "virtual/block/loop")) { pb_log("SKIP: %s: ignored (path=%s)\n", name, path); return 0; } + if (path && strstr(path, "virtual/block/ram")) { + device_handler_add_ramdisk(udev->handler, node); + return 0; + } + cdrom = node && !!udev_device_get_property_value(dev, "ID_CDROM"); if (cdrom) { /* CDROMs require a little initialisation, to get @@ -111,12 +124,28 @@ static int udev_handle_block_add(struct pb_udev *udev, struct udev_device *dev, } } + /* If our environment's udev can recognise them explictly skip any + * device mapper devices we encounter */ + devname = udev_device_get_property_value(dev, "DM_NAME"); + if (devname) { + pb_debug("SKIP: dm-device %s\n", devname); + return 0; + } + type = udev_device_get_property_value(dev, "ID_FS_TYPE"); if (!type) { pb_log("SKIP: %s: no ID_FS_TYPE property\n", name); return 0; } + while (ignored_types[i]) { + if (!strncmp(type, ignored_types[i], strlen(ignored_types[i]))) { + pb_log("SKIP: %s: ignore '%s' filesystem\n", name, type); + return 0; + } + i++; + } + /* We may see multipath devices; they'll have the same uuid as an * existing device, so only parse the first. */ uuid = udev_device_get_property_value(dev, "ID_FS_UUID"); @@ -138,10 +167,21 @@ static int udev_handle_block_add(struct pb_udev *udev, struct udev_device *dev, prop = udev_device_get_property_value(dev, "ID_FS_LABEL"); if (prop) ddev->label = talloc_strdup(ddev, prop); - ddev->device->type = cdrom ? DEVICE_TYPE_OPTICAL : DEVICE_TYPE_DISK; + + usb = !!udev_device_get_property_value(dev, "ID_USB_DRIVER"); + if (cdrom) + ddev->device->type = DEVICE_TYPE_OPTICAL; + else + ddev->device->type = usb ? DEVICE_TYPE_USB : DEVICE_TYPE_DISK; udev_setup_device_params(dev, ddev); + /* Create a snapshot for all disks, unless it is an assembled RAID array */ + if ((ddev->device->type == DEVICE_TYPE_DISK || + ddev->device->type == DEVICE_TYPE_USB) && + !udev_device_get_property_value(dev, "MD_LEVEL")) + devmapper_init_snapshot(udev->handler, ddev); + device_handler_discover(udev->handler, ddev); return 0; diff --git a/lib/Makefile.am b/lib/Makefile.am index b39cc9b..a2421a5 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -26,6 +26,7 @@ lib_libpbcore_la_SOURCES = \ lib/fold/fold.h \ lib/fold/fold.c \ lib/i18n/i18n.h \ + lib/i18n/i18n.c \ lib/log/log.h \ lib/log/log.c \ lib/list/list.c \ diff --git a/lib/fold/fold.c b/lib/fold/fold.c index fd23b06..2566253 100644 --- a/lib/fold/fold.c +++ b/lib/fold/fold.c @@ -36,8 +36,9 @@ void fold_text(const char *text, assert(bytes != (size_t)-1); - /* we'll get a zero size for the nul terminator */ - if (!bytes) { + /* we'll get a zero size for the nul terminator, or (size_t) -2 + * if we've reached the end of the buffer */ + if (!bytes || bytes == (size_t) -2) { line_cb(arg, start, end - start); break; } diff --git a/lib/i18n/i18n.c b/lib/i18n/i18n.c new file mode 100644 index 0000000..dd8d79b --- /dev/null +++ b/lib/i18n/i18n.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2013 IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _XOPEN_SOURCE + +#include +#include +#include + +#include + +/* Return the number of columns required to display a localised string */ +int strncols(const char *str) +{ + int wlen, ncols; + wchar_t *wstr; + + wlen = mbstowcs(NULL, str, 0); + if (wlen <= 0) + return wlen; + + wstr = malloc(sizeof(wchar_t) * wlen + 1); + if (!wstr) + return -1; + + wlen = mbstowcs(wstr, str, wlen); + if (wlen <= 0) { + free(wstr); + return wlen; + } + + ncols = wcswidth(wstr, wlen); + + free(wstr); + return ncols; +} diff --git a/lib/i18n/i18n.h b/lib/i18n/i18n.h index d7ff154..dde02f1 100644 --- a/lib/i18n/i18n.h +++ b/lib/i18n/i18n.h @@ -22,5 +22,7 @@ #define _(x) gettext(x) +int strncols(const char *str); + #endif /* I18N_H */ diff --git a/lib/pb-config/pb-config.c b/lib/pb-config/pb-config.c index 98a6078..8200883 100644 --- a/lib/pb-config/pb-config.c +++ b/lib/pb-config/pb-config.c @@ -77,6 +77,8 @@ struct config *config_copy(void *ctx, const struct config *src) dest->ipmi_bootdev = src->ipmi_bootdev; dest->ipmi_bootdev_persistent = src->ipmi_bootdev_persistent; + dest->allow_writes = src->allow_writes; + if (src->lang && strlen(src->lang)) dest->lang = talloc_strdup(dest, src->lang); else diff --git a/lib/pb-protocol/pb-protocol.c b/lib/pb-protocol/pb-protocol.c index 69ea35d..7d45f51 100644 --- a/lib/pb-protocol/pb-protocol.c +++ b/lib/pb-protocol/pb-protocol.c @@ -290,6 +290,8 @@ int pb_protocol_config_len(const struct config *config) len += 4 + 4; /* ipmi_bootdev, ipmi_bootdev_persistent */ + len += 4; /* allow_writes */ + len += 4 + optional_strlen(config->lang); return len; @@ -502,6 +504,9 @@ int pb_protocol_serialise_config(const struct config *config, *(uint32_t *)pos = config->ipmi_bootdev_persistent; pos += 4; + *(uint32_t *)pos = config->allow_writes; + pos += 4; + pos += pb_protocol_serialise_string(pos, config->lang); assert(pos <= buf + buf_len); @@ -958,6 +963,10 @@ int pb_protocol_deserialise_config(struct config *config, goto out; config->ipmi_bootdev_persistent = !!tmp; + if (read_u32(&pos, &len, &tmp)) + goto out; + config->allow_writes = !!tmp; + if (read_string(config, &pos, &len, &str)) goto out; diff --git a/lib/types/types.c b/lib/types/types.c index 95a3a48..63045e1 100644 --- a/lib/types/types.c +++ b/lib/types/types.c @@ -27,8 +27,10 @@ const char *device_type_display_name(enum device_type type) switch (type) { case DEVICE_TYPE_DISK: return _("Disk"); + case DEVICE_TYPE_USB: + return _("USB"); case DEVICE_TYPE_OPTICAL: - return _("Optical"); + return _("CD/DVD"); case DEVICE_TYPE_NETWORK: return _("Network"); case DEVICE_TYPE_ANY: @@ -44,6 +46,8 @@ const char *device_type_name(enum device_type type) switch (type) { case DEVICE_TYPE_DISK: return "disk"; + case DEVICE_TYPE_USB: + return "usb"; case DEVICE_TYPE_OPTICAL: return "optical"; case DEVICE_TYPE_NETWORK: @@ -60,6 +64,8 @@ enum device_type find_device_type(const char *str) { if (!strncmp(str, "disk", strlen("disk"))) return DEVICE_TYPE_DISK; + if (!strncmp(str, "usb", strlen("usb"))) + return DEVICE_TYPE_USB; if (!strncmp(str, "optical", strlen("optical"))) return DEVICE_TYPE_OPTICAL; if (!strncmp(str, "network", strlen("network"))) diff --git a/lib/types/types.h b/lib/types/types.h index e5c7e3e..6a2c258 100644 --- a/lib/types/types.h +++ b/lib/types/types.h @@ -8,6 +8,7 @@ enum device_type { DEVICE_TYPE_NETWORK, DEVICE_TYPE_DISK, + DEVICE_TYPE_USB, DEVICE_TYPE_OPTICAL, DEVICE_TYPE_ANY, DEVICE_TYPE_UNKNOWN, @@ -146,9 +147,12 @@ struct config { unsigned int ipmi_bootdev; bool ipmi_bootdev_persistent; + bool allow_writes; + char *lang; /* not user-settable */ + bool disable_snapshots; bool safe_mode; bool debug; }; diff --git a/po/de.po b/po/de.po index c6b41f2..5db0e24 100644 --- a/po/de.po +++ b/po/de.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: petitboot 20140623-g89bd2ed2-dirty\n" "Report-Msgid-Bugs-To: Geoff Levand \n" -"POT-Creation-Date: 2014-10-13 09:24+1100\n" +"POT-Creation-Date: 2015-08-19 14:19+1000\n" "PO-Revision-Date: 2014-06-24 13:56+0800\n" "Last-Translator: Jeremy Kerr \n" "Language-Team: German\n" @@ -17,7 +17,7 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "running boot hooks" -msgstr "Aktive Boot-Anbindungspunkte (Hooks)" +msgstr "Aktive Bootanbindungspunkte" #, c-format msgid "Couldn't load %s" @@ -130,20 +130,28 @@ msgstr "Systemkonfiguration" msgid "No IP / mask values are set" msgstr "Keine Werte für IP/Maske festgelegt" +msgid "Select a boot device to add" +msgstr "Wählen Sie eine Booteinheit aus, die hinzugefügt werden soll" + msgid "Waiting for configuration data..." msgstr "Warten auf Konfigurationsdaten..." -msgid "Autoboot:" -msgstr "Autom. Booten:" +#, fuzzy +msgid "Add Device" +msgstr "Einheit:" -msgid "Don't autoboot" -msgstr "Kein automatisches Booten" +msgid "Clear" +msgstr "Inhalt löschen" -msgid "Autoboot from any disk/network device" -msgstr "Von jeder Platte/Netzeinheit automatisch booten" +msgid "Clear & Boot Any" +msgstr "Inhalt löschen & beliebige booten" -msgid "Only autoboot from a specific disk/network device" -msgstr "Nur von bestimmter Platte/Netzeinheit autom. booten" +#, fuzzy +msgid "Boot Order:" +msgstr "Bootargumente:" + +msgid "(None)" +msgstr "(Keine Angabe)" #, c-format msgid "disk: %s [uuid: %s]" @@ -153,9 +161,13 @@ msgstr "Platte: %s [UUID: %s]" msgid "net: %s [mac: %s]" msgstr "Netz: %s [MAC: %s]" +#, fuzzy +msgid "Any Device" +msgstr "Einheit:" + #, c-format -msgid "Unknown UUID: %s" -msgstr "Unbekannte UUID: %s" +msgid "Any %s device" +msgstr "Jede %s-Einheit" msgid "Timeout:" msgstr "Zeitlimit:" @@ -163,6 +175,13 @@ msgstr "Zeitlimit:" msgid "seconds" msgstr "Sekunden" +#, c-format +msgid "%s IPMI boot option: %s" +msgstr "IPMI-Bootoption für %s: %s" + +msgid "Clear option:" +msgstr "Option 'Inhalt löschen':" + msgid "Network:" msgstr "Netz:" @@ -205,6 +224,17 @@ msgstr "(falls nicht vom DHCP-Server bereitgestellt)" msgid "Selecting 'OK' will exit safe mode" msgstr "Durch die Auswahl von 'OK' wird der abgesicherte Modus beendet" +#, fuzzy +msgid "Disk R/W:" +msgstr "Platte" + +msgid "Prevent all writes to disk" +msgstr "Alle Schreibvorgänge auf die Platte verhindern" + +msgid "Allow bootloader scripts to modify disks" +msgstr "" +"Zulassen, dass mit Scripts des Bootladeprogramms Platten geändert werden" + msgid "Petitboot System Configuration" msgstr "Petitboot-Systemkonfiguration" @@ -425,7 +455,7 @@ msgid "" "host/pxeconffile or http://host/pxeconffile" msgstr "" "Geben Sie hier eine gültige URL ein, um eine ferne Konfigurationsdatei vom " -"Typ 'pxe-boot' abzurufen, und analysieren sie sie.\n" +"Typ 'pxe-boot' abzurufen, und analysieren Sie sie.\n" "\n" "URLs haben das Format 'Schema://host/path/to/pxeconffile'. Beispiele: tftp://" "host/pxeconffile oder http://host/pxeconffile" @@ -483,24 +513,29 @@ msgstr "" "Beispiel: root=/dev/sda1 console=hvc0\n" "\n" +#, fuzzy msgid "" -"Autoboot: There are three possible options for automatic-boot hehaviour:\n" -"\n" -"Don't autoboot: boot options will be listed in the petitboot menu, but none " -"will be booted automatically. User interaction will be required to continue " +"Autoboot: Specify which devices to autoboot from.\n" +"\n" +"By selecting the 'Add Device' button new devices can be added to the " +"autoboot list, either by UUID, MAC address, or device type. Once added to " +"the boot order, the priority of devices can be changed with the 'left' and " +"'right' keys Devices can be individually removed from the boot order with " +"the minus key. Use this option if you have multiple operating system images " +"installed.\n" +"\n" +"To autoboot from any device, select the 'Clear & Boot Any' button. In this " +"case, any boot option that is marked as a default (by bootloader " +"configuration) will be booted automatically after a timeout. Use this option " +"if you want to quickly boot your system without changing any boot option " +"settings. This is the typical configuration.\n" +"\n" +"To disable autoboot, select the 'Clear' button, which will clear the boot " +"order. With autoboot disabled, user interaction will be required to continue " "past the petitboot menu. Use this option if you want the machine to wait for " "an explicit boot selection, or want to interact with petitboot before " "booting the system\n" "\n" -"Autoboot from any disk/network device: any boot option that is marked as a " -"default (by bootloader configuration) will be booted automatically after a " -"timeout. Use this option if you want to quickly boot your system without " -"changing any boot option settings. This is the typical configuration.\n" -"\n" -"Only autoboot from a specific disk/network device: only boot options from a " -"single device (specifed here) will be booted automatically after a timeout. " -"Use this option if you have multiple operating system images installed.\n" -"\n" "Timeout: Specify the length of time, in seconds, that the main menu will be " "displayed before the default boot option is started. This option is only " "displayed if autoboot is enabled.\n" @@ -567,3 +602,18 @@ msgstr "" msgid "Usage" msgstr "Verwendung" + +#~ msgid "Autoboot:" +#~ msgstr "Autoboot:" + +#~ msgid "Don't autoboot" +#~ msgstr "Don't autoboot" + +#~ msgid "Autoboot from any disk/network device" +#~ msgstr "Autoboot from any disk/network device" + +#~ msgid "Only autoboot from a specific disk/network device" +#~ msgstr "Only autoboot from a specific disk/network device" + +#~ msgid "Unknown UUID: %s" +#~ msgstr "Unknown UUID: %s" diff --git a/po/en.po b/po/en.po index 5a3edde..e3e07b5 100644 --- a/po/en.po +++ b/po/en.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: petitboot 20140623-g89bd2ed2-dirty\n" "Report-Msgid-Bugs-To: Geoff Levand \n" -"POT-Creation-Date: 2014-10-13 09:24+1100\n" +"POT-Creation-Date: 2015-08-19 14:19+1000\n" "PO-Revision-Date: 2014-06-24 13:56+0800\n" "Last-Translator: Jeremy Kerr \n" "Language-Team: English\n" @@ -128,20 +128,28 @@ msgstr "System Configuration" msgid "No IP / mask values are set" msgstr "No IP / mask values are set" +msgid "Select a boot device to add" +msgstr "" + msgid "Waiting for configuration data..." msgstr "Waiting for configuration data..." -msgid "Autoboot:" -msgstr "Autoboot:" +#, fuzzy +msgid "Add Device" +msgstr "Device:" + +msgid "Clear" +msgstr "" -msgid "Don't autoboot" -msgstr "Don't autoboot" +msgid "Clear & Boot Any" +msgstr "" -msgid "Autoboot from any disk/network device" -msgstr "Autoboot from any disk/network device" +#, fuzzy +msgid "Boot Order:" +msgstr "Boot arguments:" -msgid "Only autoboot from a specific disk/network device" -msgstr "Only autoboot from a specific disk/network device" +msgid "(None)" +msgstr "" #, c-format msgid "disk: %s [uuid: %s]" @@ -151,9 +159,13 @@ msgstr "disk: %s [uuid: %s]" msgid "net: %s [mac: %s]" msgstr "net: %s [mac: %s]" +#, fuzzy +msgid "Any Device" +msgstr "Device:" + #, c-format -msgid "Unknown UUID: %s" -msgstr "Unknown UUID: %s" +msgid "Any %s device" +msgstr "" msgid "Timeout:" msgstr "Timeout:" @@ -161,6 +173,13 @@ msgstr "Timeout:" msgid "seconds" msgstr "seconds" +#, c-format +msgid "%s IPMI boot option: %s" +msgstr "" + +msgid "Clear option:" +msgstr "" + msgid "Network:" msgstr "Network:" @@ -203,6 +222,16 @@ msgstr "(if not provided by DHCP server)" msgid "Selecting 'OK' will exit safe mode" msgstr "Selecting 'OK' will exit safe mode" +#, fuzzy +msgid "Disk R/W:" +msgstr "Disk" + +msgid "Prevent all writes to disk" +msgstr "" + +msgid "Allow bootloader scripts to modify disks" +msgstr "" + msgid "Petitboot System Configuration" msgstr "Petitboot System Configuration" @@ -470,24 +499,29 @@ msgstr "" "Example: root=/dev/sda1 console=hvc0\n" "\n" +#, fuzzy msgid "" -"Autoboot: There are three possible options for automatic-boot hehaviour:\n" -"\n" -"Don't autoboot: boot options will be listed in the petitboot menu, but none " -"will be booted automatically. User interaction will be required to continue " +"Autoboot: Specify which devices to autoboot from.\n" +"\n" +"By selecting the 'Add Device' button new devices can be added to the " +"autoboot list, either by UUID, MAC address, or device type. Once added to " +"the boot order, the priority of devices can be changed with the 'left' and " +"'right' keys Devices can be individually removed from the boot order with " +"the minus key. Use this option if you have multiple operating system images " +"installed.\n" +"\n" +"To autoboot from any device, select the 'Clear & Boot Any' button. In this " +"case, any boot option that is marked as a default (by bootloader " +"configuration) will be booted automatically after a timeout. Use this option " +"if you want to quickly boot your system without changing any boot option " +"settings. This is the typical configuration.\n" +"\n" +"To disable autoboot, select the 'Clear' button, which will clear the boot " +"order. With autoboot disabled, user interaction will be required to continue " "past the petitboot menu. Use this option if you want the machine to wait for " "an explicit boot selection, or want to interact with petitboot before " "booting the system\n" "\n" -"Autoboot from any disk/network device: any boot option that is marked as a " -"default (by bootloader configuration) will be booted automatically after a " -"timeout. Use this option if you want to quickly boot your system without " -"changing any boot option settings. This is the typical configuration.\n" -"\n" -"Only autoboot from a specific disk/network device: only boot options from a " -"single device (specifed here) will be booted automatically after a timeout. " -"Use this option if you have multiple operating system images installed.\n" -"\n" "Timeout: Specify the length of time, in seconds, that the main menu will be " "displayed before the default boot option is started. This option is only " "displayed if autoboot is enabled.\n" @@ -547,3 +581,18 @@ msgstr "" msgid "Usage" msgstr "Usage" + +#~ msgid "Autoboot:" +#~ msgstr "Autoboot:" + +#~ msgid "Don't autoboot" +#~ msgstr "Don't autoboot" + +#~ msgid "Autoboot from any disk/network device" +#~ msgstr "Autoboot from any disk/network device" + +#~ msgid "Only autoboot from a specific disk/network device" +#~ msgstr "Only autoboot from a specific disk/network device" + +#~ msgid "Unknown UUID: %s" +#~ msgstr "Unknown UUID: %s" diff --git a/po/es.po b/po/es.po index 09629e2..1683881 100644 --- a/po/es.po +++ b/po/es.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: petitboot 20140623-g89bd2ed2-dirty\n" "Report-Msgid-Bugs-To: Geoff Levand \n" -"POT-Creation-Date: 2014-10-13 09:24+1100\n" +"POT-Creation-Date: 2015-08-19 14:19+1000\n" "PO-Revision-Date: 2014-06-24 13:56+0800\n" "Last-Translator: Jeremy Kerr \n" "Language-Team: Spanish\n" @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" msgid "running boot hooks" msgstr "ejecutando ganchos de arranque" @@ -96,7 +96,7 @@ msgid "Petitboot Config Retrieval" msgstr "Recuperación de configuración de Petitboot" msgid "tab=next, shift+tab=previous, x=exit, h=help" -msgstr "tab=siguiente, shift+tab=anterior, x=salida, h=ayuda" +msgstr "tab=siguiente, mayús+tab=anterior, x=salir, h=ayuda" msgid "Boot Option Editor" msgstr "Editor de opciones de arranque" @@ -128,20 +128,28 @@ msgstr "Configuración del sistema" msgid "No IP / mask values are set" msgstr "No se han establecido valores IP / máscara" +msgid "Select a boot device to add" +msgstr "Seleccione un dispositivo de arranque para añadirlo" + msgid "Waiting for configuration data..." msgstr "Esperando datos de configuración..." -msgid "Autoboot:" -msgstr "Arranque automático:" +#, fuzzy +msgid "Add Device" +msgstr "Dispositivo:" -msgid "Don't autoboot" -msgstr "No arrancar automáticamente" +msgid "Clear" +msgstr "Borrar" -msgid "Autoboot from any disk/network device" -msgstr "Arranque automático desde cualquier dispositivo de disco/red" +msgid "Clear & Boot Any" +msgstr "Borrar y realizar cualquier arranque" -msgid "Only autoboot from a specific disk/network device" -msgstr "Arranque automático sólo desde un dispositivo de disco/red" +#, fuzzy +msgid "Boot Order:" +msgstr "Argumentos de arranque:" + +msgid "(None)" +msgstr "(Ninguno)" #, c-format msgid "disk: %s [uuid: %s]" @@ -151,16 +159,27 @@ msgstr "disco: %s [uuid: %s]" msgid "net: %s [mac: %s]" msgstr "red: %s [mac: %s]" +#, fuzzy +msgid "Any Device" +msgstr "Dispositivo:" + #, c-format -msgid "Unknown UUID: %s" -msgstr "UUID desconocido: %s" +msgid "Any %s device" +msgstr "Cualquier dispositivo %s" msgid "Timeout:" -msgstr "Tiempo de espera:" +msgstr "Tiempo espera:" msgid "seconds" msgstr "segundos" +#, c-format +msgid "%s IPMI boot option: %s" +msgstr "Opción de arranque de IPMI %s: %s" + +msgid "Clear option:" +msgstr "Borrar opción:" + msgid "Network:" msgstr "Red:" @@ -203,6 +222,16 @@ msgstr "(si no se proporciona por servidor DHCP)" msgid "Selecting 'OK' will exit safe mode" msgstr "Si selecciona 'Aceptar' saldrá de la modalidad segura" +#, fuzzy +msgid "Disk R/W:" +msgstr "Disco" + +msgid "Prevent all writes to disk" +msgstr "Impide todas las escrituras en disco" + +msgid "Allow bootloader scripts to modify disks" +msgstr "Permite a los scripts del gestor de arranque modificar los discos" + msgid "Petitboot System Configuration" msgstr "Configuración del sistema de Petitboot" @@ -475,24 +504,29 @@ msgstr "" "Ejemplo: root=/dev/sda1 console=hvc0\n" "\n" +#, fuzzy msgid "" -"Autoboot: There are three possible options for automatic-boot hehaviour:\n" -"\n" -"Don't autoboot: boot options will be listed in the petitboot menu, but none " -"will be booted automatically. User interaction will be required to continue " +"Autoboot: Specify which devices to autoboot from.\n" +"\n" +"By selecting the 'Add Device' button new devices can be added to the " +"autoboot list, either by UUID, MAC address, or device type. Once added to " +"the boot order, the priority of devices can be changed with the 'left' and " +"'right' keys Devices can be individually removed from the boot order with " +"the minus key. Use this option if you have multiple operating system images " +"installed.\n" +"\n" +"To autoboot from any device, select the 'Clear & Boot Any' button. In this " +"case, any boot option that is marked as a default (by bootloader " +"configuration) will be booted automatically after a timeout. Use this option " +"if you want to quickly boot your system without changing any boot option " +"settings. This is the typical configuration.\n" +"\n" +"To disable autoboot, select the 'Clear' button, which will clear the boot " +"order. With autoboot disabled, user interaction will be required to continue " "past the petitboot menu. Use this option if you want the machine to wait for " "an explicit boot selection, or want to interact with petitboot before " "booting the system\n" "\n" -"Autoboot from any disk/network device: any boot option that is marked as a " -"default (by bootloader configuration) will be booted automatically after a " -"timeout. Use this option if you want to quickly boot your system without " -"changing any boot option settings. This is the typical configuration.\n" -"\n" -"Only autoboot from a specific disk/network device: only boot options from a " -"single device (specifed here) will be booted automatically after a timeout. " -"Use this option if you have multiple operating system images installed.\n" -"\n" "Timeout: Specify the length of time, in seconds, that the main menu will be " "displayed before the default boot option is started. This option is only " "displayed if autoboot is enabled.\n" @@ -557,3 +591,18 @@ msgstr "" msgid "Usage" msgstr "Uso" + +#~ msgid "Autoboot:" +#~ msgstr "Autoboot:" + +#~ msgid "Don't autoboot" +#~ msgstr "Don't autoboot" + +#~ msgid "Autoboot from any disk/network device" +#~ msgstr "Autoboot from any disk/network device" + +#~ msgid "Only autoboot from a specific disk/network device" +#~ msgstr "Only autoboot from a specific disk/network device" + +#~ msgid "Unknown UUID: %s" +#~ msgstr "Unknown UUID: %s" diff --git a/po/fr.po b/po/fr.po index 6d3e15f..a136ad9 100644 --- a/po/fr.po +++ b/po/fr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: petitboot 20140623-g89bd2ed2-dirty\n" "Report-Msgid-Bugs-To: Geoff Levand \n" -"POT-Creation-Date: 2014-10-13 09:24+1100\n" +"POT-Creation-Date: 2015-08-19 14:19+1000\n" "PO-Revision-Date: 2014-06-24 13:56+0800\n" "Last-Translator: Jeremy Kerr \n" "Language-Team: French\n" @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=n>1;\n" msgid "running boot hooks" msgstr "exécution points d'ancrage d'amorçage" @@ -128,20 +128,28 @@ msgstr "Configuration système" msgid "No IP / mask values are set" msgstr "Aucune valeur IP/de masque définie" +msgid "Select a boot device to add" +msgstr "Sélectionner une unité d'amorçage à ajouter" + msgid "Waiting for configuration data..." msgstr "Attente de données de configuration..." -msgid "Autoboot:" -msgstr "Amorçage auto :" +#, fuzzy +msgid "Add Device" +msgstr "Unité :" -msgid "Don't autoboot" -msgstr "Pas d'amorçage automatique" +msgid "Clear" +msgstr "Effacer" -msgid "Autoboot from any disk/network device" -msgstr "Amorçage automatique depuis unité de disque/réseau" +msgid "Clear & Boot Any" +msgstr "Effacer & amorcer" -msgid "Only autoboot from a specific disk/network device" -msgstr "Amorçage auto seulement depuis unité disque/réseau spécifique" +#, fuzzy +msgid "Boot Order:" +msgstr "Arguments d'amorçage :" + +msgid "(None)" +msgstr "(Aucun)" #, c-format msgid "disk: %s [uuid: %s]" @@ -151,9 +159,13 @@ msgstr "disque : %s [uuid : %s]" msgid "net: %s [mac: %s]" msgstr "réseau : %s [mac : %s]" +#, fuzzy +msgid "Any Device" +msgstr "Unité :" + #, c-format -msgid "Unknown UUID: %s" -msgstr "UUID inconnu : %s" +msgid "Any %s device" +msgstr "N'importe quelle unité %s" msgid "Timeout:" msgstr "Délai attente :" @@ -161,6 +173,13 @@ msgstr "Délai attente :" msgid "seconds" msgstr "secondes" +#, c-format +msgid "%s IPMI boot option: %s" +msgstr "%s Option d'amorçage IPMI : %s" + +msgid "Clear option:" +msgstr "Option d'effacement :" + msgid "Network:" msgstr "Réseau :" @@ -203,6 +222,16 @@ msgstr "(si non fourni par le serveur DHCP)" msgid "Selecting 'OK' will exit safe mode" msgstr "Sélectionner 'OK' vous fera sortir du mode sans échec" +#, fuzzy +msgid "Disk R/W:" +msgstr "Disque" + +msgid "Prevent all writes to disk" +msgstr "Empêcher toute écriture sur le disque " + +msgid "Allow bootloader scripts to modify disks" +msgstr "Autoriser les scripts de chargeur de démarrage à modifier les disques " + msgid "Petitboot System Configuration" msgstr "Configuration de système Petitboot" @@ -476,24 +505,29 @@ msgstr "" "Exemple : root=/dev/sda1 console=hvc0\n" "\n" +#, fuzzy msgid "" -"Autoboot: There are three possible options for automatic-boot hehaviour:\n" -"\n" -"Don't autoboot: boot options will be listed in the petitboot menu, but none " -"will be booted automatically. User interaction will be required to continue " +"Autoboot: Specify which devices to autoboot from.\n" +"\n" +"By selecting the 'Add Device' button new devices can be added to the " +"autoboot list, either by UUID, MAC address, or device type. Once added to " +"the boot order, the priority of devices can be changed with the 'left' and " +"'right' keys Devices can be individually removed from the boot order with " +"the minus key. Use this option if you have multiple operating system images " +"installed.\n" +"\n" +"To autoboot from any device, select the 'Clear & Boot Any' button. In this " +"case, any boot option that is marked as a default (by bootloader " +"configuration) will be booted automatically after a timeout. Use this option " +"if you want to quickly boot your system without changing any boot option " +"settings. This is the typical configuration.\n" +"\n" +"To disable autoboot, select the 'Clear' button, which will clear the boot " +"order. With autoboot disabled, user interaction will be required to continue " "past the petitboot menu. Use this option if you want the machine to wait for " "an explicit boot selection, or want to interact with petitboot before " "booting the system\n" "\n" -"Autoboot from any disk/network device: any boot option that is marked as a " -"default (by bootloader configuration) will be booted automatically after a " -"timeout. Use this option if you want to quickly boot your system without " -"changing any boot option settings. This is the typical configuration.\n" -"\n" -"Only autoboot from a specific disk/network device: only boot options from a " -"single device (specifed here) will be booted automatically after a timeout. " -"Use this option if you have multiple operating system images installed.\n" -"\n" "Timeout: Specify the length of time, in seconds, that the main menu will be " "displayed before the default boot option is started. This option is only " "displayed if autoboot is enabled.\n" @@ -558,3 +592,18 @@ msgstr "" msgid "Usage" msgstr "Utilisation" + +#~ msgid "Autoboot:" +#~ msgstr "Autoboot:" + +#~ msgid "Don't autoboot" +#~ msgstr "Don't autoboot" + +#~ msgid "Autoboot from any disk/network device" +#~ msgstr "Autoboot from any disk/network device" + +#~ msgid "Only autoboot from a specific disk/network device" +#~ msgstr "Only autoboot from a specific disk/network device" + +#~ msgid "Unknown UUID: %s" +#~ msgstr "Unknown UUID: %s" diff --git a/po/it.po b/po/it.po index 1c35198..601b85f 100644 --- a/po/it.po +++ b/po/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: petitboot 20140623-g89bd2ed2-dirty\n" "Report-Msgid-Bugs-To: Geoff Levand \n" -"POT-Creation-Date: 2014-10-13 09:24+1100\n" +"POT-Creation-Date: 2015-08-19 14:19+1000\n" "PO-Revision-Date: 2014-06-24 13:56+0800\n" "Last-Translator: Jeremy Kerr \n" "Language-Team: Italian\n" @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" msgid "running boot hooks" msgstr "esecuzione di hook di avvio" @@ -129,20 +129,28 @@ msgstr "Configurazione di sistema" msgid "No IP / mask values are set" msgstr "Non è stato impostato alcun valore di IP/maschera" +msgid "Select a boot device to add" +msgstr "Selezionare un dispositivo di avvio da aggiungere" + msgid "Waiting for configuration data..." msgstr "In attesa dei dati di configurazione..." -msgid "Autoboot:" -msgstr "Avvio automatico:" +#, fuzzy +msgid "Add Device" +msgstr "Dispositivo:" -msgid "Don't autoboot" -msgstr "Non eseguire l'avvio automatico" +msgid "Clear" +msgstr "Ripulisci" -msgid "Autoboot from any disk/network device" -msgstr "Avvia automaticamente da qualsiasi dispositivo di rete/disco" +msgid "Clear & Boot Any" +msgstr "Ripulisci e avvia tutto" -msgid "Only autoboot from a specific disk/network device" -msgstr "Avvia automaticamente solo da uno specifico dispositivo di rete/disco" +#, fuzzy +msgid "Boot Order:" +msgstr "Argomenti avvio:" + +msgid "(None)" +msgstr "(Nessuno)" #, c-format msgid "disk: %s [uuid: %s]" @@ -152,9 +160,13 @@ msgstr "disco: %s [uuid: %s]" msgid "net: %s [mac: %s]" msgstr "rete: %s [mac: %s]" +#, fuzzy +msgid "Any Device" +msgstr "Dispositivo:" + #, c-format -msgid "Unknown UUID: %s" -msgstr "UUID sconosciuto: %s" +msgid "Any %s device" +msgstr "Qualsiasi dispositivo %s" msgid "Timeout:" msgstr "Timeout:" @@ -162,6 +174,13 @@ msgstr "Timeout:" msgid "seconds" msgstr "secondi" +#, c-format +msgid "%s IPMI boot option: %s" +msgstr "Opzione di avvio IPMI %s: %s" + +msgid "Clear option:" +msgstr "Ripulisci opzione:" + msgid "Network:" msgstr "Rete:" @@ -204,6 +223,16 @@ msgstr "(se non fornito dal server DHCP)" msgid "Selecting 'OK' will exit safe mode" msgstr "Selezionando 'OK' si uscirà in modalità sicura" +#, fuzzy +msgid "Disk R/W:" +msgstr "Disco" + +msgid "Prevent all writes to disk" +msgstr "Impedisci tutte le scritture su disco" + +msgid "Allow bootloader scripts to modify disks" +msgstr "Consenti script bootloader per modificare i dischi" + msgid "Petitboot System Configuration" msgstr "Configurazione di sistema Petitboot" @@ -476,24 +505,29 @@ msgstr "" "Esempio: root=/dev/sda1 console=hvc0\n" "\n" +#, fuzzy msgid "" -"Autoboot: There are three possible options for automatic-boot hehaviour:\n" -"\n" -"Don't autoboot: boot options will be listed in the petitboot menu, but none " -"will be booted automatically. User interaction will be required to continue " +"Autoboot: Specify which devices to autoboot from.\n" +"\n" +"By selecting the 'Add Device' button new devices can be added to the " +"autoboot list, either by UUID, MAC address, or device type. Once added to " +"the boot order, the priority of devices can be changed with the 'left' and " +"'right' keys Devices can be individually removed from the boot order with " +"the minus key. Use this option if you have multiple operating system images " +"installed.\n" +"\n" +"To autoboot from any device, select the 'Clear & Boot Any' button. In this " +"case, any boot option that is marked as a default (by bootloader " +"configuration) will be booted automatically after a timeout. Use this option " +"if you want to quickly boot your system without changing any boot option " +"settings. This is the typical configuration.\n" +"\n" +"To disable autoboot, select the 'Clear' button, which will clear the boot " +"order. With autoboot disabled, user interaction will be required to continue " "past the petitboot menu. Use this option if you want the machine to wait for " "an explicit boot selection, or want to interact with petitboot before " "booting the system\n" "\n" -"Autoboot from any disk/network device: any boot option that is marked as a " -"default (by bootloader configuration) will be booted automatically after a " -"timeout. Use this option if you want to quickly boot your system without " -"changing any boot option settings. This is the typical configuration.\n" -"\n" -"Only autoboot from a specific disk/network device: only boot options from a " -"single device (specifed here) will be booted automatically after a timeout. " -"Use this option if you have multiple operating system images installed.\n" -"\n" "Timeout: Specify the length of time, in seconds, that the main menu will be " "displayed before the default boot option is started. This option is only " "displayed if autoboot is enabled.\n" @@ -559,3 +593,18 @@ msgstr "" msgid "Usage" msgstr "Utilizzo" + +#~ msgid "Autoboot:" +#~ msgstr "Autoboot:" + +#~ msgid "Don't autoboot" +#~ msgstr "Don't autoboot" + +#~ msgid "Autoboot from any disk/network device" +#~ msgstr "Autoboot from any disk/network device" + +#~ msgid "Only autoboot from a specific disk/network device" +#~ msgstr "Only autoboot from a specific disk/network device" + +#~ msgid "Unknown UUID: %s" +#~ msgstr "Unknown UUID: %s" diff --git a/po/ja.po b/po/ja.po index c225fe8..52f635c 100644 --- a/po/ja.po +++ b/po/ja.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: petitboot 20140623-g89bd2ed2-dirty\n" "Report-Msgid-Bugs-To: Geoff Levand \n" -"POT-Creation-Date: 2014-10-13 09:24+1100\n" +"POT-Creation-Date: 2015-08-19 14:19+1000\n" "PO-Revision-Date: 2014-06-24 13:56+0800\n" "Last-Translator: Jeremy Kerr \n" "Language-Team: Japanese\n" @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=1; plural=0;\n" msgid "running boot hooks" msgstr "ブート・フックを実行しています" @@ -128,20 +128,28 @@ msgstr "システム構成" msgid "No IP / mask values are set" msgstr "IP/マスク値が設定されていません" +msgid "Select a boot device to add" +msgstr "追加するブート・デバイスの選択" + msgid "Waiting for configuration data..." msgstr "構成データを待っています..." -msgid "Autoboot:" -msgstr "自動ブート:" +#, fuzzy +msgid "Add Device" +msgstr "デバイス: " -msgid "Don't autoboot" -msgstr "自動ブートしない" +msgid "Clear" +msgstr "消去" -msgid "Autoboot from any disk/network device" -msgstr "任意のディスク/ネットワーク・デバイスから自動ブート" +msgid "Clear & Boot Any" +msgstr "消去していずれかをブート" -msgid "Only autoboot from a specific disk/network device" -msgstr "特定ディスク/ネットワークデバイスからのみ自動ブート" +#, fuzzy +msgid "Boot Order:" +msgstr "ブート引数:" + +msgid "(None)" +msgstr "(なし)" #, c-format msgid "disk: %s [uuid: %s]" @@ -151,9 +159,13 @@ msgstr "ディスク: %s [uuid: %s]" msgid "net: %s [mac: %s]" msgstr "net: %s [mac: %s]" +#, fuzzy +msgid "Any Device" +msgstr "デバイス: " + #, c-format -msgid "Unknown UUID: %s" -msgstr "不明 UUID: %s" +msgid "Any %s device" +msgstr "任意の %s デバイス" msgid "Timeout:" msgstr "タイムアウト:" @@ -161,6 +173,13 @@ msgstr "タイムアウト:" msgid "seconds" msgstr "秒" +#, c-format +msgid "%s IPMI boot option: %s" +msgstr "%s IPMI ブート・オプション: %s" + +msgid "Clear option:" +msgstr "消去オプション:" + msgid "Network:" msgstr "ネットワーク:" @@ -203,6 +222,16 @@ msgstr "(DHCP サーバーから提供されない場合)" msgid "Selecting 'OK' will exit safe mode" msgstr "「OK」を選択するとセーフ・モードが終了します" +#, fuzzy +msgid "Disk R/W:" +msgstr "ディスク" + +msgid "Prevent all writes to disk" +msgstr "ディスクへの書き込みをすべて抑止する" + +msgid "Allow bootloader scripts to modify disks" +msgstr "ブート・ローダー・スクリプトでディスクを変更できるようにする" + msgid "Petitboot System Configuration" msgstr "Petitboot システム構成" @@ -348,7 +377,7 @@ msgstr "アップ" #, fuzzy msgid "down" -msgstr "ダウン" +msgstr "リンクダウン" msgid "Petitboot System Information" msgstr "Petitboot システム情報" @@ -479,24 +508,29 @@ msgstr "" "例えば、root=/dev/sda1 console=hvc0 のように入力します。\n" "\n" +#, fuzzy msgid "" -"Autoboot: There are three possible options for automatic-boot hehaviour:\n" -"\n" -"Don't autoboot: boot options will be listed in the petitboot menu, but none " -"will be booted automatically. User interaction will be required to continue " +"Autoboot: Specify which devices to autoboot from.\n" +"\n" +"By selecting the 'Add Device' button new devices can be added to the " +"autoboot list, either by UUID, MAC address, or device type. Once added to " +"the boot order, the priority of devices can be changed with the 'left' and " +"'right' keys Devices can be individually removed from the boot order with " +"the minus key. Use this option if you have multiple operating system images " +"installed.\n" +"\n" +"To autoboot from any device, select the 'Clear & Boot Any' button. In this " +"case, any boot option that is marked as a default (by bootloader " +"configuration) will be booted automatically after a timeout. Use this option " +"if you want to quickly boot your system without changing any boot option " +"settings. This is the typical configuration.\n" +"\n" +"To disable autoboot, select the 'Clear' button, which will clear the boot " +"order. With autoboot disabled, user interaction will be required to continue " "past the petitboot menu. Use this option if you want the machine to wait for " "an explicit boot selection, or want to interact with petitboot before " "booting the system\n" "\n" -"Autoboot from any disk/network device: any boot option that is marked as a " -"default (by bootloader configuration) will be booted automatically after a " -"timeout. Use this option if you want to quickly boot your system without " -"changing any boot option settings. This is the typical configuration.\n" -"\n" -"Only autoboot from a specific disk/network device: only boot options from a " -"single device (specifed here) will be booted automatically after a timeout. " -"Use this option if you have multiple operating system images installed.\n" -"\n" "Timeout: Specify the length of time, in seconds, that the main menu will be " "displayed before the default boot option is started. This option is only " "displayed if autoboot is enabled.\n" @@ -559,3 +593,18 @@ msgstr "" msgid "Usage" msgstr "使用法" + +#~ msgid "Autoboot:" +#~ msgstr "Autoboot:" + +#~ msgid "Don't autoboot" +#~ msgstr "Don't autoboot" + +#~ msgid "Autoboot from any disk/network device" +#~ msgstr "Autoboot from any disk/network device" + +#~ msgid "Only autoboot from a specific disk/network device" +#~ msgstr "Only autoboot from a specific disk/network device" + +#~ msgid "Unknown UUID: %s" +#~ msgstr "Unknown UUID: %s" diff --git a/po/ko.po b/po/ko.po index 7690836..9e899cf 100644 --- a/po/ko.po +++ b/po/ko.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: petitboot 20140623-g89bd2ed2-dirty\n" "Report-Msgid-Bugs-To: Geoff Levand \n" -"POT-Creation-Date: 2014-10-13 09:24+1100\n" +"POT-Creation-Date: 2015-08-19 14:19+1000\n" "PO-Revision-Date: 2014-06-24 13:56+0800\n" "Last-Translator: Jeremy Kerr \n" "Language-Team: Korean\n" @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=1; plural=0;\n" msgid "running boot hooks" msgstr "부트 후크 실행 중" @@ -128,20 +128,28 @@ msgstr "시스템 구성" msgid "No IP / mask values are set" msgstr "IP/마스크 값이 설정되지 않음" +msgid "Select a boot device to add" +msgstr "추가할 부트 장치를 선택하십시오. " + msgid "Waiting for configuration data..." msgstr "구성 데이터 대기 중..." -msgid "Autoboot:" -msgstr "자동 부트:" +#, fuzzy +msgid "Add Device" +msgstr "장치: " -msgid "Don't autoboot" -msgstr "자동 부트하지 않음" +msgid "Clear" +msgstr "선택 취소" -msgid "Autoboot from any disk/network device" -msgstr "모든 디스크/네트워크 장치에서 자동 부트" +msgid "Clear & Boot Any" +msgstr "선택 취소 & 모든 부트" -msgid "Only autoboot from a specific disk/network device" -msgstr "특정 디스크/네트워크 장치에서만 자동 부트" +#, fuzzy +msgid "Boot Order:" +msgstr "부트 인수:" + +msgid "(None)" +msgstr "(없음)" #, c-format msgid "disk: %s [uuid: %s]" @@ -151,9 +159,13 @@ msgstr "디스크: %s [uuid: %s]" msgid "net: %s [mac: %s]" msgstr "네트: %s [mac: %s]" +#, fuzzy +msgid "Any Device" +msgstr "장치: " + #, c-format -msgid "Unknown UUID: %s" -msgstr "알 수 없는 UUID: %s" +msgid "Any %s device" +msgstr "모든 %s 장치" msgid "Timeout:" msgstr "제한시간:" @@ -161,6 +173,13 @@ msgstr "제한시간:" msgid "seconds" msgstr "초" +#, c-format +msgid "%s IPMI boot option: %s" +msgstr "%s IPMI 부트 옵션: %s" + +msgid "Clear option:" +msgstr "선택 취소 옵션:" + msgid "Network:" msgstr "네트워크:" @@ -203,6 +222,16 @@ msgstr "(DHCP 서버에서 제공되지 않은 경우)" msgid "Selecting 'OK' will exit safe mode" msgstr "'확인'을 선택하면 안전 모드를 종료합니다." +#, fuzzy +msgid "Disk R/W:" +msgstr "디스크" + +msgid "Prevent all writes to disk" +msgstr "디스크에 대한 모든 쓰기 방지" + +msgid "Allow bootloader scripts to modify disks" +msgstr "부트 로더 스크립트가 디스크를 수정하도록 허용" + msgid "Petitboot System Configuration" msgstr "Petitboot 시스템 구성" @@ -471,24 +500,29 @@ msgstr "" "예: root=/dev/sda1 console=hvc0\n" "\n" +#, fuzzy msgid "" -"Autoboot: There are three possible options for automatic-boot hehaviour:\n" -"\n" -"Don't autoboot: boot options will be listed in the petitboot menu, but none " -"will be booted automatically. User interaction will be required to continue " +"Autoboot: Specify which devices to autoboot from.\n" +"\n" +"By selecting the 'Add Device' button new devices can be added to the " +"autoboot list, either by UUID, MAC address, or device type. Once added to " +"the boot order, the priority of devices can be changed with the 'left' and " +"'right' keys Devices can be individually removed from the boot order with " +"the minus key. Use this option if you have multiple operating system images " +"installed.\n" +"\n" +"To autoboot from any device, select the 'Clear & Boot Any' button. In this " +"case, any boot option that is marked as a default (by bootloader " +"configuration) will be booted automatically after a timeout. Use this option " +"if you want to quickly boot your system without changing any boot option " +"settings. This is the typical configuration.\n" +"\n" +"To disable autoboot, select the 'Clear' button, which will clear the boot " +"order. With autoboot disabled, user interaction will be required to continue " "past the petitboot menu. Use this option if you want the machine to wait for " "an explicit boot selection, or want to interact with petitboot before " "booting the system\n" "\n" -"Autoboot from any disk/network device: any boot option that is marked as a " -"default (by bootloader configuration) will be booted automatically after a " -"timeout. Use this option if you want to quickly boot your system without " -"changing any boot option settings. This is the typical configuration.\n" -"\n" -"Only autoboot from a specific disk/network device: only boot options from a " -"single device (specifed here) will be booted automatically after a timeout. " -"Use this option if you have multiple operating system images installed.\n" -"\n" "Timeout: Specify the length of time, in seconds, that the main menu will be " "displayed before the default boot option is started. This option is only " "displayed if autoboot is enabled.\n" @@ -544,3 +578,18 @@ msgstr "" msgid "Usage" msgstr "사용법" + +#~ msgid "Autoboot:" +#~ msgstr "Autoboot:" + +#~ msgid "Don't autoboot" +#~ msgstr "Don't autoboot" + +#~ msgid "Autoboot from any disk/network device" +#~ msgstr "Autoboot from any disk/network device" + +#~ msgid "Only autoboot from a specific disk/network device" +#~ msgstr "Only autoboot from a specific disk/network device" + +#~ msgid "Unknown UUID: %s" +#~ msgstr "Unknown UUID: %s" diff --git a/po/pt_BR.po b/po/pt_BR.po index 6e71d6e..be8d0f0 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: petitboot 20140623-g89bd2ed2-dirty\n" "Report-Msgid-Bugs-To: Geoff Levand \n" -"POT-Creation-Date: 2014-10-13 09:24+1100\n" +"POT-Creation-Date: 2015-08-19 14:19+1000\n" "PO-Revision-Date: 2014-06-24 13:56+0800\n" "Last-Translator: Jeremy Kerr \n" "Language-Team: Portugese (Brazil)\n" @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=n>1;\n" msgid "running boot hooks" msgstr "executando ganchos de inicialização" @@ -128,24 +128,28 @@ msgstr "Configuração do Sistema" msgid "No IP / mask values are set" msgstr "Nenhum valor de máscara/IP está configurado" +msgid "Select a boot device to add" +msgstr "Selecione um dispositivo de inicialização a incluir." + msgid "Waiting for configuration data..." msgstr "Aguardando dados de configuração..." -msgid "Autoboot:" -msgstr "Executar a inicialização automática:" +#, fuzzy +msgid "Add Device" +msgstr "Dispositivo:" -msgid "Don't autoboot" -msgstr "Não executar a inicialização automática" +msgid "Clear" +msgstr "Limpar" -msgid "Autoboot from any disk/network device" -msgstr "" -"Executar a inicialização automática a partir de qualquer dispositivo de " -"disco/rede" +msgid "Clear & Boot Any" +msgstr "Limpar e inicializar qualquer um" -msgid "Only autoboot from a specific disk/network device" -msgstr "" -"Executar a inicialização automática apenas a partir de um dispositivo de " -"disco/rede específico" +#, fuzzy +msgid "Boot Order:" +msgstr "Argumentos de inicialização:" + +msgid "(None)" +msgstr "(Nenhum)" #, c-format msgid "disk: %s [uuid: %s]" @@ -155,9 +159,13 @@ msgstr "disco: %s [uuid: %s]" msgid "net: %s [mac: %s]" msgstr "rede: %s [mac: %s]" +#, fuzzy +msgid "Any Device" +msgstr "Dispositivo:" + #, c-format -msgid "Unknown UUID: %s" -msgstr "UUID (identificador exclusivo universal) Desconhecido: %s" +msgid "Any %s device" +msgstr "Qualquer dispositivo %s" msgid "Timeout:" msgstr "Tempo Limite:" @@ -165,6 +173,13 @@ msgstr "Tempo Limite:" msgid "seconds" msgstr "segundos" +#, c-format +msgid "%s IPMI boot option: %s" +msgstr "%s Opção de inicialização de IPMI: %s" + +msgid "Clear option:" +msgstr "Limpar opção:" + msgid "Network:" msgstr "Rede:" @@ -210,6 +225,16 @@ msgstr "(se não for fornecido pelo servidor DHCP)" msgid "Selecting 'OK' will exit safe mode" msgstr "Selecionar 'OK' irá sair do modo de segurança" +#, fuzzy +msgid "Disk R/W:" +msgstr "Disco" + +msgid "Prevent all writes to disk" +msgstr "Evitar todas as gravações em disco" + +msgid "Allow bootloader scripts to modify disks" +msgstr "Permitir que scripts de carregador de inicialização modifiquem discos" + msgid "Petitboot System Configuration" msgstr "Configuração do Sistema Petitboot" @@ -410,7 +435,7 @@ msgstr "" "Para configurar o idioma da interface do petitboot, digite L (idioma).\n" "\n" "Para localizar opções de inicialização novas ou atualizadas no sistema, " -"selecione a opção 'Varrer novamentedispositivos'.\n" +"selecione a opção 'Varrer novamente dispositivos'.\n" "\n" "Para recuperar novas opções de inicialização a partir de um arquivo de " "configuração remoto, selecione a opção 'Recuperar configuração a partir da " @@ -482,24 +507,29 @@ msgstr "" "Exemplo: root=/dev/sda1 console=hvc0\n" "\n" +#, fuzzy msgid "" -"Autoboot: There are three possible options for automatic-boot hehaviour:\n" -"\n" -"Don't autoboot: boot options will be listed in the petitboot menu, but none " -"will be booted automatically. User interaction will be required to continue " +"Autoboot: Specify which devices to autoboot from.\n" +"\n" +"By selecting the 'Add Device' button new devices can be added to the " +"autoboot list, either by UUID, MAC address, or device type. Once added to " +"the boot order, the priority of devices can be changed with the 'left' and " +"'right' keys Devices can be individually removed from the boot order with " +"the minus key. Use this option if you have multiple operating system images " +"installed.\n" +"\n" +"To autoboot from any device, select the 'Clear & Boot Any' button. In this " +"case, any boot option that is marked as a default (by bootloader " +"configuration) will be booted automatically after a timeout. Use this option " +"if you want to quickly boot your system without changing any boot option " +"settings. This is the typical configuration.\n" +"\n" +"To disable autoboot, select the 'Clear' button, which will clear the boot " +"order. With autoboot disabled, user interaction will be required to continue " "past the petitboot menu. Use this option if you want the machine to wait for " "an explicit boot selection, or want to interact with petitboot before " "booting the system\n" "\n" -"Autoboot from any disk/network device: any boot option that is marked as a " -"default (by bootloader configuration) will be booted automatically after a " -"timeout. Use this option if you want to quickly boot your system without " -"changing any boot option settings. This is the typical configuration.\n" -"\n" -"Only autoboot from a specific disk/network device: only boot options from a " -"single device (specifed here) will be booted automatically after a timeout. " -"Use this option if you have multiple operating system images installed.\n" -"\n" "Timeout: Specify the length of time, in seconds, that the main menu will be " "displayed before the default boot option is started. This option is only " "displayed if autoboot is enabled.\n" @@ -567,3 +597,18 @@ msgstr "" msgid "Usage" msgstr "Uso" + +#~ msgid "Autoboot:" +#~ msgstr "Autoboot:" + +#~ msgid "Don't autoboot" +#~ msgstr "Don't autoboot" + +#~ msgid "Autoboot from any disk/network device" +#~ msgstr "Autoboot from any disk/network device" + +#~ msgid "Only autoboot from a specific disk/network device" +#~ msgstr "Only autoboot from a specific disk/network device" + +#~ msgid "Unknown UUID: %s" +#~ msgstr "Unknown UUID: %s" diff --git a/po/ru.po b/po/ru.po index f913db1..bfbb503 100644 --- a/po/ru.po +++ b/po/ru.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: petitboot 20140623-g89bd2ed2-dirty\n" "Report-Msgid-Bugs-To: Geoff Levand \n" -"POT-Creation-Date: 2014-10-13 09:24+1100\n" +"POT-Creation-Date: 2015-08-19 14:19+1000\n" "PO-Revision-Date: 2014-06-24 13:56+0800\n" "Last-Translator: Jeremy Kerr \n" "Language-Team: Russian\n" @@ -14,7 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "running boot hooks" msgstr "выполнение привязок загрузки" @@ -128,21 +129,28 @@ msgstr "Конфигурация системы" msgid "No IP / mask values are set" msgstr "Не задано значение IP / маски" +msgid "Select a boot device to add" +msgstr "Выберите загрузочное устройство для добавления" + msgid "Waiting for configuration data..." msgstr "Ожидание данных конфигурации..." -msgid "Autoboot:" -msgstr "Автоматическая загрузка:" +#, fuzzy +msgid "Add Device" +msgstr "Устройство:" -msgid "Don't autoboot" -msgstr "Не загружаться автоматически" +msgid "Clear" +msgstr "Очистить" -msgid "Autoboot from any disk/network device" -msgstr "Автоматически загружаться с любого диска/сетевого устройства" +msgid "Clear & Boot Any" +msgstr "Очистить и загрузить все" -msgid "Only autoboot from a specific disk/network device" -msgstr "" -"Автоматически загружаться только с указанного диска/сетевого устройства" +#, fuzzy +msgid "Boot Order:" +msgstr "Аргументы загрузки:" + +msgid "(None)" +msgstr "(Нет)" #, c-format msgid "disk: %s [uuid: %s]" @@ -152,9 +160,13 @@ msgstr "диск: %s [uuid: %s]" msgid "net: %s [mac: %s]" msgstr "сеть: %s [mac: %s]" +#, fuzzy +msgid "Any Device" +msgstr "Устройство:" + #, c-format -msgid "Unknown UUID: %s" -msgstr "Неизвестный UUID: %s" +msgid "Any %s device" +msgstr "Любое устройство %s" msgid "Timeout:" msgstr "Тайм-аут:" @@ -162,6 +174,13 @@ msgstr "Тайм-аут:" msgid "seconds" msgstr "секунд" +#, c-format +msgid "%s IPMI boot option: %s" +msgstr "Опция загрузки IPMI %s: %s" + +msgid "Clear option:" +msgstr "Опция очистки:" + msgid "Network:" msgstr "Сеть:" @@ -175,10 +194,10 @@ msgid "Static IP configuration" msgstr "Конфигурация статического IP" msgid "link up" -msgstr "подключиться" +msgstr "линия связи активна" msgid "link down" -msgstr "отключиться" +msgstr "линия связи неактивна" msgid "IP/mask:" msgstr "IP/маска:" @@ -204,6 +223,16 @@ msgstr "(если не предоставляется сервером DHCP)" msgid "Selecting 'OK' will exit safe mode" msgstr "После нажатия 'OK' безопасный режим будет выключен" +#, fuzzy +msgid "Disk R/W:" +msgstr "Диск" + +msgid "Prevent all writes to disk" +msgstr "Запретить любую запись на диск" + +msgid "Allow bootloader scripts to modify disks" +msgstr "Разрешить сценарии загрузчика для изменения дисков" + msgid "Petitboot System Configuration" msgstr "Конфигурация Petitboot System" @@ -328,7 +357,7 @@ msgstr " UUID: %s" #, c-format msgid " mounted at: %s" -msgstr " установлено в: %s" +msgstr " точка монтирования: %s" msgid "Network interfaces" msgstr "Сетевые интерфейсы" @@ -341,14 +370,14 @@ msgstr " MAC: %s" #. * link status for a network connection. #, c-format msgid " link: %s" -msgstr " связь: %s" +msgstr " линия связи: %s" msgid "up" -msgstr "вкл" +msgstr "активна" #, fuzzy msgid "down" -msgstr "выкл" +msgstr "неактивна" msgid "Petitboot System Information" msgstr "Информация о системе Petitboot" @@ -473,24 +502,29 @@ msgstr "" "Пример: root=/dev/sda1 console=hvc0\n" "\n" +#, fuzzy msgid "" -"Autoboot: There are three possible options for automatic-boot hehaviour:\n" -"\n" -"Don't autoboot: boot options will be listed in the petitboot menu, but none " -"will be booted automatically. User interaction will be required to continue " +"Autoboot: Specify which devices to autoboot from.\n" +"\n" +"By selecting the 'Add Device' button new devices can be added to the " +"autoboot list, either by UUID, MAC address, or device type. Once added to " +"the boot order, the priority of devices can be changed with the 'left' and " +"'right' keys Devices can be individually removed from the boot order with " +"the minus key. Use this option if you have multiple operating system images " +"installed.\n" +"\n" +"To autoboot from any device, select the 'Clear & Boot Any' button. In this " +"case, any boot option that is marked as a default (by bootloader " +"configuration) will be booted automatically after a timeout. Use this option " +"if you want to quickly boot your system without changing any boot option " +"settings. This is the typical configuration.\n" +"\n" +"To disable autoboot, select the 'Clear' button, which will clear the boot " +"order. With autoboot disabled, user interaction will be required to continue " "past the petitboot menu. Use this option if you want the machine to wait for " "an explicit boot selection, or want to interact with petitboot before " "booting the system\n" "\n" -"Autoboot from any disk/network device: any boot option that is marked as a " -"default (by bootloader configuration) will be booted automatically after a " -"timeout. Use this option if you want to quickly boot your system without " -"changing any boot option settings. This is the typical configuration.\n" -"\n" -"Only autoboot from a specific disk/network device: only boot options from a " -"single device (specifed here) will be booted automatically after a timeout. " -"Use this option if you have multiple operating system images installed.\n" -"\n" "Timeout: Specify the length of time, in seconds, that the main menu will be " "displayed before the default boot option is started. This option is only " "displayed if autoboot is enabled.\n" @@ -520,7 +554,7 @@ msgstr "" "или если хотите поработать с petitboot до загрузки системы\n" "\n" "Автозагрузка с любого диска/сетевого устройства: любой вариант загрузки с " -"отметкой по умолчанию (задается в настройках bootloader) будет автоматически " +"отметкой по умолчанию (в конфигурации загрузчика) будет автоматически " "загружен после тайм-аута. Используйте этот вариант в том случае, если хотите " "быстро загрузить систему без изменения каких-либо настроек варианта " "загрузки. Является стандартной конфигурацией.\n" @@ -552,3 +586,18 @@ msgstr "" msgid "Usage" msgstr "Использование" + +#~ msgid "Autoboot:" +#~ msgstr "Autoboot:" + +#~ msgid "Don't autoboot" +#~ msgstr "Don't autoboot" + +#~ msgid "Autoboot from any disk/network device" +#~ msgstr "Autoboot from any disk/network device" + +#~ msgid "Only autoboot from a specific disk/network device" +#~ msgstr "Only autoboot from a specific disk/network device" + +#~ msgid "Unknown UUID: %s" +#~ msgstr "Unknown UUID: %s" diff --git a/po/zh_CN.po b/po/zh_CN.po index 62976b0..1ba5e95 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: petitboot 20140623-g89bd2ed2-dirty\n" "Report-Msgid-Bugs-To: Geoff Levand \n" -"POT-Creation-Date: 2014-10-13 09:24+1100\n" +"POT-Creation-Date: 2015-08-19 14:19+1000\n" "PO-Revision-Date: 2014-06-24 13:56+0800\n" "Last-Translator: Jeremy Kerr \n" "Language-Team: Simplified Chinese\n" @@ -128,20 +128,28 @@ msgstr "系统配置" msgid "No IP / mask values are set" msgstr "未设置任何 IP/掩码值" +msgid "Select a boot device to add" +msgstr "选择要添加的引导设备" + msgid "Waiting for configuration data..." msgstr "正在等待配置数据..." -msgid "Autoboot:" -msgstr "自动引导:" +#, fuzzy +msgid "Add Device" +msgstr "设备:" -msgid "Don't autoboot" -msgstr "不自动引导" +msgid "Clear" +msgstr "清除" -msgid "Autoboot from any disk/network device" -msgstr "从任何磁盘/网络设备自动引导" +msgid "Clear & Boot Any" +msgstr "清除并引导任何项" -msgid "Only autoboot from a specific disk/network device" -msgstr "仅从特定磁盘/网络设备自动引导" +#, fuzzy +msgid "Boot Order:" +msgstr "引导参数:" + +msgid "(None)" +msgstr "(无)" #, c-format msgid "disk: %s [uuid: %s]" @@ -151,9 +159,13 @@ msgstr "磁盘:%s [uuid:%s]" msgid "net: %s [mac: %s]" msgstr "网路:%s [mac:%s]" +#, fuzzy +msgid "Any Device" +msgstr "设备:" + #, c-format -msgid "Unknown UUID: %s" -msgstr "未知 UUID:%s" +msgid "Any %s device" +msgstr "任何 %s 设备" msgid "Timeout:" msgstr "超时:" @@ -161,6 +173,13 @@ msgstr "超时:" msgid "seconds" msgstr "秒" +#, c-format +msgid "%s IPMI boot option: %s" +msgstr "%s IPMI 引导选项:%s" + +msgid "Clear option:" +msgstr "清除选项:" + msgid "Network:" msgstr "网络:" @@ -203,6 +222,16 @@ msgstr "(如果不是由 DHCP 服务器提供)" msgid "Selecting 'OK' will exit safe mode" msgstr "选择“确定”将退出安全模式" +#, fuzzy +msgid "Disk R/W:" +msgstr "磁盘" + +msgid "Prevent all writes to disk" +msgstr "阻止对磁盘的所有写入操作" + +msgid "Allow bootloader scripts to modify disks" +msgstr "允许引导程序脚本修改磁盘" + msgid "Petitboot System Configuration" msgstr "Petitboot 系统配置" @@ -295,7 +324,7 @@ msgstr "选择 Petitboot 语言" #, c-format msgid "!Invalid option %d" -msgstr "!无效的选项 %d" +msgstr "!无效选项 %d" msgid "Disk" msgstr "磁盘" @@ -462,24 +491,29 @@ msgstr "" "示例:root=/dev/sda1 console=hvc0\n" "\n" +#, fuzzy msgid "" -"Autoboot: There are three possible options for automatic-boot hehaviour:\n" -"\n" -"Don't autoboot: boot options will be listed in the petitboot menu, but none " -"will be booted automatically. User interaction will be required to continue " +"Autoboot: Specify which devices to autoboot from.\n" +"\n" +"By selecting the 'Add Device' button new devices can be added to the " +"autoboot list, either by UUID, MAC address, or device type. Once added to " +"the boot order, the priority of devices can be changed with the 'left' and " +"'right' keys Devices can be individually removed from the boot order with " +"the minus key. Use this option if you have multiple operating system images " +"installed.\n" +"\n" +"To autoboot from any device, select the 'Clear & Boot Any' button. In this " +"case, any boot option that is marked as a default (by bootloader " +"configuration) will be booted automatically after a timeout. Use this option " +"if you want to quickly boot your system without changing any boot option " +"settings. This is the typical configuration.\n" +"\n" +"To disable autoboot, select the 'Clear' button, which will clear the boot " +"order. With autoboot disabled, user interaction will be required to continue " "past the petitboot menu. Use this option if you want the machine to wait for " "an explicit boot selection, or want to interact with petitboot before " "booting the system\n" "\n" -"Autoboot from any disk/network device: any boot option that is marked as a " -"default (by bootloader configuration) will be booted automatically after a " -"timeout. Use this option if you want to quickly boot your system without " -"changing any boot option settings. This is the typical configuration.\n" -"\n" -"Only autoboot from a specific disk/network device: only boot options from a " -"single device (specifed here) will be booted automatically after a timeout. " -"Use this option if you have multiple operating system images installed.\n" -"\n" "Timeout: Specify the length of time, in seconds, that the main menu will be " "displayed before the default boot option is started. This option is only " "displayed if autoboot is enabled.\n" @@ -518,8 +552,8 @@ msgstr "" "\n" "网络选项:\n" "\n" -"所有活动接口上的 DHCP:自动将 IP 地址分配给每个网络接口。如果您的网络上有 " -"DHCP 服务器,请使用 此选项。\n" +"所有活动接口上的 DHCP:自动将 IP 地址分配给每个网络接口。如果您的网络中存在 " +"DHCP 服务器,请使用此选项。\n" "\n" "特定接口上的 DHCP:自动将 IP 地址分配给选择的网络接口。不配置其他接口。如果您" "在不同的接口上有多个 DHCP 服务器,但在引导期间只想配置单个接口,请选择此选" @@ -530,3 +564,18 @@ msgstr "" msgid "Usage" msgstr "用法" + +#~ msgid "Autoboot:" +#~ msgstr "Autoboot:" + +#~ msgid "Don't autoboot" +#~ msgstr "Don't autoboot" + +#~ msgid "Autoboot from any disk/network device" +#~ msgstr "Autoboot from any disk/network device" + +#~ msgid "Only autoboot from a specific disk/network device" +#~ msgstr "Only autoboot from a specific disk/network device" + +#~ msgid "Unknown UUID: %s" +#~ msgstr "Unknown UUID: %s" diff --git a/po/zh_TW.po b/po/zh_TW.po index 657062f..d25038e 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: petitboot 20140623-g89bd2ed2-dirty\n" "Report-Msgid-Bugs-To: Geoff Levand \n" -"POT-Creation-Date: 2014-10-13 09:24+1100\n" +"POT-Creation-Date: 2015-08-19 14:19+1000\n" "PO-Revision-Date: 2014-06-24 13:56+0800\n" "Last-Translator: Jeremy Kerr \n" "Language-Team: Traditional Chinese\n" @@ -128,20 +128,28 @@ msgstr "系統配置" msgid "No IP / mask values are set" msgstr "未設定任何 IP/遮罩值" +msgid "Select a boot device to add" +msgstr "選取要新增的啟動裝置" + msgid "Waiting for configuration data..." msgstr "正在等待配置資料..." -msgid "Autoboot:" -msgstr "自動啟動:" +#, fuzzy +msgid "Add Device" +msgstr "裝置:" -msgid "Don't autoboot" -msgstr "不自動啟動" +msgid "Clear" +msgstr "清除" -msgid "Autoboot from any disk/network device" -msgstr "從任何磁碟/網路裝置自動啟動" +msgid "Clear & Boot Any" +msgstr "清除並啟動任意項" -msgid "Only autoboot from a specific disk/network device" -msgstr "僅從特定的磁碟/網路裝置自動啟動" +#, fuzzy +msgid "Boot Order:" +msgstr "啟動引數:" + +msgid "(None)" +msgstr "(無)" #, c-format msgid "disk: %s [uuid: %s]" @@ -151,9 +159,13 @@ msgstr "磁碟:%s [UUID:%s]" msgid "net: %s [mac: %s]" msgstr "網路:%s [MAC:%s]" +#, fuzzy +msgid "Any Device" +msgstr "裝置:" + #, c-format -msgid "Unknown UUID: %s" -msgstr "不明 UUID:%s" +msgid "Any %s device" +msgstr "任何 %s 裝置" msgid "Timeout:" msgstr "逾時:" @@ -161,6 +173,13 @@ msgstr "逾時:" msgid "seconds" msgstr "秒" +#, c-format +msgid "%s IPMI boot option: %s" +msgstr "%s IPMI 啟動選項:%s" + +msgid "Clear option:" +msgstr "清除選項:" + msgid "Network:" msgstr "網路:" @@ -203,6 +222,16 @@ msgstr "(如果 DHCP 伺服器未提供的話)" msgid "Selecting 'OK' will exit safe mode" msgstr "選取「確定」將會結束安全模式" +#, fuzzy +msgid "Disk R/W:" +msgstr "磁碟" + +msgid "Prevent all writes to disk" +msgstr "阻止全部寫入磁碟" + +msgid "Allow bootloader scripts to modify disks" +msgstr "容許開機載入器 Script 修改磁碟" + msgid "Petitboot System Configuration" msgstr "Petitboot 系統配置" @@ -295,7 +324,7 @@ msgstr "選取 Petitboot 語言" #, c-format msgid "!Invalid option %d" -msgstr "選項 %d 無效!" +msgstr "!無效選項 %d" msgid "Disk" msgstr "磁碟" @@ -465,24 +494,29 @@ msgstr "" "範例:root=/dev/sda1 console=hvc0\n" "\n" +#, fuzzy msgid "" -"Autoboot: There are three possible options for automatic-boot hehaviour:\n" -"\n" -"Don't autoboot: boot options will be listed in the petitboot menu, but none " -"will be booted automatically. User interaction will be required to continue " +"Autoboot: Specify which devices to autoboot from.\n" +"\n" +"By selecting the 'Add Device' button new devices can be added to the " +"autoboot list, either by UUID, MAC address, or device type. Once added to " +"the boot order, the priority of devices can be changed with the 'left' and " +"'right' keys Devices can be individually removed from the boot order with " +"the minus key. Use this option if you have multiple operating system images " +"installed.\n" +"\n" +"To autoboot from any device, select the 'Clear & Boot Any' button. In this " +"case, any boot option that is marked as a default (by bootloader " +"configuration) will be booted automatically after a timeout. Use this option " +"if you want to quickly boot your system without changing any boot option " +"settings. This is the typical configuration.\n" +"\n" +"To disable autoboot, select the 'Clear' button, which will clear the boot " +"order. With autoboot disabled, user interaction will be required to continue " "past the petitboot menu. Use this option if you want the machine to wait for " "an explicit boot selection, or want to interact with petitboot before " "booting the system\n" "\n" -"Autoboot from any disk/network device: any boot option that is marked as a " -"default (by bootloader configuration) will be booted automatically after a " -"timeout. Use this option if you want to quickly boot your system without " -"changing any boot option settings. This is the typical configuration.\n" -"\n" -"Only autoboot from a specific disk/network device: only boot options from a " -"single device (specifed here) will be booted automatically after a timeout. " -"Use this option if you have multiple operating system images installed.\n" -"\n" "Timeout: Specify the length of time, in seconds, that the main menu will be " "displayed before the default boot option is started. This option is only " "displayed if autoboot is enabled.\n" @@ -522,7 +556,7 @@ msgstr "" "網路選項:\n" "\n" "對所有作用中介面使用 DHCP:自動將 IP 位址指派給每一個網路介面。如果您的網路中" -"有 DHCP 伺服器,請使用此選項。\n" +"有 DHCP 伺服器請使用此選項。\n" "\n" "對特定介面使用 DHCP:自動將 IP 位址指派給選定的網路介面。不配置其他介面。如果" "您在不同的介面上具有多個 DHCP 伺服器,但在啟動期間只想配置單一介面,請選取此" @@ -533,3 +567,18 @@ msgstr "" msgid "Usage" msgstr "用法" + +#~ msgid "Autoboot:" +#~ msgstr "Autoboot:" + +#~ msgid "Don't autoboot" +#~ msgstr "Don't autoboot" + +#~ msgid "Autoboot from any disk/network device" +#~ msgstr "Autoboot from any disk/network device" + +#~ msgid "Only autoboot from a specific disk/network device" +#~ msgstr "Only autoboot from a specific disk/network device" + +#~ msgid "Unknown UUID: %s" +#~ msgstr "Unknown UUID: %s" diff --git a/ui/ncurses/nc-add-url.c b/ui/ncurses/nc-add-url.c index cf55b03..451b050 100644 --- a/ui/ncurses/nc-add-url.c +++ b/ui/ncurses/nc-add-url.c @@ -194,9 +194,9 @@ static void add_url_screen_layout_widgets(struct add_url_screen *screen) widget_move(widget_button_base(screen->widgets.ok_b), y, screen->field_x); widget_move(widget_button_base(screen->widgets.help_b), - y, screen->field_x + 10); + y, screen->field_x + 14); widget_move(widget_button_base(screen->widgets.cancel_b), - y, screen->field_x + 24); + y, screen->field_x + 28); } static void add_url_screen_setup_widgets(struct add_url_screen *screen) @@ -210,7 +210,7 @@ static void add_url_screen_setup_widgets(struct add_url_screen *screen) _("Configuration URL:")); screen->widgets.url_f = widget_new_textbox(set, 0, 0, 50, NULL); - screen->widgets.ok_b = widget_new_button(set, 0, 0, 6, _("OK"), + screen->widgets.ok_b = widget_new_button(set, 0, 0, 10, _("OK"), ok_click, screen); screen->widgets.help_b = widget_new_button(set, 0, 0, 10, _("Help"), help_click, screen); diff --git a/ui/ncurses/nc-boot-editor.c b/ui/ncurses/nc-boot-editor.c index 274bd9d..4012ec5 100644 --- a/ui/ncurses/nc-boot-editor.c +++ b/ui/ncurses/nc-boot-editor.c @@ -22,7 +22,6 @@ #include #include -#include #include "log/log.h" #include "talloc/talloc.h" @@ -45,6 +44,7 @@ struct boot_editor { struct pmenu_item *item, struct pb_boot_data *bd); bool need_redraw; + bool need_update; int label_x; int field_x; @@ -110,7 +110,14 @@ static struct boot_editor *boot_editor_from_arg(void *arg) static int boot_editor_post(struct nc_scr *scr) { struct boot_editor *boot_editor = boot_editor_from_scr(scr); - widgetset_post(boot_editor->widgetset); + + if (boot_editor->need_update) { + boot_editor_update(boot_editor, boot_editor->cui->sysinfo); + boot_editor->need_update = false; + } else { + widgetset_post(boot_editor->widgetset); + } + nc_scr_frame_draw(scr); if (boot_editor->need_redraw) { redrawwin(scr->main_ncw); @@ -318,9 +325,12 @@ static void boot_editor_layout_widgets(struct boot_editor *boot_editor) y++; - widget_move(widget_button_base(boot_editor->widgets.ok_b), y, 9); - widget_move(widget_button_base(boot_editor->widgets.help_b), y, 19); - widget_move(widget_button_base(boot_editor->widgets.cancel_b), y, 33); + widget_move(widget_button_base(boot_editor->widgets.ok_b), y, + boot_editor->field_x); + widget_move(widget_button_base(boot_editor->widgets.help_b), y, + boot_editor->field_x + 14); + widget_move(widget_button_base(boot_editor->widgets.cancel_b), y, + boot_editor->field_x + 28); } static void boot_editor_widget_focus(struct nc_widget *widget, void *arg) @@ -491,7 +501,7 @@ static void boot_editor_setup_widgets(struct boot_editor *boot_editor, boot_editor->widgets.args_f = widget_new_textbox(set, 0, 0, field_size, boot_editor->args); - boot_editor->widgets.ok_b = widget_new_button(set, 0, 0, 6, + boot_editor->widgets.ok_b = widget_new_button(set, 0, 0, 10, _("OK"), ok_click, boot_editor); boot_editor->widgets.help_b = widget_new_button(set, 0, 0, 10, _("Help"), help_click, boot_editor); @@ -504,6 +514,11 @@ void boot_editor_update(struct boot_editor *boot_editor, { int height; + if (boot_editor->cui->current != boot_editor_scr(boot_editor)) { + boot_editor->need_update = true; + return; + } + widgetset_unpost(boot_editor->widgetset); height = pad_height(sysinfo ? sysinfo->n_blockdevs : 0); @@ -524,36 +539,6 @@ void boot_editor_update(struct boot_editor *boot_editor, pad_refresh(boot_editor); } -/* Return the number of columns required to display a localised string */ -static int strncols(const char *str) -{ - int i, wlen, ncols = 0; - wchar_t *wstr; - - wlen = mbstowcs(NULL, str, 0); - if (wlen <= 0) - return wlen; - - wstr = malloc(sizeof(wchar_t) * wlen + 1); - if (!wstr) - return -1; - - wlen = mbstowcs(wstr, str, wlen); - if (wlen <= 0) { - free(wstr); - return wlen; - } - - /* Processing each character individually lets us use the same - * check for all languages */ - for (i = 0; i < wlen; i++) { - ncols += wcwidth(wstr[i]); - } - - free(wstr); - return ncols; -} - struct boot_editor *boot_editor_init(struct cui *cui, struct pmenu_item *item, const struct system_info *sysinfo, @@ -574,6 +559,7 @@ struct boot_editor *boot_editor_init(struct cui *cui, boot_editor->on_exit = on_exit; boot_editor->state = STATE_EDIT; boot_editor->need_redraw = false; + boot_editor->need_update = false; int ncols1 = strncols(_("Device tree:")); int ncols2 = strncols(_("Boot arguments:")); diff --git a/ui/ncurses/nc-config-help.c b/ui/ncurses/nc-config-help.c index 22ced3c..23bcd9d 100644 --- a/ui/ncurses/nc-config-help.c +++ b/ui/ncurses/nc-config-help.c @@ -40,4 +40,8 @@ only want to configure a single interface during boot.\n" "Static IP configuration: Allows you to specify an IPv4 address and network \ mask, gateway, and a DNS server or servers for a network interface. Select \ this option if you do not have a DHCP server, or want explicit control of \ -network settings."); +network settings.\n" +"\n" +"Disk R/W: Certain bootloader configurations may request write access to \ +disks to save information or update parameters (eg. GRUB2). " +"Use this option to control access to disks.\n"); diff --git a/ui/ncurses/nc-config.c b/ui/ncurses/nc-config.c index 76ede39..64fb4c7 100644 --- a/ui/ncurses/nc-config.c +++ b/ui/ncurses/nc-config.c @@ -33,7 +33,7 @@ #include "nc-config.h" #include "nc-widgets.h" -#define N_FIELDS 32 +#define N_FIELDS 34 extern struct help_text config_help_text; @@ -53,6 +53,7 @@ struct config_screen { bool show_help; bool show_subset; bool need_redraw; + bool need_update; void (*on_exit)(struct cui *); @@ -100,6 +101,9 @@ struct config_screen { struct nc_widget_label *dns_dhcp_help_l; struct nc_widget_label *dns_help_l; + struct nc_widget_label *allow_write_l; + struct nc_widget_select *allow_write_f; + struct nc_widget_label *safe_mode; struct nc_widget_button *ok_b; struct nc_widget_button *help_b; @@ -167,21 +171,6 @@ static void config_screen_resize(struct nc_scr *scr) (void)screen; } -static int config_screen_post(struct nc_scr *scr) -{ - struct config_screen *screen = config_screen_from_scr(scr); - screen->show_subset = false; - widgetset_post(screen->widgetset); - nc_scr_frame_draw(scr); - if (screen->need_redraw) { - redrawwin(scr->main_ncw); - screen->need_redraw = false; - } - wrefresh(screen->scr.main_ncw); - pad_refresh(screen); - return 0; -} - static int config_screen_unpost(struct nc_scr *scr) { struct config_screen *screen = config_screen_from_scr(scr); @@ -203,6 +192,7 @@ static int screen_process_form(struct config_screen *screen) struct config *config; int i, n_boot_opts, rc, idx; unsigned int *order; + bool allow_write; char mac[20]; config = config_copy(screen, screen->cui->config); @@ -331,6 +321,10 @@ static int screen_process_form(struct config_screen *screen) } } + allow_write = widget_select_get_value(screen->widgets.allow_write_f); + if (allow_write != config->allow_writes) + config->allow_writes = allow_write; + config->safe_mode = false; rc = cui_send_config(screen->cui, config); talloc_free(config); @@ -410,11 +404,11 @@ static void config_screen_layout_widgets(struct config_screen *screen) y += 1; widget_move(widget_button_base(screen->widgets.boot_add_b), - y, screen->field_x); + y++, screen->field_x); widget_move(widget_button_base(screen->widgets.boot_any_b), - y, screen->field_x + 14); + y++, screen->field_x); widget_move(widget_button_base(screen->widgets.boot_none_b), - y, screen->field_x + 34); + y, screen->field_x); wf = widget_button_base(screen->widgets.boot_add_b); if (widget_subset_n_inactive(screen->widgets.boot_order_f)) @@ -540,12 +534,18 @@ static void config_screen_layout_widgets(struct config_screen *screen) y += 1; } + layout_pair(screen, y, screen->widgets.allow_write_l, + widget_select_base(screen->widgets.allow_write_f)); + y += widget_height(widget_select_base(screen->widgets.allow_write_f)); + + y += 1; + widget_move(widget_button_base(screen->widgets.ok_b), y, screen->field_x); widget_move(widget_button_base(screen->widgets.help_b), - y, screen->field_x + 10); + y, screen->field_x + 14); widget_move(widget_button_base(screen->widgets.cancel_b), - y, screen->field_x + 24); + y, screen->field_x + 28); } static void config_screen_network_change(void *arg, int value) @@ -696,6 +696,7 @@ static void config_screen_setup_widgets(struct config_screen *screen, char *str, *ip, *mask, *gw; enum net_conf_type type; unsigned int i; + int add_len, clear_len, any_len, min_len = 20; build_assert(sizeof(screen->widgets) / sizeof(struct widget *) == N_FIELDS); @@ -703,15 +704,19 @@ static void config_screen_setup_widgets(struct config_screen *screen, type = screen->net_conf_type; ifcfg = first_active_interface(config); - screen->widgets.boot_add_b = widget_new_button(set, 0, 0, 10, + add_len = max(min_len, strncols(_("Add Device"))); + clear_len = max(min_len, strncols(_("Clear"))); + any_len = max(min_len, strncols(_("Clear & Boot Any"))); + + screen->widgets.boot_add_b = widget_new_button(set, 0, 0, add_len, _("Add Device"), config_screen_add_device, screen); - screen->widgets.boot_none_b = widget_new_button(set, 0, 0, 10, + screen->widgets.boot_none_b = widget_new_button(set, 0, 0, clear_len, _("Clear"), config_screen_autoboot_none, screen); - screen->widgets.boot_any_b = widget_new_button(set, 0, 0, 16, + screen->widgets.boot_any_b = widget_new_button(set, 0, 0, any_len, _("Clear & Boot Any"), config_screen_autoboot_any, screen); @@ -748,7 +753,7 @@ static void config_screen_setup_widgets(struct config_screen *screen, widget_subset_add_option(screen->widgets.boot_order_f, label); } - for (i = DEVICE_TYPE_NETWORK; i < DEVICE_TYPE_NETWORK + 4; i++) { + for (i = DEVICE_TYPE_NETWORK; i < DEVICE_TYPE_UNKNOWN; i++) { char *label; if (i == DEVICE_TYPE_ANY) @@ -806,7 +811,8 @@ static void config_screen_setup_widgets(struct config_screen *screen, } screen->widgets.network_l = widget_new_label(set, 0, 0, _("Network:")); - screen->widgets.network_f = widget_new_select(set, 0, 0, 50); + screen->widgets.network_f = widget_new_select(set, 0, 0, + COLS - screen->field_x - 1); widget_select_add_option(screen->widgets.network_f, NET_CONF_TYPE_DHCP_ALL, @@ -900,7 +906,20 @@ static void config_screen_setup_widgets(struct config_screen *screen, screen->widgets.safe_mode = widget_new_label(set, 0, 0, _("Selecting 'OK' will exit safe mode")); - screen->widgets.ok_b = widget_new_button(set, 0, 0, 6, _("OK"), + screen->widgets.allow_write_l = widget_new_label(set, 0, 0, + _("Disk R/W:")); + screen->widgets.allow_write_f = widget_new_select(set, 0, 0, + COLS - screen->field_x - 1); + + widget_select_add_option(screen->widgets.allow_write_f, 0, + _("Prevent all writes to disk"), + !config->allow_writes); + + widget_select_add_option(screen->widgets.allow_write_f, 1, + _("Allow bootloader scripts to modify disks"), + config->allow_writes); + + screen->widgets.ok_b = widget_new_button(set, 0, 0, 10, _("OK"), ok_click, screen); screen->widgets.help_b = widget_new_button(set, 0, 0, 10, _("Help"), help_click, screen); @@ -911,18 +930,22 @@ static void config_screen_setup_widgets(struct config_screen *screen, static void config_screen_widget_focus(struct nc_widget *widget, void *arg) { struct config_screen *screen = arg; - int w_y, s_max; + int w_y, w_height, w_focus, s_max, adjust; - w_y = widget_y(widget) + widget_focus_y(widget); + w_height = widget_height(widget); + w_focus = widget_focus_y(widget); + w_y = widget_y(widget) + w_focus; s_max = getmaxy(screen->scr.sub_ncw) - 1; if (w_y < screen->scroll_y) screen->scroll_y = w_y; - else if (w_y + screen->scroll_y + 1 > s_max) - screen->scroll_y = 1 + w_y - s_max; - - else + else if (w_y + screen->scroll_y + 1 > s_max) { + /* Fit as much of the widget into the screen as possible */ + adjust = min(s_max - 1, w_height - w_focus); + if (w_y + adjust >= screen->scroll_y + s_max) + screen->scroll_y = max(0, 1 + w_y + adjust - s_max); + } else return; pad_refresh(screen); @@ -983,10 +1006,38 @@ void config_screen_update(struct config_screen *screen, const struct config *config, const struct system_info *sysinfo) { + if (screen->cui->current != config_screen_scr(screen)) { + screen->need_update = true; + return; + } + config_screen_draw(screen, config, sysinfo); pad_refresh(screen); } +static int config_screen_post(struct nc_scr *scr) +{ + struct config_screen *screen = config_screen_from_scr(scr); + screen->show_subset = false; + + if (screen->need_update) { + config_screen_draw(screen, screen->cui->config, + screen->cui->sysinfo); + screen->need_update = false; + } else { + widgetset_post(screen->widgetset); + } + + nc_scr_frame_draw(scr); + if (screen->need_redraw) { + redrawwin(scr->main_ncw); + screen->need_redraw = false; + } + wrefresh(screen->scr.main_ncw); + pad_refresh(screen); + return 0; +} + static int config_screen_destroy(void *arg) { struct config_screen *screen = arg; @@ -1012,6 +1063,7 @@ struct config_screen *config_screen_init(struct cui *cui, screen->cui = cui; screen->on_exit = on_exit; screen->need_redraw = false; + screen->need_update = false; screen->label_x = 2; screen->field_x = 17; diff --git a/ui/ncurses/nc-cui.c b/ui/ncurses/nc-cui.c index 56e7653..c975c0f 100644 --- a/ui/ncurses/nc-cui.c +++ b/ui/ncurses/nc-cui.c @@ -698,6 +698,9 @@ static void cui_update_sysinfo(struct system_info *sysinfo, void *arg) if (cui->sysinfo_screen) sysinfo_screen_update(cui->sysinfo_screen, sysinfo); + if (cui->subset_screen) + subset_screen_update(cui->subset_screen); + /* ... and do the same with the config screen... */ if (cui->config_screen) config_screen_update(cui->config_screen, cui->config, sysinfo); @@ -744,6 +747,9 @@ static void cui_update_config(struct config *config, void *arg) if (config->lang) cui_update_language(cui, config->lang); + if (cui->subset_screen) + subset_screen_update(cui->subset_screen); + if (cui->config_screen) config_screen_update(cui->config_screen, config, cui->sysinfo); diff --git a/ui/ncurses/nc-lang.c b/ui/ncurses/nc-lang.c index 0b87156..3d86659 100644 --- a/ui/ncurses/nc-lang.c +++ b/ui/ncurses/nc-lang.c @@ -229,7 +229,7 @@ static void lang_screen_layout_widgets(struct lang_screen *screen) widget_move(widget_button_base(screen->widgets.ok_b), y, screen->field_x); widget_move(widget_button_base(screen->widgets.cancel_b), - y, screen->field_x + 10); + y, screen->field_x + 14); } static void lang_screen_setup_empty(struct lang_screen *screen) @@ -286,7 +286,7 @@ static void lang_screen_setup_widgets(struct lang_screen *screen, screen->widgets.safe_mode = widget_new_label(set, 0, 0, _("Selecting 'OK' will exit safe mode")); - screen->widgets.ok_b = widget_new_button(set, 0, 0, 6, _("OK"), + screen->widgets.ok_b = widget_new_button(set, 0, 0, 10, _("OK"), ok_click, screen); screen->widgets.cancel_b = widget_new_button(set, 0, 0, 10, _("Cancel"), cancel_click, screen); diff --git a/ui/ncurses/nc-menu.c b/ui/ncurses/nc-menu.c index b8f9a35..3f09d62 100644 --- a/ui/ncurses/nc-menu.c +++ b/ui/ncurses/nc-menu.c @@ -253,6 +253,7 @@ struct pmenu_item *pmenu_find_device(struct pmenu *menu, struct device *dev, switch (dev->type) { case DEVICE_TYPE_OPTICAL: case DEVICE_TYPE_DISK: + case DEVICE_TYPE_USB: /* Find block info */ for (i = 0; sys && i < sys->n_blockdevs; i++) { bd = sys->blockdevs[i]; @@ -263,8 +264,7 @@ struct pmenu_item *pmenu_find_device(struct pmenu *menu, struct device *dev, } if (matched) { snprintf(buf,sizeof(buf),"[%s: %s / %s]", - dev->type == DEVICE_TYPE_DISK ? - _("Disk") : _("CD/DVD"), + device_type_display_name(dev->type), bd->name, bd->uuid); } break; diff --git a/ui/ncurses/nc-subset.c b/ui/ncurses/nc-subset.c index f38e394..0faed3b 100644 --- a/ui/ncurses/nc-subset.c +++ b/ui/ncurses/nc-subset.c @@ -62,6 +62,12 @@ struct nc_scr *subset_screen_return_scr(struct subset_screen *screen) return screen->return_scr; } +void subset_screen_update(struct subset_screen *screen) +{ + pb_debug("Exiting subset due to update\n"); + return screen->on_exit(screen->cui); +} + static struct subset_screen *subset_screen_from_scr(struct nc_scr *scr) { struct subset_screen *subset_screen; diff --git a/ui/ncurses/nc-sysinfo.c b/ui/ncurses/nc-sysinfo.c index bde8b33..ac8ece7 100644 --- a/ui/ncurses/nc-sysinfo.c +++ b/ui/ncurses/nc-sysinfo.c @@ -104,7 +104,11 @@ void sysinfo_screen_update(struct sysinfo_screen *screen, const struct system_info *sysinfo) { sysinfo_screen_populate(screen, sysinfo); - text_screen_draw(&screen->text_scr); + + if (screen->text_scr.cui->help_screen) + screen->text_scr.need_update = true; + else + text_screen_draw(&screen->text_scr); } struct sysinfo_screen *sysinfo_screen_init(struct cui *cui, diff --git a/ui/ncurses/nc-textscreen.c b/ui/ncurses/nc-textscreen.c index 826244c..55428e7 100644 --- a/ui/ncurses/nc-textscreen.c +++ b/ui/ncurses/nc-textscreen.c @@ -183,6 +183,13 @@ void text_screen_set_help(struct text_screen *screen, const char *title, static int text_screen_post(struct nc_scr *scr) { + struct text_screen *screen = text_screen_from_scr(scr); + + if (screen->need_update) { + text_screen_draw(screen); + screen->need_update = false; + } + nc_scr_frame_draw(scr); redrawwin(scr->main_ncw); wrefresh(scr->main_ncw); @@ -202,6 +209,7 @@ void text_screen_init(struct text_screen *screen, struct cui *cui, screen->cui = cui; screen->on_exit = on_exit; + screen->need_update = false; screen->scr.frame.ltitle = talloc_strdup(screen, title); screen->scr.frame.rtitle = NULL; diff --git a/ui/ncurses/nc-textscreen.h b/ui/ncurses/nc-textscreen.h index 25107cb..df47186 100644 --- a/ui/ncurses/nc-textscreen.h +++ b/ui/ncurses/nc-textscreen.h @@ -28,6 +28,7 @@ struct text_screen { int n_lines; int n_alloc_lines; int scroll_y; + bool need_update; const char *help_title; const struct help_text *help_text; void (*on_exit)(struct cui *); diff --git a/ui/ncurses/nc-widgets.c b/ui/ncurses/nc-widgets.c index 3daced1..7e03e57 100644 --- a/ui/ncurses/nc-widgets.c +++ b/ui/ncurses/nc-widgets.c @@ -51,6 +51,8 @@ #include #include #include +#include +#include #include "nc-cui.h" #include "nc-widgets.h" @@ -137,6 +139,7 @@ struct nc_widget_select { char *str; int val; FIELD *field; + int lines; } *options; int top, left, size; int n_options, selected_option; @@ -838,21 +841,25 @@ static void select_set_visible(struct nc_widget *widget, bool visible) static void select_move(struct nc_widget *widget, int y, int x) { struct nc_widget_select *select = to_select(widget); - int i; + int i, cur = 0; - for (i = 0; i < select->n_options; i++) - field_move(select->options[i].field, y + i, x); + for (i = 0; i < select->n_options; i++) { + field_move(select->options[i].field, y + cur, x); + cur += select->options[i].lines; + } } static void select_field_focus(struct nc_widget *widget, FIELD *field) { struct nc_widget_select *select = to_select(widget); - int i; + int i, cur = 0; for (i = 0; i < select->n_options; i++) { - if (field != select->options[i].field) + if (field != select->options[i].field) { + cur += select->options[i].lines; continue; - widget->focus_y = i; + } + widget->focus_y = cur; return; } } @@ -894,10 +901,47 @@ struct nc_widget_select *widget_new_select(struct nc_widgetset *set, return select; } +static int widget_select_fold_cb(void *arg, const char *buf, int len) +{ + struct nc_widget_select *select = arg; + char *line, *newstr, *padbuf = NULL; + int i, pad; + + if (!len) + return 0; + + line = talloc_strndup(select->options, buf, len); + + i = select->n_options - 1; + pad = max(0, select->widget.width - strncols(line)); + + if (pad) { + padbuf = talloc_array(select->options, char, pad + 1); + memset(padbuf, ' ', pad); + padbuf[pad] = '\0'; + } + + if (select->options[i].str) + newstr = talloc_asprintf_append(select->options[i].str, + "%s%s", line, + pad ? padbuf : ""); + else + newstr = talloc_asprintf(select->options, "%s%s", line, + pad ? padbuf : ""); + + select->options[i].str = newstr; + select->options[i].lines++; + + talloc_free(padbuf); + talloc_free(line); + return 0; +} + void widget_select_add_option(struct nc_widget_select *select, int value, const char *text, bool selected) { const char *str; + char *full_text; FIELD *f; int i; @@ -916,23 +960,29 @@ void widget_select_add_option(struct nc_widget_select *select, int value, str = select_unselected_str; i = select->n_options++; - select->widget.height = select->n_options; - select->options = talloc_realloc(select, select->options, struct select_option, i + 2); select->options[i].val = value; - select->options[i].str = talloc_asprintf(select->options, - "%s %s", str, text); + select->options[i].lines = 0; + select->options[i].str = NULL; - select->options[i].field = f = new_field(1, select->size, - select->top + i, - select->left, 0, 0); + full_text = talloc_asprintf(select->options, "%s %s", str, text); + fold_text(full_text, select->widget.width, + widget_select_fold_cb, select); - field_opts_off(f, O_WRAP | O_EDIT); + select->options[i].field = f = new_field(select->options[i].lines, + select->size, + select->top + select->widget.height, + select->left, 0, 0); + + select->widget.height += select->options[i].lines; + + field_opts_off(f, O_EDIT); set_field_userptr(f, &select->widget); set_field_buffer(f, 0, select->options[i].str); widgetset_add_field(select->set, f); + talloc_free(full_text); } int widget_select_get_value(struct nc_widget_select *select) @@ -944,7 +994,7 @@ int widget_select_get_value(struct nc_widget_select *select) int widget_select_height(struct nc_widget_select *select) { - return select->n_options; + return select->widget.height; } void widget_select_on_change(struct nc_widget_select *select, @@ -1002,16 +1052,18 @@ struct nc_widget_button *widget_new_button(struct nc_widgetset *set, void (*click)(void *), void *arg) { struct nc_widget_button *button; + int idx, len, pad1, pad2, bufsz; char *text; FIELD *f; - int idx, len; + + int field_size = size + 2; button = talloc_zero(set, struct nc_widget_button); button->widget.height = 1; - button->widget.width = size; + button->widget.width = field_size; button->widget.x = x; button->widget.y = y; - button->widget.field = f = new_field(1, size + 2, y, x, 0, 0); + button->widget.field = f = new_field(1, field_size, y, x, 0, 0); button->widget.process_key = button_process_key; button->widget.focussed_attr = A_REVERSE; button->widget.unfocussed_attr = A_NORMAL; @@ -1021,17 +1073,28 @@ struct nc_widget_button *widget_new_button(struct nc_widgetset *set, field_opts_off(f, O_EDIT); set_field_userptr(f, &button->widget); - /* center str in a size-char buffer, but don't overrun */ - len = strlen(str); - len = min(len, size); - idx = (size - len) / 2; + /* Center str in the field. This depends on the number of columns used + * by the string, not the number of chars in str */ + len = strncols(str); + if (len <= size) { + idx = (field_size - len) / 2; + } else { + idx = 1; + pb_log("Warning: '%s' %d columns wide " + "but button is %d columns wide\n", + str, len, size); + } + + pad1 = max(idx - 1, 0); + pad2 = max(size - len - pad1, 0); + bufsz = 1 + pad1 + strlen(str) + pad2 + 2; - text = talloc_array(button, char, size + 3); - memset(text, ' ', size + 2); - memcpy(text + idx + 1, str, len); + text = talloc_array(button, char, bufsz); + memset(text, ' ', bufsz); + memcpy(text + idx, str, strlen(str)); text[0] = '['; - text[size + 1] = ']'; - text[size + 2] = '\0'; + text[bufsz - 2] = ']'; + text[bufsz - 1] = '\0'; set_field_buffer(f, 0, text); diff --git a/ui/test/discover-test.c b/ui/test/discover-test.c index 363a289..b099b59 100644 --- a/ui/test/discover-test.c +++ b/ui/test/discover-test.c @@ -8,6 +8,8 @@ static const char *device_type_string(enum device_type type) switch (type) { case DEVICE_TYPE_DISK: return "disk"; + case DEVICE_TYPE_USB: + return "usb"; case DEVICE_TYPE_NETWORK: return "network"; case DEVICE_TYPE_OPTICAL: diff --git a/utils/pb-config.c b/utils/pb-config.c index 009bec7..c52180b 100644 --- a/utils/pb-config.c +++ b/utils/pb-config.c @@ -79,6 +79,8 @@ static void print_config(void *ctx, struct config *config, const char *var) config->safe_mode ? "enabled" : "disabled"); print_one_config(ctx, var, "debug", "%s", config->debug ? "enabled" : "disabled"); + print_one_config(ctx, var, "dm-snapshots", "%s", + config->disable_snapshots ? "disabled" : "enabled"); } int main(int argc, char **argv)