master xplshn/aruu / cmd / posix / df.c
  1/* See LICENSE file for copyright and license details. */
  2
  3#include <sys/statvfs.h>
  4
  5#include <mntent.h>
  6#include <stdio.h>
  7#include <stdlib.h>
  8#include <string.h>
  9
 10#include "util.h"
 11
 12static long blksize = 512;
 13static int  aflag   = 0;
 14static int  hflag   = 0;
 15static int  kflag   = 0;
 16
 17#define CALC_POWER(n, power, base, i)                                                              \
 18  do {                                                                                             \
 19    while (n > power) {                                                                            \
 20      power = power * base;                                                                        \
 21      i++;                                                                                         \
 22    }                                                                                              \
 23  } while (0)
 24
 25static void
 26print_human(
 27    const char        *fsname,
 28    unsigned long long total,
 29    unsigned long long used,
 30    unsigned long long avail,
 31    int                capacity,
 32    const char        *dir
 33)
 34{
 35  long               base        = 1024;
 36  unsigned long long power_total = base;
 37  unsigned long long power_used  = base;
 38  unsigned long long power_avail = base;
 39  char               postfixes[] = {'B', 'K', 'M', 'G', 'T', 'P', 'E'};
 40  int                i = 0, j = 0, k = 0;
 41
 42  total = total * blksize;
 43  used  = used * blksize;
 44  avail = avail * blksize;
 45
 46  CALC_POWER(total, power_total, base, i);
 47  CALC_POWER(used, power_used, base, j);
 48  CALC_POWER(avail, power_avail, base, k);
 49
 50  total = i ? total / (power_total / base) : total;
 51  used  = j ? used / (power_used / base) : used;
 52  avail = k ? avail / (power_avail / base) : avail;
 53  printf(
 54      "%-12s %9llu%c %9llu%c %9llu%c %7d%%  %s\n",
 55      fsname,
 56      total,
 57      postfixes[i],
 58      used,
 59      postfixes[j],
 60      avail,
 61      postfixes[k],
 62      capacity,
 63      dir
 64  );
 65}
 66
 67static int
 68mnt_show(const char *fsname, const char *dir)
 69{
 70  struct statvfs     s;
 71  unsigned long long total, used, avail;
 72  int                capacity = 0;
 73  int                bs;
 74
 75  if (statvfs(dir, &s) < 0)
 76    return -1;
 77
 78  bs    = s.f_frsize / blksize;
 79  total = s.f_blocks * bs;
 80  avail = s.f_bfree * bs;
 81  used  = total - avail;
 82
 83  if (used + avail) {
 84    capacity = (used * 100) / (used + avail);
 85    if (used * 100 != capacity * (used + avail))
 86      capacity++;
 87  }
 88
 89  if (hflag)
 90    print_human(fsname, total, used, avail, capacity, dir);
 91  else
 92    printf("%-12s %9llu %9llu %9llu %7d%%  %s\n", fsname, total, used, avail, capacity, dir);
 93
 94  return 0;
 95}
 96
 97static void
 98usage(void)
 99{
100  eprintf("usage: %s [-a]\n", argv0);
101}
102
103// ?man df: report disk space usage
104// ?man display free and used disk space on filesystems
105int
106main(int argc, char *argv[])
107{
108  struct mntent *me = NULL;
109  FILE          *fp;
110  int            ret = 0;
111
112  ARGBEGIN
113  {
114    // ?man -a: print or show all entries
115    case 'a':
116      aflag = 1;
117      break;
118    // ?man -h: suppress headers or print help
119    case 'h':
120      hflag = 1;
121      kflag = 0;
122      break;
123    // ?man -k: specify option flag
124    case 'k':
125      kflag   = 1;
126      hflag   = 0;
127      blksize = 1024;
128      break;
129    // ?man -s: silent mode or print summary
130    case 's':
131    // ?man -i: interactive mode or prompt for confirmation
132    case 'i':
133      eprintf("not implemented\n");
134      break;
135    default:
136      usage();
137  }
138  ARGEND;
139
140  if (hflag)
141    printf(
142        "Filesystem         Size       Used      "
143        "Avail Capacity   Mounted on\n"
144    );
145  else
146    printf(
147        "Filesystem  %ld-blocks      Used     "
148        "Avail Capacity  Mounted on\n",
149        blksize
150    );
151
152  fp = setmntent("/proc/mounts", "r");
153  if (!fp)
154    eprintf("setmntent %s:", "/proc/mounts");
155  while ((me = getmntent(fp)) != NULL) {
156    if (aflag == 0)
157      if (strcmp(me->mnt_type, "rootfs") == 0)
158        continue;
159    if (mnt_show(me->mnt_fsname, me->mnt_dir) < 0)
160      ret = 1;
161  }
162  endmntent(fp);
163
164  return ret;
165}