summaryrefslogtreecommitdiffstats
path: root/df
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-06-13 14:49:06 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-06-13 23:07:26 +0100
commit8735e92a1dae603f2584684ea802b0f5dc332543 (patch)
tree6efce20d29b6ac2e9cedee4bf3a0bd63b4716a3d /df
parenta9d7d044f552855a7ef78d953c0c2672e35bfc80 (diff)
downloadlibguestfs-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.c42
-rw-r--r--df/domains.c48
-rw-r--r--df/output.c101
3 files changed, 142 insertions, 49 deletions
diff --git a/df/df.c b/df/df.c
index f398d0c2..56a55cf1 100644
--- a/df/df.c
+++ b/df/df.c
@@ -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;
+}