diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-06-13 14:49:06 +0100 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-06-13 23:07:26 +0100 |
commit | 8735e92a1dae603f2584684ea802b0f5dc332543 (patch) | |
tree | 6efce20d29b6ac2e9cedee4bf3a0bd63b4716a3d /df | |
parent | a9d7d044f552855a7ef78d953c0c2672e35bfc80 (diff) | |
download | libguestfs-8735e92a1dae603f2584684ea802b0f5dc332543.tar.gz libguestfs-8735e92a1dae603f2584684ea802b0f5dc332543.tar.xz libguestfs-8735e92a1dae603f2584684ea802b0f5dc332543.zip |
virt-df: Use guestfs_max_disks instead of hard-coding limit of 25.
And comprehensively fix it so it works with > 26 disks.
Diffstat (limited to 'df')
-rw-r--r-- | df/df.c | 42 | ||||
-rw-r--r-- | df/domains.c | 48 | ||||
-rw-r--r-- | df/output.c | 101 |
3 files changed, 142 insertions, 49 deletions
@@ -30,6 +30,7 @@ #endif #include "progname.h" +#include "c-ctype.h" #include "guestfs.h" #include "options.h" @@ -115,17 +116,50 @@ df_on_handle (const char *name, const char *uuid, char **devices, int offset) return ret; } +/* dev is a device or partition name such as "/dev/sda" or "/dev/sda1". + * See if dev occurs somewhere in the list of devices. + */ static int find_dev_in_devices (const char *dev, char **devices) { - size_t i; + guestfs_error_handler_cb old_error_cb; + void *old_error_data; + size_t i, len; + char *whole_disk; + int free_whole_disk; + int ret = 0; + + /* Convert 'dev' to a whole disk name. */ + len = strlen (dev); + if (len > 0 && c_isdigit (dev[len-1])) { + old_error_cb = guestfs_get_error_handler (g, &old_error_data); + guestfs_set_error_handler (g, NULL, NULL); + + whole_disk = guestfs_part_to_dev (g, dev); + + guestfs_set_error_handler (g, old_error_cb, old_error_data); + + if (!whole_disk) /* probably an MD device or similar */ + return 0; + + free_whole_disk = 1; + } + else { + whole_disk = (char *) dev; + free_whole_disk = 0; + } for (i = 0; devices[i] != NULL; ++i) { - if (STRPREFIX (dev, devices[i])) - return 1; + if (STREQ (whole_disk, devices[i])) { + ret = 1; + break; + } } - return 0; + if (free_whole_disk) + free (whole_disk); + + return ret; } static void diff --git a/df/domains.c b/df/domains.c index f2ee8546..2b1f4680 100644 --- a/df/domains.c +++ b/df/domains.c @@ -41,14 +41,6 @@ #if defined(HAVE_LIBVIRT) && defined(HAVE_LIBXML2) -/* Limit the number of devices we will ever add to the appliance. The - * overall limit in current libguestfs is 25: 26 = number of letters - * in the English alphabet since we are only confident that - * /dev/sd[a-z] will work because of various limits, minus 1 because - * that may be used by the ext2 initial filesystem. (RHBZ#635373). - */ -#define MAX_DISKS 25 - /* The list of domains and disks that we build up in * get_domains_from_libvirt. */ @@ -94,9 +86,9 @@ free_domain (struct domain *domain) free (domain->uuid); } -static void add_domains_by_id (virConnectPtr conn, int *ids, size_t n); -static void add_domains_by_name (virConnectPtr conn, char **names, size_t n); -static void add_domain (virDomainPtr dom); +static void add_domains_by_id (virConnectPtr conn, int *ids, size_t n, size_t max_disks); +static void add_domains_by_name (virConnectPtr conn, char **names, size_t n, size_t max_disks); +static void add_domain (virDomainPtr dom, size_t max_disks); static int add_disk (guestfs_h *g, const char *filename, const char *format, int readonly, void *domain_vp); static void multi_df (struct domain *, size_t n, size_t *errors); @@ -105,8 +97,13 @@ get_domains_from_libvirt (void) { virErrorPtr err; virConnectPtr conn; - int n; - size_t i, j, nr_disks_added, errors; + int n, r; + size_t i, j, nr_disks_added, errors, max_disks; + + r = guestfs_max_disks (g); + if (r == -1) + exit (EXIT_FAILURE); + max_disks = (size_t) r; nr_domains = 0; domains = NULL; @@ -140,7 +137,7 @@ get_domains_from_libvirt (void) exit (EXIT_FAILURE); } - add_domains_by_id (conn, ids, n); + add_domains_by_id (conn, ids, n, max_disks); n = virConnectNumOfDefinedDomains (conn); if (n == -1) { @@ -161,7 +158,7 @@ get_domains_from_libvirt (void) exit (EXIT_FAILURE); } - add_domains_by_name (conn, names, n); + add_domains_by_name (conn, names, n, max_disks); /* You must free these even though the libvirt documentation doesn't * mention it. @@ -182,7 +179,7 @@ get_domains_from_libvirt (void) /* To minimize the number of times we have to launch the appliance, * shuffle as many domains together as we can, but not exceeding - * MAX_DISKS per request. If --one-per-guest was requested then only + * max_disks per request. If --one-per-guest was requested then only * request disks from a single guest each time. * Interesting application for NP-complete knapsack problem here. */ @@ -196,7 +193,7 @@ get_domains_from_libvirt (void) /* Make a request with domains [i..j-1]. */ for (j = i; j < nr_domains; ++j) { - if (nr_disks_added + domains[j].nr_disks > MAX_DISKS) + if (nr_disks_added + domains[j].nr_disks > max_disks) break; nr_disks_added += domains[j].nr_disks; } @@ -219,7 +216,7 @@ get_domains_from_libvirt (void) } static void -add_domains_by_id (virConnectPtr conn, int *ids, size_t n) +add_domains_by_id (virConnectPtr conn, int *ids, size_t n, size_t max_disks) { size_t i; virDomainPtr dom; @@ -228,7 +225,7 @@ add_domains_by_id (virConnectPtr conn, int *ids, size_t n) if (ids[i] != 0) { /* RHBZ#538041 */ dom = virDomainLookupByID (conn, ids[i]); if (dom) { /* transient errors are possible here, ignore them */ - add_domain (dom); + add_domain (dom, max_disks); virDomainFree (dom); } } @@ -236,7 +233,8 @@ add_domains_by_id (virConnectPtr conn, int *ids, size_t n) } static void -add_domains_by_name (virConnectPtr conn, char **names, size_t n) +add_domains_by_name (virConnectPtr conn, char **names, size_t n, + size_t max_disks) { size_t i; virDomainPtr dom; @@ -244,14 +242,14 @@ add_domains_by_name (virConnectPtr conn, char **names, size_t n) for (i = 0; i < n; ++i) { dom = virDomainLookupByName (conn, names[i]); if (dom) { /* transient errors are possible here, ignore them */ - add_domain (dom); + add_domain (dom, max_disks); virDomainFree (dom); } } } static void -add_domain (virDomainPtr dom) +add_domain (virDomainPtr dom, size_t max_disks) { struct domain *domain; @@ -287,10 +285,10 @@ add_domain (virDomainPtr dom) exit (EXIT_FAILURE); domain->nr_disks = n; - if (domain->nr_disks > MAX_DISKS) { + if (domain->nr_disks > max_disks) { fprintf (stderr, - _("%s: ignoring %s, it has too many disks (%zu > %d)\n"), - program_name, domain->name, domain->nr_disks, MAX_DISKS); + _("%s: ignoring %s, it has too many disks (%zu > %zu)\n"), + program_name, domain->name, domain->nr_disks, max_disks); free_domain (domain); nr_domains--; return; diff --git a/df/output.c b/df/output.c index ba513ded..5729dd4b 100644 --- a/df/output.c +++ b/df/output.c @@ -82,7 +82,7 @@ print_title (void) } } -static void canonical_device (char *dev, int offset); +static char *adjust_device_offset (const char *device, int offset); void print_stat (const char *name, const char *uuid_param, @@ -102,13 +102,17 @@ print_stat (const char *name, const char *uuid_param, float percent; int hopts = human_round_to_nearest|human_autoscale|human_base_1024|human_SI; size_t i, len; + char *dev; - /* Make the device canonical. */ - len = strlen (dev_param) + 1; - char dev[len]; - strcpy (dev, dev_param); - if (offset >= 0) - canonical_device (dev, offset); + /* Make a canonical name, adjusting the device offset if necessary. */ + dev = guestfs_canonical_device_name (g, dev_param); + if (!dev) + exit (EXIT_FAILURE); + if (offset >= 0) { + char *p = dev; + dev = adjust_device_offset (p, offset); + free (p); + } if (!inodes) { /* 1K blocks */ if (!human) { @@ -190,20 +194,8 @@ print_stat (const char *name, const char *uuid_param, putchar ('\n'); } -} -/* /dev/vda1 -> /dev/sda, adjusting the device offset. */ -static void -canonical_device (char *dev, int offset) -{ - if (STRPREFIX (dev, "/dev/") && - (dev[5] == 'h' || dev[5] == 'v') && - dev[6] == 'd' && - c_isalpha (dev[7]) && - (c_isdigit (dev[8]) || dev[8] == '\0')) { - dev[5] = 's'; - dev[7] -= offset; - } + free (dev); } /* Function to quote CSV fields on output without requiring an @@ -241,3 +233,72 @@ write_csv_field (const char *field) } putchar ('"'); } + +static char *drive_name (int index, char *ret); + +static char * +adjust_device_offset (const char *device, int offset) +{ + int index; + int part_num; + char *whole_device; + int free_whole_device; + size_t len; + char *ret; + + /* Could be a whole disk or a partition. guestfs_device_index will + * only work with the whole disk name. + */ + len = strlen (device); + if (len > 0 && c_isdigit (device[len-1])) { + whole_device = guestfs_part_to_dev (g, device); + if (whole_device == NULL) + exit (EXIT_FAILURE); + free_whole_device = 1; + part_num = guestfs_part_to_partnum (g, device); + if (part_num == -1) + exit (EXIT_FAILURE); + } else { + whole_device = (char *) device; + free_whole_device = 0; + part_num = 0; + } + + index = guestfs_device_index (g, whole_device); + if (index == -1) + exit (EXIT_FAILURE); + + if (free_whole_device) + free (whole_device); + + assert (index >= offset); + + index -= offset; + + /* Construct the final device name. */ + ret = malloc (128); + if (!ret) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + + strcpy (ret, "/dev/sd"); + drive_name (index, &ret[7]); + len = strlen (ret); + if (part_num > 0) + snprintf (&ret[len], 128-len, "%d", part_num); + + return ret; +} + +/* https://rwmj.wordpress.com/2011/01/09/how-are-linux-drives-named-beyond-drive-26-devsdz/ */ +static char * +drive_name (int index, char *ret) +{ + if (index >= 26) + ret = drive_name (index/26 - 1, ret); + index %= 26; + *ret++ = 'a' + index; + *ret = '\0'; + return ret; +} |