mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
daemon: Fix order of devices in guestfs_list_devices when > 26 disks.
Sort the device names correctly, not just treating them as strings. As a result, /dev/sdz < /dev/sdaa.
This commit is contained in:
@@ -79,6 +79,9 @@ extern void sort_strings (char **argv, size_t len);
|
||||
extern void free_strings (char **argv);
|
||||
extern void free_stringslen (char **argv, size_t len);
|
||||
|
||||
extern void sort_device_names (char **argv, size_t len);
|
||||
extern int compare_device_names (const char *a, const char *b);
|
||||
|
||||
extern char **split_lines (char *str);
|
||||
|
||||
#define command(out,err,name,...) commandf((out),(err),0,(name),__VA_ARGS__)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009 Red Hat Inc.
|
||||
* Copyright (C) 2009-2012 Red Hat Inc.
|
||||
*
|
||||
* 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
|
||||
@@ -106,7 +106,7 @@ foreach_block_device (block_dev_func_t func)
|
||||
|
||||
/* Sort the devices. */
|
||||
if (r.size > 0)
|
||||
sort_strings (r.argv, r.size);
|
||||
sort_device_names (r.argv, r.size);
|
||||
|
||||
/* NULL terminate the list */
|
||||
if (end_stringsbuf (&r) == -1) {
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef HAVE_PRINTF_H
|
||||
# include <printf.h>
|
||||
@@ -514,6 +515,69 @@ free_stringslen (char **argv, size_t len)
|
||||
free (argv);
|
||||
}
|
||||
|
||||
/* Compare device names (including partition numbers if present).
|
||||
* https://rwmj.wordpress.com/2011/01/09/how-are-linux-drives-named-beyond-drive-26-devsdz/
|
||||
*/
|
||||
int
|
||||
compare_device_names (const char *a, const char *b)
|
||||
{
|
||||
size_t a_devlen, b_devlen;
|
||||
int r;
|
||||
int a_partnum, b_partnum;
|
||||
|
||||
/* Skip /dev/ prefix if present. */
|
||||
if (STRPREFIX (a, "/dev/"))
|
||||
a += 5;
|
||||
if (STRPREFIX (b, "/dev/"))
|
||||
b += 5;
|
||||
|
||||
/* Skip sd/hd/vd. */
|
||||
assert (a[1] == 'd');
|
||||
a += 2;
|
||||
assert (b[1] == 'd');
|
||||
b += 2;
|
||||
|
||||
/* Get device name part, that is, just 'a', 'ab' etc. */
|
||||
a_devlen = strcspn (a, "0123456789");
|
||||
b_devlen = strcspn (b, "0123456789");
|
||||
|
||||
/* If device name part is longer, it is always greater, eg.
|
||||
* "/dev/sdz" < "/dev/sdaa".
|
||||
*/
|
||||
if (a_devlen != b_devlen)
|
||||
return a_devlen - b_devlen;
|
||||
|
||||
/* Device name parts are the same length, so do a regular compare. */
|
||||
r = strncmp (a, b, a_devlen);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
/* Compare partitions numbers. */
|
||||
a += a_devlen;
|
||||
b += a_devlen;
|
||||
|
||||
r = sscanf (a, "%d", &a_partnum);
|
||||
assert (r == 1);
|
||||
r = sscanf (b, "%d", &b_partnum);
|
||||
assert (r == 1);
|
||||
|
||||
return a_partnum - b_partnum;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_device_names_vp (const void *vp1, const void *vp2)
|
||||
{
|
||||
char * const *p1 = (char * const *) vp1;
|
||||
char * const *p2 = (char * const *) vp2;
|
||||
return compare_device_names (*p1, *p2);
|
||||
}
|
||||
|
||||
void
|
||||
sort_device_names (char **argv, size_t len)
|
||||
{
|
||||
qsort (argv, len, sizeof (char *), compare_device_names_vp);
|
||||
}
|
||||
|
||||
/* Easy ways to run external commands. For full documentation, see
|
||||
* 'commandrvf' below.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user