bdd5bccf11
Use exit() instead of return in main(). The difference in practice is subtle: C standard requires the language runtime to make return of int from main() behave like calling exit(), and in FreeBSD we do: exit(main(argc, argv, env)) In lib/csu/${ARCH}/crt1.c, so the real difference is using exit() explicitly would use an additional stack frame. Note however, if there is a on stack pointer is the last reference of an allocated memory block, returning from the function would, technically, result in a memory leak because we lost the last reference to the memory block, and calling exit() from C runtime could potentionally overwrite that stack frame that used to belong to the main() function. In practice, this is normally Okay because eventually the kernel would tear down the whole address space that belongs to the process in the _exit(2) system call, but the difference could confuse compilers (which may want to do stack overflow checks) and static analyzers. Replacing return with exit() in main() allows compilers/static analyzers to correctly omit or generate the right warnings when they do not treat main() specifically. With the current version of clang on FreeBSD/amd64, use of exit() would result in slightly smaller code being generated and eliminated a false positive warning of memory leak.
639 lines
16 KiB
C
639 lines
16 KiB
C
/*-
|
|
* Copyright (c) 1980, 1990, 1993, 1994
|
|
* The Regents of the University of California. All rights reserved.
|
|
* (c) UNIX System Laboratories, Inc.
|
|
* All or some portions of this file are derived from material licensed
|
|
* to the University of California by American Telephone and Telegraph
|
|
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
|
* the permission of UNIX System Laboratories, Inc.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#if 0
|
|
#ifndef lint
|
|
static const char copyright[] =
|
|
"@(#) Copyright (c) 1980, 1990, 1993, 1994\n\
|
|
The Regents of the University of California. All rights reserved.\n";
|
|
#endif /* not lint */
|
|
|
|
#ifndef lint
|
|
static char sccsid[] = "@(#)df.c 8.9 (Berkeley) 5/8/95";
|
|
#endif /* not lint */
|
|
#endif
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/sysctl.h>
|
|
#include <ufs/ufs/ufsmount.h>
|
|
#include <err.h>
|
|
#include <libutil.h>
|
|
#include <locale.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sysexits.h>
|
|
#include <unistd.h>
|
|
|
|
#include "extern.h"
|
|
|
|
#define UNITS_SI 1
|
|
#define UNITS_2 2
|
|
|
|
/* Maximum widths of various fields. */
|
|
struct maxwidths {
|
|
int mntfrom;
|
|
int fstype;
|
|
int total;
|
|
int used;
|
|
int avail;
|
|
int iused;
|
|
int ifree;
|
|
};
|
|
|
|
static void addstat(struct statfs *, struct statfs *);
|
|
static char *getmntpt(const char *);
|
|
static int int64width(int64_t);
|
|
static char *makenetvfslist(void);
|
|
static void prthuman(const struct statfs *, int64_t);
|
|
static void prthumanval(int64_t);
|
|
static intmax_t fsbtoblk(int64_t, uint64_t, u_long);
|
|
static void prtstat(struct statfs *, struct maxwidths *);
|
|
static size_t regetmntinfo(struct statfs **, long, const char **);
|
|
static void update_maxwidths(struct maxwidths *, const struct statfs *);
|
|
static void usage(void);
|
|
|
|
static __inline int
|
|
imax(int a, int b)
|
|
{
|
|
return (a > b ? a : b);
|
|
}
|
|
|
|
static int aflag = 0, cflag, hflag, iflag, kflag, lflag = 0, nflag, Tflag;
|
|
static int thousands;
|
|
static struct ufs_args mdev;
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
struct stat stbuf;
|
|
struct statfs statfsbuf, totalbuf;
|
|
struct maxwidths maxwidths;
|
|
struct statfs *mntbuf;
|
|
const char *fstype;
|
|
char *mntpath, *mntpt;
|
|
const char **vfslist;
|
|
int i, mntsize;
|
|
int ch, rv;
|
|
|
|
fstype = "ufs";
|
|
(void)setlocale(LC_ALL, "");
|
|
memset(&maxwidths, 0, sizeof(maxwidths));
|
|
memset(&totalbuf, 0, sizeof(totalbuf));
|
|
totalbuf.f_bsize = DEV_BSIZE;
|
|
strlcpy(totalbuf.f_mntfromname, "total", MNAMELEN);
|
|
vfslist = NULL;
|
|
while ((ch = getopt(argc, argv, "abcgHhiklmnPt:T,")) != -1)
|
|
switch (ch) {
|
|
case 'a':
|
|
aflag = 1;
|
|
break;
|
|
case 'b':
|
|
/* FALLTHROUGH */
|
|
case 'P':
|
|
/*
|
|
* POSIX specifically discusses the behavior of
|
|
* both -k and -P. It states that the blocksize should
|
|
* be set to 1024. Thus, if this occurs, simply break
|
|
* rather than clobbering the old blocksize.
|
|
*/
|
|
if (kflag)
|
|
break;
|
|
setenv("BLOCKSIZE", "512", 1);
|
|
hflag = 0;
|
|
break;
|
|
case 'c':
|
|
cflag = 1;
|
|
break;
|
|
case 'g':
|
|
setenv("BLOCKSIZE", "1g", 1);
|
|
hflag = 0;
|
|
break;
|
|
case 'H':
|
|
hflag = UNITS_SI;
|
|
break;
|
|
case 'h':
|
|
hflag = UNITS_2;
|
|
break;
|
|
case 'i':
|
|
iflag = 1;
|
|
break;
|
|
case 'k':
|
|
kflag++;
|
|
setenv("BLOCKSIZE", "1024", 1);
|
|
hflag = 0;
|
|
break;
|
|
case 'l':
|
|
if (vfslist != NULL)
|
|
errx(1, "-l and -t are mutually exclusive.");
|
|
vfslist = makevfslist(makenetvfslist());
|
|
lflag = 1;
|
|
break;
|
|
case 'm':
|
|
setenv("BLOCKSIZE", "1m", 1);
|
|
hflag = 0;
|
|
break;
|
|
case 'n':
|
|
nflag = 1;
|
|
break;
|
|
case 't':
|
|
if (lflag)
|
|
errx(1, "-l and -t are mutually exclusive.");
|
|
if (vfslist != NULL)
|
|
errx(1, "only one -t option may be specified");
|
|
fstype = optarg;
|
|
vfslist = makevfslist(optarg);
|
|
break;
|
|
case 'T':
|
|
Tflag = 1;
|
|
break;
|
|
case ',':
|
|
thousands = 1;
|
|
break;
|
|
case '?':
|
|
default:
|
|
usage();
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
rv = 0;
|
|
if (!*argv) {
|
|
/* everything (modulo -t) */
|
|
mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
|
|
mntsize = regetmntinfo(&mntbuf, mntsize, vfslist);
|
|
} else {
|
|
/* just the filesystems specified on the command line */
|
|
mntbuf = malloc(argc * sizeof(*mntbuf));
|
|
if (mntbuf == NULL)
|
|
err(1, "malloc()");
|
|
mntsize = 0;
|
|
/* continued in for loop below */
|
|
}
|
|
|
|
/* iterate through specified filesystems */
|
|
for (; *argv; argv++) {
|
|
if (stat(*argv, &stbuf) < 0) {
|
|
if ((mntpt = getmntpt(*argv)) == NULL) {
|
|
warn("%s", *argv);
|
|
rv = 1;
|
|
continue;
|
|
}
|
|
} else if (S_ISCHR(stbuf.st_mode)) {
|
|
if ((mntpt = getmntpt(*argv)) == NULL) {
|
|
mdev.fspec = *argv;
|
|
mntpath = strdup("/tmp/df.XXXXXX");
|
|
if (mntpath == NULL) {
|
|
warn("strdup failed");
|
|
rv = 1;
|
|
continue;
|
|
}
|
|
mntpt = mkdtemp(mntpath);
|
|
if (mntpt == NULL) {
|
|
warn("mkdtemp(\"%s\") failed", mntpath);
|
|
rv = 1;
|
|
free(mntpath);
|
|
continue;
|
|
}
|
|
if (mount(fstype, mntpt, MNT_RDONLY,
|
|
&mdev) != 0) {
|
|
warn("%s", *argv);
|
|
rv = 1;
|
|
(void)rmdir(mntpt);
|
|
free(mntpath);
|
|
continue;
|
|
} else if (statfs(mntpt, &statfsbuf) == 0) {
|
|
statfsbuf.f_mntonname[0] = '\0';
|
|
prtstat(&statfsbuf, &maxwidths);
|
|
if (cflag)
|
|
addstat(&totalbuf, &statfsbuf);
|
|
} else {
|
|
warn("%s", *argv);
|
|
rv = 1;
|
|
}
|
|
(void)unmount(mntpt, 0);
|
|
(void)rmdir(mntpt);
|
|
free(mntpath);
|
|
continue;
|
|
}
|
|
} else
|
|
mntpt = *argv;
|
|
|
|
/*
|
|
* Statfs does not take a `wait' flag, so we cannot
|
|
* implement nflag here.
|
|
*/
|
|
if (statfs(mntpt, &statfsbuf) < 0) {
|
|
warn("%s", mntpt);
|
|
rv = 1;
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Check to make sure the arguments we've been given are
|
|
* satisfied. Return an error if we have been asked to
|
|
* list a mount point that does not match the other args
|
|
* we've been given (-l, -t, etc.).
|
|
*/
|
|
if (checkvfsname(statfsbuf.f_fstypename, vfslist)) {
|
|
rv = 1;
|
|
continue;
|
|
}
|
|
|
|
/* the user asked for it, so ignore the ignore flag */
|
|
statfsbuf.f_flags &= ~MNT_IGNORE;
|
|
|
|
/* add to list */
|
|
mntbuf[mntsize++] = statfsbuf;
|
|
}
|
|
|
|
memset(&maxwidths, 0, sizeof(maxwidths));
|
|
for (i = 0; i < mntsize; i++) {
|
|
if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0) {
|
|
update_maxwidths(&maxwidths, &mntbuf[i]);
|
|
if (cflag)
|
|
addstat(&totalbuf, &mntbuf[i]);
|
|
}
|
|
}
|
|
for (i = 0; i < mntsize; i++)
|
|
if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0)
|
|
prtstat(&mntbuf[i], &maxwidths);
|
|
if (cflag)
|
|
prtstat(&totalbuf, &maxwidths);
|
|
exit(rv);
|
|
}
|
|
|
|
static char *
|
|
getmntpt(const char *name)
|
|
{
|
|
size_t mntsize, i;
|
|
struct statfs *mntbuf;
|
|
|
|
mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
|
|
for (i = 0; i < mntsize; i++) {
|
|
if (!strcmp(mntbuf[i].f_mntfromname, name))
|
|
return (mntbuf[i].f_mntonname);
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
/*
|
|
* Make a pass over the file system info in ``mntbuf'' filtering out
|
|
* file system types not in vfslist and possibly re-stating to get
|
|
* current (not cached) info. Returns the new count of valid statfs bufs.
|
|
*/
|
|
static size_t
|
|
regetmntinfo(struct statfs **mntbufp, long mntsize, const char **vfslist)
|
|
{
|
|
int error, i, j;
|
|
struct statfs *mntbuf;
|
|
|
|
if (vfslist == NULL)
|
|
return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT));
|
|
|
|
mntbuf = *mntbufp;
|
|
for (j = 0, i = 0; i < mntsize; i++) {
|
|
if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
|
|
continue;
|
|
/*
|
|
* XXX statfs(2) can fail for various reasons. It may be
|
|
* possible that the user does not have access to the
|
|
* pathname, if this happens, we will fall back on
|
|
* "stale" filesystem statistics.
|
|
*/
|
|
error = statfs(mntbuf[i].f_mntonname, &mntbuf[j]);
|
|
if (nflag || error < 0)
|
|
if (i != j) {
|
|
if (error < 0)
|
|
warnx("%s stats possibly stale",
|
|
mntbuf[i].f_mntonname);
|
|
mntbuf[j] = mntbuf[i];
|
|
}
|
|
j++;
|
|
}
|
|
return (j);
|
|
}
|
|
|
|
static void
|
|
prthuman(const struct statfs *sfsp, int64_t used)
|
|
{
|
|
|
|
prthumanval(sfsp->f_blocks * sfsp->f_bsize);
|
|
prthumanval(used * sfsp->f_bsize);
|
|
prthumanval(sfsp->f_bavail * sfsp->f_bsize);
|
|
}
|
|
|
|
static void
|
|
prthumanval(int64_t bytes)
|
|
{
|
|
char buf[6];
|
|
int flags;
|
|
|
|
flags = HN_B | HN_NOSPACE | HN_DECIMAL;
|
|
if (hflag == UNITS_SI)
|
|
flags |= HN_DIVISOR_1000;
|
|
|
|
humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1),
|
|
bytes, "", HN_AUTOSCALE, flags);
|
|
|
|
(void)printf(" %6s", buf);
|
|
}
|
|
|
|
/*
|
|
* Print an inode count in "human-readable" format.
|
|
*/
|
|
static void
|
|
prthumanvalinode(int64_t bytes)
|
|
{
|
|
char buf[6];
|
|
int flags;
|
|
|
|
flags = HN_NOSPACE | HN_DECIMAL | HN_DIVISOR_1000;
|
|
|
|
humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1),
|
|
bytes, "", HN_AUTOSCALE, flags);
|
|
|
|
(void)printf(" %5s", buf);
|
|
}
|
|
|
|
/*
|
|
* Convert statfs returned file system size into BLOCKSIZE units.
|
|
*/
|
|
static intmax_t
|
|
fsbtoblk(int64_t num, uint64_t fsbs, u_long bs)
|
|
{
|
|
return (num * (intmax_t) fsbs / (int64_t) bs);
|
|
}
|
|
|
|
/*
|
|
* Print out status about a file system.
|
|
*/
|
|
static void
|
|
prtstat(struct statfs *sfsp, struct maxwidths *mwp)
|
|
{
|
|
static long blocksize;
|
|
static int headerlen, timesthrough = 0;
|
|
static const char *header;
|
|
int64_t used, availblks, inodes;
|
|
const char *format;
|
|
|
|
if (++timesthrough == 1) {
|
|
mwp->mntfrom = imax(mwp->mntfrom, (int)strlen("Filesystem"));
|
|
mwp->fstype = imax(mwp->fstype, (int)strlen("Type"));
|
|
if (thousands) { /* make space for commas */
|
|
mwp->total += (mwp->total - 1) / 3;
|
|
mwp->used += (mwp->used - 1) / 3;
|
|
mwp->avail += (mwp->avail - 1) / 3;
|
|
mwp->iused += (mwp->iused - 1) / 3;
|
|
mwp->ifree += (mwp->ifree - 1) / 3;
|
|
}
|
|
if (hflag) {
|
|
header = " Size";
|
|
mwp->total = mwp->used = mwp->avail =
|
|
(int)strlen(header);
|
|
} else {
|
|
header = getbsize(&headerlen, &blocksize);
|
|
mwp->total = imax(mwp->total, headerlen);
|
|
}
|
|
mwp->used = imax(mwp->used, (int)strlen("Used"));
|
|
mwp->avail = imax(mwp->avail, (int)strlen("Avail"));
|
|
|
|
(void)printf("%-*s", mwp->mntfrom, "Filesystem");
|
|
if (Tflag)
|
|
(void)printf(" %-*s", mwp->fstype, "Type");
|
|
(void)printf(" %*s %*s %*s Capacity", mwp->total, header,
|
|
mwp->used, "Used", mwp->avail, "Avail");
|
|
if (iflag) {
|
|
mwp->iused = imax(hflag ? 0 : mwp->iused,
|
|
(int)strlen(" iused"));
|
|
mwp->ifree = imax(hflag ? 0 : mwp->ifree,
|
|
(int)strlen("ifree"));
|
|
(void)printf(" %*s %*s %%iused",
|
|
mwp->iused - 2, "iused", mwp->ifree, "ifree");
|
|
}
|
|
(void)printf(" Mounted on\n");
|
|
}
|
|
/* Check for 0 block size. Can this happen? */
|
|
if (sfsp->f_bsize == 0) {
|
|
warnx ("File system %s does not have a block size, assuming 512.",
|
|
sfsp->f_mntonname);
|
|
sfsp->f_bsize = 512;
|
|
}
|
|
(void)printf("%-*s", mwp->mntfrom, sfsp->f_mntfromname);
|
|
if (Tflag)
|
|
(void)printf(" %-*s", mwp->fstype, sfsp->f_fstypename);
|
|
used = sfsp->f_blocks - sfsp->f_bfree;
|
|
availblks = sfsp->f_bavail + used;
|
|
if (hflag) {
|
|
prthuman(sfsp, used);
|
|
} else {
|
|
if (thousands)
|
|
format = " %*j'd %*j'd %*j'd";
|
|
else
|
|
format = " %*jd %*jd %*jd";
|
|
(void)printf(format,
|
|
mwp->total, fsbtoblk(sfsp->f_blocks,
|
|
sfsp->f_bsize, blocksize),
|
|
mwp->used, fsbtoblk(used, sfsp->f_bsize, blocksize),
|
|
mwp->avail, fsbtoblk(sfsp->f_bavail,
|
|
sfsp->f_bsize, blocksize));
|
|
}
|
|
(void)printf(" %5.0f%%",
|
|
availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
|
|
if (iflag) {
|
|
inodes = sfsp->f_files;
|
|
used = inodes - sfsp->f_ffree;
|
|
if (hflag) {
|
|
(void)printf(" ");
|
|
prthumanvalinode(used);
|
|
prthumanvalinode(sfsp->f_ffree);
|
|
} else {
|
|
if (thousands)
|
|
format = " %*j'd %*j'd";
|
|
else
|
|
format = " %*jd %*jd";
|
|
(void)printf(format, mwp->iused, (intmax_t)used,
|
|
mwp->ifree, (intmax_t)sfsp->f_ffree);
|
|
}
|
|
(void)printf(" %4.0f%% ", inodes == 0 ? 100.0 :
|
|
(double)used / (double)inodes * 100.0);
|
|
} else
|
|
(void)printf(" ");
|
|
if (strncmp(sfsp->f_mntfromname, "total", MNAMELEN) != 0)
|
|
(void)printf(" %s", sfsp->f_mntonname);
|
|
(void)printf("\n");
|
|
}
|
|
|
|
static void
|
|
addstat(struct statfs *totalfsp, struct statfs *statfsp)
|
|
{
|
|
uint64_t bsize;
|
|
|
|
bsize = statfsp->f_bsize / totalfsp->f_bsize;
|
|
totalfsp->f_blocks += statfsp->f_blocks * bsize;
|
|
totalfsp->f_bfree += statfsp->f_bfree * bsize;
|
|
totalfsp->f_bavail += statfsp->f_bavail * bsize;
|
|
totalfsp->f_files += statfsp->f_files;
|
|
totalfsp->f_ffree += statfsp->f_ffree;
|
|
}
|
|
|
|
/*
|
|
* Update the maximum field-width information in `mwp' based on
|
|
* the file system specified by `sfsp'.
|
|
*/
|
|
static void
|
|
update_maxwidths(struct maxwidths *mwp, const struct statfs *sfsp)
|
|
{
|
|
static long blocksize = 0;
|
|
int dummy;
|
|
|
|
if (blocksize == 0)
|
|
getbsize(&dummy, &blocksize);
|
|
|
|
mwp->mntfrom = imax(mwp->mntfrom, (int)strlen(sfsp->f_mntfromname));
|
|
mwp->fstype = imax(mwp->fstype, (int)strlen(sfsp->f_fstypename));
|
|
mwp->total = imax(mwp->total, int64width(
|
|
fsbtoblk((int64_t)sfsp->f_blocks, sfsp->f_bsize, blocksize)));
|
|
mwp->used = imax(mwp->used,
|
|
int64width(fsbtoblk((int64_t)sfsp->f_blocks -
|
|
(int64_t)sfsp->f_bfree, sfsp->f_bsize, blocksize)));
|
|
mwp->avail = imax(mwp->avail, int64width(fsbtoblk(sfsp->f_bavail,
|
|
sfsp->f_bsize, blocksize)));
|
|
mwp->iused = imax(mwp->iused, int64width((int64_t)sfsp->f_files -
|
|
sfsp->f_ffree));
|
|
mwp->ifree = imax(mwp->ifree, int64width(sfsp->f_ffree));
|
|
}
|
|
|
|
/* Return the width in characters of the specified value. */
|
|
static int
|
|
int64width(int64_t val)
|
|
{
|
|
int len;
|
|
|
|
len = 0;
|
|
/* Negative or zero values require one extra digit. */
|
|
if (val <= 0) {
|
|
val = -val;
|
|
len++;
|
|
}
|
|
while (val > 0) {
|
|
len++;
|
|
val /= 10;
|
|
}
|
|
|
|
return (len);
|
|
}
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
|
|
(void)fprintf(stderr,
|
|
"usage: df [-b | -g | -H | -h | -k | -m | -P] [-acilnT] [-t type] [-,]\n"
|
|
" [file | filesystem ...]\n");
|
|
exit(EX_USAGE);
|
|
}
|
|
|
|
static char *
|
|
makenetvfslist(void)
|
|
{
|
|
char *str, *strptr, **listptr;
|
|
struct xvfsconf *xvfsp, *keep_xvfsp;
|
|
size_t buflen;
|
|
int cnt, i, maxvfsconf;
|
|
|
|
if (sysctlbyname("vfs.conflist", NULL, &buflen, NULL, 0) < 0) {
|
|
warn("sysctl(vfs.conflist)");
|
|
return (NULL);
|
|
}
|
|
xvfsp = malloc(buflen);
|
|
if (xvfsp == NULL) {
|
|
warnx("malloc failed");
|
|
return (NULL);
|
|
}
|
|
keep_xvfsp = xvfsp;
|
|
if (sysctlbyname("vfs.conflist", xvfsp, &buflen, NULL, 0) < 0) {
|
|
warn("sysctl(vfs.conflist)");
|
|
free(keep_xvfsp);
|
|
return (NULL);
|
|
}
|
|
maxvfsconf = buflen / sizeof(struct xvfsconf);
|
|
|
|
if ((listptr = malloc(sizeof(char*) * maxvfsconf)) == NULL) {
|
|
warnx("malloc failed");
|
|
free(keep_xvfsp);
|
|
return (NULL);
|
|
}
|
|
|
|
for (cnt = 0, i = 0; i < maxvfsconf; i++) {
|
|
if (xvfsp->vfc_flags & VFCF_NETWORK) {
|
|
listptr[cnt++] = strdup(xvfsp->vfc_name);
|
|
if (listptr[cnt-1] == NULL) {
|
|
warnx("malloc failed");
|
|
free(listptr);
|
|
free(keep_xvfsp);
|
|
return (NULL);
|
|
}
|
|
}
|
|
xvfsp++;
|
|
}
|
|
|
|
if (cnt == 0 ||
|
|
(str = malloc(sizeof(char) * (32 * cnt + cnt + 2))) == NULL) {
|
|
if (cnt > 0)
|
|
warnx("malloc failed");
|
|
free(listptr);
|
|
free(keep_xvfsp);
|
|
return (NULL);
|
|
}
|
|
|
|
*str = 'n'; *(str + 1) = 'o';
|
|
for (i = 0, strptr = str + 2; i < cnt; i++, strptr++) {
|
|
strlcpy(strptr, listptr[i], 32);
|
|
strptr += strlen(listptr[i]);
|
|
*strptr = ',';
|
|
free(listptr[i]);
|
|
}
|
|
*(--strptr) = '\0';
|
|
|
|
free(keep_xvfsp);
|
|
free(listptr);
|
|
return (str);
|
|
}
|