/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1989-2011 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Research
*
* df -- free disk block report
*/
static const char usage[] =
"[-?\n@(#)$Id: df (AT&T Research) 2010-08-11 $\n]"
"[+NAME?df - summarize disk free space]"
"[+DESCRIPTION?\bdf\b displays the available disk space for the filesystem"
" of each file argument. If no \afile\a arguments are given then all"
" mounted filesystems are displayed.]"
"[b:blockbytes?Measure disk usage in 512 byte blocks. This is the default"
" if \bgetconf CONFORMANCE\b is \bstandard\b.]"
"[D:define?Define \akey\a with optional \avalue\a. \avalue\a will be expanded"
" when \b%(\b\akey\a\b)\b is specified in \b--format\b. \akey\a may"
" override internal \b--format\b identifiers.]:[key[=value]]]"
"[e:decimal-scale|thousands?Scale disk usage to powers of 1000.]"
"[f:format?Append to the listing format string. The \bls\b(1), \bpax\b(1) and"
" \bps\b(1) commands also have \b--format\b options in this same style."
" \aformat\a follows \bprintf\b(3) conventions, except that \bsfio\b(3)"
" inline ids are used instead of arguments:"
" %[#-+]][\awidth\a[.\aprecis\a[.\abase\a]]]]]](\aid\a[:\asubformat\a]])\achar\a."
" If \b#\b is specified then the internal width and precision are used."
" If \abase\a is non-zero and \b--posix\b is not on then the field values"
" are wrapped when they exceed the field width. If \achar\a is \bs\b then"
" the string form of the item is listed, otherwise the corresponding"
" numeric form is listed. If \achar\a is \bq\b then the string form of"
" the item is $'...' quoted if it contains space or non-printing"
" characters. If \awidth\a is omitted then the default width"
" is assumed. \asubformat\a overrides the default formatting for \aid\a."
" Supported \aid\as and \asubformat\as are:]:[format]{\fformats\f}"
"[g:gigabytes?Measure disk usage in 1024M byte blocks.]"
"[h!:header|heading?Display a heading line.]"
"[i:inodes?Display inode usage instead of block usage. There is at least one"
" inode for each active file and directory on a filesystem.]"
"[k:kilobytes?Measure disk usage in 1024 byte blocks.]"
"[K:scale|binary-scale|human-readable?Scale disk usage to powers of 1024."
" This is the default if \bgetconf CONFORMANCE\b is not \bstandard\b.]"
"[l:local?List information on local filesystems only, i.e., network"
" mounts are omitted.]"
"[m:megabytes?Measure disk usage in 1024K byte blocks.]"
"[n:native-block?Measure disk usage in the native filesystem block size."
" This size may vary between filesystems; it is displayed by the"
" \bsize\b format identifier.]"
"[O:options?Display the \bmount\b(1) options.]"
"[P:portable?Display each filesystem on one line. By default output is"
" folded for readability. Also implies \b--blockbytes\b.]"
"[s:sync?Call \bsync\b(2) before querying the filesystems.]"
"[F|t:type?Display all filesystems of type \atype\a. Unknown types are"
" listed as \blocal\b. Typical (but not supported on all systems) values"
" are:]:[type]{"
" [+ufs?default UNIX file system]"
" [+ext2?default linux file system]"
" [+xfs?sgi XFS]"
" [+nfs?network file system version 2]"
" [+nfs3?network file system version 3]"
" [+afs3?Andrew file system]"
" [+proc?process file system]"
" [+fat?DOS FAT file system]"
" [+ntfs?nt file system]"
" [+lofs?loopback file system for submounts]"
"}"
"[v:verbose?Report all filesystem query errors.]"
"[q|T?Ignored by this implementation.]"
"\n"
"\n[ file ... ]\n"
"\n"
"[+EXAMPLES?The default \b--format\b is"
" \"%#..1(filesystem)s %#(type)s %#(blocks)s %#(used)s %#(available)s %#(capacity)s %(mounted)s\"]"
"[+SEE ALSO?\bgetconf\b(1), \bmount\b(1), \bls\b(1), \bpax\b(1), \bps\b(1),"
" \bmount\b(2)]"
;
#include <ast.h>
#include <error.h>
#include <cdt.h>
#include <ls.h>
#include <mnt.h>
#include <sig.h>
#include <sfdisc.h>
typedef struct /* df entry */
{
unsigned long avail;
unsigned long tavail;
unsigned long total;
unsigned long ttotal;
unsigned long used;
unsigned long tused;
unsigned long itotal;
unsigned long iavail;
unsigned long iused;
int percent;
int fraction;
int ipercent;
} Df_t;
typedef struct /* sfkeyprintf() keys */
{
} Key_t;
{
{
0
},
{
"available",
"Available",
"Unused block count.",
0,
5
},
{
"blocks",
0,
"Total block count.",
0,
0
},
{
"capacity",
"Capacity",
"Percent of total blocks used.",
4,
3
},
{
"filesystem",
"Filesystem",
"Filesystem special device name.",
-19,
0
},
{
"iavailable",
"Iavailable",
"Unused inode count.",
7,
6
},
{
"icapacity",
"Icapacity",
"Percent of total inodes used.",
4,
4
},
{
"inodes",
"Inodes",
"Total inode count.",
7,
3
},
{
"iused",
"Iused",
"Used inode count.",
7,
3
},
{
"mounted",
"Mounted on",
"Mounted on path.",
-19,
5
},
{
"size",
"Size",
"Native block size.",
4,
3
},
{
"options",
"Options",
"\bmount\b(1) options.",
-29,
3
},
{
"type",
"Type",
"Filesystem type.",
10,
3
},
{
"used",
"Used",
"Used block count.",
0,
3
},
};
static const char fmt_def[] = "%#..1(filesystem)s %#(type)s %#(blocks)s %#(used)s %#(available)s %#(capacity)s %(mounted)s";
static const char fmt_ino[] = "%#..1(filesystem)s %#(type)s %#(blocks)s %#(available)s %#(capacity)s %#(inodes)s %#(iavailable)s %#(icapacity)s %(mounted)s";
static const char fmt_std[] = "%#..1(filesystem)s %#(blocks)s %#(used)s %#(available)s %8(capacity)s %(mounted)s";
/*
* man page and header comments notwithstanding
* some systems insist on reporting block counts in 512 units
* let me know how you probe for this
*/
#else
#else
#endif
#endif
#else
static char*
{
}
#endif
#define REALITY(n) ((((long)(n))<0)?0:(n))
#if _lib_sync
extern void sync(void);
#endif
static struct
{
} state;
/*
* optget() info discipline function
*/
static int
{
register int i;
if (streq(s, "formats"))
{
else
sfprintf(sp, "%s determined by the \b-b\b, \b-g\b, \b-k\b, \b-m\b and \b-n\b options.]", keys[i].heading ? "is" : "are");
}
return 0;
}
/*
* append format string to fmt
*/
static void
{
}
/*
* scale <m,w,p> into op
*/
static char*
scale(int m, unsigned long w, unsigned long p)
{
Sfulong_t n;
{
n = w;
}
else if (!m || !w && !p || w > 9)
else
}
/*
* sfkeyprintf() lookup
* handle==0 for heading
*/
static int
{
register char* s = 0;
register Sflong_t n = 0;
char* t;
return 0;
{
{
return 0;
}
}
{
}
else if (!df)
{
{
{
}
}
{
{
}
}
*ps = s;
}
else
{
{
}
{
case KEY_available:
break;
case KEY_blocks:
break;
case KEY_capacity:
s = (df->total || df->ttotal) ? (sfsprintf(state.buf, sizeof(state.buf), "%3d%%", df->percent), state.buf) : "-";
break;
case KEY_environ:
return 0;
break;
case KEY_filesystem:
s = "";
break;
case KEY_iavailable:
else
s = "-";
break;
case KEY_icapacity:
s = (df->total || df->ttotal) ? (sfsprintf(state.buf, sizeof(state.buf), "%3d%%", df->ipercent), state.buf) : "-";
break;
case KEY_inodes:
else
s = "-";
break;
case KEY_iused:
else
s = "-";
break;
case KEY_mounted:
s = "";
break;
case KEY_native:
else
break;
case KEY_options:
s = "";
break;
case KEY_type:
s = "";
break;
case KEY_used:
break;
default:
return 0;
}
if (s)
{
{
{
}
}
*ps = s;
}
else
*pn = n;
}
return 1;
}
/*
* catch statvfs() timeout
*/
static void
{
}
/*
* statvfs() with timeout
*/
static int
{
int r;
alarm(4);
alarm(0);
if (r)
{
else
}
return r;
}
/*
* list one entry
*/
static void
{
unsigned long b;
int s;
if ((!state.type || strmatch(df->mnt->type, state.type)) && (!state.local || !(df->mnt->flags & MNT_REMOTE)))
{
{
}
else
{
/*
* NOTE: on some systems vfs.f_* are unsigned,
* and on others signed negative values
* denote error
*/
df->used = ((long)df->vfs.f_blocks <= (long)df->vfs.f_bfree) ? 0 : (df->vfs.f_blocks - df->vfs.f_bfree);
df->percent = (df->ttotal = df->avail + df->used) ? (unsigned long)(((double)df->used / (double)df->ttotal + 0.005) * 100.0) : 0;
}
{
{
}
{
{
}
}
}
else
df->ipercent = (s = df->iused + df->iavail) ? (unsigned long)(((double)df->iused / (double)s + 0.005) * 100.0) : 0;
}
}
int
{
register int n;
int rem;
int head;
int i;
int* match;
void* mp;
char* s;
char* format;
dev = 0;
head = 1;
/*
* set up the disciplines
*/
/*
* initialize the tables and string streams
*/
/*
* grab the options
*/
for (;;)
{
{
case 'b':
continue;
case 'D':
*s++ = 0;
{
s = 0;
}
{
if (!s)
continue;
}
stresc(s);
continue;
case 'e':
continue;
case 'f':
continue;
case 'F':
case 't':
continue;
case 'g':
continue;
case 'h':
continue;
case 'i':
continue;
case 'k':
continue;
case 'K':
continue;
case 'l':
continue;
case 'm':
continue;
case 'n':
continue;
case 'O':
continue;
case 'P':
continue;
case 'q':
continue;
case 's':
continue;
case 'T':
continue;
case 'v':
continue;
case '?':
break;
case ':':
break;
}
break;
}
if (error_info.errors)
{
else
{
}
}
s = 0;
{
n = 5;
s = "Size";
}
{
n = 10;
s = "blocks";
}
{
n = 8;
s = "Kbytes";
}
{
n = 6;
s = "Mbytes";
}
{
n = 6;
s = "Gbytes";
}
if (!s)
{
n = strlen(s);
}
#if _lib_sync
sync();
#endif
{
}
else
{
if (argc)
{
for (n = 0; n < argc; n++)
{
argv[n] = 0;
rem--;
}
else
dev[n] =
#endif
}
else
rem = 0;
{
/*
* scan the mount table (up to 3x) for prefix matches
* to avoid the more expensive stat() and statvfs()
* calls in the final loop below
*/
for (n = 0; n < argc; n++)
if (argv[n] && (i = strlen(df.mnt->dir)) > 1 && i > match[n] && strneq(argv[n], df.mnt->dir, i) && (argv[n][i] == '/' || !argv[n][i]))
match[n] = i;
for (n = 0; n < argc; n++)
if (match[n] && (i = strlen(df.mnt->dir)) == match[n] && strneq(argv[n], df.mnt->dir, i) && (argv[n][i] == '/' || !argv[n][i]))
{
{
argv[n] = 0;
match[n] = 0;
if (!--rem)
break;
}
}
if (rem)
{
}
}
{
{
continue;
}
if (rem)
{
for (n = 0; n < argc; n++)
{
argv[n] = 0;
rem--;
break;
}
if (n >= argc)
continue;
}
if (rem)
{
while (++n < argc)
{
argv[n] = 0;
rem--;
}
if (rem <= 0)
break;
}
}
if (argc > 0)
{
for (n = 0; n < argc; n++)
}
}
return error_info.errors != 0;
}