X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=daemon%2Fdevsparts.c;h=95e4a6828e6d1767c9147afbe39ed41a4eb57783;hp=b0d79569ef57e16447a30894d1a08919f9b1a971;hb=5c31f6126ba4ea3e9056c34c300f6f5e332ab997;hpb=8e570870f577ff0c3db074f88924633b559af5d4 diff --git a/daemon/devsparts.c b/daemon/devsparts.c index b0d7956..95e4a68 100644 --- a/daemon/devsparts.c +++ b/daemon/devsparts.c @@ -1,5 +1,5 @@ /* libguestfs - the guestfsd daemon - * Copyright (C) 2009 Red Hat Inc. + * Copyright (C) 2009 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 @@ -29,14 +29,18 @@ #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,90 +48,145 @@ do_list_devices (void) return NULL; } - while ((d = readdir (dir)) != NULL) { - if (strncmp (d->d_name, "sd", 2) == 0) { - snprintf (buf, sizeof buf, "/dev/%s", d->d_name); - if (add_string (&r, &size, &alloc, buf) == -1) { - closedir (dir); - return NULL; + while(1) { + errno = 0; + struct dirent *d = readdir(dir); + if(NULL == d) break; + + if (STREQLEN (d->d_name, "sd", 2) || + STREQLEN (d->d_name, "hd", 2) || + STREQLEN (d->d_name, "vd", 2) || + STREQLEN (d->d_name, "sr", 2)) { + char dev_path[256]; + snprintf (dev_path, sizeof dev_path, "/dev/%s", d->d_name); + + /* Ignore the root device. */ + if (is_root_device (dev_path)) + continue; + + /* 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 (dev_path, O_RDONLY); + if (fd == -1) { + perror (dev_path); + continue; + } + close (fd); + + /* 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; } +/* 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 dev_path[256]; + snprintf (dev_path, sizeof dev_path, "/dev/%s", device); + + if (add_string (r, size, alloc, dev_path) == -1) { + return -1; + } + + return 0; +} + char ** -do_list_partitions (void) +do_list_devices (void) { - char **r = NULL; - int size = 0, alloc = 0; - DIR *dir, *dir2; - struct dirent *d; - char buf[256], devname[256]; + return foreach_block_device(add_device); +} - dir = opendir ("/sys/block"); +static int +add_partitions(const char *device, + char ***const r, int *const size, int *const alloc) +{ + char devdir[256]; + + /* Open the device's directory under /sys/block */ + snprintf (devdir, sizeof devdir, "/sys/block/%s", device); + + DIR *dir = opendir (devdir); if (!dir) { - reply_with_perror ("opendir: /sys/block"); - return NULL; + reply_with_perror ("opendir: %s", devdir); + free_stringslen (*r, *size); + return -1; } + /* 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, "sd", 2) == 0) { - strncpy (devname, d->d_name, sizeof devname); - devname[sizeof devname - 1] = '\0'; - - snprintf (buf, sizeof buf, "/sys/block/%s", devname); + if (STREQLEN (d->d_name, device, strlen (device))) { + char part[256]; + snprintf (part, sizeof part, "/dev/%s", d->d_name); - 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; - } - } - } - - if (closedir (dir2) == -1) { - reply_with_perror ("closedir: /sys/block/%s", devname); - free_stringslen (r, size); - return NULL; + 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); }