19ddb49cbSWarner Losh /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 44b88c807SRodney W. Grimes * Copyright (c) 1980, 1990, 1993, 1994 54b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved. 64b88c807SRodney W. Grimes * (c) UNIX System Laboratories, Inc. 74b88c807SRodney W. Grimes * All or some portions of this file are derived from material licensed 84b88c807SRodney W. Grimes * to the University of California by American Telephone and Telegraph 94b88c807SRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 104b88c807SRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 114b88c807SRodney W. Grimes * 124b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 134b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions 144b88c807SRodney W. Grimes * are met: 154b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 164b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 174b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 184b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 194b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution. 20fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 214b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 224b88c807SRodney W. Grimes * without specific prior written permission. 234b88c807SRodney W. Grimes * 244b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 254b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 264b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 274b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 284b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 294b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 304b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 314b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 324b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 334b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 344b88c807SRodney W. Grimes * SUCH DAMAGE. 354b88c807SRodney W. Grimes */ 364b88c807SRodney W. Grimes 3709a80d48SDavid E. O'Brien #if 0 384b88c807SRodney W. Grimes #ifndef lint 3916cc192aSSteve Price static const char copyright[] = 404b88c807SRodney W. Grimes "@(#) Copyright (c) 1980, 1990, 1993, 1994\n\ 414b88c807SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 424b88c807SRodney W. Grimes #endif /* not lint */ 434b88c807SRodney W. Grimes 444b88c807SRodney W. Grimes #ifndef lint 4516cc192aSSteve Price static char sccsid[] = "@(#)df.c 8.9 (Berkeley) 5/8/95"; 464b88c807SRodney W. Grimes #endif /* not lint */ 4709a80d48SDavid E. O'Brien #endif 485eb43ac2SDavid E. O'Brien #include <sys/cdefs.h> 495eb43ac2SDavid E. O'Brien __FBSDID("$FreeBSD$"); 504b88c807SRodney W. Grimes 514b88c807SRodney W. Grimes #include <sys/param.h> 524b88c807SRodney W. Grimes #include <sys/stat.h> 534b88c807SRodney W. Grimes #include <sys/mount.h> 54a25695c3SJim Pirzyk #include <sys/sysctl.h> 554b88c807SRodney W. Grimes #include <err.h> 56d0bc27e4SKyle Evans #include <getopt.h> 577d3940bbSPawel Jakub Dawidek #include <libutil.h> 58019e4a53SGreg Lehey #include <locale.h> 590bd9f151SIan Dowse #include <stdint.h> 604b88c807SRodney W. Grimes #include <stdio.h> 614b88c807SRodney W. Grimes #include <stdlib.h> 624b88c807SRodney W. Grimes #include <string.h> 63dd6d33e8SMichael Haro #include <sysexits.h> 644b88c807SRodney W. Grimes #include <unistd.h> 65b6ff8745SMarcel Moolenaar #include <libxo/xo.h> 664b88c807SRodney W. Grimes 67dd6d33e8SMichael Haro #define UNITS_SI 1 68dd6d33e8SMichael Haro #define UNITS_2 2 69dd6d33e8SMichael Haro 7062edbd31SIan Dowse /* Maximum widths of various fields. */ 7162edbd31SIan Dowse struct maxwidths { 720bd9f151SIan Dowse int mntfrom; 73b56ca465SPawel Jakub Dawidek int fstype; 740bd9f151SIan Dowse int total; 750bd9f151SIan Dowse int used; 760bd9f151SIan Dowse int avail; 770bd9f151SIan Dowse int iused; 780bd9f151SIan Dowse int ifree; 7962edbd31SIan Dowse }; 8062edbd31SIan Dowse 81c6f13844SDavid E. O'Brien static void addstat(struct statfs *, struct statfs *); 82b7dbd3e9SMark Murray static char *getmntpt(const char *); 83*f0fd4a32SStefan Eßer static const char **makevfslist(char *fslist, int *skip); 84*f0fd4a32SStefan Eßer static int checkvfsname(const char *vfsname, const char **vfslist, int skip); 85*f0fd4a32SStefan Eßer static int checkvfsselected(char *); 860bd9f151SIan Dowse static int int64width(int64_t); 87532aff98SPoul-Henning Kamp static char *makenetvfslist(void); 88fde81c7dSKirk McKusick static void prthuman(const struct statfs *, int64_t); 89b6ff8745SMarcel Moolenaar static void prthumanval(const char *, int64_t); 90841fe8e8SDavid Schultz static intmax_t fsbtoblk(int64_t, uint64_t, u_long); 91532aff98SPoul-Henning Kamp static void prtstat(struct statfs *, struct maxwidths *); 92*f0fd4a32SStefan Eßer static size_t regetmntinfo(struct statfs **, long); 93b7dbd3e9SMark Murray static void update_maxwidths(struct maxwidths *, const struct statfs *); 94532aff98SPoul-Henning Kamp static void usage(void); 954b88c807SRodney W. Grimes 960bd9f151SIan Dowse static __inline int 970bd9f151SIan Dowse imax(int a, int b) 9862edbd31SIan Dowse { 99b7dbd3e9SMark Murray return (a > b ? a : b); 10062edbd31SIan Dowse } 10162edbd31SIan Dowse 102b56ca465SPawel Jakub Dawidek static int aflag = 0, cflag, hflag, iflag, kflag, lflag = 0, nflag, Tflag; 103019e4a53SGreg Lehey static int thousands; 104*f0fd4a32SStefan Eßer static int skipvfs_l, skipvfs_t; 105*f0fd4a32SStefan Eßer static const char **vfslist_l, **vfslist_t; 106532aff98SPoul-Henning Kamp 107d0bc27e4SKyle Evans static const struct option long_options[] = 108d0bc27e4SKyle Evans { 109d0bc27e4SKyle Evans { "si", no_argument, NULL, 'H' }, 110d0bc27e4SKyle Evans { NULL, no_argument, NULL, 0 }, 111d0bc27e4SKyle Evans }; 112d0bc27e4SKyle Evans 1134b88c807SRodney W. Grimes int 114f9bcb0beSWarner Losh main(int argc, char *argv[]) 1154b88c807SRodney W. Grimes { 1164b88c807SRodney W. Grimes struct stat stbuf; 117c6f13844SDavid E. O'Brien struct statfs statfsbuf, totalbuf; 11862edbd31SIan Dowse struct maxwidths maxwidths; 119c6f13844SDavid E. O'Brien struct statfs *mntbuf; 120176d3efdSBrooks Davis char *mntpt; 1217b0514faSDag-Erling Smørgrav int i, mntsize; 122be2c4e54SDavid E. O'Brien int ch, rv; 123f3895a82SKris Kennaway 124019e4a53SGreg Lehey (void)setlocale(LC_ALL, ""); 12511ed25f2SUlrich Spörlein memset(&maxwidths, 0, sizeof(maxwidths)); 126076419d2SDavid E. O'Brien memset(&totalbuf, 0, sizeof(totalbuf)); 127076419d2SDavid E. O'Brien totalbuf.f_bsize = DEV_BSIZE; 128d7c881e8SWarner Losh strlcpy(totalbuf.f_mntfromname, "total", MNAMELEN); 129b6ff8745SMarcel Moolenaar 130b6ff8745SMarcel Moolenaar argc = xo_parse_args(argc, argv); 131b6ff8745SMarcel Moolenaar if (argc < 0) 132b6ff8745SMarcel Moolenaar exit(1); 133b6ff8745SMarcel Moolenaar 134d0bc27e4SKyle Evans while ((ch = getopt_long(argc, argv, "+abcgHhiklmnPt:T,", long_options, 135d0bc27e4SKyle Evans NULL)) != -1) 1364b88c807SRodney W. Grimes switch (ch) { 1375b42dac8SJulian Elischer case 'a': 1385b42dac8SJulian Elischer aflag = 1; 1395b42dac8SJulian Elischer break; 140dd6d33e8SMichael Haro case 'b': 141dd6d33e8SMichael Haro /* FALLTHROUGH */ 142dd6d33e8SMichael Haro case 'P': 143df464e43SChristian S.J. Peron /* 1446bccea7cSRebecca Cran * POSIX specifically discusses the behavior of 145df464e43SChristian S.J. Peron * both -k and -P. It states that the blocksize should 146df464e43SChristian S.J. Peron * be set to 1024. Thus, if this occurs, simply break 147df464e43SChristian S.J. Peron * rather than clobbering the old blocksize. 148df464e43SChristian S.J. Peron */ 149df464e43SChristian S.J. Peron if (kflag) 150df464e43SChristian S.J. Peron break; 1512966d28cSSean Farley setenv("BLOCKSIZE", "512", 1); 152dd6d33e8SMichael Haro hflag = 0; 153dd6d33e8SMichael Haro break; 154c6f13844SDavid E. O'Brien case 'c': 155c6f13844SDavid E. O'Brien cflag = 1; 156c6f13844SDavid E. O'Brien break; 15793a3fa19SJohn W. De Boskey case 'g': 1582966d28cSSean Farley setenv("BLOCKSIZE", "1g", 1); 15993a3fa19SJohn W. De Boskey hflag = 0; 16093a3fa19SJohn W. De Boskey break; 161dd6d33e8SMichael Haro case 'H': 162dd6d33e8SMichael Haro hflag = UNITS_SI; 163dd6d33e8SMichael Haro break; 164dd6d33e8SMichael Haro case 'h': 165dd6d33e8SMichael Haro hflag = UNITS_2; 166dd6d33e8SMichael Haro break; 1674b88c807SRodney W. Grimes case 'i': 1684b88c807SRodney W. Grimes iflag = 1; 1694b88c807SRodney W. Grimes break; 1707f0eabfdSGarrett Wollman case 'k': 171df464e43SChristian S.J. Peron kflag++; 1722966d28cSSean Farley setenv("BLOCKSIZE", "1024", 1); 173dd6d33e8SMichael Haro hflag = 0; 174dd6d33e8SMichael Haro break; 175a25695c3SJim Pirzyk case 'l': 176246ef54fSConrad Meyer /* Ignore duplicate -l */ 177246ef54fSConrad Meyer if (lflag) 178246ef54fSConrad Meyer break; 179*f0fd4a32SStefan Eßer vfslist_l = makevfslist(makenetvfslist(), &skipvfs_l); 18027f82335SWill Andrews lflag = 1; 181a25695c3SJim Pirzyk break; 182dd6d33e8SMichael Haro case 'm': 1832966d28cSSean Farley setenv("BLOCKSIZE", "1m", 1); 184dd6d33e8SMichael Haro hflag = 0; 1857f0eabfdSGarrett Wollman break; 1864b88c807SRodney W. Grimes case 'n': 1874b88c807SRodney W. Grimes nflag = 1; 1884b88c807SRodney W. Grimes break; 1894b88c807SRodney W. Grimes case 't': 190*f0fd4a32SStefan Eßer if (vfslist_t != NULL) 191b6ff8745SMarcel Moolenaar xo_errx(1, "only one -t option may be specified"); 192*f0fd4a32SStefan Eßer vfslist_t = makevfslist(optarg, &skipvfs_t); 1934b88c807SRodney W. Grimes break; 194b56ca465SPawel Jakub Dawidek case 'T': 195b56ca465SPawel Jakub Dawidek Tflag = 1; 196b56ca465SPawel Jakub Dawidek break; 197019e4a53SGreg Lehey case ',': 198019e4a53SGreg Lehey thousands = 1; 199019e4a53SGreg Lehey break; 2004b88c807SRodney W. Grimes case '?': 2014b88c807SRodney W. Grimes default: 2024b88c807SRodney W. Grimes usage(); 2034b88c807SRodney W. Grimes } 2044b88c807SRodney W. Grimes argc -= optind; 2054b88c807SRodney W. Grimes argv += optind; 2064b88c807SRodney W. Grimes 207b8904f2aSJoerg Wunsch rv = 0; 2084b88c807SRodney W. Grimes if (!*argv) { 2097b0514faSDag-Erling Smørgrav /* everything (modulo -t) */ 2107b0514faSDag-Erling Smørgrav mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 211*f0fd4a32SStefan Eßer mntsize = regetmntinfo(&mntbuf, mntsize); 2127b0514faSDag-Erling Smørgrav } else { 2137b0514faSDag-Erling Smørgrav /* just the filesystems specified on the command line */ 2147b0514faSDag-Erling Smørgrav mntbuf = malloc(argc * sizeof(*mntbuf)); 21511ed25f2SUlrich Spörlein if (mntbuf == NULL) 216b6ff8745SMarcel Moolenaar xo_err(1, "malloc()"); 2177b0514faSDag-Erling Smørgrav mntsize = 0; 2187b0514faSDag-Erling Smørgrav /* continued in for loop below */ 2194b88c807SRodney W. Grimes } 2204b88c807SRodney W. Grimes 221b6ff8745SMarcel Moolenaar xo_open_container("storage-system-information"); 222b6ff8745SMarcel Moolenaar xo_open_list("filesystem"); 223b6ff8745SMarcel Moolenaar 2247b0514faSDag-Erling Smørgrav /* iterate through specified filesystems */ 2254b88c807SRodney W. Grimes for (; *argv; argv++) { 2264b88c807SRodney W. Grimes if (stat(*argv, &stbuf) < 0) { 22711ed25f2SUlrich Spörlein if ((mntpt = getmntpt(*argv)) == NULL) { 228b6ff8745SMarcel Moolenaar xo_warn("%s", *argv); 229b8904f2aSJoerg Wunsch rv = 1; 2304b88c807SRodney W. Grimes continue; 2314b88c807SRodney W. Grimes } 232f3895a82SKris Kennaway } else if (S_ISCHR(stbuf.st_mode)) { 2331740c2dbSMark Johnston mntpt = getmntpt(*argv); 234f3895a82SKris Kennaway if (mntpt == NULL) { 235e3e94324SBrooks Davis xo_warnx("%s: not mounted", *argv); 236e3e94324SBrooks Davis rv = 1; 237e3e94324SBrooks Davis continue; 238e3e94324SBrooks Davis } 2391740c2dbSMark Johnston } else { 2404b88c807SRodney W. Grimes mntpt = *argv; 2411740c2dbSMark Johnston } 2420e7d023fSBruce Evans 2434b88c807SRodney W. Grimes /* 2444b88c807SRodney W. Grimes * Statfs does not take a `wait' flag, so we cannot 2454b88c807SRodney W. Grimes * implement nflag here. 2464b88c807SRodney W. Grimes */ 2474b88c807SRodney W. Grimes if (statfs(mntpt, &statfsbuf) < 0) { 248b6ff8745SMarcel Moolenaar xo_warn("%s", mntpt); 249b8904f2aSJoerg Wunsch rv = 1; 2504b88c807SRodney W. Grimes continue; 2514b88c807SRodney W. Grimes } 2520e7d023fSBruce Evans 2530e7d023fSBruce Evans /* 2540e7d023fSBruce Evans * Check to make sure the arguments we've been given are 2550e7d023fSBruce Evans * satisfied. Return an error if we have been asked to 2560e7d023fSBruce Evans * list a mount point that does not match the other args 2570e7d023fSBruce Evans * we've been given (-l, -t, etc.). 258c22acefbSJordan K. Hubbard */ 259*f0fd4a32SStefan Eßer if (checkvfsselected(statfsbuf.f_fstypename) != 0) { 2600e7d023fSBruce Evans rv = 1; 261c22acefbSJordan K. Hubbard continue; 262c22acefbSJordan K. Hubbard } 2630e7d023fSBruce Evans 2647b0514faSDag-Erling Smørgrav /* the user asked for it, so ignore the ignore flag */ 2657b0514faSDag-Erling Smørgrav statfsbuf.f_flags &= ~MNT_IGNORE; 2667b0514faSDag-Erling Smørgrav 2677b0514faSDag-Erling Smørgrav /* add to list */ 2687b0514faSDag-Erling Smørgrav mntbuf[mntsize++] = statfsbuf; 2697b0514faSDag-Erling Smørgrav } 2707b0514faSDag-Erling Smørgrav 27111ed25f2SUlrich Spörlein memset(&maxwidths, 0, sizeof(maxwidths)); 2727b0514faSDag-Erling Smørgrav for (i = 0; i < mntsize; i++) { 2737b0514faSDag-Erling Smørgrav if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0) { 2747b0514faSDag-Erling Smørgrav update_maxwidths(&maxwidths, &mntbuf[i]); 275076419d2SDavid E. O'Brien if (cflag) 2767b0514faSDag-Erling Smørgrav addstat(&totalbuf, &mntbuf[i]); 2774b88c807SRodney W. Grimes } 2787b0514faSDag-Erling Smørgrav } 2797b0514faSDag-Erling Smørgrav for (i = 0; i < mntsize; i++) 2807b0514faSDag-Erling Smørgrav if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0) 2817b0514faSDag-Erling Smørgrav prtstat(&mntbuf[i], &maxwidths); 282b6ff8745SMarcel Moolenaar 283b6ff8745SMarcel Moolenaar xo_close_list("filesystem"); 284b6ff8745SMarcel Moolenaar 285076419d2SDavid E. O'Brien if (cflag) 286076419d2SDavid E. O'Brien prtstat(&totalbuf, &maxwidths); 287b6ff8745SMarcel Moolenaar 288b6ff8745SMarcel Moolenaar xo_close_container("storage-system-information"); 289b6ff8745SMarcel Moolenaar xo_finish(); 290d5183594SXin LI exit(rv); 2914b88c807SRodney W. Grimes } 2924b88c807SRodney W. Grimes 293532aff98SPoul-Henning Kamp static char * 294b7dbd3e9SMark Murray getmntpt(const char *name) 2954b88c807SRodney W. Grimes { 296be2c4e54SDavid E. O'Brien size_t mntsize, i; 2974b88c807SRodney W. Grimes struct statfs *mntbuf; 2984b88c807SRodney W. Grimes 2994b88c807SRodney W. Grimes mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 3004b88c807SRodney W. Grimes for (i = 0; i < mntsize; i++) { 3014b88c807SRodney W. Grimes if (!strcmp(mntbuf[i].f_mntfromname, name)) 3024b88c807SRodney W. Grimes return (mntbuf[i].f_mntonname); 3034b88c807SRodney W. Grimes } 30411ed25f2SUlrich Spörlein return (NULL); 3054b88c807SRodney W. Grimes } 3064b88c807SRodney W. Grimes 307*f0fd4a32SStefan Eßer static const char ** 308*f0fd4a32SStefan Eßer makevfslist(char *fslist, int *skip) 309*f0fd4a32SStefan Eßer { 310*f0fd4a32SStefan Eßer const char **av; 311*f0fd4a32SStefan Eßer int i; 312*f0fd4a32SStefan Eßer char *nextcp; 313*f0fd4a32SStefan Eßer 314*f0fd4a32SStefan Eßer if (fslist == NULL) 315*f0fd4a32SStefan Eßer return (NULL); 316*f0fd4a32SStefan Eßer *skip = 0; 317*f0fd4a32SStefan Eßer if (fslist[0] == 'n' && fslist[1] == 'o') { 318*f0fd4a32SStefan Eßer fslist += 2; 319*f0fd4a32SStefan Eßer *skip = 1; 320*f0fd4a32SStefan Eßer } 321*f0fd4a32SStefan Eßer for (i = 0, nextcp = fslist; *nextcp; nextcp++) 322*f0fd4a32SStefan Eßer if (*nextcp == ',') 323*f0fd4a32SStefan Eßer i++; 324*f0fd4a32SStefan Eßer if ((av = malloc((size_t)(i + 2) * sizeof(char *))) == NULL) { 325*f0fd4a32SStefan Eßer warnx("malloc failed"); 326*f0fd4a32SStefan Eßer return (NULL); 327*f0fd4a32SStefan Eßer } 328*f0fd4a32SStefan Eßer nextcp = fslist; 329*f0fd4a32SStefan Eßer i = 0; 330*f0fd4a32SStefan Eßer av[i++] = nextcp; 331*f0fd4a32SStefan Eßer while ((nextcp = strchr(nextcp, ',')) != NULL) { 332*f0fd4a32SStefan Eßer *nextcp++ = '\0'; 333*f0fd4a32SStefan Eßer av[i++] = nextcp; 334*f0fd4a32SStefan Eßer } 335*f0fd4a32SStefan Eßer av[i++] = NULL; 336*f0fd4a32SStefan Eßer return (av); 337*f0fd4a32SStefan Eßer } 338*f0fd4a32SStefan Eßer 339*f0fd4a32SStefan Eßer static int 340*f0fd4a32SStefan Eßer checkvfsname(const char *vfsname, const char **vfslist, int skip) 341*f0fd4a32SStefan Eßer { 342*f0fd4a32SStefan Eßer 343*f0fd4a32SStefan Eßer if (vfslist == NULL) 344*f0fd4a32SStefan Eßer return (0); 345*f0fd4a32SStefan Eßer while (*vfslist != NULL) { 346*f0fd4a32SStefan Eßer if (strcmp(vfsname, *vfslist) == 0) 347*f0fd4a32SStefan Eßer return (skip); 348*f0fd4a32SStefan Eßer ++vfslist; 349*f0fd4a32SStefan Eßer } 350*f0fd4a32SStefan Eßer return (!skip); 351*f0fd4a32SStefan Eßer } 352*f0fd4a32SStefan Eßer 353*f0fd4a32SStefan Eßer /* 354*f0fd4a32SStefan Eßer * Without -l and -t option, all file system types are enabled. 355*f0fd4a32SStefan Eßer * The -l option selects the local file systems, if present. 356*f0fd4a32SStefan Eßer * A -t option modifies the selection by adding or removing further 357*f0fd4a32SStefan Eßer * file system types, based on the argument that is passed. 358*f0fd4a32SStefan Eßer */ 359*f0fd4a32SStefan Eßer static int 360*f0fd4a32SStefan Eßer checkvfsselected(char *fstypename) 361*f0fd4a32SStefan Eßer { 362*f0fd4a32SStefan Eßer int result; 363*f0fd4a32SStefan Eßer 364*f0fd4a32SStefan Eßer if (vfslist_t) { 365*f0fd4a32SStefan Eßer /* if -t option used then select passed types */ 366*f0fd4a32SStefan Eßer result = checkvfsname(fstypename, vfslist_t, skipvfs_t); 367*f0fd4a32SStefan Eßer if (vfslist_l) { 368*f0fd4a32SStefan Eßer /* if -l option then adjust selection */ 369*f0fd4a32SStefan Eßer if (checkvfsname(fstypename, vfslist_l, skipvfs_l) == skipvfs_t) 370*f0fd4a32SStefan Eßer result = skipvfs_t; 371*f0fd4a32SStefan Eßer } 372*f0fd4a32SStefan Eßer } else { 373*f0fd4a32SStefan Eßer /* no -t option then -l decides */ 374*f0fd4a32SStefan Eßer result = checkvfsname(fstypename, vfslist_l, skipvfs_l); 375*f0fd4a32SStefan Eßer } 376*f0fd4a32SStefan Eßer return (result); 377*f0fd4a32SStefan Eßer } 378*f0fd4a32SStefan Eßer 3794b88c807SRodney W. Grimes /* 3804b88c807SRodney W. Grimes * Make a pass over the file system info in ``mntbuf'' filtering out 381*f0fd4a32SStefan Eßer * file system types not in vfslist_{l,t} and possibly re-stating to get 3824b88c807SRodney W. Grimes * current (not cached) info. Returns the new count of valid statfs bufs. 3834b88c807SRodney W. Grimes */ 384be2c4e54SDavid E. O'Brien static size_t 385*f0fd4a32SStefan Eßer regetmntinfo(struct statfs **mntbufp, long mntsize) 3864b88c807SRodney W. Grimes { 387239c9e60SChristian S.J. Peron int error, i, j; 3884b88c807SRodney W. Grimes struct statfs *mntbuf; 3894b88c807SRodney W. Grimes 390*f0fd4a32SStefan Eßer if (vfslist_l == NULL && vfslist_t == NULL) 3914b88c807SRodney W. Grimes return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT)); 3924b88c807SRodney W. Grimes 3934b88c807SRodney W. Grimes mntbuf = *mntbufp; 394a78192e3SBruce Evans for (j = 0, i = 0; i < mntsize; i++) { 395*f0fd4a32SStefan Eßer if (checkvfsselected(mntbuf[i].f_fstypename) != 0) 396a78192e3SBruce Evans continue; 397239c9e60SChristian S.J. Peron /* 398239c9e60SChristian S.J. Peron * XXX statfs(2) can fail for various reasons. It may be 399239c9e60SChristian S.J. Peron * possible that the user does not have access to the 400239c9e60SChristian S.J. Peron * pathname, if this happens, we will fall back on 401239c9e60SChristian S.J. Peron * "stale" filesystem statistics. 402239c9e60SChristian S.J. Peron */ 403239c9e60SChristian S.J. Peron error = statfs(mntbuf[i].f_mntonname, &mntbuf[j]); 404239c9e60SChristian S.J. Peron if (nflag || error < 0) 405239c9e60SChristian S.J. Peron if (i != j) { 406239c9e60SChristian S.J. Peron if (error < 0) 407b6ff8745SMarcel Moolenaar xo_warnx("%s stats possibly stale", 408239c9e60SChristian S.J. Peron mntbuf[i].f_mntonname); 4094b88c807SRodney W. Grimes mntbuf[j] = mntbuf[i]; 410239c9e60SChristian S.J. Peron } 4114b88c807SRodney W. Grimes j++; 4124b88c807SRodney W. Grimes } 4134b88c807SRodney W. Grimes return (j); 4144b88c807SRodney W. Grimes } 4154b88c807SRodney W. Grimes 416532aff98SPoul-Henning Kamp static void 417fde81c7dSKirk McKusick prthuman(const struct statfs *sfsp, int64_t used) 418dd6d33e8SMichael Haro { 419dd6d33e8SMichael Haro 420b6ff8745SMarcel Moolenaar prthumanval(" {:blocks/%6s}", sfsp->f_blocks * sfsp->f_bsize); 421b6ff8745SMarcel Moolenaar prthumanval(" {:used/%6s}", used * sfsp->f_bsize); 422b6ff8745SMarcel Moolenaar prthumanval(" {:available/%6s}", sfsp->f_bavail * sfsp->f_bsize); 423dd6d33e8SMichael Haro } 424dd6d33e8SMichael Haro 425532aff98SPoul-Henning Kamp static void 426b6ff8745SMarcel Moolenaar prthumanval(const char *fmt, int64_t bytes) 427dd6d33e8SMichael Haro { 4287d3940bbSPawel Jakub Dawidek char buf[6]; 4297d3940bbSPawel Jakub Dawidek int flags; 430dd6d33e8SMichael Haro 4317d3940bbSPawel Jakub Dawidek flags = HN_B | HN_NOSPACE | HN_DECIMAL; 4327d3940bbSPawel Jakub Dawidek if (hflag == UNITS_SI) 4337d3940bbSPawel Jakub Dawidek flags |= HN_DIVISOR_1000; 434dd6d33e8SMichael Haro 4357d3940bbSPawel Jakub Dawidek humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), 4367d3940bbSPawel Jakub Dawidek bytes, "", HN_AUTOSCALE, flags); 4377d3940bbSPawel Jakub Dawidek 438b6ff8745SMarcel Moolenaar xo_attr("value", "%lld", (long long) bytes); 439b6ff8745SMarcel Moolenaar xo_emit(fmt, buf); 440dd6d33e8SMichael Haro } 441dd6d33e8SMichael Haro 442dd6d33e8SMichael Haro /* 443b93ce3b7SSimon L. B. Nielsen * Print an inode count in "human-readable" format. 444b93ce3b7SSimon L. B. Nielsen */ 445b93ce3b7SSimon L. B. Nielsen static void 446b6ff8745SMarcel Moolenaar prthumanvalinode(const char *fmt, int64_t bytes) 447b93ce3b7SSimon L. B. Nielsen { 448b93ce3b7SSimon L. B. Nielsen char buf[6]; 449b93ce3b7SSimon L. B. Nielsen int flags; 450b93ce3b7SSimon L. B. Nielsen 451b93ce3b7SSimon L. B. Nielsen flags = HN_NOSPACE | HN_DECIMAL | HN_DIVISOR_1000; 452b93ce3b7SSimon L. B. Nielsen 453b93ce3b7SSimon L. B. Nielsen humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), 454b93ce3b7SSimon L. B. Nielsen bytes, "", HN_AUTOSCALE, flags); 455b93ce3b7SSimon L. B. Nielsen 456b6ff8745SMarcel Moolenaar xo_attr("value", "%lld", (long long) bytes); 457b6ff8745SMarcel Moolenaar xo_emit(fmt, buf); 458b93ce3b7SSimon L. B. Nielsen } 459b93ce3b7SSimon L. B. Nielsen 460b93ce3b7SSimon L. B. Nielsen /* 4614b88c807SRodney W. Grimes * Convert statfs returned file system size into BLOCKSIZE units. 4624b88c807SRodney W. Grimes */ 463841fe8e8SDavid Schultz static intmax_t 464841fe8e8SDavid Schultz fsbtoblk(int64_t num, uint64_t fsbs, u_long bs) 465841fe8e8SDavid Schultz { 4666b7aceb8SGreg Lehey return (num * (intmax_t) fsbs / (int64_t) bs); 467841fe8e8SDavid Schultz } 4684b88c807SRodney W. Grimes 4694b88c807SRodney W. Grimes /* 4704b88c807SRodney W. Grimes * Print out status about a file system. 4714b88c807SRodney W. Grimes */ 472532aff98SPoul-Henning Kamp static void 47362edbd31SIan Dowse prtstat(struct statfs *sfsp, struct maxwidths *mwp) 4744b88c807SRodney W. Grimes { 4752897dce8SAlexander Kabaev static long blocksize; 476b7dbd3e9SMark Murray static int headerlen, timesthrough = 0; 477a95a13bbSKris Kennaway static const char *header; 478fde81c7dSKirk McKusick int64_t used, availblks, inodes; 479019e4a53SGreg Lehey const char *format; 4804b88c807SRodney W. Grimes 4814b88c807SRodney W. Grimes if (++timesthrough == 1) { 4820bd9f151SIan Dowse mwp->mntfrom = imax(mwp->mntfrom, (int)strlen("Filesystem")); 483b56ca465SPawel Jakub Dawidek mwp->fstype = imax(mwp->fstype, (int)strlen("Type")); 484019e4a53SGreg Lehey if (thousands) { /* make space for commas */ 485019e4a53SGreg Lehey mwp->total += (mwp->total - 1) / 3; 486019e4a53SGreg Lehey mwp->used += (mwp->used - 1) / 3; 487019e4a53SGreg Lehey mwp->avail += (mwp->avail - 1) / 3; 488019e4a53SGreg Lehey mwp->iused += (mwp->iused - 1) / 3; 489019e4a53SGreg Lehey mwp->ifree += (mwp->ifree - 1) / 3; 490019e4a53SGreg Lehey } 491dd6d33e8SMichael Haro if (hflag) { 492dd6d33e8SMichael Haro header = " Size"; 4930bd9f151SIan Dowse mwp->total = mwp->used = mwp->avail = 4940bd9f151SIan Dowse (int)strlen(header); 495dd6d33e8SMichael Haro } else { 496dd6d33e8SMichael Haro header = getbsize(&headerlen, &blocksize); 4970bd9f151SIan Dowse mwp->total = imax(mwp->total, headerlen); 498dd6d33e8SMichael Haro } 4990bd9f151SIan Dowse mwp->used = imax(mwp->used, (int)strlen("Used")); 5000bd9f151SIan Dowse mwp->avail = imax(mwp->avail, (int)strlen("Avail")); 50162edbd31SIan Dowse 502b6ff8745SMarcel Moolenaar xo_emit("{T:/%-*s}", mwp->mntfrom, "Filesystem"); 503b56ca465SPawel Jakub Dawidek if (Tflag) 504b6ff8745SMarcel Moolenaar xo_emit(" {T:/%-*s}", mwp->fstype, "Type"); 505dfde8e4bSPhil Shafer xo_emit(" {T:/%*s} {T:/%*s} {T:/%*s} {T:Capacity}", 506b6ff8745SMarcel Moolenaar mwp->total, header, 5070bd9f151SIan Dowse mwp->used, "Used", mwp->avail, "Avail"); 50862edbd31SIan Dowse if (iflag) { 509b93ce3b7SSimon L. B. Nielsen mwp->iused = imax(hflag ? 0 : mwp->iused, 510b93ce3b7SSimon L. B. Nielsen (int)strlen(" iused")); 511b93ce3b7SSimon L. B. Nielsen mwp->ifree = imax(hflag ? 0 : mwp->ifree, 512b93ce3b7SSimon L. B. Nielsen (int)strlen("ifree")); 513b6ff8745SMarcel Moolenaar xo_emit(" {T:/%*s} {T:/%*s} {T:\%iused}", 5140bd9f151SIan Dowse mwp->iused - 2, "iused", mwp->ifree, "ifree"); 51562edbd31SIan Dowse } 516b6ff8745SMarcel Moolenaar xo_emit(" {T:Mounted on}\n"); 5174b88c807SRodney W. Grimes } 518b6ff8745SMarcel Moolenaar 519b6ff8745SMarcel Moolenaar xo_open_instance("filesystem"); 52071cfc678SGreg Lehey /* Check for 0 block size. Can this happen? */ 52171cfc678SGreg Lehey if (sfsp->f_bsize == 0) { 522b6ff8745SMarcel Moolenaar xo_warnx ("File system %s does not have a block size, assuming 512.", 52371cfc678SGreg Lehey sfsp->f_mntonname); 52471cfc678SGreg Lehey sfsp->f_bsize = 512; 52571cfc678SGreg Lehey } 526b6ff8745SMarcel Moolenaar xo_emit("{tk:name/%-*s}", mwp->mntfrom, sfsp->f_mntfromname); 527b56ca465SPawel Jakub Dawidek if (Tflag) 528b6ff8745SMarcel Moolenaar xo_emit(" {:type/%-*s}", mwp->fstype, sfsp->f_fstypename); 5294b88c807SRodney W. Grimes used = sfsp->f_blocks - sfsp->f_bfree; 5304b88c807SRodney W. Grimes availblks = sfsp->f_bavail + used; 531dd6d33e8SMichael Haro if (hflag) { 532dd6d33e8SMichael Haro prthuman(sfsp, used); 533dd6d33e8SMichael Haro } else { 534019e4a53SGreg Lehey if (thousands) 535b6ff8745SMarcel Moolenaar format = " {t:total-blocks/%*j'd} {t:used-blocks/%*j'd} " 536b6ff8745SMarcel Moolenaar "{t:available-blocks/%*j'd}"; 537019e4a53SGreg Lehey else 538b6ff8745SMarcel Moolenaar format = " {t:total-blocks/%*jd} {t:used-blocks/%*jd} " 539b6ff8745SMarcel Moolenaar "{t:available-blocks/%*jd}"; 540b6ff8745SMarcel Moolenaar xo_emit(format, 541841fe8e8SDavid Schultz mwp->total, fsbtoblk(sfsp->f_blocks, 5420bd9f151SIan Dowse sfsp->f_bsize, blocksize), 543841fe8e8SDavid Schultz mwp->used, fsbtoblk(used, sfsp->f_bsize, blocksize), 544841fe8e8SDavid Schultz mwp->avail, fsbtoblk(sfsp->f_bavail, 5450bd9f151SIan Dowse sfsp->f_bsize, blocksize)); 546dd6d33e8SMichael Haro } 547b6ff8745SMarcel Moolenaar xo_emit(" {:used-percent/%5.0f}{U:%%}", 5484b88c807SRodney W. Grimes availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0); 5494b88c807SRodney W. Grimes if (iflag) { 5504b88c807SRodney W. Grimes inodes = sfsp->f_files; 5514b88c807SRodney W. Grimes used = inodes - sfsp->f_ffree; 552b93ce3b7SSimon L. B. Nielsen if (hflag) { 553b6ff8745SMarcel Moolenaar xo_emit(" "); 554b6ff8745SMarcel Moolenaar prthumanvalinode(" {:inodes-used/%5s}", used); 555b6ff8745SMarcel Moolenaar prthumanvalinode(" {:inodes-free/%5s}", sfsp->f_ffree); 556b93ce3b7SSimon L. B. Nielsen } else { 557019e4a53SGreg Lehey if (thousands) 558b6ff8745SMarcel Moolenaar format = " {:inodes-used/%*j'd} {:inodes-free/%*j'd}"; 559019e4a53SGreg Lehey else 560b6ff8745SMarcel Moolenaar format = " {:inodes-used/%*jd} {:inodes-free/%*jd}"; 561b6ff8745SMarcel Moolenaar xo_emit(format, mwp->iused, (intmax_t)used, 562b93ce3b7SSimon L. B. Nielsen mwp->ifree, (intmax_t)sfsp->f_ffree); 563b93ce3b7SSimon L. B. Nielsen } 564b6ff8745SMarcel Moolenaar xo_emit(" {:inodes-used-percent/%4.0f}{U:%%} ", 565b6ff8745SMarcel Moolenaar inodes == 0 ? 100.0 : 5660bd9f151SIan Dowse (double)used / (double)inodes * 100.0); 567cca108e6SDavid E. O'Brien } else 568b6ff8745SMarcel Moolenaar xo_emit(" "); 569c6f13844SDavid E. O'Brien if (strncmp(sfsp->f_mntfromname, "total", MNAMELEN) != 0) 570b6ff8745SMarcel Moolenaar xo_emit(" {:mounted-on}", sfsp->f_mntonname); 571b6ff8745SMarcel Moolenaar xo_emit("\n"); 572b6ff8745SMarcel Moolenaar xo_close_instance("filesystem"); 573076419d2SDavid E. O'Brien } 574076419d2SDavid E. O'Brien 575431586a8SXin LI static void 576076419d2SDavid E. O'Brien addstat(struct statfs *totalfsp, struct statfs *statfsp) 577076419d2SDavid E. O'Brien { 578c6f13844SDavid E. O'Brien uint64_t bsize; 579076419d2SDavid E. O'Brien 580c6f13844SDavid E. O'Brien bsize = statfsp->f_bsize / totalfsp->f_bsize; 581076419d2SDavid E. O'Brien totalfsp->f_blocks += statfsp->f_blocks * bsize; 582076419d2SDavid E. O'Brien totalfsp->f_bfree += statfsp->f_bfree * bsize; 583076419d2SDavid E. O'Brien totalfsp->f_bavail += statfsp->f_bavail * bsize; 584076419d2SDavid E. O'Brien totalfsp->f_files += statfsp->f_files; 585076419d2SDavid E. O'Brien totalfsp->f_ffree += statfsp->f_ffree; 5864b88c807SRodney W. Grimes } 5874b88c807SRodney W. Grimes 5884b88c807SRodney W. Grimes /* 58962edbd31SIan Dowse * Update the maximum field-width information in `mwp' based on 59062edbd31SIan Dowse * the file system specified by `sfsp'. 59162edbd31SIan Dowse */ 592532aff98SPoul-Henning Kamp static void 593b7dbd3e9SMark Murray update_maxwidths(struct maxwidths *mwp, const struct statfs *sfsp) 59462edbd31SIan Dowse { 5952897dce8SAlexander Kabaev static long blocksize = 0; 596dc474219SMike Barcroft int dummy; 59762edbd31SIan Dowse 59862edbd31SIan Dowse if (blocksize == 0) 59962edbd31SIan Dowse getbsize(&dummy, &blocksize); 60062edbd31SIan Dowse 6010bd9f151SIan Dowse mwp->mntfrom = imax(mwp->mntfrom, (int)strlen(sfsp->f_mntfromname)); 602b56ca465SPawel Jakub Dawidek mwp->fstype = imax(mwp->fstype, (int)strlen(sfsp->f_fstypename)); 6030bd9f151SIan Dowse mwp->total = imax(mwp->total, int64width( 604fde81c7dSKirk McKusick fsbtoblk((int64_t)sfsp->f_blocks, sfsp->f_bsize, blocksize))); 6050bd9f151SIan Dowse mwp->used = imax(mwp->used, 6060bd9f151SIan Dowse int64width(fsbtoblk((int64_t)sfsp->f_blocks - 607fde81c7dSKirk McKusick (int64_t)sfsp->f_bfree, sfsp->f_bsize, blocksize))); 6080bd9f151SIan Dowse mwp->avail = imax(mwp->avail, int64width(fsbtoblk(sfsp->f_bavail, 60962edbd31SIan Dowse sfsp->f_bsize, blocksize))); 6100bd9f151SIan Dowse mwp->iused = imax(mwp->iused, int64width((int64_t)sfsp->f_files - 61162edbd31SIan Dowse sfsp->f_ffree)); 6120bd9f151SIan Dowse mwp->ifree = imax(mwp->ifree, int64width(sfsp->f_ffree)); 61362edbd31SIan Dowse } 61462edbd31SIan Dowse 6150bd9f151SIan Dowse /* Return the width in characters of the specified value. */ 6160bd9f151SIan Dowse static int 617fde81c7dSKirk McKusick int64width(int64_t val) 61862edbd31SIan Dowse { 6190bd9f151SIan Dowse int len; 62062edbd31SIan Dowse 62162edbd31SIan Dowse len = 0; 62262edbd31SIan Dowse /* Negative or zero values require one extra digit. */ 62362edbd31SIan Dowse if (val <= 0) { 62462edbd31SIan Dowse val = -val; 62562edbd31SIan Dowse len++; 62662edbd31SIan Dowse } 62762edbd31SIan Dowse while (val > 0) { 62862edbd31SIan Dowse len++; 62962edbd31SIan Dowse val /= 10; 63062edbd31SIan Dowse } 63162edbd31SIan Dowse 63262edbd31SIan Dowse return (len); 63362edbd31SIan Dowse } 63462edbd31SIan Dowse 635532aff98SPoul-Henning Kamp static void 636f9bcb0beSWarner Losh usage(void) 6374b88c807SRodney W. Grimes { 638dd6d33e8SMichael Haro 639b6ff8745SMarcel Moolenaar xo_error( 6407eb55d4dSXin LI "usage: df [-b | -g | -H | -h | -k | -m | -P] [-acilnT] [-t type] [-,]\n" 6417eb55d4dSXin LI " [file | filesystem ...]\n"); 642dd6d33e8SMichael Haro exit(EX_USAGE); 6434b88c807SRodney W. Grimes } 644a25695c3SJim Pirzyk 645532aff98SPoul-Henning Kamp static char * 646f9bcb0beSWarner Losh makenetvfslist(void) 647a25695c3SJim Pirzyk { 648a25695c3SJim Pirzyk char *str, *strptr, **listptr; 649b7dbd3e9SMark Murray struct xvfsconf *xvfsp, *keep_xvfsp; 6505965373eSMaxime Henrion size_t buflen; 6515965373eSMaxime Henrion int cnt, i, maxvfsconf; 652a25695c3SJim Pirzyk 6535965373eSMaxime Henrion if (sysctlbyname("vfs.conflist", NULL, &buflen, NULL, 0) < 0) { 654b6ff8745SMarcel Moolenaar xo_warn("sysctl(vfs.conflist)"); 655a25695c3SJim Pirzyk return (NULL); 656a25695c3SJim Pirzyk } 6575965373eSMaxime Henrion xvfsp = malloc(buflen); 6585965373eSMaxime Henrion if (xvfsp == NULL) { 659b6ff8745SMarcel Moolenaar xo_warnx("malloc failed"); 6605965373eSMaxime Henrion return (NULL); 6615965373eSMaxime Henrion } 662b7dbd3e9SMark Murray keep_xvfsp = xvfsp; 6635965373eSMaxime Henrion if (sysctlbyname("vfs.conflist", xvfsp, &buflen, NULL, 0) < 0) { 664b6ff8745SMarcel Moolenaar xo_warn("sysctl(vfs.conflist)"); 665b7dbd3e9SMark Murray free(keep_xvfsp); 6665965373eSMaxime Henrion return (NULL); 6675965373eSMaxime Henrion } 6685965373eSMaxime Henrion maxvfsconf = buflen / sizeof(struct xvfsconf); 669a25695c3SJim Pirzyk 670a25695c3SJim Pirzyk if ((listptr = malloc(sizeof(char*) * maxvfsconf)) == NULL) { 671b6ff8745SMarcel Moolenaar xo_warnx("malloc failed"); 672b7dbd3e9SMark Murray free(keep_xvfsp); 673a25695c3SJim Pirzyk return (NULL); 674a25695c3SJim Pirzyk } 675a25695c3SJim Pirzyk 6765965373eSMaxime Henrion for (cnt = 0, i = 0; i < maxvfsconf; i++) { 6775965373eSMaxime Henrion if (xvfsp->vfc_flags & VFCF_NETWORK) { 6785965373eSMaxime Henrion listptr[cnt++] = strdup(xvfsp->vfc_name); 679a067aeceSGarrett Wollman if (listptr[cnt-1] == NULL) { 680b6ff8745SMarcel Moolenaar xo_warnx("malloc failed"); 681b7dbd3e9SMark Murray free(listptr); 682b7dbd3e9SMark Murray free(keep_xvfsp); 683a25695c3SJim Pirzyk return (NULL); 684a25695c3SJim Pirzyk } 685a25695c3SJim Pirzyk } 6865965373eSMaxime Henrion xvfsp++; 6875965373eSMaxime Henrion } 688a25695c3SJim Pirzyk 689cf5b29e1SRuslan Ermilov if (cnt == 0 || 690cf5b29e1SRuslan Ermilov (str = malloc(sizeof(char) * (32 * cnt + cnt + 2))) == NULL) { 691cf5b29e1SRuslan Ermilov if (cnt > 0) 692b6ff8745SMarcel Moolenaar xo_warnx("malloc failed"); 693a25695c3SJim Pirzyk free(listptr); 694b7dbd3e9SMark Murray free(keep_xvfsp); 695a25695c3SJim Pirzyk return (NULL); 696a25695c3SJim Pirzyk } 697a25695c3SJim Pirzyk 698a25695c3SJim Pirzyk *str = 'n'; *(str + 1) = 'o'; 699a25695c3SJim Pirzyk for (i = 0, strptr = str + 2; i < cnt; i++, strptr++) { 700d7c881e8SWarner Losh strlcpy(strptr, listptr[i], 32); 701a25695c3SJim Pirzyk strptr += strlen(listptr[i]); 702a25695c3SJim Pirzyk *strptr = ','; 703a25695c3SJim Pirzyk free(listptr[i]); 704a25695c3SJim Pirzyk } 70516fc3635SMark Murray *(--strptr) = '\0'; 706a25695c3SJim Pirzyk 707b7dbd3e9SMark Murray free(keep_xvfsp); 708a25695c3SJim Pirzyk free(listptr); 709a25695c3SJim Pirzyk return (str); 710a25695c3SJim Pirzyk } 711