diff options
Diffstat (limited to 'df/df.c')
-rw-r--r-- | df/df.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/df/df.c b/df/df.c new file mode 100644 index 00000000..c2db970f --- /dev/null +++ b/df/df.c @@ -0,0 +1,158 @@ +/* virt-df + * Copyright (C) 2010 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> + +#ifdef HAVE_LIBVIRT +#include <libvirt/libvirt.h> +#include <libvirt/virterror.h> +#endif + +#include "progname.h" + +#include "guestfs.h" +#include "options.h" +#include "virt-df.h" + +static void try_df (const char *name, const char *uuid, const char *dev, int offset); +static int find_dev_in_devices (const char *dev, char **devices); + +/* Since we want this function to be robust against very bad failure + * cases (hello, https://bugzilla.kernel.org/show_bug.cgi?id=18792) it + * won't exit on guestfs failures. + */ +int +df_on_handle (const char *name, const char *uuid, char **devices, int offset) +{ + int ret = -1; + size_t i; + char **fses = NULL; + int free_devices = 0, is_lv; + + if (verbose) { + fprintf (stderr, "df_on_handle %s devices=", name); + if (devices) { + fputc ('[', stderr); + for (i = 0; devices[i] != NULL; ++i) { + if (i > 0) + fputc (' ', stderr); + fputs (devices[i], stderr); + } + fputc (']', stderr); + } + else + fprintf (stderr, "null"); + fputc ('\n', stderr); + } + + if (devices == NULL) { + devices = guestfs_list_devices (g); + if (devices == NULL) + goto cleanup; + free_devices = 1; + } else { + /* Mask LVM for just the devices in the set. */ + if (guestfs_lvm_set_filter (g, devices) == -1) + goto cleanup; + } + + /* list-filesystems will return filesystems on every device ... */ + fses = guestfs_list_filesystems (g); + if (fses == NULL) + goto cleanup; + + /* ... so we need to filter out only the devices we are interested in. */ + for (i = 0; fses[i] != NULL; i += 2) { + if (STRNEQ (fses[i+1], "") && + STRNEQ (fses[i+1], "swap") && + STRNEQ (fses[i+1], "unknown")) { + is_lv = guestfs_is_lv (g, fses[i]); + if (is_lv > 0) /* LVs are OK because of the LVM filter */ + try_df (name, uuid, fses[i], -1); + else if (is_lv == 0) { + if (find_dev_in_devices (fses[i], devices)) + try_df (name, uuid, fses[i], offset); + } + } + } + + ret = 0; + + cleanup: + if (fses) { + for (i = 0; fses[i] != NULL; ++i) + free (fses[i]); + free (fses); + } + + if (free_devices) { + for (i = 0; devices[i] != NULL; ++i) + free (devices[i]); + free (devices); + } + + return ret; +} + +static int +find_dev_in_devices (const char *dev, char **devices) +{ + size_t i; + + for (i = 0; devices[i] != NULL; ++i) { + if (STRPREFIX (dev, devices[i])) + return 1; + } + + return 0; +} + +static void +try_df (const char *name, const char *uuid, + const char *dev, int offset) +{ + struct guestfs_statvfs *stat = NULL; + guestfs_error_handler_cb old_error_cb; + void *old_error_data; + + if (verbose) + fprintf (stderr, "try_df %s %s %d\n", name, dev, offset); + + /* Try mounting and stating the device. This might reasonably fail, + * so don't show errors. + */ + old_error_cb = guestfs_get_error_handler (g, &old_error_data); + guestfs_set_error_handler (g, NULL, NULL); + + if (guestfs_mount_ro (g, dev, "/") == 0) { + stat = guestfs_statvfs (g, "/"); + guestfs_umount_all (g); + } + + guestfs_set_error_handler (g, old_error_cb, old_error_data); + + if (stat) { + print_stat (name, uuid, dev, offset, stat); + guestfs_free_statvfs (stat); + } +} |