summaryrefslogtreecommitdiff
path: root/usr/src/cmd/fs.d/df.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/fs.d/df.c')
-rw-r--r--usr/src/cmd/fs.d/df.c119
1 files changed, 116 insertions, 3 deletions
diff --git a/usr/src/cmd/fs.d/df.c b/usr/src/cmd/fs.d/df.c
index 0d55abfcf5..6852626a68 100644
--- a/usr/src/cmd/fs.d/df.c
+++ b/usr/src/cmd/fs.d/df.c
@@ -24,13 +24,14 @@
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
+#include <dlfcn.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
@@ -51,6 +52,7 @@
#include <sys/mkdev.h>
#include <sys/int_limits.h>
#include <sys/zone.h>
+#include <libzfs.h>
#include "fslib.h"
@@ -171,6 +173,7 @@ struct df_request {
#define DFR_MOUNT_POINT(dfrp) (dfrp)->dfr_mte->mte_mount->mnt_mountp
#define DFR_SPECIAL(dfrp) (dfrp)->dfr_mte->mte_mount->mnt_special
+#define DFR_FSTYPE(dfrp) (dfrp)->dfr_mte->mte_mount->mnt_fstype
#define DFR_ISMOUNTEDFS(dfrp) ((dfrp)->dfr_mte != NULL)
#define DFRP(p) ((struct df_request *)(p))
@@ -236,9 +239,23 @@ static void parse_options(int, char **);
static char *basename(char *);
+/* ARGSUSED */
+static void
+dummy_error_handler(const char *fmt, va_list ap)
+{
+ /* Do nothing */
+}
+
+static zfs_handle_t *(*_zfs_open)(const char *, int);
+static void (*_zfs_close)(zfs_handle_t *);
+static uint64_t (*_zfs_prop_get_int)(zfs_handle_t *, zfs_prop_t);
+static void (*_zfs_set_error_handler)(void (*)(const char *, va_list));
+
void
main(int argc, char *argv[])
{
+ void *hdl;
+
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
@@ -252,6 +269,32 @@ main(int argc, char *argv[])
sysv3_set = getenv("SYSV3");
#endif /* _iBCS2 */
+ /*
+ * Dynamically check for libzfs, in case the user hasn't installed the
+ * SUNWzfs packages. A basic utility such as df shouldn't depend on
+ * optional filesystems.
+ */
+ if ((hdl = dlopen("libzfs.so", RTLD_LAZY)) != NULL) {
+ _zfs_set_error_handler = (void (*)())
+ dlsym(hdl, "zfs_set_error_handler");
+ _zfs_open = (zfs_handle_t *(*)())dlsym(hdl, "zfs_open");
+ _zfs_close = (void (*)())dlsym(hdl, "zfs_close");
+ _zfs_prop_get_int = (uint64_t (*)())
+ dlsym(hdl, "zfs_prop_get_int");
+
+ if (_zfs_set_error_handler != NULL) {
+ assert(_zfs_open != NULL);
+ assert(_zfs_close != NULL);
+ assert(_zfs_prop_get_int != NULL);
+
+ /*
+ * Disable ZFS error reporting, so we don't get messages
+ * like "can't open ..." under race conditions.
+ */
+ _zfs_set_error_handler(dummy_error_handler);
+ }
+ }
+
if (EQ(program_name, DEVNM_CMD))
do_devnm(argc, argv);
@@ -1169,6 +1212,68 @@ number_to_scaled_string(
return (buf);
}
+/*
+ * The statvfs() implementation allows us to return only two values, the total
+ * number of blocks and the number of blocks free. The equation 'used = total -
+ * free' will not work for ZFS filesystems, due to the nature of pooled storage.
+ * We choose to return values in the statvfs structure that will produce correct
+ * results for 'used' and 'available', but not 'total'. This function will open
+ * the underlying ZFS dataset if necessary and get the real value.
+ */
+static void
+adjust_total_blocks(struct df_request *dfrp, fsblkcnt64_t *total,
+ uint64_t blocksize)
+{
+ zfs_handle_t *zhp;
+ char *dataset, *slash;
+ uint64_t quota;
+
+ if (strcmp(DFR_FSTYPE(dfrp), MNTTYPE_ZFS) != 0 ||
+ _zfs_open == NULL)
+ return;
+
+ /*
+ * We want to get the total size for this filesystem as bounded by any
+ * quotas. In order to do this, we start at the current filesystem and
+ * work upwards until we find a dataset with a quota. If we reach the
+ * pool itself, then the total space is the amount used plus the amount
+ * available.
+ */
+ if ((dataset = strdup(DFR_SPECIAL(dfrp))) == NULL)
+ return;
+
+ slash = dataset + strlen(dataset);
+ do {
+ *slash = '\0';
+
+ if ((zhp = _zfs_open(dataset, ZFS_TYPE_ANY)) == NULL) {
+ free(dataset);
+ return;
+ }
+
+ if ((quota = _zfs_prop_get_int(zhp, ZFS_PROP_QUOTA)) != 0) {
+ *total = quota / blocksize;
+ _zfs_close(zhp);
+ free(dataset);
+ return;
+ }
+
+ _zfs_close(zhp);
+
+ } while ((slash = strrchr(dataset, '/')) != NULL);
+
+
+ if ((zhp = _zfs_open(dataset, ZFS_TYPE_ANY)) == NULL) {
+ free(dataset);
+ return;
+ }
+
+ *total = (_zfs_prop_get_int(zhp, ZFS_PROP_USED) +
+ _zfs_prop_get_int(zhp, ZFS_PROP_AVAILABLE)) / blocksize;
+
+ _zfs_close(zhp);
+ free(dataset);
+}
/*
* The output will appear properly columnized regardless of the names of
@@ -1178,6 +1283,7 @@ static void
g_output(struct df_request *dfrp, struct statvfs64 *fsp)
{
fsblkcnt64_t available_blocks = fsp->f_bavail;
+ fsblkcnt64_t total_blocks = fsp->f_blocks;
numbuf_t total_blocks_buf;
numbuf_t total_files_buf;
numbuf_t free_blocks_buf;
@@ -1258,9 +1364,11 @@ g_output(struct df_request *dfrp, struct statvfs64 *fsp)
if ((long long)available_blocks < (long long)0)
available_blocks = (fsblkcnt64_t)0;
+ adjust_total_blocks(dfrp, &total_blocks, fsp->f_frsize);
+
(void) printf("%*s %-*s %*s %-*s %*s %-*s %*s %-*s\n",
NCOL1_WIDTH, number_to_string(total_blocks_buf,
- fsp->f_blocks, fsp->f_frsize, 512),
+ total_blocks, fsp->f_frsize, 512),
SCOL1_WIDTH, total_blocks_str,
NCOL2_WIDTH, number_to_string(free_blocks_buf,
fsp->f_bfree, fsp->f_frsize, 512),
@@ -1346,6 +1454,8 @@ k_output(struct df_request *dfrp, struct statvfs64 *fsp)
file_system = "";
}
+ adjust_total_blocks(dfrp, &total_blocks, fsp->f_frsize);
+
if (use_scaling) { /* comes from the -h option */
(void) printf("%-*s %*s %*s %*s %-*s %-s\n",
FILESYSTEM_WIDTH, file_system,
@@ -1428,6 +1538,7 @@ strings_init()
static void
t_output(struct df_request *dfrp, struct statvfs64 *fsp)
{
+ fsblkcnt64_t total_blocks = fsp->f_blocks;
numbuf_t total_blocks_buf;
numbuf_t total_files_buf;
numbuf_t free_blocks_buf;
@@ -1435,6 +1546,8 @@ t_output(struct df_request *dfrp, struct statvfs64 *fsp)
STRINGS_INIT();
+ adjust_total_blocks(dfrp, &total_blocks, fsp->f_frsize);
+
(void) printf("%-*s(%-*s): %*s %s %*s %s\n",
MOUNT_POINT_WIDTH, DFR_MOUNT_POINT(dfrp),
SPECIAL_DEVICE_WIDTH, DFR_SPECIAL(dfrp),
@@ -1456,7 +1569,7 @@ t_output(struct df_request *dfrp, struct statvfs64 *fsp)
(void) printf("%*s: %*s %s %*s %s\n",
MNT_SPEC_WIDTH, total_str,
BLOCK_WIDTH, number_to_string(total_blocks_buf,
- fsp->f_blocks, fsp->f_frsize, 512),
+ total_blocks, fsp->f_frsize, 512),
blocks_str,
NFILES_WIDTH, number_to_string(total_files_buf,
fsp->f_files, 1, 1),