busybox/coreutils/df.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Mini df implementation for busybox
   4 *
   5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
   6 * based on original code by (I think) Bruce Perens <bruce@pixar.com>.
   7 *
   8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
   9 */
  10
  11/* BB_AUDIT SUSv3 _NOT_ compliant -- option -t missing. */
  12/* http://www.opengroup.org/onlinepubs/007904975/utilities/df.html */
  13
  14/* Mar 16, 2003      Manuel Novoa III   (mjn3@codepoet.org)
  15 *
  16 * Size reduction.  Removed floating point dependency.  Added error checking
  17 * on output.  Output stats on 0-sized filesystems if specifically listed on
  18 * the command line.  Properly round *-blocks, Used, and Available quantities.
  19 *
  20 * Aug 28, 2008      Bernhard Reutner-Fischer
  21 *
  22 * Implement -P and -B; better coreutils compat; cleanup
  23 */
  24
  25#include <mntent.h>
  26#include <sys/vfs.h>
  27#include "libbb.h"
  28
  29#if !ENABLE_FEATURE_HUMAN_READABLE
  30static unsigned long kscale(unsigned long b, unsigned long bs)
  31{
  32        return (b * (unsigned long long) bs + 1024/2) / 1024;
  33}
  34#endif
  35
  36int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  37int df_main(int argc, char **argv)
  38{
  39        unsigned long blocks_used;
  40        unsigned blocks_percent_used;
  41        unsigned long df_disp_hr = 1024;
  42        int status = EXIT_SUCCESS;
  43        unsigned opt;
  44        FILE *mount_table;
  45        struct mntent *mount_entry;
  46        struct statfs s;
  47
  48        enum {
  49                OPT_KILO  = (1 << 0),
  50                OPT_POSIX = (1 << 1),
  51                OPT_ALL   = (1 << 2) * ENABLE_FEATURE_DF_FANCY,
  52                OPT_INODE = (1 << 3) * ENABLE_FEATURE_DF_FANCY,
  53                OPT_BSIZE = (1 << 4) * ENABLE_FEATURE_DF_FANCY,
  54                OPT_HUMAN = (1 << (2 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE,
  55                OPT_MEGA  = (1 << (3 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE,
  56        };
  57        const char *disp_units_hdr = NULL;
  58        char *chp;
  59
  60#if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY
  61        opt_complementary = "k-mB:m-Bk:B-km";
  62#elif ENABLE_FEATURE_HUMAN_READABLE
  63        opt_complementary = "k-m:m-k";
  64#endif
  65        opt = getopt32(argv, "kP"
  66                        USE_FEATURE_DF_FANCY("aiB:")
  67                        USE_FEATURE_HUMAN_READABLE("hm")
  68                        USE_FEATURE_DF_FANCY(, &chp));
  69        if (opt & OPT_MEGA)
  70                df_disp_hr = 1024*1024;
  71
  72        if (opt & OPT_BSIZE)
  73                df_disp_hr = xatoul_range(chp, 1, ULONG_MAX); /* disallow 0 */
  74
  75        /* From the manpage of df from coreutils-6.10:
  76           Disk space is shown in 1K blocks by default, unless the environment
  77           variable POSIXLY_CORRECT is set, in which case 512-byte blocks are used.
  78        */
  79        if (getenv("POSIXLY_CORRECT")) /* TODO - a new libbb function? */
  80                df_disp_hr = 512;
  81
  82        if (opt & OPT_HUMAN) {
  83                df_disp_hr = 0;
  84                disp_units_hdr = "     Size";
  85        }
  86        if (opt & OPT_INODE)
  87                disp_units_hdr = "   Inodes";
  88
  89        if (disp_units_hdr == NULL) {
  90#if ENABLE_FEATURE_HUMAN_READABLE
  91                disp_units_hdr = xasprintf("%s-blocks",
  92                        make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX)));
  93#else
  94                disp_units_hdr = xasprintf("%lu-blocks", df_disp_hr);
  95#endif
  96        }
  97        printf("Filesystem           %-15sUsed Available %s Mounted on\n",
  98                        disp_units_hdr, (opt & OPT_POSIX) ? "Capacity" : "Use%");
  99
 100        mount_table = NULL;
 101        argv += optind;
 102        if (optind >= argc) {
 103                mount_table = setmntent(bb_path_mtab_file, "r");
 104                if (!mount_table)
 105                        bb_perror_msg_and_die(bb_path_mtab_file);
 106        }
 107
 108        while (1) {
 109                const char *device;
 110                const char *mount_point;
 111
 112                if (mount_table) {
 113                        mount_entry = getmntent(mount_table);
 114                        if (!mount_entry) {
 115                                endmntent(mount_table);
 116                                break;
 117                        }
 118                } else {
 119                        mount_point = *argv++;
 120                        if (!mount_point)
 121                                break;
 122                        mount_entry = find_mount_point(mount_point);
 123                        if (!mount_entry) {
 124                                bb_error_msg("%s: can't find mount point", mount_point);
 125 set_error:
 126                                status = EXIT_FAILURE;
 127                                continue;
 128                        }
 129                }
 130
 131                device = mount_entry->mnt_fsname;
 132                mount_point = mount_entry->mnt_dir;
 133
 134                if (statfs(mount_point, &s) != 0) {
 135                        bb_simple_perror_msg(mount_point);
 136                        goto set_error;
 137                }
 138
 139                if ((s.f_blocks > 0) || !mount_table || (opt & OPT_ALL)) {
 140                        if (opt & OPT_INODE) {
 141                                s.f_blocks = s.f_files;
 142                                s.f_bavail = s.f_bfree = s.f_ffree;
 143                                s.f_bsize = 1;
 144
 145                                if (df_disp_hr)
 146                                        df_disp_hr = 1;
 147                        }
 148                        blocks_used = s.f_blocks - s.f_bfree;
 149                        blocks_percent_used = 0;
 150                        if (blocks_used + s.f_bavail) {
 151                                blocks_percent_used = (blocks_used * 100ULL
 152                                                + (blocks_used + s.f_bavail)/2
 153                                                ) / (blocks_used + s.f_bavail);
 154                        }
 155
 156                        /* GNU coreutils 6.10 skips certain mounts, try to be compatible.  */
 157                        if (strcmp(device, "rootfs") == 0)
 158                                continue;
 159
 160#ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY
 161/* ... and also this is the only user of find_block_device */
 162                        if (strcmp(device, "/dev/root") == 0) {
 163                                /* Adjusts device to be the real root device,
 164                                * or leaves device alone if it can't find it */
 165                                device = find_block_device("/");
 166                                if (!device) {
 167                                        goto set_error;
 168                                }
 169                        }
 170#endif
 171
 172                        if (printf("\n%-20s" + 1, device) > 20)
 173                                    printf("\n%-20s", "");
 174#if ENABLE_FEATURE_HUMAN_READABLE
 175                        printf(" %9s ",
 176                                make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr));
 177
 178                        printf(" %9s " + 1,
 179                                make_human_readable_str((s.f_blocks - s.f_bfree),
 180                                                s.f_bsize, df_disp_hr));
 181
 182                        printf("%9s %3u%% %s\n",
 183                                        make_human_readable_str(s.f_bavail, s.f_bsize, df_disp_hr),
 184                                        blocks_percent_used, mount_point);
 185#else
 186                        printf(" %9lu %9lu %9lu %3u%% %s\n",
 187                                        kscale(s.f_blocks, s.f_bsize),
 188                                        kscale(s.f_blocks - s.f_bfree, s.f_bsize),
 189                                        kscale(s.f_bavail, s.f_bsize),
 190                                        blocks_percent_used, mount_point);
 191#endif
 192                }
 193        }
 194
 195        return status;
 196}
 197