From 98bc29fda446f5c667f4bc799161b3446bfc2ca1 Mon Sep 17 00:00:00 2001 From: Matthew Booth Date: Mon, 3 Aug 2009 16:04:50 +0100 Subject: [PATCH] Recognise cd-rom devices in devsparts.c Also: * Un-duplicate device detection code by creating a common mapping function. * Add some more comments. --- daemon/devsparts.c | 168 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 96 insertions(+), 72 deletions(-) diff --git a/daemon/devsparts.c b/daemon/devsparts.c index 1970e7d..b89682c 100644 --- a/daemon/devsparts.c +++ b/daemon/devsparts.c @@ -29,14 +29,19 @@ #include "daemon.h" #include "actions.h" -char ** -do_list_devices (void) +typedef int (*block_dev_func_t)(const char *dev, + char ***r, int *size, int *alloc); + +/* Execute a given function for each discovered block device */ +static char** +foreach_block_device (block_dev_func_t func) { char **r = NULL; int size = 0, alloc = 0; + DIR *dir; struct dirent *d; - char buf[256]; + int err = 0; dir = opendir ("/sys/block"); if (!dir) { @@ -44,121 +49,140 @@ do_list_devices (void) return NULL; } + errno = 0; while ((d = readdir (dir)) != NULL) { if (strncmp (d->d_name, "sd", 2) == 0 || strncmp (d->d_name, "hd", 2) == 0 || - strncmp (d->d_name, "vd", 2) == 0) { - snprintf (buf, sizeof buf, "/dev/%s", d->d_name); + strncmp (d->d_name, "vd", 2) == 0 || + strncmp (d->d_name, "sr", 2) == 0) { + char dev_path[256]; + snprintf (dev_path, sizeof dev_path, "/dev/%s", d->d_name); /* RHBZ#514505: Some versions of qemu <= 0.10 add a * CD-ROM device even though we didn't request it. Try to * detect this by seeing if the device contains media. */ - int fd = open (buf, O_RDONLY); + int fd = open (dev_path, O_RDONLY); if (fd == -1) { - perror (buf); + perror (dev_path); continue; } close (fd); - if (add_string (&r, &size, &alloc, buf) == -1) { - closedir (dir); - return NULL; + /* Call the map function for this device */ + if((*func)(d->d_name, &r, &size, &alloc) != 0) { + err = 1; + break; } } } - if (add_string (&r, &size, &alloc, NULL) == -1) { - closedir (dir); + /* Check readdir didn't fail */ + if(0 != errno) { + reply_with_perror ("readdir: /sys/block"); + free_stringslen(r, size); return NULL; } + /* Close the directory handle */ if (closedir (dir) == -1) { reply_with_perror ("closedir: /sys/block"); - free_strings (r); + free_stringslen(r, size); + return NULL; + } + + /* Free the result list on error */ + if(err) { + free_stringslen(r, size); + return NULL; + } + + /* Sort the devices */ + sort_strings (r, size); + + /* NULL terminate the list */ + if (add_string (&r, &size, &alloc, NULL) == -1) { return NULL; } - sort_strings (r, size-1); return r; } -char ** -do_list_partitions (void) +/* Add a device to the list of devices */ +static int +add_device(const char *device, + char ***const r, int *const size, int *const alloc) { - char **r = NULL; - int size = 0, alloc = 0; - DIR *dir, *dir2; - struct dirent *d; - char buf[256], devname[256]; + char dev_path[256]; + snprintf (dev_path, sizeof dev_path, "/dev/%s", device); - dir = opendir ("/sys/block"); - if (!dir) { - reply_with_perror ("opendir: /sys/block"); - return NULL; + if (add_string (r, size, alloc, dev_path) == -1) { + return -1; } - while ((d = readdir (dir)) != NULL) { - if (strncmp (d->d_name, "sd", 2) == 0 || - strncmp (d->d_name, "hd", 2) == 0 || - strncmp (d->d_name, "vd", 2) == 0) { - snprintf (buf, sizeof buf, "/dev/%s", d->d_name); + return 0; +} - /* RHBZ#514505: Some versions of qemu <= 0.10 add a - * CD-ROM device even though we didn't request it. Try to - * detect this by seeing if the device contains media. - */ - int fd = open (buf, O_RDONLY); - if (fd == -1) { - perror (buf); - continue; - } - close (fd); +char ** +do_list_devices (void) +{ + return foreach_block_device(add_device); +} - strncpy (devname, d->d_name, sizeof devname); - devname[sizeof devname - 1] = '\0'; +static int +add_partitions(const char *device, + char ***const r, int *const size, int *const alloc) +{ + char devdir[256]; - snprintf (buf, sizeof buf, "/sys/block/%s", devname); + /* Open the device's directory under /sys/block */ + snprintf (devdir, sizeof devdir, "/sys/block/%s", device); - dir2 = opendir (buf); - if (!dir2) { - reply_with_perror ("opendir: %s", buf); - free_stringslen (r, size); - return NULL; - } - while ((d = readdir (dir2)) != NULL) { - if (strncmp (d->d_name, devname, strlen (devname)) == 0) { - snprintf (buf, sizeof buf, "/dev/%s", d->d_name); - - if (add_string (&r, &size, &alloc, buf) == -1) { - closedir (dir2); - closedir (dir); - return NULL; - } - } - } + DIR *dir = opendir (devdir); + if (!dir) { + reply_with_perror ("opendir: %s", devdir); + free_stringslen (*r, *size); + return -1; + } - if (closedir (dir2) == -1) { - reply_with_perror ("closedir: /sys/block/%s", devname); - free_stringslen (r, size); - return NULL; + /* Look in /sys/block// for entries starting with + * e.g. /sys/block/sda/sda1 + */ + errno = 0; + struct dirent *d; + while ((d = readdir (dir)) != NULL) { + if (strncmp (d->d_name, device, strlen (device)) == 0) { + char part[256]; + snprintf (part, sizeof part, "/dev/%s", d->d_name); + + if (add_string (r, size, alloc, part) == -1) { + closedir (dir); + return -1; } } } - if (add_string (&r, &size, &alloc, NULL) == -1) { - closedir (dir); - return NULL; + /* Check if readdir failed */ + if(0 != errno) { + reply_with_perror ("readdir: %s", devdir); + free_stringslen(*r, *size); + return -1; } + /* Close the directory handle */ if (closedir (dir) == -1) { - reply_with_perror ("closedir: /sys/block"); - free_strings (r); - return NULL; + reply_with_perror ("closedir: /sys/block/%s", device); + free_stringslen (*r, *size); + return -1; } - sort_strings (r, size-1); - return r; + return 0; +} + +char ** +do_list_partitions (void) +{ + return foreach_block_device(add_partitions); } int -- 1.8.3.1