summaryrefslogtreecommitdiffstats
path: root/df/output.c
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2010-11-23 12:05:04 +0000
committerRichard W.M. Jones <rjones@redhat.com>2010-11-25 18:58:13 +0000
commit18374b5b7d3154e0b8b8a07e3590f6eee762b58e (patch)
tree13a8254ab4e06a1736761005866fc313182b8e58 /df/output.c
parent4838ec3326d2970e6afe3cde6b368aeae840b969 (diff)
downloadlibguestfs-18374b5b7d3154e0b8b8a07e3590f6eee762b58e.tar.gz
libguestfs-18374b5b7d3154e0b8b8a07e3590f6eee762b58e.tar.xz
libguestfs-18374b5b7d3154e0b8b8a07e3590f6eee762b58e.zip
df: Rewrite virt-df in C.
I have diffed the output from the original virt-df with this new version, and they agree very closely. Some differences: - Old virt-df have a divide-by-zero error in cases where the number of used inodes was 0. New virt-df fixes this. - New virt-df uses gnulib human_readable library which displays numbers to 3 significant figures for -h output (old version used an ad hoc function).
Diffstat (limited to 'df/output.c')
-rw-r--r--df/output.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/df/output.c b/df/output.c
new file mode 100644
index 00000000..52ce0631
--- /dev/null
+++ b/df/output.c
@@ -0,0 +1,242 @@
+/* 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>
+#include <xvasprintf.h>
+#include <math.h>
+#include <assert.h>
+
+#ifdef HAVE_LIBVIRT
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+#endif
+
+#include "c-ctype.h"
+#include "human.h"
+#include "progname.h"
+
+#include "guestfs.h"
+#include "options.h"
+#include "virt-df.h"
+
+static void write_csv_field (const char *field);
+
+void
+print_title (void)
+{
+ const char *cols[6];
+ size_t i;
+
+ cols[0] = _("VirtualMachine");
+ cols[1] = _("Filesystem");
+ if (!inodes) {
+ if (!human)
+ cols[2] = _("1K-blocks");
+ else
+ cols[2] = _("Size");
+ cols[3] = _("Used");
+ cols[4] = _("Available");
+ cols[5] = _("Use%");
+ } else {
+ cols[2] = _("Inodes");
+ cols[3] = _("IUsed");
+ cols[4] = _("IFree");
+ cols[5] = _("IUse%");
+ }
+
+ if (!csv) {
+ /* ignore cols[0] in this mode */
+ printf ("%-36s%10s %10s %10s %5s\n",
+ cols[1], cols[2], cols[3], cols[4], cols[5]);
+ }
+ else {
+ size_t i;
+
+ for (i = 0; i < 6; ++i) {
+ if (i > 0)
+ putchar (',');
+ write_csv_field (cols[i]);
+ }
+ putchar ('\n');
+ }
+}
+
+static void canonical_device (char *dev, int offset);
+
+void
+print_stat (const char *name, const char *uuid_param,
+ const char *dev_param, int offset,
+ const struct guestfs_statvfs *stat)
+{
+ /* First two columns are always 'name' and 'dev', followed by four
+ * other data columns. In text mode the 'name' and 'dev' are
+ * combined into a single 'name:dev' column. In CSV mode they are
+ * kept as two separate columns. In UUID mode the name might be
+ * replaced by 'uuid', if available.
+ */
+#define MAX_LEN (LONGEST_HUMAN_READABLE > 128 ? LONGEST_HUMAN_READABLE : 128)
+ char buf[4][MAX_LEN];
+ const char *cols[4];
+ int64_t factor, v;
+ float percent;
+ int hopts = human_round_to_nearest|human_autoscale|human_base_1024|human_SI;
+ size_t i, len;
+
+ /* Make the device canonical. */
+ len = strlen (dev_param) + 1;
+ char dev[len];
+ strcpy (dev, dev_param);
+ if (offset >= 0)
+ canonical_device (dev, offset);
+
+ if (!inodes) { /* 1K blocks */
+ if (!human) {
+ factor = stat->bsize / 1024;
+
+ v = stat->blocks * factor;
+ snprintf (buf[0], MAX_LEN, "%" PRIi64, v);
+ cols[0] = buf[0];
+ v = (stat->blocks - stat->bfree) * factor;
+ snprintf (buf[1], MAX_LEN, "%" PRIi64, v);
+ cols[1] = buf[1];
+ v = stat->bavail * factor;
+ snprintf (buf[2], MAX_LEN, "%" PRIi64, v);
+ cols[2] = buf[2];
+ } else {
+ cols[0] =
+ human_readable ((uintmax_t) stat->blocks, buf[0],
+ hopts, stat->bsize, 1);
+ v = stat->blocks - stat->bfree;
+ cols[1] =
+ human_readable ((uintmax_t) v, buf[1], hopts, stat->bsize, 1);
+ cols[2] =
+ human_readable ((uintmax_t) stat->bavail, buf[2],
+ hopts, stat->bsize, 1);
+ }
+
+ if (stat->blocks != 0)
+ percent = 100. - 100. * stat->bfree / stat->blocks;
+ else
+ percent = 0;
+ }
+ else { /* inodes */
+ snprintf (buf[0], MAX_LEN, "%" PRIi64, stat->files);
+ cols[0] = buf[0];
+ snprintf (buf[1], MAX_LEN, "%" PRIi64, stat->files - stat->ffree);
+ cols[1] = buf[1];
+ snprintf (buf[2], MAX_LEN, "%" PRIi64, stat->ffree);
+ cols[2] = buf[2];
+
+ if (stat->files != 0)
+ percent = 100. - 100. * stat->ffree / stat->files;
+ else
+ percent = 0;
+ }
+
+ if (!csv)
+ /* Use 'ceil' on the percentage in order to emulate what df itself does. */
+ snprintf (buf[3], MAX_LEN, "%3.0f%%", ceil (percent));
+ else
+ snprintf (buf[3], MAX_LEN, "%.1f", percent);
+ cols[3] = buf[3];
+
+#undef MAX_LEN
+
+ if (uuid && uuid_param)
+ name = uuid_param;
+
+ if (!csv) {
+ len = strlen (name) + strlen (dev) + 1;
+ printf ("%s:%s", name, dev);
+ if (len <= 36) {
+ for (i = len; i < 36; ++i)
+ putchar (' ');
+ } else {
+ printf ("\n ");
+ }
+
+ printf ("%10s %10s %10s %5s\n", cols[0], cols[1], cols[2], cols[3]);
+ }
+ else {
+ write_csv_field (name);
+ putchar (',');
+ write_csv_field (dev);
+
+ for (i = 0; i < 4; ++i) {
+ putchar (',');
+ write_csv_field (cols[i]);
+ }
+
+ 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;
+ }
+}
+
+/* Function to quote CSV fields on output without requiring an
+ * external module.
+ */
+static void
+write_csv_field (const char *field)
+{
+ size_t i, len;
+ int needs_quoting = 0;
+
+ len = strlen (field);
+
+ for (i = 0; i < len; ++i) {
+ if (field[i] == ' ' || field[i] == '"' ||
+ field[i] == '\n' || field[i] == ',') {
+ needs_quoting = 1;
+ break;
+ }
+ }
+
+ if (!needs_quoting) {
+ printf ("%s", field);
+ return;
+ }
+
+ /* Quoting for CSV fields. */
+ putchar ('"');
+ for (i = 0; i < len; ++i) {
+ if (field[i] == '"') {
+ putchar ('"');
+ putchar ('"');
+ } else
+ putchar (field[i]);
+ }
+ putchar ('"');
+}