/*
$Id: di.c,v 2.45 2007-06-01 10:04:56-07 bll Exp $
$Source: /export/home/bll/DI/RCS/di.c,v $
Copyright 1994-2007 Brad Lanam, Walnut Creek, CA
*/
/*
* di.c
*
* Copyright 1994-2007 Brad Lanam, Walnut Creek, CA
*
* Warning: Do not replace your system's 'df' command with this program.
* You will in all likelihood break your installation procedures.
*
* Display sizes:
* 512 - posix (512 bytes)
* k - kilobytes
* m - megabytes
* g - gigabytes
* t - terabytes
* P - petabytes
* E - exabytes
* h - "human readable" scaled alternative 1
* H - "human readable" scaled alternative 2
*
* Sort types:
* N - name (default)
* n - none (mount order)
* s - special
* a - avail
* t - type
* r - reverse sort
*
* Format string values:
* m - mount point
* M - mount point, full length
* b - total kbytes
* B - total kbytes available for use by the user.
* [ (tot - (free - avail)) ]
* u - kbytes used (actual number of kbytes used) [ (tot - free) ]
* c - calculated number of kbytes used [ (tot - avail) ]
* f - kbytes free
* v - kbytes available
* p - percentage not available for use.
* (number of blocks not available for use / total disk space)
* [ (tot - avail) / tot ]
* 1 - percentage used.
* (actual number of blocks used / total disk space)
* [ (tot - free) / tot ]
* 2 - percentage of user-available space in use (bsd style).
* Note that values over 100% are possible.
* (actual number of blocks used / disk space available to user)
* [ (tot - free) / (tot - (free - avail)) ]
* i - total i-nodes (files)
* U - used i-nodes
* F - free i-nodes
* P - percent i-nodes used [ (tot - avail) / tot ]
* s - filesystem name (special)
* S - filesystem name (special), full length
* t - disk partition type
* T - disk partition type (full length)
* I - mount time
* O - mount options.
*
* System V.4 `/usr/bin/df -v` Has format: msbuf1 (w/-P option: 512 byte blocks)
* System V.4 `/usr/bin/df -k` Has format: sbcvpm
* System V.4 `/usr/ucb/df` Has format: sbuv2m
*
* The default format string for this program is: smbuvpT
*
* The environment variable "DIFMT" may be set to the desired format
* string.
*
* Note that for filesystems that do not have (S512K fs) or systems (SysV.3)
* that do not report available blocks, the number of available blocks is
* equal to the number of free blocks.
*
*/
#include "config.h"
#include "di.h"
#include "version.h"
#include <stdio.h>
#if _hdr_ctype
# include <ctype.h>
#endif
#if _hdr_errno
# include <errno.h>
#endif
#if _hdr_stdlib
# include <stdlib.h>
#endif
#if _hdr_getopt
# include <getopt.h>
#endif
#if _sys_types
# include <sys/types.h>
#endif
#if _hdr_string
# include <string.h>
#endif
#if _hdr_strings && ((! defined (_hdr_string)) || (_include_string))
# include <strings.h>
#endif
#if _hdr_memory
# include <memory.h>
#endif
#if _include_malloc && _hdr_malloc
# include <malloc.h>
#endif
#if _hdr_math
# include <math.h>
#endif
#if _hdr_unistd
# include <unistd.h>
#endif
#if _hdr_time
# include <time.h>
#endif
#if _sys_time
# include <sys/time.h>
#endif
#if _sys_stat
# include <sys/stat.h>
#endif
#if _hdr_libintl
# include <libintl.h>
#endif
#if _hdr_locale
# include <locale.h>
#endif
#if _hdr_zone
# include <zone.h>
#endif
extern int di_lib_debug;
#if _npt_getenv
extern char *getenv _((char *));
#endif
#if ! defined (_dcl_errno)
extern int errno;
#endif
#if ! defined (_dcl_optind)
extern int optind;
#endif
#if ! defined (_dcl_optarg)
extern char *optarg;
#endif
/* macro for gettext() */
#ifndef GT
# if _enable_nls
# define GT(args) gettext (args)
# else
# define GT(args) (args)
# endif
#endif
/* end of system specific includes/configurations */
#define DI_F_ALL 0x00000001
#define DI_F_LOCAL_ONLY 0x00000002
#define DI_F_TOTAL 0x00000010
#define DI_F_NO_HEADER 0x00000020
#define DI_F_DEBUG_HDR 0x00000040
#define DI_F_INCLUDE_LOOPBACK 0x00000080
/* mount information */
#define DI_FMT_MOUNT 'm'
#define DI_FMT_MOUNT_FULL 'M'
#define DI_FMT_SPECIAL 's'
#define DI_FMT_SPECIAL_FULL 'S'
#define DI_FMT_TYPE 't'
#define DI_FMT_TYPE_FULL 'T'
/* disk information */
#define DI_FMT_BTOT 'b'
#define DI_FMT_BTOT_AVAIL 'B'
#define DI_FMT_BUSED 'u'
#define DI_FMT_BCUSED 'c'
#define DI_FMT_BFREE 'f'
#define DI_FMT_BAVAIL 'v'
#define DI_FMT_BPERC_NAVAIL 'p'
#define DI_FMT_BPERC_USED '1'
#define DI_FMT_BPERC_BSD '2'
#define DI_FMT_BPERC_AVAIL 'a'
#define DI_FMT_BPERC_FREE '3'
#define DI_FMT_ITOT 'i'
#define DI_FMT_IUSED 'U'
#define DI_FMT_IFREE 'F'
#define DI_FMT_IPERC 'P'
#define DI_FMT_MOUNT_TIME 'I'
#define DI_FMT_MOUNT_OPTIONS 'O'
#define DI_SORT_MAX 10
#define DI_SORT_NONE 'n'
#define DI_SORT_MOUNT 'm'
#define DI_SORT_SPECIAL 's'
#define DI_SORT_AVAIL 'a'
#define DI_SORT_REVERSE 'r'
#define DI_SORT_TYPE 't'
#define DI_SORT_ASCENDING 1
#define DI_SORT_DESCENDING -1
#define DI_UNKNOWN_DEV -1L
#define DI_LIST_SEP ","
#define DI_ARGV_SEP " " /* space, tab */
#define DI_MAX_ARGV 50
#define DI_ALL_FORMAT "MTS\n\tIO\n\tbuf13\n\tbcvpa\n\tBuv2\n\tiUFP"
#define DI_POSIX_FORMAT "SbuvpM"
#define DI_VAL_1000 1000.0
#define DI_VAL_1024 1024.0
/* these are indexes into the dispTable array... */
#define DI_ONE_K 0
#define DI_ONE_MEG 1
#define DI_ONE_GIG 2
#define DI_ONE_TERA 3
#define DI_ONE_PETA 4
#define DI_ONE_EXA 5
#define DI_ONE_ZETTA 6
#define DI_ONE_YOTTA 7
#define DI_DISP_HR -20
#define DI_DISP_HR_2 -21
/* you may want to change some of these values. Be sure to change all */
/* related entries. */
#if ! defined (DI_DEFAULT_FORMAT)
# define DI_DEFAULT_FORMAT "smbuvpT"
/* # define DI_DEFAULT_FORMAT "MbuvpT" */ /* an alternative */
#endif
#if _lib_mnt_time
# define DI_DEF_MOUNT_FORMAT "MST\n\tI\n\tO"
#else
# define DI_DEF_MOUNT_FORMAT "MST\n\tO"
#endif
#define DI_PERC_FMT "%3.0f%% "
#define DI_POSIX_PERC_FMT " %3.0f%% "
#define DI_POSIX_PERC_LBL_FMT "%8s"
#define DI_PERC_LBL_FMT "%5s"
#define DI_FSTYPE_FMT "%-7.7s"
#define DI_MOUNT_FMT "%-15.15s"
#define DI_SPEC_FMT "%-18.18s"
typedef struct
{
int count;
char **list;
} iList_t;
typedef struct
{
double low;
double high;
double dbs; /* display block size */
char *format;
char *suffix;
} sizeTable_t;
typedef struct
{
double size;
char *disp;
} dispTable_t;
#define zoneId_t int
#define ZONENAME_MAX 65
typedef struct {
zoneId_t zoneid;
char name [ZONENAME_MAX];
char rootpath [MAXPATHLEN];
Size_t rootpathlen;
} zoneSummary_t;
typedef struct {
Uid_t uid;
zoneId_t myzoneid;
zoneSummary_t *zones;
Uint_t zoneCount;
char zoneDisplay [MAXPATHLEN];
int globalIdx;
} zoneInfo_t;
typedef struct {
char *formatString;
char mountFormat [20];
char specialFormat [20];
char typeFormat [20];
char optFormat [20];
char mTimeFormat [20];
int width;
int inodeWidth;
char blockFormat [40];
char blockFormatNR [40]; /* no radix */
char blockLabelFormat [40];
char inodeFormat [40];
char inodeLabelFormat [40];
double dispBlockSize;
char dispBlockLabel [30];
double baseDispSize;
__ulong flags;
char sortType [DI_SORT_MAX + 1];
int sortOrder;
int posix_compat;
} diOptions_t;
typedef struct {
diOptions_t options;
diDiskInfo_t *diskInfo;
int count;
iList_t ignoreList;
iList_t includeList;
zoneInfo_t zoneInfo;
} diData_t;
static int debug = { 0 };
static sizeTable_t sizeTable [] =
{
{ 0, 0, 1, (char *) NULL, " " },
{ 0, 0, 0, (char *) NULL, "k" },
#define DI_ONE_MEG_SZTAB 2
{ 0, 0, 0, (char *) NULL, "M" },
{ 0, 0, 0, (char *) NULL, "G" },
{ 0, 0, 0, (char *) NULL, "T" },
{ 0, 0, 0, (char *) NULL, "P" },
{ 0, 0, 0, (char *) NULL, "E" },
{ 0, 0, 0, (char *) NULL, "Z" },
{ 0, 0, 0, (char *) NULL, "Y" }
};
#define DI_SIZETAB_SIZE (sizeof (sizeTable) / sizeof (sizeTable_t))
static dispTable_t dispTable [] =
{
{ 0.0, "KBytes" },
{ 0.0, "Megs" },
{ 0.0, "Gigs" },
{ 0.0, "Teras" },
{ 0.0, "Petas" },
{ 0.0, "Exas" },
{ 0.0, "Zettas" },
{ 0.0, "Yottas" }
};
#define DI_DISPTAB_SIZE (sizeof (dispTable) / sizeof (dispTable_t))
typedef int (*DI_SORT_FUNC) _((diOptions_t *, void *, void *));
static void addTotals _((diDiskInfo_t *, diDiskInfo_t *));
static void checkDiskInfo _((diData_t *));
static int checkFileInfo _((diData_t *, int, int, char *[]));
static void checkIgnoreList _((diDiskInfo_t *, iList_t *));
static void checkIncludeList _((diDiskInfo_t *, iList_t *));
static void checkZone _((diDiskInfo_t *, zoneInfo_t *, int));
static void cleanup _((diData_t *, char *));
static int diCompare _((diOptions_t *, void *, void *));
static int findDispSize _((double));
static void getDiskSpecialInfo _((diData_t *));
static void getDiskStatInfo _((diData_t *));
static char *getPrintFlagText _((int));
static void parseList _((iList_t *, char *));
static void preCheckDiskInfo _((diData_t *));
static void printDiskInfo _((diData_t *));
static void printInfo _((diDiskInfo_t *, diOptions_t *));
static void printBlocks _((diOptions_t *, _fs_size_t, _fs_size_t, int));
static void printTitle _((diOptions_t *));
static void printPerc _((_fs_size_t, _fs_size_t, char *));
static void processArgs _((int, char *[], diData_t *, char *));
static void setDispBlockSize _((char *, diOptions_t *));
static void sortArray _((diOptions_t *, char *, Size_t, int, DI_SORT_FUNC));
static void usage _((void));
#if ! _mth_fmod && ! _lib_fmod
static double fmod _((double, double));
#endif
int
#if _proto_stdc
main (int argc, char *argv [])
#else
main (argc, argv)
int argc;
char *argv [];
#endif
{
diData_t diData;
diOptions_t *diopts;
int i;
char *ptr;
char *argvptr;
char dbsstr [30];
/* initialization */
diData.count = 0;
diData.diskInfo = (diDiskInfo_t *) NULL;
diData.ignoreList.count = 0;
diData.ignoreList.list = (char **) NULL;
diData.includeList.count = 0;
diData.includeList.list = (char **) NULL;
diData.zoneInfo.uid = geteuid ();
diData.zoneInfo.zoneDisplay [0] = '\0';
diData.zoneInfo.zoneCount = 0;
diData.zoneInfo.zones = (zoneSummary_t *) NULL;
/* options defaults */
diopts = &diData.options;
diopts->formatString = DI_DEFAULT_FORMAT;
diopts->dispBlockSize = DI_VAL_1024 * DI_VAL_1024;
diopts->width = 8;
diopts->inodeWidth = 7;
diopts->flags = 0;
/* Linux users may want as the default: */
/* diopts->flags = { DI_F_INCLUDE_LOOPBACK }; */
strcpy (diopts->sortType, "m"); /* default - sort by mount point */
diopts->sortOrder = DI_SORT_ASCENDING;
diopts->posix_compat = 0;
diopts->baseDispSize = DI_VAL_1024;
*dbsstr = '\0';
#if _lib_setlocale && defined (LC_ALL)
ptr = setlocale (LC_ALL, "");
#endif
#if _enable_nls
ptr = bindtextdomain (PROG, DI_LOCALE_DIR);
ptr = textdomain (PROG);
#endif
ptr = argv [0] + strlen (argv [0]) - 2;
if (memcmp (ptr, MPROG, 2) == 0)
{
diopts->formatString = DI_DEF_MOUNT_FORMAT;
}
else /* don't use DIFMT env var if running mi. */
{
if ((ptr = getenv ("DIFMT")) != (char *) NULL)
{
diopts->formatString = ptr;
}
}
/* gnu df */
if ((ptr = getenv ("POSIXLY_CORRECT")) != (char *) NULL)
{
strncpy (dbsstr, "512", sizeof (dbsstr));
diopts->formatString = DI_POSIX_FORMAT;
diopts->posix_compat = 1;
}
/* bsd df */
if ((ptr = getenv ("BLOCKSIZE")) != (char *) NULL)
{
strncpy (dbsstr, ptr, sizeof (dbsstr));
}
/* gnu df */
if ((ptr = getenv ("DF_BLOCK_SIZE")) != (char *) NULL)
{
strncpy (dbsstr, ptr, sizeof (dbsstr));
}
argvptr = (char *) NULL;
if ((ptr = getenv ("DI_ARGS")) != (char *) NULL)
{
char *tptr;
int nargc;
int ooptind;
char *ooptarg;
char *nargv [DI_MAX_ARGV];
argvptr = strdup (ptr);
ooptind = optind;
ooptarg = optarg;
if (argvptr != (char *) NULL)
{
tptr = strtok (argvptr, DI_ARGV_SEP);
nargc = 1;
nargv[0] = argv[0];
while (tptr != (char *) NULL)
{
if (nargc >= DI_MAX_ARGV)
{
break;
}
nargv[nargc++] = tptr;
tptr = strtok ((char *) NULL, DI_ARGV_SEP);
}
processArgs (nargc, nargv, &diData, dbsstr);
optind = ooptind; /* reset so command line can be parsed */
optarg = ooptarg;
}
}
processArgs (argc, argv, &diData, dbsstr);
#if _lib_zone_list && _lib_getzoneid && _lib_zone_getattr
{
zoneId_t *zids = (zoneId_t *) NULL;
zoneInfo_t *zi;
zi = &diData.zoneInfo;
zi->myzoneid = getzoneid ();
if (zone_list (zids, &zi->zoneCount) == 0)
{
if (zi->zoneCount > 0)
{
zids = malloc (sizeof (zoneId_t) * zi->zoneCount);
if (zids == (zoneId_t *) NULL)
{
fprintf (stderr, "malloc failed in main() (1). errno %d\n", errno);
exit (1);
}
zone_list (zids, &zi->zoneCount);
zi->zones = malloc (sizeof (zoneSummary_t) *
zi->zoneCount);
if (zi->zones == (zoneSummary_t *) NULL)
{
fprintf (stderr, "malloc failed in main() (2). errno %d\n", errno);
exit (1);
}
}
}
zi->globalIdx = 0;
for (i = 0; i < zi->zoneCount; ++i)
{
int len;
zi->zones[i].zoneid = zids[i];
len = zone_getattr (zids[i], ZONE_ATTR_ROOT,
zi->zones[i].rootpath, MAXPATHLEN);
if (len >= 0)
{
zi->zones[i].rootpathlen = len;
strncat (zi->zones[i].rootpath, "/", MAXPATHLEN - 1);
if (zi->zones[i].zoneid == 0)
{
zi->globalIdx = i;
}
len = zone_getattr (zids[i], ZONE_ATTR_NAME,
zi->zones[i].name, ZONENAME_MAX);
if (*zi->zoneDisplay == '\0' &&
zi->myzoneid == zi->zones[i].zoneid)
{
strncpy (zi->zoneDisplay, zi->zones[i].name, ZONENAME_MAX);
}
if (debug > 4)
{
printf ("zone:%d:%s:%s:\n", (int) zi->zones[i].zoneid,
zi->zones[i].name, zi->zones[i].rootpath);
}
}
}
free ((void *) zids);
}
if (debug > 4)
{
printf ("zone:my:%d:%s:glob:%d:\n", (int) diData.zoneInfo.myzoneid,
diData.zoneInfo.zoneDisplay, diData.zoneInfo.globalIdx);
}
#endif
/* initialize dispTable array */
dispTable [0].size = diopts->baseDispSize;
for (i = 1; i < DI_DISPTAB_SIZE; ++i)
{
dispTable [i].size = dispTable [i - 1].size *
diopts->baseDispSize;
}
/* default - one meg */
strncpy (diopts->dispBlockLabel, GT(dispTable [DI_ONE_MEG].disp),
sizeof (diopts->dispBlockLabel));
/* do this afterwards, because we need to know what the */
/* user wants for baseDispSize */
setDispBlockSize (dbsstr, diopts);
/* initialize display size tables */
sizeTable [0].format = diopts->blockFormatNR;
sizeTable [1].format = diopts->blockFormat;
sizeTable [0].high = diopts->baseDispSize;
sizeTable [1].low = diopts->baseDispSize;
sizeTable [1].high = diopts->baseDispSize * diopts->baseDispSize;
sizeTable [1].dbs = diopts->baseDispSize;
for (i = 2; i < DI_SIZETAB_SIZE; ++i)
{
sizeTable [i].format = diopts->blockFormat;
sizeTable [i].low = sizeTable [i - 1].low * diopts->baseDispSize;
sizeTable [i].high = sizeTable [i - 1].high * diopts->baseDispSize;
sizeTable [i].dbs = sizeTable [i - 1].dbs * diopts->baseDispSize;
}
if (debug > 0)
{
printf ("di ver %s\n", DI_VERSION);
}
if (debug > 4)
{
for (i = 0; i < DI_DISPTAB_SIZE; ++i)
{
printf ("i:%d ", i);
printf ("size: %8.2f ", dispTable[i].size);
printf ("%s ", dispTable[i].disp);
printf ("\n");
}
printf ("dispBlockSize: %8.2f\n", diopts->dispBlockSize);
for (i = 0; i < DI_SIZETAB_SIZE; ++i)
{
printf ("i:%d ", i);
printf ("suffix: %s ", sizeTable[i].suffix);
printf ("low: %8.2f ", sizeTable[i].low);
printf ("high: %8.2f ", sizeTable[i].high);
printf ("dbs: %8.2f ", sizeTable[i].dbs);
printf ("\n");
}
}
/* main processing */
if (di_getDiskEntries (&diData.diskInfo, &diData.count) < 0)
{
cleanup (&diData, argvptr);
exit (1);
}
preCheckDiskInfo (&diData);
if (optind < argc)
{
int rc;
getDiskStatInfo (&diData);
rc = checkFileInfo (&diData, optind, argc, argv);
if (rc < 0)
{
cleanup (&diData, argvptr);
exit (1);
}
}
di_getDiskInfo (&diData.diskInfo, &diData.count);
getDiskSpecialInfo (&diData);
checkDiskInfo (&diData);
printDiskInfo (&diData);
cleanup (&diData, argvptr);
exit (0);
}
/*
* cleanup
*
* free up allocated memory
*
*/
static void
#if _proto_stdc
cleanup (diData_t *diData, char *argvptr)
#else
cleanup (diData, argvptr)
diData_t *diskInfo;
char *argvptr;
#endif
{
if (diData->diskInfo != (diDiskInfo_t *) NULL)
{
free ((char *) diData->diskInfo);
}
if (diData->ignoreList.count > 0 &&
diData->ignoreList.list != (char **) NULL)
{
free ((char *) diData->ignoreList.list);
}
if (diData->includeList.count > 0 &&
diData->includeList.list != (char **) NULL)
{
free ((char *) diData->includeList.list);
}
if (argvptr != (char *) NULL)
{
free ((char *) argvptr);
}
if (diData->zoneInfo.zones != (zoneSummary_t *) NULL)
{
free ((void *) diData->zoneInfo.zones);
}
}
/*
* printDiskInfo
*
* Print out the disk information table.
* Loops through all mounted disks, prints and calculates totals.
*
*/
static void
#if _proto_stdc
printDiskInfo (diData_t *diData)
#else
printDiskInfo (diData)
diData_t *diData;
#endif
{
int i;
diOptions_t *diopts;
diDiskInfo_t totals;
char lastpool [DI_SPEC_NAME_LEN + 1];
Size_t lastpoollen = { 0 };
int inpool = { 0 };
char tempSortType [DI_SORT_MAX + 1];
lastpool[0] = '\0';
memset ((char *) &totals, '\0', sizeof (diDiskInfo_t));
totals.blockSize = 8192;
strncpy (totals.name, GT("Total"), DI_NAME_LEN);
totals.printFlag = DI_PRNT_OK;
diopts = &diData->options;
if ((diopts->flags & DI_F_NO_HEADER) != DI_F_NO_HEADER)
{
printTitle (diopts);
}
if ((diopts->flags & DI_F_TOTAL) == DI_F_TOTAL &&
(diopts->flags & DI_F_NO_HEADER) != DI_F_NO_HEADER)
{
/* need to make a copy of the diskinfo array, as we */
/* want to preserve the sort order. */
diDiskInfo_t *tempDiskInfo;
/* in order to find the main pool entry, */
/* we must have the array sorted by special device name */
tempDiskInfo = (diDiskInfo_t *) malloc (sizeof (diDiskInfo_t) *
diData->count);
memcpy ((char *) tempDiskInfo, (char *) diData->diskInfo,
sizeof (diDiskInfo_t) * diData->count);
strcpy (tempSortType, diopts->sortType);
strcpy (diopts->sortType, "s");
sortArray (diopts, (char *) tempDiskInfo, sizeof (diDiskInfo_t),
diData->count, diCompare);
strcpy (diopts->sortType, tempSortType);
for (i = 0; i < diData->count; ++i)
{
int ispooled = { 0 };
if (tempDiskInfo [i].printFlag == DI_PRNT_EXCLUDE ||
tempDiskInfo [i].printFlag == DI_PRNT_BAD ||
tempDiskInfo [i].printFlag == DI_PRNT_OUTOFZONE)
{
continue;
}
if (tempDiskInfo [i].printFlag == DI_PRNT_IGNORE &&
(diopts->flags & DI_F_ALL) != DI_F_ALL)
{
continue;
}
/* is it a pooled filesystem type? */
if (strcmp (tempDiskInfo [i].fsType, "zfs") == 0 ||
strcmp (tempDiskInfo [i].fsType, "advfs") == 0)
{
ispooled = 1;
if (lastpoollen == 0 ||
strncmp (lastpool, tempDiskInfo [i].special, lastpoollen) != 0)
{
strncpy (lastpool, tempDiskInfo [i].special, sizeof (lastpool));
lastpoollen = strlen (lastpool);
inpool = 0;
}
}
/* only total the disks that make sense! */
/* don't add memory filesystems to totals. */
/* only add the main pool to totals for pooled filesystems */
if (strcmp (tempDiskInfo [i].fsType, "tmpfs") != 0 &&
strcmp (tempDiskInfo [i].fsType, "mfs") != 0 &&
tempDiskInfo [i].isReadOnly == FALSE &&
inpool == 0)
{
addTotals (&tempDiskInfo [i], &totals);
}
/* is it a pooled filesystem type? */
if (ispooled)
{
if (strncmp (lastpool, tempDiskInfo [i].special, lastpoollen) == 0)
{
inpool = 1;
}
}
} /* for each entry */
free ((char *) tempDiskInfo);
} /* if the totals are to be printed */
if (strcmp (diopts->sortType, "n") != 0)
{
sortArray (diopts, (char *) diData->diskInfo, sizeof (diDiskInfo_t),
diData->count, diCompare);
}
for (i = 0; i < diData->count; ++i)
{
diDiskInfo_t *dinfo;
dinfo = &diData->diskInfo [i];
if (debug > 5)
{
printf ("pdi:%s:%s:\n", dinfo->name,
getPrintFlagText ((int) dinfo->printFlag));
}
if (dinfo->printFlag == DI_PRNT_EXCLUDE ||
dinfo->printFlag == DI_PRNT_BAD ||
dinfo->printFlag == DI_PRNT_OUTOFZONE)
{
continue;
}
if (dinfo->printFlag == DI_PRNT_IGNORE &&
(diopts->flags & DI_F_ALL) != DI_F_ALL)
{
continue;
}
printInfo (dinfo, diopts);
}
if ((diopts->flags & DI_F_TOTAL) == DI_F_TOTAL &&
(diopts->flags & DI_F_NO_HEADER) != DI_F_NO_HEADER)
{
printInfo (&totals, diopts);
}
}
/*
* printInfo
*
* Print the information for a single partition. Loop through the
* format string and print the particular items wanted.
*
*/
static void
#if _proto_stdc
printInfo (diDiskInfo_t *diskInfo, diOptions_t *diopts)
#else
printInfo (diskInfo, diopts)
diDiskInfo_t *diskInfo;
diOptions_t *diopts;
#endif
{
_fs_size_t used;
_fs_size_t totAvail;
char *ptr;
int valid;
double temp;
int idx;
int tidx;
idx = 0;
temp = 0.0; /* gcc compile warning */
if (diopts->dispBlockSize == DI_DISP_HR_2)
{
idx = DI_ONE_MEG_SZTAB; /* default */
ptr = diopts->formatString;
while (*ptr)
{
valid = FALSE;
switch (*ptr)
{
case DI_FMT_BTOT:
{
temp = diskInfo->totalBlocks;
valid = TRUE;
break;
}
case DI_FMT_BTOT_AVAIL:
{
temp = diskInfo->totalBlocks -
(diskInfo->freeBlocks - diskInfo->availBlocks);
valid = TRUE;
break;
}
case DI_FMT_BUSED:
{
temp = diskInfo->totalBlocks - diskInfo->freeBlocks;
valid = TRUE;
break;
}
case DI_FMT_BCUSED:
{
temp = diskInfo->totalBlocks - diskInfo->availBlocks;
valid = TRUE;
break;
}
case DI_FMT_BFREE:
{
temp = diskInfo->freeBlocks;
valid = TRUE;
break;
}
case DI_FMT_BAVAIL:
{
temp = diskInfo->availBlocks;
valid = TRUE;
break;
}
}
if (valid)
{
temp *= diskInfo->blockSize;
tidx = findDispSize (temp);
/* want largest index */
if (tidx > idx)
{
idx = tidx;
}
}
++ptr;
}
}
ptr = diopts->formatString;
while (*ptr)
{
valid = TRUE;
switch (*ptr)
{
case DI_FMT_MOUNT:
{
printf (DI_MOUNT_FMT, diskInfo->name);
break;
}
case DI_FMT_MOUNT_FULL:
{
printf (diopts->mountFormat, diskInfo->name);
break;
}
case DI_FMT_BTOT:
{
printBlocks (diopts, diskInfo->totalBlocks, diskInfo->blockSize, idx);
break;
}
case DI_FMT_BTOT_AVAIL:
{
printBlocks (diopts, diskInfo->totalBlocks -
(diskInfo->freeBlocks - diskInfo->availBlocks),
diskInfo->blockSize, idx);
break;
}
case DI_FMT_BUSED:
{
printBlocks (diopts, diskInfo->totalBlocks - diskInfo->freeBlocks,
diskInfo->blockSize, idx);
break;
}
case DI_FMT_BCUSED:
{
printBlocks (diopts, diskInfo->totalBlocks - diskInfo->availBlocks,
diskInfo->blockSize, idx);
break;
}
case DI_FMT_BFREE:
{
printBlocks (diopts, diskInfo->freeBlocks, diskInfo->blockSize, idx);
break;
}
case DI_FMT_BAVAIL:
{
printBlocks (diopts, diskInfo->availBlocks, diskInfo->blockSize, idx);
break;
}
case DI_FMT_BPERC_NAVAIL:
{
used = diskInfo->totalBlocks - diskInfo->availBlocks;
totAvail = diskInfo->totalBlocks;
if (diopts->posix_compat == 1)
{
printPerc (used, totAvail, DI_POSIX_PERC_FMT);
}
else
{
printPerc (used, totAvail, DI_PERC_FMT);
}
break;
}
case DI_FMT_BPERC_USED:
{
used = diskInfo->totalBlocks - diskInfo->freeBlocks;
totAvail = diskInfo->totalBlocks;
if (diopts->posix_compat == 1)
{
printPerc (used, totAvail, DI_POSIX_PERC_FMT);
}
else
{
printPerc (used, totAvail, DI_PERC_FMT);
}
break;
}
case DI_FMT_BPERC_BSD:
{
used = diskInfo->totalBlocks - diskInfo->freeBlocks;
totAvail = diskInfo->totalBlocks -
(diskInfo->freeBlocks - diskInfo->availBlocks);
if (diopts->posix_compat == 1)
{
printPerc (used, totAvail, DI_POSIX_PERC_FMT);
}
else
{
printPerc (used, totAvail, DI_PERC_FMT);
}
break;
}
case DI_FMT_BPERC_AVAIL:
{
_fs_size_t bfree;
bfree = diskInfo->availBlocks;
totAvail = diskInfo->totalBlocks;
printPerc (bfree, totAvail, DI_PERC_FMT);
break;
}
case DI_FMT_BPERC_FREE:
{
_fs_size_t bfree;
bfree = diskInfo->freeBlocks;
totAvail = diskInfo->totalBlocks;
printPerc (bfree, totAvail, DI_PERC_FMT);
break;
}
case DI_FMT_ITOT:
{
printf (diopts->inodeFormat, diskInfo->totalInodes);
break;
}
case DI_FMT_IUSED:
{
printf (diopts->inodeFormat, diskInfo->totalInodes - diskInfo->freeInodes);
break;
}
case DI_FMT_IFREE:
{
printf (diopts->inodeFormat, diskInfo->freeInodes);
break;
}
case DI_FMT_IPERC:
{
used = diskInfo->totalInodes - diskInfo->availInodes;
totAvail = diskInfo->totalInodes;
printPerc (used, totAvail, DI_PERC_FMT);
break;
}
case DI_FMT_SPECIAL:
{
printf (DI_SPEC_FMT, diskInfo->special);
break;
}
case DI_FMT_SPECIAL_FULL:
{
printf (diopts->specialFormat, diskInfo->special);
break;
}
case DI_FMT_TYPE:
{
printf (DI_FSTYPE_FMT, diskInfo->fsType);
break;
}
case DI_FMT_TYPE_FULL:
{
printf (diopts->typeFormat, diskInfo->fsType);
break;
}
case DI_FMT_MOUNT_OPTIONS:
{
printf (diopts->optFormat, diskInfo->options);
break;
}
case DI_FMT_MOUNT_TIME:
{
#if _lib_mnt_time
printf (diopts->mTimeFormat, diskInfo->mountTime);
#endif
break;
}
default:
{
printf ("%c", *ptr);
valid = FALSE;
break;
}
}
++ptr;
if (*ptr && valid)
{
printf (" ");
}
}
printf ("\n");
}
static void
#if _proto_stdc
printBlocks (diOptions_t *diopts, _fs_size_t blocks,
_fs_size_t blockSize, int idx)
#else
printBlocks (diopts, blocks, blockSize, idx)
diOptions_t *diopts;
_fs_size_t blocks;
_fs_size_t blockSize;
int idx;
#endif
{
double tdbs;
double mult;
double temp;
char *suffix;
char *format;
suffix = "";
format = diopts->blockFormat;
tdbs = diopts->dispBlockSize;
if (diopts->dispBlockSize == DI_DISP_HR)
{
temp = (double) blocks * (double) blockSize;
idx = findDispSize (temp);
}
if (diopts->dispBlockSize == DI_DISP_HR ||
diopts->dispBlockSize == DI_DISP_HR_2)
{
if (idx == -1)
{
tdbs = sizeTable [DI_ONE_MEG].dbs;
}
else
{
tdbs = sizeTable [idx].dbs;
format = sizeTable [idx].format;
suffix = sizeTable [idx].suffix;
}
}
mult = (double) blockSize / tdbs;
printf (format, (double) blocks * mult, suffix);
}
static int
#if _proto_stdc
findDispSize (double siz)
#else
findDispSize (siz)
double siz;
#endif
{
int i;
for (i = 0; i < DI_SIZETAB_SIZE; ++i)
{
if (siz >= sizeTable [i].low && siz < sizeTable [i].high)
{
return i;
}
}
return -1;
}
/*
* addTotals
*
* Add up the totals for the blocks/inodes
*
*/
static void
#if _proto_stdc
addTotals (diDiskInfo_t *diskInfo, diDiskInfo_t *totals)
#else
addTotals (diskInfo, totals)
diDiskInfo_t *diskInfo;
diDiskInfo_t *totals;
#endif
{
double mult;
mult = (double) diskInfo->blockSize / (double) totals->blockSize;
if (debug > 2)
{
#if _siz_long_long >= 8
printf ("totals:bs:%lld:mult:%f\n", diskInfo->blockSize, mult);
#else
printf ("totals:bs:%ld:mult:%f\n", diskInfo->blockSize, mult);
#endif
}
totals->totalBlocks += diskInfo->totalBlocks * mult;
totals->freeBlocks += diskInfo->freeBlocks * mult;
totals->availBlocks += diskInfo->availBlocks * mult;
totals->totalInodes += diskInfo->totalInodes;
totals->freeInodes += diskInfo->freeInodes;
totals->availInodes += diskInfo->availInodes;
}
/*
* printTitle
*
* Loop through the format string and print the appropriate headings.
*
*/
static void
#if _proto_stdc
printTitle (diOptions_t *diopts)
#else
printTitle (diopts)
diOptions_t *diopts;
#endif
{
char *ptr;
int valid;
if ((diopts->flags & DI_F_DEBUG_HDR) == DI_F_DEBUG_HDR)
{
printf (GT("di ver %s Default Format: %s\n"),
DI_VERSION, DI_DEFAULT_FORMAT);
}
ptr = diopts->formatString;
while (*ptr)
{
valid = TRUE;
switch (*ptr)
{
case DI_FMT_MOUNT:
{
printf (DI_MOUNT_FMT, GT("Mount"));
break;
}
case DI_FMT_MOUNT_FULL:
{
if (diopts->posix_compat == 1)
{
printf (diopts->mountFormat, GT("Mounted On"));
}
else
{
printf (diopts->mountFormat, GT("Mount"));
}
break;
}
case DI_FMT_BTOT:
case DI_FMT_BTOT_AVAIL:
{
printf (diopts->blockLabelFormat, diopts->dispBlockLabel);
break;
}
case DI_FMT_BUSED:
case DI_FMT_BCUSED:
{
printf (diopts->blockLabelFormat, GT("Used"));
break;
}
case DI_FMT_BFREE:
{
printf (diopts->blockLabelFormat, GT("Free"));
break;
}
case DI_FMT_BAVAIL:
{
if (diopts->posix_compat == 1)
{
printf (diopts->blockLabelFormat, GT("Available"));
}
else
{
printf (diopts->blockLabelFormat, GT("Avail"));
}
break;
}
case DI_FMT_BPERC_NAVAIL:
case DI_FMT_BPERC_USED:
case DI_FMT_BPERC_BSD:
{
if (diopts->posix_compat == 1)
{
printf (DI_POSIX_PERC_LBL_FMT, GT("Capacity"));
}
else
{
printf (DI_PERC_LBL_FMT, GT("%Used"));
}
break;
}
case DI_FMT_BPERC_AVAIL:
case DI_FMT_BPERC_FREE:
{
printf (DI_PERC_LBL_FMT, GT("%Free"));
break;
}
case DI_FMT_ITOT:
{
printf (diopts->inodeLabelFormat, GT("Inodes"));
break;
}
case DI_FMT_IUSED:
{
printf (diopts->inodeLabelFormat, GT("Used"));
break;
}
case DI_FMT_IFREE:
{
printf (diopts->inodeLabelFormat, GT("Free"));
break;
}
case DI_FMT_IPERC:
{
printf (DI_PERC_LBL_FMT, GT("%Used"));
break;
}
case DI_FMT_SPECIAL:
{
printf (DI_SPEC_FMT, GT("Filesystem"));
break;
}
case DI_FMT_SPECIAL_FULL:
{
printf (diopts->specialFormat, GT("Filesystem"));
break;
}
case DI_FMT_TYPE:
{
printf (DI_FSTYPE_FMT, GT("fsType"));
break;
}
case DI_FMT_TYPE_FULL:
{
printf (diopts->typeFormat, GT("fs Type"));
break;
}
case DI_FMT_MOUNT_OPTIONS:
{
printf (diopts->optFormat, GT("Options"));
break;
}
case DI_FMT_MOUNT_TIME:
{
#if _lib_mnt_time
printf (diopts->mTimeFormat, GT("Mount Time"));
#endif
break;
}
default:
{
printf ("%c", *ptr);
valid = FALSE;
break;
}
}
++ptr;
if (*ptr && valid)
{
printf (" ");
}
}
printf ("\n");
}
/*
* printPerc
*
* Calculate and print a percentage using the values and format passed.
*
*/
static void
#if _proto_stdc
printPerc (_fs_size_t used, _fs_size_t totAvail, char *format)
#else
printPerc (used, totAvail, format)
_fs_size_t used;
_fs_size_t totAvail;
char *format;
#endif
{
double perc;
if (totAvail > 0L)
{
perc = (double) used / (double) totAvail;
perc *= 100.0;
}
else
{
perc = 0.0;
}
printf (format, perc);
}
static int
#if _proto_stdc
checkFileInfo (diData_t *diData, int optidx, int argc, char *argv [])
#else
checkFileInfo (diData, optidx, argc, argv)
diData_t *diData;
int optidx;
int argc;
char *argv [];
#endif
{
int rc;
int i;
int j;
struct stat statBuf;
rc = 0;
/* turn everything off */
for (j = 0; j < diData->count; ++j)
{
if (diData->diskInfo [j].printFlag == DI_PRNT_OK)
{
diData->diskInfo [j].printFlag = DI_PRNT_IGNORE;
}
}
for (i = optidx; i < argc; ++i)
{
if (stat (argv [i], &statBuf) == 0)
{
for (j = 0; j < diData->count; ++j)
{
diDiskInfo_t *dinfo;
dinfo = &diData->diskInfo[j];
if (dinfo->printFlag == DI_PRNT_IGNORE &&
dinfo->st_dev != DI_UNKNOWN_DEV &&
(__ulong) statBuf.st_dev == dinfo->st_dev)
{
dinfo->printFlag = DI_PRNT_OK;
break; /* out of inner for */
}
}
} /* if stat ok */
else
{
fprintf (stderr, "stat: %s ", argv[i]);
perror ("");
rc = -1;
}
} /* for each file specified on command line */
return rc;
}
/*
* sortArray ()
*
* shellsort!
*
*/
static void
#if _proto_stdc
sortArray (diOptions_t *diopts, char *data, Size_t dataSize, int count, DI_SORT_FUNC compareFunc)
#else
sortArray (diopts, data, dataSize, count, compareFunc)
diOptions_t *diopts;
char *data;
Size_t dataSize;
int count;
DI_SORT_FUNC compareFunc;
#endif
{
register int j;
char *tempData;
int i;
int gap;
if (count <= 1)
{
return;
}
tempData = (char *) malloc (dataSize);
if (tempData == (char *) NULL)
{
fprintf (stderr, "malloc failed in sortArray(). errno %d\n", errno);
exit (1);
}
gap = 1;
while (gap < count)
{
gap = 3 * gap + 1;
}
for (gap /= 3; gap > 0; gap /= 3)
{
for (i = gap; i < count; ++i)
{
j = i - gap;
memcpy ((char *) tempData, (char *) &(data [i * dataSize]),
dataSize);
while (j >= 0 &&
compareFunc (diopts,
&(data [j * dataSize]), tempData) > 0)
{
memcpy ((char *) &(data [(j + gap) * dataSize]),
(char *) &(data [j * dataSize]), dataSize);
j -= gap;
}
j += gap;
if (j != i)
{
memcpy ((char *) &(data [j * dataSize]),
(char *) tempData, dataSize);
}
}
}
free ((char *) tempData);
}
static int
#if _proto_stdc
diCompare (diOptions_t *diopts, void *a, void *b)
#else
diCompare (diopts, a, b)
diOptions_t *diopts;
void *a;
void *b;
#endif
{
diDiskInfo_t *di1;
diDiskInfo_t *di2;
int rc;
char *ptr;
di1 = (diDiskInfo_t *) a;
di2 = (diDiskInfo_t *) b;
/* reset sort order to the default start value */
diopts->sortOrder = DI_SORT_ASCENDING;
rc = 0;
ptr = diopts->sortType;
while (*ptr)
{
switch (*ptr)
{
case DI_SORT_NONE:
{
break;
}
case DI_SORT_MOUNT:
{
rc = strcmp (di1->name, di2->name);
break;
}
case DI_SORT_REVERSE:
{
diopts->sortOrder *= -1;
break;
}
case DI_SORT_SPECIAL:
{
rc = strcmp (di1->special, di2->special);
break;
}
case DI_SORT_TYPE:
{
rc = strcmp (di1->fsType, di2->fsType);
break;
}
case DI_SORT_AVAIL:
{
rc = (int) ((di1->availBlocks * di1->blockSize) -
(di2->availBlocks * di2->blockSize));
break;
}
} /* switch on sort type */
rc *= diopts->sortOrder;
if (rc != 0)
{
return rc;
}
++ptr;
}
return rc;
}
/*
* getDiskStatInfo
*
* gets the disk device number for each entry.
*
*/
static void
#if _proto_stdc
getDiskStatInfo (diData_t *diData)
#else
getDiskStatInfo (diData)
diData_t *diData;
#endif
{
int i;
struct stat statBuf;
for (i = 0; i < diData->count; ++i)
{
diDiskInfo_t *dinfo;
dinfo = &diData->diskInfo [i];
/* don't try to stat devices that are not accessible */
if (dinfo->printFlag == DI_PRNT_EXCLUDE ||
dinfo->printFlag == DI_PRNT_BAD ||
dinfo->printFlag == DI_PRNT_OUTOFZONE)
{
continue;
}
dinfo->st_dev = (__ulong) DI_UNKNOWN_DEV;
if (stat (dinfo->name, &statBuf) == 0)
{
dinfo->st_dev = (__ulong) statBuf.st_dev;
if (debug > 2)
{
printf ("dev: %s: %ld\n", dinfo->name, dinfo->st_dev);
}
}
else
{
fprintf (stderr, "stat: %s ", dinfo->name);
perror ("");
}
}
}
/*
* getDiskSpecialInfo
*
* gets the disk device number for each entry.
*
*/
static void
#if _proto_stdc
getDiskSpecialInfo (diData_t *diData)
#else
getDiskSpecialInfo (diData)
diData_t *diData;
#endif
{
int i;
struct stat statBuf;
for (i = 0; i < diData->count; ++i)
{
diDiskInfo_t *dinfo;
dinfo = &diData->diskInfo [i];
/* check for initial slash; otherwise we can pick up normal files */
if (*(dinfo->special) == '/' &&
stat (dinfo->special, &statBuf) == 0)
{
dinfo->sp_dev = (__ulong) statBuf.st_dev;
dinfo->sp_rdev = (__ulong) statBuf.st_rdev;
if (debug > 2)
{
printf ("special dev: %s: %ld rdev: %ld\n",
dinfo->special, dinfo->sp_dev,
dinfo->sp_rdev);
}
}
else
{
dinfo->sp_dev = 0;
dinfo->sp_rdev = 0;
}
}
}
/*
* checkDiskInfo
*
* checks the disk information returned for various return values.
*
*/
static void
#if _proto_stdc
checkDiskInfo (diData_t *diData)
#else
checkDiskInfo (diData)
diData_t *diData;
#endif
{
int i;
int j;
int dupCount;
int len;
int maxMountString;
int maxSpecialString;
int maxTypeString;
int maxOptString;
int maxMntTimeString;
_fs_size_t temp;
__ulong sp_dev;
__ulong sp_rdev;
diOptions_t *diopts;
diopts = &diData->options;
maxMountString = (diopts->flags & DI_F_NO_HEADER) == DI_F_NO_HEADER ? 0 : 5;
maxSpecialString = (diopts->flags & DI_F_NO_HEADER) == DI_F_NO_HEADER ? 0 : 10;
maxTypeString = (diopts->flags & DI_F_NO_HEADER) == DI_F_NO_HEADER ? 0 : 7;
maxOptString = (diopts->flags & DI_F_NO_HEADER) == DI_F_NO_HEADER ? 0 : 7;
maxMntTimeString = (diopts->flags & DI_F_NO_HEADER) == DI_F_NO_HEADER ? 0 : 26;
for (i = 0; i < diData->count; ++i)
{
diDiskInfo_t *dinfo;
dinfo = &diData->diskInfo[i];
if (dinfo->printFlag == DI_PRNT_EXCLUDE ||
dinfo->printFlag == DI_PRNT_BAD ||
dinfo->printFlag == DI_PRNT_OUTOFZONE)
{
if (debug > 2)
{
printf ("chk: skipping(%s):%s\n",
getPrintFlagText ((int) dinfo->printFlag), dinfo->name);
}
continue;
}
/* Solaris reports a cdrom as having no free blocks, */
/* no available. Their df doesn't always work right! */
/* -1 is returned. */
if (debug > 2)
{
#if _siz_long_long >= 8
printf ("chk: %s free: %llu\n", dinfo->name,
dinfo->freeBlocks);
#else
printf ("chk: %s free: %lu\n", dinfo->name,
dinfo->freeBlocks);
#endif
}
if ((_s_fs_size_t) dinfo->freeBlocks < 0L)
{
dinfo->freeBlocks = 0L;
}
if ((_s_fs_size_t) dinfo->availBlocks < 0L)
{
dinfo->availBlocks = 0L;
}
temp = (_fs_size_t) ~ 0;
if (dinfo->totalInodes == temp)
{
dinfo->totalInodes = 0;
dinfo->freeInodes = 0;
dinfo->availInodes = 0;
}
if (dinfo->printFlag == DI_PRNT_OK)
{
if (debug > 2)
{
#if _siz_long_long >= 8
printf ("chk: %s total: %lld\n", dinfo->name,
dinfo->totalBlocks);
#else
printf ("chk: %s total: %ld\n", dinfo->name,
dinfo->totalBlocks);
#endif
}
if (dinfo->totalBlocks <= 0L)
{
dinfo->printFlag = DI_PRNT_IGNORE;
if (debug > 2)
{
printf ("chk: ignore: totalBlocks <= 0: %s\n",
dinfo->name);
}
}
}
/* make sure anything in the include list didn't get turned off */
checkIncludeList (dinfo, &diData->includeList);
} /* for all disks */
if ((diopts->flags & DI_F_INCLUDE_LOOPBACK) != DI_F_INCLUDE_LOOPBACK)
{
/* this loop sets duplicate entries to be ignored. */
for (i = 0; i < diData->count; ++i)
{
diDiskInfo_t *dinfo;
dinfo = &diData->diskInfo[i];
if (dinfo->printFlag == DI_PRNT_IGNORE ||
dinfo->printFlag == DI_PRNT_EXCLUDE ||
dinfo->printFlag == DI_PRNT_BAD ||
dinfo->printFlag == DI_PRNT_OUTOFZONE)
{
if (debug > 2)
{
printf ("chk: skipping(%s):%s\n",
getPrintFlagText ((int) dinfo->printFlag), dinfo->name);
}
continue;
}
/* don't need to bother checking real partitions */
/* don't bother if already ignored */
if (dinfo->sp_rdev != 0 &&
dinfo->printFlag == DI_PRNT_OK)
{
sp_dev = dinfo->sp_dev;
sp_rdev = dinfo->sp_rdev;
dupCount = 0;
for (j = 0; j < diData->count; ++j)
{
if (diData->diskInfo [j].sp_dev == sp_rdev)
{
++dupCount;
}
}
if (debug > 2)
{
printf ("dup: chk: i: %s dev: %ld rdev: %ld dup: %d\n",
dinfo->name, sp_dev, sp_rdev, dupCount);
}
for (j = 0; dupCount > 0 && j < diData->count; ++j)
{
diDiskInfo_t *dinfob;
dinfob = &diData->diskInfo [j];
/* don't reset flags! */
if (dinfob->sp_rdev == 0 &&
dinfob->sp_dev == sp_rdev &&
dinfob->printFlag == DI_PRNT_OK)
{
dinfob->printFlag = DI_PRNT_IGNORE;
if (debug > 2)
{
printf ("chk: ignore: duplicate: %s of %s\n",
dinfob->name, dinfo->name);
printf ("dup: ign: j: rdev: %ld dev: %ld\n",
dinfob->sp_dev, dinfob->sp_rdev);
}
}
} /* duplicate check for each disk */
} /* if this is a printable disk */
else
{
if (debug > 2)
{
printf ("chk: dup: not checked: %s prnt: %d dev: %ld rdev: %ld\n",
dinfo->name, dinfo->printFlag,
dinfo->sp_dev, dinfo->sp_rdev);
}
}
} /* for each disk */
} /* if the duplicate loopback mounts are to be excluded */
if (diopts->posix_compat == 1)
{
/* Mounted On */
len = strlen (GT("Mounted On"));
maxMountString = maxMountString < len ? len : maxMountString;
len = strlen (diopts->dispBlockLabel);
diopts->width = diopts->width < len ? len : diopts->width;
}
/* this loop gets the max string lengths */
for (i = 0; i < diData->count; ++i)
{
diDiskInfo_t *dinfo;
dinfo = &diData->diskInfo[i];
if (dinfo->printFlag == DI_PRNT_OK ||
(dinfo->printFlag == DI_PRNT_IGNORE &&
(diopts->flags & DI_F_ALL) == DI_F_ALL))
{
len = strlen (dinfo->name);
if (len > maxMountString)
{
maxMountString = len;
}
len = strlen (dinfo->special);
if (len > maxSpecialString)
{
maxSpecialString = len;
}
len = strlen (dinfo->fsType);
if (len > maxTypeString)
{
maxTypeString = len;
}
len = strlen (dinfo->options);
if (len > maxOptString)
{
maxOptString = len;
}
len = strlen (dinfo->mountTime);
if (len > maxMntTimeString)
{
maxMntTimeString = len;
}
} /* if we are printing this item */
} /* for all disks */
Snprintf (SPF(diopts->mountFormat, sizeof (diopts->mountFormat), "%%-%d.%ds"),
maxMountString, maxMountString);
Snprintf (SPF(diopts->specialFormat, sizeof (diopts->specialFormat), "%%-%d.%ds"),
maxSpecialString, maxSpecialString);
Snprintf (SPF(diopts->typeFormat, sizeof (diopts->typeFormat), "%%-%d.%ds"),
maxTypeString, maxTypeString);
Snprintf (SPF(diopts->optFormat, sizeof (diopts->optFormat), "%%-%d.%ds"),
maxOptString, maxOptString);
Snprintf (SPF(diopts->mTimeFormat, sizeof (diopts->mTimeFormat), "%%-%d.%ds"),
maxMntTimeString, maxMntTimeString);
if (diopts->dispBlockSize == DI_DISP_HR ||
diopts->dispBlockSize == DI_DISP_HR_2)
{
--diopts->width;
}
if (diopts->dispBlockSize != DI_DISP_HR &&
diopts->dispBlockSize != DI_DISP_HR_2 &&
(diopts->dispBlockSize > 0 && diopts->dispBlockSize <= DI_VAL_1024))
{
Snprintf (SPF(diopts->blockFormat,
sizeof (diopts->blockFormat), "%%%d.0f%%s"), diopts->width);
}
else
{
Snprintf (SPF(diopts->blockFormatNR,
sizeof (diopts->blockFormatNR), "%%%d.0f%%s"), diopts->width);
Snprintf (SPF(diopts->blockFormat,
sizeof (diopts->blockFormat), "%%%d.1f%%s"), diopts->width);
}
if (diopts->dispBlockSize == DI_DISP_HR ||
diopts->dispBlockSize == DI_DISP_HR_2)
{
++diopts->width;
}
Snprintf (SPF(diopts->blockLabelFormat,
sizeof (diopts->blockLabelFormat), "%%%ds"), diopts->width);
#if _siz_long_long >= 8
Snprintf (SPF(diopts->inodeFormat,
sizeof (diopts->inodeFormat), "%%%dllu"), diopts->inodeWidth);
#else
Snprintf (SPF(diopts->inodeFormat,
sizeof (diopts->inodeFormat), "%%%dlu"), diopts->inodeWidth);
#endif
Snprintf (SPF(diopts->inodeLabelFormat,
sizeof (diopts->inodeLabelFormat), "%%%ds"), diopts->inodeWidth);
}
/*
* preCheckDiskInfo
*
* checks for ignore/include list; check for remote filesystems
* and local only flag set.
* checks for zones (Solaris)
*
*/
static void
#if _proto_stdc
preCheckDiskInfo (diData_t *diData)
#else
preCheckDiskInfo (diData)
diData_t *diData;
#endif
{
int i;
diOptions_t *diopts;
diopts = &diData->options;
for (i = 0; i < diData->count; ++i)
{
diDiskInfo_t *dinfo;
dinfo = &diData->diskInfo[i];
if (debug > 4)
{
printf ("## prechk:%s:\n", dinfo->name);
}
checkZone (dinfo, &diData->zoneInfo,
((diopts->flags & DI_F_ALL) == DI_F_ALL));
if (dinfo->printFlag == DI_PRNT_OK)
{
/* don't bother w/this check is all flag is set. */
if ((diopts->flags & DI_F_ALL) != DI_F_ALL)
{
di_testRemoteDisk (dinfo);
if (dinfo->isLocal == FALSE &&
(diopts->flags & DI_F_LOCAL_ONLY) == DI_F_LOCAL_ONLY)
{
dinfo->printFlag = DI_PRNT_IGNORE;
if (debug > 2)
{
printf ("prechk: ignore: remote disk; local flag set: %s\n",
dinfo->name);
}
}
}
}
if (dinfo->printFlag == DI_PRNT_OK ||
dinfo->printFlag == DI_PRNT_IGNORE)
{
/* do do these checks to override the all flag */
checkIgnoreList (dinfo, &diData->ignoreList);
checkIncludeList (dinfo, &diData->includeList);
}
} /* for all disks */
}
/*
* usage
*
*/
static void
#if _proto_stdc
usage (void)
#else
usage ()
#endif
{
printf (GT("di ver %s Default Format: %s\n"), DI_VERSION, DI_DEFAULT_FORMAT);
/* 12345678901234567890123456789012345678901234567890123456789012345678901234567890 */
printf (GT("Usage: di [-ant] [-d display-size] [-f format] [-x exclude-fstyp-list]\n"));
printf (GT(" [-I include-fstyp-list] [file [...]]\n"));
printf (GT(" -a : print all mounted devices\n"));
printf (GT(" -d x : size to print blocks in (512 - POSIX, k - kbytes,\n"));
printf (GT(" m - megabytes, g - gigabytes, t - terabytes, h - human readable).\n"));
printf (GT(" -f x : use format string <x>\n"));
printf (GT(" -I x : include only file system types in <x>\n"));
printf (GT(" -x x : exclude file system types in <x>\n"));
printf (GT(" -l : display local filesystems only\n"));
printf (GT(" -n : don't print header\n"));
printf (GT(" -t : print totals\n"));
printf (GT(" Format string values:\n"));
printf (GT(" m - mount point M - mount point, full length\n"));
printf (GT(" b - total kbytes B - kbytes available for use\n"));
printf (GT(" u - used kbytes c - calculated kbytes in use\n"));
printf (GT(" f - kbytes free v - kbytes available\n"));
printf (GT(" p - percentage not avail. for use 1 - percentage used\n"));
printf (GT(" 2 - percentage of user-available space in use.\n"));
printf (GT(" i - total file slots (i-nodes) U - used file slots\n"));
printf (GT(" F - free file slots P - percentage file slots used\n"));
printf (GT(" s - filesystem name S - filesystem name, full length\n"));
printf (GT(" t - disk partition type T - partition type, full length\n"));
printf (GT("See manual page for more options.\n"));
}
static void
#if _proto_stdc
processArgs (int argc,
char *argv [],
diData_t *diData,
char *dbsstr)
#else
processArgs (argc, argv, diData, dbsstr)
int argc;
char *argv [];
diData_t *diData;
char *dbsstr;
#endif
{
int ch;
int hasdashk;
diOptions_t *diopts;
diopts = &diData->options;
hasdashk = 0;
while ((ch = getopt (argc, argv,
"Aab:B:d:D:f:F:ghHi:I:klLmnPs:tvw:W:x:X:z:Z")) != -1)
{
switch (ch)
{
case 'A': /* for debugging */
{
diopts->formatString = DI_ALL_FORMAT;
break;
}
case 'a':
{
diopts->flags |= DI_F_ALL;
strcpy (diData->zoneInfo.zoneDisplay, "all");
break;
}
case 'b':
case 'B':
{
if (isdigit ((int) (*optarg)))
{
diopts->baseDispSize = atof (optarg);
}
else if (*optarg == 'k')
{
diopts->baseDispSize = DI_VAL_1024;
}
else if (*optarg == 'd')
{
diopts->baseDispSize = DI_VAL_1000;
}
break;
}
case 'd':
{
strncpy (dbsstr, optarg, sizeof (dbsstr));
break;
}
/* for debugging; can be replaced */
case 'D':
{
debug = atoi (optarg);
di_lib_debug = debug;
break;
}
case 'f':
{
diopts->formatString = optarg;
break;
}
case 'g':
{
strncpy (dbsstr, "g", sizeof (dbsstr));
break;
}
case 'h':
{
strncpy (dbsstr, "h", sizeof (dbsstr));
break;
}
case 'H':
{
strncpy (dbsstr, "H", sizeof (dbsstr));
break;
}
case 'm':
{
strncpy (dbsstr, "m", sizeof (dbsstr));
break;
}
case 'i': /* backwards compatibility */
case 'x': /* preferred */
{
parseList (&diData->ignoreList, optarg);
break;
}
case 'F': /* compatibility w/other df */
case 'I':
{
parseList (&diData->includeList, optarg);
break;
}
case 'k':
{
strncpy (dbsstr, "k", sizeof (dbsstr));
hasdashk = 1;
break;
}
case 'l':
{
diopts->flags |= DI_F_LOCAL_ONLY;
break;
}
case 'L':
{
diopts->flags |= DI_F_INCLUDE_LOOPBACK;
break;
}
case 'n':
{
diopts->flags |= DI_F_NO_HEADER;
break;
}
case 'P':
{
if (hasdashk == 0) /* don't override -k option */
{
strncpy (dbsstr, "512", sizeof (dbsstr));
}
diopts->formatString = DI_POSIX_FORMAT;
diopts->posix_compat = 1;
break;
}
case 's':
{
strncpy (diopts->sortType, optarg, sizeof (diopts->sortType));
/* for backwards compatibility */
/* reverse by itself - change to reverse mount point */
if (strcmp (diopts->sortType, "r") == 0)
{
strcpy (diopts->sortType, "rm");
}
/* add some sense to the sort order */
if (strcmp (diopts->sortType, "t") == 0)
{
strcpy (diopts->sortType, "tm");
}
break;
}
case 't':
{
diopts->flags |= DI_F_TOTAL;
break;
}
case 'v':
{
break;
}
case 'w':
{
diopts->width = atoi (optarg);
break;
}
case 'W':
{
diopts->inodeWidth = atoi (optarg);
break;
}
case 'X':
{
debug = atoi (optarg);
di_lib_debug = debug;
diopts->flags |= DI_F_DEBUG_HDR | DI_F_TOTAL;
diopts->flags &= ~ DI_F_NO_HEADER;
diopts->width = 10;
diopts->inodeWidth = 10;
break;
}
case 'z':
{
strcpy (diData->zoneInfo.zoneDisplay, optarg);
break;
}
case 'Z':
{
strcpy (diData->zoneInfo.zoneDisplay, "all");
break;
}
case '?':
{
usage ();
exit (1);
}
}
}
}
static void
#if _proto_stdc
parseList (iList_t *list, char *str)
#else
parseList (list, str)
iList_t *list;
char *str;
#endif
{
char *dstr;
char *ptr;
char *lptr;
int count;
int ocount;
int ncount;
int i;
int len;
i = strlen (str);
dstr = (char *) malloc ((Size_t) i + 1);
if (dstr == (char *) NULL)
{
fprintf (stderr, "malloc failed in parseList() (1). errno %d\n", errno);
exit (1);
}
memcpy (dstr, str, (Size_t) i);
dstr [i] = '\0';
ptr = strtok (dstr, DI_LIST_SEP);
count = 0;
while (ptr != (char *) NULL)
{
++count;
ptr = strtok ((char *) NULL, DI_LIST_SEP);
}
ocount = list->count;
list->count += count;
ncount = list->count;
list->list = (char **) Realloc ((char *) list->list,
list->count * sizeof (char *));
if (list->list == (char **) NULL)
{
fprintf (stderr, "malloc failed in parseList() (2). errno %d\n", errno);
exit (1);
}
ptr = dstr;
for (i = ocount; i < ncount; ++i)
{
len = strlen (ptr);
lptr = (char *) malloc ((Size_t) len + 1);
if (lptr == (char *) NULL)
{
fprintf (stderr, "malloc failed in parseList() (3). errno %d\n",
errno);
exit (1);
}
strncpy (lptr, ptr, (Size_t) len);
lptr[len] = '\0';
list->list [i] = lptr;
ptr += len + 1;
}
free ((char *) dstr);
}
static void
#if _proto_stdc
checkIgnoreList (diDiskInfo_t *diskInfo, iList_t *ignoreList)
#else
checkIgnoreList (diskInfo, ignoreList)
diDiskInfo_t *diskInfo;
iList_t *ignoreList;
#endif
{
char *ptr;
int i;
/* if the file system type is in the ignore list, skip it */
if (ignoreList->count > 0)
{
for (i = 0; i < ignoreList->count; ++i)
{
ptr = ignoreList->list [i];
if (debug > 2)
{
printf ("chkign: test: fstype %s/%s : %s\n", ptr,
diskInfo->fsType, diskInfo->name);
}
if (strcmp (ptr, diskInfo->fsType) == 0)
{
diskInfo->printFlag = DI_PRNT_EXCLUDE;
if (debug > 2)
{
printf ("chkign: ignore: fstype %s match: %s\n", ptr,
diskInfo->name);
}
break;
}
}
} /* if an ignore list was specified */
}
static void
#if _proto_stdc
checkIncludeList (diDiskInfo_t *diskInfo, iList_t *includeList)
#else
checkIncludeList (diskInfo, includeList)
diDiskInfo_t *diskInfo;
iList_t *includeList;
#endif
{
char *ptr;
int i;
/* if the file system type is not in the include list, skip it */
if (includeList->count > 0)
{
for (i = 0; i < includeList->count; ++i)
{
ptr = includeList->list [i];
if (debug > 2)
{
printf ("chkinc: test: fstype %s/%s : %s\n", ptr,
diskInfo->fsType, diskInfo->name);
}
if (strcmp (ptr, diskInfo->fsType) == 0)
{
diskInfo->printFlag = DI_PRNT_OK;
if (debug > 2)
{
printf ("chkinc:include:fstype %s match: %s\n", ptr,
diskInfo->name);
}
break;
}
else
{
diskInfo->printFlag = DI_PRNT_EXCLUDE;
if (debug > 2)
{
printf ("chkinc:!include:fstype %s no match: %s\n", ptr,
diskInfo->name);
}
}
}
} /* if an include list was specified */
}
static void
# if _proto_stdc
checkZone (diDiskInfo_t *diskInfo, zoneInfo_t *zoneInfo, int allFlag)
# else
checkZone (diskInfo, zoneInfo, allFlag)
diDiskInfo_t *diskInfo;
zoneInfo_t *zoneInfo;
int allFlag;
# endif
{
int i;
int idx = { -1 };
#if _lib_zone_list && _lib_getzoneid && _lib_zone_getattr
if (strcmp (zoneInfo->zoneDisplay, "all") == 0 &&
zoneInfo->uid == 0)
{
return;
}
for (i = 0; i < zoneInfo->zoneCount; ++i)
{
/* find the zone the filesystem is in, if non-global */
if (debug > 5)
{
printf (" checkZone:%s:compare:%d:%s:\n",
diskInfo->name,
zoneInfo->zones[i].rootpathlen,
zoneInfo->zones[i].rootpath);
}
if (strncmp (zoneInfo->zones[i].rootpath,
diskInfo->name, zoneInfo->zones[i].rootpathlen) == 0)
{
if (debug > 4)
{
printf (" checkZone:%s:found zone:%s:\n",
diskInfo->name, zoneInfo->zones[i].name);
}
idx = i;
break;
}
if (idx == -1)
{
idx = zoneInfo->globalIdx;
}
}
/* no root access, ignore any zones */
/* that don't match our zone id */
/* this will override any ignore flags */
/* already set */
if (zoneInfo->uid != 0)
{
if (debug > 5)
{
printf (" checkZone:uid non-zero:chk zone:%d:%d:\n",
(int) zoneInfo->myzoneid,
(int) zoneInfo->zones[idx].zoneid);
}
if (zoneInfo->myzoneid != zoneInfo->zones[idx].zoneid)
{
if (debug > 4)
{
printf (" checkZone:not root, not zone:%d:%d:outofzone:\n",
(int) zoneInfo->myzoneid,
(int) zoneInfo->zones[idx].zoneid);
}
diskInfo->printFlag = DI_PRNT_OUTOFZONE;
}
}
if (debug > 5)
{
printf (" checkZone:chk name:%s:%s:\n",
zoneInfo->zoneDisplay, zoneInfo->zones[idx].name);
}
/* not the zone we want. ignore */
if (! allFlag &&
diskInfo->printFlag == DI_PRNT_OK &&
strcmp (zoneInfo->zoneDisplay, "all") != 0 &&
strcmp (zoneInfo->zoneDisplay,
zoneInfo->zones[idx].name) != 0)
{
if (debug > 4)
{
printf (" checkZone:wrong zone:ignore:\n");
}
diskInfo->printFlag = DI_PRNT_IGNORE;
}
/* if displaying a non-global zone, */
/* don't display loopback filesystems */
if (! allFlag &&
diskInfo->printFlag == DI_PRNT_OK &&
strcmp (zoneInfo->zoneDisplay, "global") != 0 &&
strcmp (diskInfo->fsType, "lofs") == 0)
{
if (debug > 4)
{
printf (" checkZone:non-global/lofs:ignore:\n");
}
diskInfo->printFlag = DI_PRNT_IGNORE;
}
#endif
return;
}
static void
#if _proto_stdc
setDispBlockSize (char *ptr, diOptions_t *diopts)
#else
setDispBlockSize (ptr, diopts)
char *ptr;
diOptions_t *diopts;
#endif
{
int len;
double val;
char *tptr;
if (ptr == (char *) NULL ||
*ptr == '\0')
{
return;
}
if (isdigit ((int) (*ptr)))
{
val = (_fs_size_t) atof (ptr);
}
else
{
val = 1.0;
}
tptr = ptr;
len = strlen (ptr);
tptr += len;
--tptr;
if (! isdigit ((int) *tptr))
{
int idx;
idx = -1;
switch (*tptr)
{
case 'k':
case 'K':
{
idx = DI_ONE_K;
break;
}
case 'm':
case 'M':
{
idx = DI_ONE_MEG;
break;
}
case 'g':
case 'G':
{
idx = DI_ONE_GIG;
break;
}
case 't':
case 'T':
{
idx = DI_ONE_TERA;
break;
}
case 'p':
case 'P':
{
idx = DI_ONE_PETA;
break;
}
case 'e':
case 'E':
{
idx = DI_ONE_EXA;
break;
}
case 'z':
case 'Z':
{
idx = DI_ONE_ZETTA;
break;
}
case 'y':
case 'Y':
{
idx = DI_ONE_YOTTA;
break;
}
case 'h':
{
val = DI_DISP_HR;
strncpy (diopts->dispBlockLabel, GT("Size"),
sizeof (diopts->dispBlockLabel));
break;
}
case 'H':
{
val = DI_DISP_HR_2;
strncpy (diopts->dispBlockLabel, GT("Size"),
sizeof (diopts->dispBlockLabel));
break;
}
default:
{
if (strncmp (ptr, "HUMAN", 5) == 0)
{
val = DI_DISP_HR;
}
else
{
/* some unknown string value */
val = diopts->dispBlockSize;
}
break;
}
}
if (idx >= 0)
{
if (val == 1.0)
{
strncpy (diopts->dispBlockLabel, GT(dispTable [idx].disp),
sizeof (diopts->dispBlockLabel));
}
else
{
Snprintf (SPF (diopts->dispBlockLabel,
sizeof (diopts->dispBlockLabel), "%.0f %s"),
val, GT(dispTable [idx].disp));
}
val *= dispTable [idx].size;
} /* known size multiplier */
}
else
{
int i;
int ok;
ok = 0;
for (i = 0; i < DI_DISPTAB_SIZE; ++i)
{
if (val == dispTable [i].size)
{
strncpy (diopts->dispBlockLabel, GT(dispTable [i].disp),
sizeof (diopts->dispBlockLabel));
ok = 1;
break;
}
}
if (ok == 0)
{
Snprintf (SPF (diopts->dispBlockLabel,
sizeof (diopts->dispBlockLabel), "%.0fb"), val);
}
} /* some oddball block size */
if (diopts->posix_compat == 1 && val == 512)
{
strncpy (diopts->dispBlockLabel, GT ("512-blocks"),
sizeof (diopts->dispBlockLabel));
}
if (diopts->posix_compat == 1 && val == 1024)
{
strncpy (diopts->dispBlockLabel, GT ("1024-blocks"),
sizeof (diopts->dispBlockLabel));
}
diopts->dispBlockSize = val;
}
/* for debugging */
static char *
#if _proto_stdc
getPrintFlagText (int pf)
#else
getPrintFlagText (pf)
int pf;
#endif
{
return pf == DI_PRNT_OK ? "ok" :
pf == DI_PRNT_BAD ? "bad" :
pf == DI_PRNT_IGNORE ? "ignore" :
pf == DI_PRNT_EXCLUDE ? "exclude" :
pf == DI_PRNT_OUTOFZONE ? "outofzone" : "unknown";
}
#if ! _mth_fmod && ! _lib_fmod
static double
#if _proto_stdc
fmod (double a, double b)
#else
fmod (a, b)
double a;
double b;
#endif
{
double temp;
temp = a - (int) (a/b) * b;
return temp;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1