df.c revision af33352a19f03e8fe054fe9b44b19c20aeed0da6
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
/*
* df
*/
#include <stdio.h>
#include <fcntl.h>
#include <locale.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <libintl.h>
extern char *getenv();
extern char *getcwd();
extern char *realpath();
/*
* Raw name to block device name translation function.
* This comes from libadm.
*/
extern char *getfullblkname();
static char *mpath(char *);
static char *zap_chroot(char *);
static char *pathsuffix(char *, char *);
static char *xmalloc(unsigned int);
static int chroot_stat(char *, int (*)(), char *, char **);
static int subpath(char *, char *);
static int abspath(char *, char *, char *);
static void show_inode_usage();
static void dfreedev(char *);
static void print_totals();
static void print_itotals();
static void print_statvfs(struct statvfs64 *);
#define dbtok(x, b) \
((b) < (fsblkcnt64_t)1024 ? \
int aflag = 0; /* even the uninteresting ones */
int bflag = 0; /* print only number of kilobytes free */
int eflag = 0; /* print only number of file entries free */
int gflag = 0; /* print entire statvfs structure */
int hflag = 0; /* don't print header */
int iflag = 0; /* information for inodes */
int nflag = 0; /* print VFStype name */
int tflag = 0; /* print totals */
int errflag = 0;
int errcode = 0;
char *typestr = "ufs";
/*
* cached information recording previous chroot history.
*/
static char *chrootpath;
extern int optind;
extern char *optarg;
union {
} sb;
/*
* This structure is used to chain mntent structures into a list
* and to cache stat information for each member of the list.
*/
struct mntlist {
int mntl_devvalid;
};
char *subopts [] = {
#define A_FLAG 0
"a",
#define I_FLAG 1
"i",
};
int
{
int opt;
char *suboptions, *value;
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
switch (opt) {
case 'b': /* print only number of kilobytes free */
bflag++;
break;
case 'e':
eflag++; /* print only number of file entries free */
iflag++;
break;
case 'g':
gflag++;
break;
case 'n':
nflag++;
break;
case 'k':
break;
case 'h':
hflag++;
break;
case 'o':
/*
* ufs specific options.
*/
suboptions = optarg;
while (*suboptions != '\0') {
switch (getsubopt(&suboptions,
case I_FLAG: /* information for inodes */
iflag++;
break;
default:
usage();
}
}
break;
case 't': /* print totals */
tflag++;
break;
case 'V': /* Print command line */
{
char *opt_text;
int opt_count;
opt_count++) {
if (opt_text)
opt_text);
}
}
break;
case '?':
errflag++;
}
}
if (errflag)
usage();
exit(1);
}
tflag = 0;
/*
* Cache CHROOT information for later use; assume that $CHROOT matches
* the cumulative arguments given to chroot calls.
*/
chrootpath = NULL;
/*
* there are no mountpoints specified.
* E.g., these command lines take us down this path
*/
exit(1);
}
pheader();
continue;
}
}
if (tflag)
if (iflag)
else
print_totals();
} else {
int i;
char **devnames;
char *cp;
/* Arguments are processed till optind, adjust the pointers */
/*
* Obtain stat64 information for each argument before
* constructing the list of mounted file systems. This
* ordering forces the automounter to establish any
* mounts required to access the arguments, so that the
* corresponding mount table entries will exist when
* we look for them.
*/
for (i = 0; i < argc; i++) {
/*
* Given a raw device name, get the block device name
*/
int j;
"df: memory allocation failure\n"));
for (j = 0; j < i; j++)
exit(1);
}
}
/*
* Mark as no longer interesting.
*/
} else {
}
}
pheader();
aflag++;
/*
* Construct the list of mounted file systems.
*/
/*
* Iterate through the argument list, reporting on each one.
*/
for (i = 0; i < argc; i++) {
int isblk;
/*
* Skip if we've already determined that we can't
* process it.
*/
continue;
/*
* If the argument names a device, report on the file
* system associated with the device rather than on
* the one containing the device's directory entry
*/
return (1);
} else {
}
continue;
}
/*
* Get this argument's corresponding mount table
* entry.
*/
gettext("Could not find mount point for %s\n"),
argv[i]);
continue;
}
}
}
return (0);
}
void
pheader()
{
if (hflag)
return;
if (nflag)
if (iflag) {
if (eflag)
/*
* TRANSLATION_NOTE
* Following string is used as a table header.
* Translated items should start at the same
* columns as the original items.
*/
"Filesystem ifree\n"));
else {
/*
* TRANSLATION_NOTE
* Following string is used as a table header.
* Translated items should start at the same
* columns as the original items.
*/
"Filesystem iused ifree %%iused Mounted on\n"));
}
} else {
if (gflag)
/*
* TRANSLATION_NOTE
* Following string is used as a table header.
* Translated items should start at the same
* columns as the original items.
*/
"Filesystem f_type f_fsize f_bfree f_bavail f_files f_ffree "
"f_fsid f_flag f_fstr\n"));
else
if (bflag)
/*
* TRANSLATION_NOTE
* Following string is used as a table header.
* Translated items should start at the same
* columns as the original items.
*/
"Filesystem avail\n"));
else {
/*
* TRANSLATION_NOTE
* Following string is used as a table header.
* Translated items should start at the same
* columns as the original items.
*/
"Filesystem kbytes used avail capacity Mounted on\n"));
}
}
}
/*
* Report on a block or character special device. Assumed not to be
* mounted. N.B. checks for a valid UFS superblock.
*/
void
{
int fi;
if (fi < 0) {
return;
}
return;
}
"df: %s: not a ufs file system\n"),
file);
return;
}
"df: %s: unrecognized version of UFS: %d\n"),
return;
}
"df: %s: unrecognized version of UFS: %d\n"),
return;
}
if (iflag) {
if (eflag) {
} else {
}
} else {
free =
if (bflag) {
} else {
(void) printf(" %7lld %7lld %7lld",
(void) printf("%6.0f%%",
availblks == 0 ? 0.0 :
(void) printf(" ");
}
if (tflag) {
}
}
else if (eflag)
(void) printf("\n");
}
void
{
return;
}
return;
}
} else {
(void) printf(" ");
} else {
}
}
if (iflag) {
if (eflag) {
} else {
}
} else {
if (gflag) {
print_statvfs(&fs);
} else {
if ((long long)avail < 0)
avail = 0;
if (bflag) {
} else {
(void) printf(" %7lld %7lld %7lld",
(void) printf("%6.0f%%",
totalblks == 0 ? 0.0 :
(void) printf(" ");
if (tflag) {
t_reserved += reserved;
}
}
}
}
else if (eflag)
(void) printf("\n");
}
static void
{
(long long)free == (long long)-1);
if (missing_info)
else
if ((long long)free == (long long)-1)
else
if (missing_info)
else
}
/*
* Return the suffix of path obtained by stripping off the prefix
* that is the value of the CHROOT environment variable. If this
* value isn't obtainable or if it's not a prefix of path, return NULL.
*/
static char *
zap_chroot(char *path)
{
}
/*
* chroot'd. Used to find the TFS mount that applies to the current
* activated NSE environment.
*/
static int
{
return (-1);
if (dirp)
}
/*
*/
char *
{
char *mname;
return ("");
}
mname = "";
continue;
}
continue;
continue;
break;
}
}
}
return (mname);
}
/*
* Given a special device, return mnttab entry
* Returns 0 on success
*/
int
{
return (1);
}
return (0);
}
}
return (1);
}
/*
* Find the entry in mlist that corresponds to the file named by path
* (i.e., that names a mount table entry for the file system in which
* path lies). The pstat argument must point to stat information for
* path.
*
* Return the entry or NULL if there's no match.
*
* As it becomes necessary to obtain stat information about previously
* unexamined mlist entries, gather the information and cache it with the
* entries.
*
* The routine's strategy is to convert path into its canonical, symlink-free
* representation canon (which will require accessing the file systems on the
* branch from the root to path and thus may cause the routine to hang if any
* of them are inaccessible) and to use it to search for a mount point whose
* name is a substring of canon and whose corresponding device matches that of
* canon. This technique avoids accessing unnecessary file system resources
* and thus prevents the program from hanging on inaccessible resources unless
* those resources are necessary for accessing path.
*/
static struct mntlist *
{
static char cwd[MAXPATHLEN];
char canon[MAXPATHLEN];
char scratch[MAXPATHLEN];
/*
* If path is relative and we haven't already determined the current
* working directory, do so now. Calculating the working directory
* here lets us do the work once, instead of (potentially) repeatedly
* in realpath().
*/
cwd[0] = '\0';
return (NULL);
}
}
/*
* Find an absolute pathname in the native file system name space that
* corresponds to path, stuffing it into canon.
*
* If CHROOT is set in the environment, assume that chroot($CHROOT)
* (or an equivalent series of calls) was executed and convert the
* path to the equivalent name in the native file system's name space.
* Doing so allows direct comparison with the names in mtab entires,
* which are assumed to be recorded relative to the native name space.
*/
return (NULL);
/*
* Force canon to be in canonical form; if the result from
* abspath was "/" and chrootpath isn't the null string, we
* must strip off a trailing slash.
*/
scratch[0] = '\0';
}
/*
* Ignore uninteresting mounts.
*/
continue;
/*
* The mount entry covers some prefix of the file.
* See whether it's the entry for the file system
* containing the file by comparing device ids.
*/
(char **)NULL) < 0) {
continue;
}
}
return (mlp);
}
return (NULL);
}
/*
* Convert the path given in raw to canonical, absolute, symlink-free
* form, storing the result in the buffer named by canon, which must be
* at least MAXPATHLEN bytes long. "wd" contains the current working
* directory; accepting this value as an argument lets our caller cache
* the value, so that realpath (called from this routine) doesn't have
* to recalculate it each time it's given a relative pathname.
*
* Return 0 on success, -1 on failure.
*/
static int
{
char absbuf[MAXPATHLEN];
/*
* Preliminary sanity check.
*/
return (-1);
/*
* If the path is relative, convert it to absolute form,
* using wd if it's been supplied.
*/
if (raw[0] != '/') {
char *d;
/* Fill in working directory. */
return (-1);
/* Add separating slash. */
if (d < limit)
*d++ = '/';
/* Glue on the relative part of the path. */
continue;
}
/*
* Call realpath to canonicalize and resolve symlinks.
*/
}
/*
* Return a pointer to the trailing suffix of full that follows the prefix
* given by pref. If pref isn't a prefix of full, return NULL. Apply
* pathname semantics to the prefix test, so that pref must match at a
* component boundary.
*/
static char *
{
int preflen;
return (NULL);
return (NULL);
/*
* pref is a substring of full. To be a subpath, it cannot cover a
* partial component of full. The last clause of the test handles the
* special case of the root.
*/
return (NULL);
return (full);
else
}
/*
* Return zero iff the path named by sub is a leading subpath
* of the path named by full.
*
* Treat null paths as matching nothing.
*/
static int
{
}
int
{
int n;
/* probably a dismounted disk if errno == EIO */
} else {
"df: premature EOF on %s\n"), file);
}
return (0);
}
return (1);
}
char *
{
char *ret;
char *malloc();
exit(1);
}
return (ret);
}
struct mnttab *
{
new->mnt_special =
new->mnt_mountp =
new->mnt_fstype =
new->mnt_mntopts =
} else {
}
#ifdef never
#endif /* never */
return (new);
}
void
usage()
{
"ufs usage: df [generic options] [-o i] [directory | special]\n"));
exit(1);
}
struct mntlist *
{
exit(1);
}
}
return (mntst);
}
void
{
int i;
for (i = 0; i < FSTYPSZ; i++)
(void) printf(" %7d %7lld %7lld",
(void) printf(" %7lld %7lld %7d",
(void) printf(" 0x%x ",
for (i = 0; i < 14; i++)
(void) printf("%c",
printf("\n");
}
void
{
/*
* TRANSLATION_NOTE
* Following string is used as a table header.
* Translated items should start at the same
* columns as the original items.
*/
(void) printf("%6.0f%%\n",
0.0 :
}
void
{
/*
* TRANSLATION_NOTE
* Following string is used as a table header.
* Translated items should start at the same
* columns as the original items.
*/
}