file_cmds-116.9.tar.gz
[apple/file_cmds.git] / df / df.c
1 /*
2 * Copyright (c) 1980, 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #ifndef lint
40 static const char copyright[] =
41 "@(#) Copyright (c) 1980, 1990, 1993, 1994\n\
42 The Regents of the University of California. All rights reserved.\n";
43 #endif /* not lint */
44
45 #ifndef lint
46 #if 0
47 static char sccsid[] = "@(#)df.c 8.9 (Berkeley) 5/8/95";
48 #else
49 static const char rcsid[] =
50 "$FreeBSD: src/bin/df/df.c,v 1.23.2.9 2002/07/01 00:14:24 iedowse Exp $";
51 #endif
52 #endif /* not lint */
53
54 #ifdef __APPLE__
55 #define MNT_IGNORE 0
56 #include <sys/types.h>
57 typedef int32_t ufs_daddr_t;
58 #endif
59
60 #include <sys/cdefs.h>
61 #include <sys/param.h>
62 #include <sys/stat.h>
63 #include <sys/mount.h>
64 #include <sys/sysctl.h>
65 #include <ufs/ufs/ufsmount.h>
66 #include <ufs/ffs/fs.h>
67 #include <err.h>
68 #include <errno.h>
69 #include <fcntl.h>
70 #include <fstab.h>
71 #include <math.h>
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 #include <sysexits.h>
76 #include <unistd.h>
77
78 #ifdef __APPLE__
79 #include "get_compat.h"
80 #else
81 #define COMPAT_MODE(func, mode) 1
82 #endif
83
84 #define UNITS_SI 1
85 #define UNITS_2 2
86
87 #define KILO_SZ(n) (n)
88 #define MEGA_SZ(n) ((n) * (n))
89 #define GIGA_SZ(n) ((n) * (n) * (n))
90 #define TERA_SZ(n) ((n) * (n) * (n) * (n))
91 #define PETA_SZ(n) ((n) * (n) * (n) * (n) * (n))
92
93 #define KILO_2_SZ (KILO_SZ(1024ULL))
94 #define MEGA_2_SZ (MEGA_SZ(1024ULL))
95 #define GIGA_2_SZ (GIGA_SZ(1024ULL))
96 #define TERA_2_SZ (TERA_SZ(1024ULL))
97 #define PETA_2_SZ (PETA_SZ(1024ULL))
98
99 #define KILO_SI_SZ (KILO_SZ(1000ULL))
100 #define MEGA_SI_SZ (MEGA_SZ(1000ULL))
101 #define GIGA_SI_SZ (GIGA_SZ(1000ULL))
102 #define TERA_SI_SZ (TERA_SZ(1000ULL))
103 #define PETA_SI_SZ (PETA_SZ(1000ULL))
104
105 /* Maximum widths of various fields. */
106 struct maxwidths {
107 int mntfrom;
108 int total;
109 int used;
110 int avail;
111 int iused;
112 int ifree;
113 };
114
115 unsigned long long vals_si [] = {1, KILO_SI_SZ, MEGA_SI_SZ, GIGA_SI_SZ, TERA_SI_SZ, PETA_SI_SZ};
116 unsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ};
117 unsigned long long *valp;
118
119 typedef enum { NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX } unit_t;
120
121 unit_t unitp [] = { NONE, KILO, MEGA, GIGA, TERA, PETA };
122
123 int bread(off_t, void *, int);
124 int checkvfsname(const char *, char **);
125 char *getmntpt(char *);
126 int longwidth(long long);
127 char *makenetvfslist(void);
128 char **makevfslist(char *);
129 void prthuman(struct statfs *, long);
130 void prthumanval(double);
131 void prtstat(struct statfs *, struct maxwidths *);
132 long regetmntinfo(struct statfs **, long, char **);
133 int ufs_df(char *, struct maxwidths *);
134 unit_t unit_adjust(double *);
135 void update_maxwidths(struct maxwidths *, struct statfs *);
136 void usage(void);
137
138 int aflag = 0, hflag, iflag, nflag;
139 struct ufs_args mdev;
140
141 static __inline int imax(int a, int b)
142 {
143 return (a > b ? a : b);
144 }
145
146 int
147 main(int argc, char *argv[])
148 {
149 struct stat stbuf;
150 struct statfs statfsbuf, *mntbuf;
151 struct maxwidths maxwidths;
152 const char *fstype;
153 char *mntpath, *mntpt, **vfslist;
154 long mntsize;
155 int ch, i, rv, tflag = 0, kludge_tflag = 0;
156 const char *options = "abgHhiklmnPt:T:";
157 if (COMPAT_MODE("bin/df", "unix2003")) {
158 /* Unix2003 requires -t be "include total capicity". which df
159 already does, but it conflits with the old -t so we need to
160 *not* expect a string after -t (we provide -T in both cases
161 to cover the old use of -t) */
162 options = "abgHhiklmnPtT:";
163 }
164
165 fstype = "ufs";
166
167 vfslist = NULL;
168 while ((ch = getopt(argc, argv, options)) != -1)
169 switch (ch) {
170 case 'a':
171 aflag = 1;
172 break;
173 case 'b':
174 /* FALLTHROUGH */
175 case 'P':
176 putenv("BLOCKSIZE=512");
177 hflag = 0;
178 break;
179 case 'g':
180 putenv("BLOCKSIZE=1g");
181 hflag = 0;
182 break;
183 case 'H':
184 hflag = UNITS_SI;
185 valp = vals_si;
186 break;
187 case 'h':
188 hflag = UNITS_2;
189 valp = vals_base2;
190 break;
191 case 'i':
192 iflag = 1;
193 break;
194 case 'k':
195 putenv("BLOCKSIZE=1k");
196 hflag = 0;
197 break;
198 case 'l':
199 if (tflag)
200 errx(1, "-l and -T are mutually exclusive.");
201 if (vfslist != NULL)
202 break;
203 vfslist = makevfslist(makenetvfslist());
204 break;
205 case 'm':
206 putenv("BLOCKSIZE=1m");
207 hflag = 0;
208 break;
209 case 'n':
210 nflag = 1;
211 break;
212 case 't':
213 /* Unix2003 uses -t for something we do by default */
214 if (COMPAT_MODE("bin/df", "unix2003")) {
215 kludge_tflag = 1;
216 break;
217 }
218 case 'T':
219 if (vfslist != NULL) {
220 if (tflag)
221 errx(1, "only one -%c option may be specified", ch);
222 else
223 errx(1, "-l and -%c are mutually exclusive.", ch);
224 }
225 tflag++;
226 fstype = optarg;
227 vfslist = makevfslist(optarg);
228 break;
229 case '?':
230 default:
231 usage();
232 }
233 argc -= optind;
234 argv += optind;
235
236 /* If we are in unix2003 mode, have seen a -t but no -T and the first
237 non switch arg isn't a file, let's pretend they used -T on it.
238 This makes the Lexmark printer installer happy (PR-3918471) */
239 if (tflag == 0 && kludge_tflag && *argv && stat(*argv, &stbuf) < 0
240 && errno == ENOENT) {
241 tflag = 1;
242 fstype = *argv++;
243 vfslist = makevfslist(fstype);
244 }
245
246 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
247 bzero(&maxwidths, sizeof(maxwidths));
248 for (i = 0; i < mntsize; i++)
249 update_maxwidths(&maxwidths, &mntbuf[i]);
250
251 rv = 0;
252 if (!*argv) {
253 mntsize = regetmntinfo(&mntbuf, mntsize, vfslist);
254 bzero(&maxwidths, sizeof(maxwidths));
255 for (i = 0; i < mntsize; i++)
256 update_maxwidths(&maxwidths, &mntbuf[i]);
257 for (i = 0; i < mntsize; i++) {
258 if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0)
259 prtstat(&mntbuf[i], &maxwidths);
260 }
261 exit(rv);
262 }
263
264 for (; *argv; argv++) {
265 if (stat(*argv, &stbuf) < 0) {
266 if ((mntpt = getmntpt(*argv)) == 0) {
267 warn("%s", *argv);
268 rv = 1;
269 continue;
270 }
271 } else if (S_ISCHR(stbuf.st_mode) || S_ISBLK(stbuf.st_mode)) {
272 if ((mntpt = getmntpt(*argv)) == 0) {
273 mdev.fspec = *argv;
274 mntpath = strdup("/tmp/df.XXXXXX");
275 if (mntpath == NULL) {
276 warn("strdup failed");
277 rv = 1;
278 continue;
279 }
280 mntpt = mkdtemp(mntpath);
281 if (mntpt == NULL) {
282 warn("mkdtemp(\"%s\") failed", mntpath);
283 rv = 1;
284 free(mntpath);
285 continue;
286 }
287 if (mount(fstype, mntpt, MNT_RDONLY,
288 &mdev) != 0) {
289 rv = ufs_df(*argv, &maxwidths) || rv;
290 (void)rmdir(mntpt);
291 free(mntpath);
292 continue;
293 } else if (statfs(mntpt, &statfsbuf) == 0) {
294 statfsbuf.f_mntonname[0] = '\0';
295 prtstat(&statfsbuf, &maxwidths);
296 } else {
297 warn("%s", *argv);
298 rv = 1;
299 }
300 (void)unmount(mntpt, 0);
301 (void)rmdir(mntpt);
302 free(mntpath);
303 continue;
304 }
305 } else
306 mntpt = *argv;
307 /*
308 * Statfs does not take a `wait' flag, so we cannot
309 * implement nflag here.
310 */
311 if (statfs(mntpt, &statfsbuf) < 0) {
312 warn("%s", mntpt);
313 rv = 1;
314 continue;
315 }
316 /* Check to make sure the arguments we've been
317 * given are satisfied. Return an error if we
318 * have been asked to list a mount point that does
319 * not match the other args we've been given (-l, -t, etc.)
320 */
321 if (checkvfsname(statfsbuf.f_fstypename, vfslist)) {
322 rv++;
323 continue;
324 }
325 if (argc == 1) {
326 bzero(&maxwidths, sizeof(maxwidths));
327 update_maxwidths(&maxwidths, &statfsbuf);
328 }
329 prtstat(&statfsbuf, &maxwidths);
330 }
331 return (rv);
332 }
333
334 char *
335 getmntpt(char *name)
336 {
337 long mntsize, i;
338 struct statfs *mntbuf;
339
340 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
341 for (i = 0; i < mntsize; i++) {
342 if (!strcmp(mntbuf[i].f_mntfromname, name))
343 return (mntbuf[i].f_mntonname);
344 }
345 return (0);
346 }
347
348 /*
349 * Make a pass over the filesystem info in ``mntbuf'' filtering out
350 * filesystem types not in vfslist and possibly re-stating to get
351 * current (not cached) info. Returns the new count of valid statfs bufs.
352 */
353 long
354 regetmntinfo(struct statfs **mntbufp, long mntsize, char **vfslist)
355 {
356 int i, j;
357 struct statfs *mntbuf;
358
359 if (vfslist == NULL)
360 return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT));
361
362 mntbuf = *mntbufp;
363 for (j = 0, i = 0; i < mntsize; i++) {
364 if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
365 continue;
366 if (!nflag)
367 (void)statfs(mntbuf[i].f_mntonname,&mntbuf[j]);
368 else if (i != j)
369 mntbuf[j] = mntbuf[i];
370 j++;
371 }
372 return (j);
373 }
374
375 /*
376 * Output in "human-readable" format. Uses 3 digits max and puts
377 * unit suffixes at the end. Makes output compact and easy to read,
378 * especially on huge disks.
379 *
380 */
381 unit_t
382 unit_adjust(double *val)
383 {
384 double abval;
385 unit_t unit;
386 unsigned int unit_sz;
387
388 abval = fabs(*val);
389
390 unit_sz = abval ? ilogb(abval) / 10 : 0;
391
392 if (unit_sz >= UNIT_MAX) {
393 unit = NONE;
394 } else {
395 unit = unitp[unit_sz];
396 *val /= (double)valp[unit_sz];
397 }
398
399 return (unit);
400 }
401
402 void
403 prthuman(struct statfs *sfsp, long used)
404 {
405
406 prthumanval((double)sfsp->f_blocks * (double)sfsp->f_bsize);
407 prthumanval((double)used * (double)sfsp->f_bsize);
408 prthumanval((double)sfsp->f_bavail * (double)sfsp->f_bsize);
409 }
410
411 void
412 prthumanval(double bytes)
413 {
414
415 unit_t unit;
416 unit = unit_adjust(&bytes);
417
418 if (bytes == 0)
419 (void)printf(" 0B");
420 else if (bytes > 10)
421 (void)printf(" %5.0f%c", bytes, "BKMGTPE"[unit]);
422 else
423 (void)printf(" %5.1f%c", bytes, "BKMGTPE"[unit]);
424 }
425
426 /*
427 * Convert statfs returned filesystem size into BLOCKSIZE units.
428 * Attempts to avoid overflow for large filesystems.
429 */
430 #define fsbtoblk(num, fsbs, bs) \
431 (((fsbs) != 0 && (fsbs) < (bs)) ? \
432 ((off_t)((unsigned)num)) / ((unsigned)(bs) / ((off_t)((unsigned)fsbs))) : ((off_t)((unsigned)num)) * ((off_t)((unsigned)fsbs)) / (bs))
433
434 /*
435 * Print out status about a filesystem.
436 */
437 void
438 prtstat(struct statfs *sfsp, struct maxwidths *mwp)
439 {
440 static long blocksize;
441 static int headerlen, timesthrough;
442 static const char *header;
443 unsigned long used, availblks, inodes;
444
445 if (++timesthrough == 1) {
446 mwp->mntfrom = imax(mwp->mntfrom, strlen("Filesystem"));
447 if (hflag) {
448 header = " Size";
449 mwp->total = mwp->used = mwp->avail = strlen(header);
450 } else {
451 header = getbsize(&headerlen, &blocksize);
452 mwp->total = imax(mwp->total, headerlen);
453 }
454 mwp->used = imax(mwp->used, strlen("Used"));
455 mwp->avail = imax(mwp->avail, strlen("Avail"));
456
457 (void)printf("%-*s %-*s %*s %*s Capacity", mwp->mntfrom,
458 "Filesystem", mwp->total, header, mwp->used, "Used",
459 mwp->avail, "Avail");
460 if (iflag) {
461 mwp->iused = imax(mwp->iused, strlen(" iused"));
462 mwp->ifree = imax(mwp->ifree, strlen("ifree"));
463 (void)printf(" %*s %*s %%iused", mwp->iused - 2,
464 "iused", mwp->ifree, "ifree");
465 }
466 (void)printf(" Mounted on\n");
467 }
468
469 (void)printf("%-*s", mwp->mntfrom, sfsp->f_mntfromname);
470 used = (off_t)((unsigned)sfsp->f_blocks) - (off_t)((unsigned)sfsp->f_bfree);
471 availblks = sfsp->f_bavail + used;
472 if (hflag) {
473 prthuman(sfsp, used);
474 } else {
475 (void)printf(" %*lld %*lld %*lld", mwp->total,
476 fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
477 mwp->used, fsbtoblk(used, sfsp->f_bsize, blocksize),
478 mwp->avail, fsbtoblk(sfsp->f_bavail, sfsp->f_bsize,
479 blocksize));
480 }
481 (void)printf(" %5.0f%%",
482 availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
483 if (iflag) {
484 inodes = (unsigned)sfsp->f_files;
485 used = inodes - sfsp->f_ffree;
486 (void)printf(" %*lu %*lu %4.0f%% ", mwp->iused, used,
487 mwp->ifree, (unsigned long)sfsp->f_ffree, inodes == 0 ? 100.0 :
488 (double)used / (double)inodes * 100.0);
489 } else
490 (void)printf(" ");
491 (void)printf(" %s\n", sfsp->f_mntonname);
492 }
493
494 /*
495 * Update the maximum field-width information in `mwp' based on
496 * the filesystem specified by `sfsp'.
497 */
498 void
499 update_maxwidths(struct maxwidths *mwp, struct statfs *sfsp)
500 {
501 static long blocksize;
502 int dummy;
503
504 if (blocksize == 0)
505 getbsize(&dummy, &blocksize);
506
507 mwp->mntfrom = imax(mwp->mntfrom, strlen(sfsp->f_mntfromname));
508 mwp->total = imax(mwp->total, longwidth(fsbtoblk(sfsp->f_blocks,
509 sfsp->f_bsize, blocksize)));
510 mwp->used = imax(mwp->used, longwidth(fsbtoblk(sfsp->f_blocks -
511 sfsp->f_bfree, sfsp->f_bsize, blocksize)));
512 mwp->avail = imax(mwp->avail, longwidth(fsbtoblk(sfsp->f_bavail,
513 sfsp->f_bsize, blocksize)));
514 mwp->iused = imax(mwp->iused, longwidth((unsigned)(sfsp->f_files -
515 sfsp->f_ffree)));
516 mwp->ifree = imax(mwp->ifree, longwidth((unsigned)(sfsp->f_ffree)));
517 }
518
519 /* Return the width in characters of the specified long. */
520 int
521 longwidth(long long val)
522 {
523 int len;
524
525 len = 0;
526 /* Negative or zero values require one extra digit. */
527 if (val <= 0) {
528 val = -val;
529 len++;
530 }
531 while (val > 0) {
532 len++;
533 val /= 10;
534 }
535
536 return (len);
537 }
538
539 /*
540 * This code constitutes the pre-system call Berkeley df code for extracting
541 * information from filesystem superblocks.
542 */
543
544 union {
545 struct fs iu_fs;
546 char dummy[SBSIZE];
547 } sb;
548 #define sblock sb.iu_fs
549
550 int rfd;
551
552 int
553 ufs_df(char *file, struct maxwidths *mwp)
554 {
555 struct statfs statfsbuf;
556 struct statfs *sfsp;
557 const char *mntpt;
558 static int synced;
559
560 if (synced++ == 0)
561 sync();
562
563 if ((rfd = open(file, O_RDONLY)) < 0) {
564 warn("%s", file);
565 return (1);
566 }
567 if (bread((off_t)SBOFF, &sblock, SBSIZE) == 0) {
568 (void)close(rfd);
569 return (1);
570 }
571 sfsp = &statfsbuf;
572 sfsp->f_type = 1;
573 strcpy(sfsp->f_fstypename, "ufs");
574 sfsp->f_flags = 0;
575 sfsp->f_bsize = sblock.fs_fsize;
576 sfsp->f_iosize = sblock.fs_bsize;
577 sfsp->f_blocks = sblock.fs_dsize;
578 sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag +
579 sblock.fs_cstotal.cs_nffree;
580 sfsp->f_bavail = freespace(&sblock, sblock.fs_minfree);
581 sfsp->f_files = sblock.fs_ncg * sblock.fs_ipg;
582 sfsp->f_ffree = sblock.fs_cstotal.cs_nifree;
583 sfsp->f_fsid.val[0] = 0;
584 sfsp->f_fsid.val[1] = 0;
585 if ((mntpt = getmntpt(file)) == 0)
586 mntpt = "";
587 memmove(&sfsp->f_mntonname[0], mntpt, (size_t)MNAMELEN);
588 memmove(&sfsp->f_mntfromname[0], file, (size_t)MNAMELEN);
589 prtstat(sfsp, mwp);
590 (void)close(rfd);
591 return (0);
592 }
593
594 int
595 bread(off_t off, void *buf, int cnt)
596 {
597 ssize_t nr;
598
599 (void)lseek(rfd, off, SEEK_SET);
600 if ((nr = read(rfd, buf, (size_t)cnt)) != (ssize_t)cnt) {
601 /* Probably a dismounted disk if errno == EIO. */
602 if (errno != EIO)
603 (void)fprintf(stderr, "\ndf: %lld: %s\n",
604 (long long)off, strerror(nr > 0 ? EIO : errno));
605 return (0);
606 }
607 return (1);
608 }
609
610 void
611 usage(void)
612 {
613
614 char *t_flag = COMPAT_MODE("bin/df", "unix2003") ? "[-t]" : "[-t type]";
615 (void)fprintf(stderr,
616 "usage: df [-b | -H | -h | -k | -m | -P] [-ailn] [-T type] %s [file | filesystem ...]\n", t_flag);
617 exit(EX_USAGE);
618 }
619
620 char *
621 makenetvfslist(void)
622 {
623 char *str, *strptr, **listptr;
624 #ifndef __APPLE__
625 int mib[3], maxvfsconf, cnt=0, i;
626 size_t miblen;
627 struct ovfsconf *ptr;
628 #else
629 int mib[4], maxvfsconf, cnt=0, i;
630 size_t miblen;
631 struct vfsconf vfc;
632 #endif
633
634 mib[0] = CTL_VFS; mib[1] = VFS_GENERIC; mib[2] = VFS_MAXTYPENUM;
635 miblen=sizeof(maxvfsconf);
636 if (sysctl(mib, (unsigned int)(sizeof(mib) / sizeof(mib[0])),
637 &maxvfsconf, &miblen, NULL, 0)) {
638 warnx("sysctl failed");
639 return (NULL);
640 }
641
642 if ((listptr = malloc(sizeof(char*) * maxvfsconf)) == NULL) {
643 warnx("malloc failed");
644 return (NULL);
645 }
646
647 #ifndef __APPLE__
648 for (ptr = getvfsent(); ptr; ptr = getvfsent())
649 if (ptr->vfc_flags & VFCF_NETWORK) {
650 listptr[cnt++] = strdup(ptr->vfc_name);
651 if (listptr[cnt-1] == NULL) {
652 warnx("malloc failed");
653 return (NULL);
654 }
655 }
656 #else
657 miblen = sizeof (struct vfsconf);
658 mib[2] = VFS_CONF;
659 for (i = 0; i < maxvfsconf; i++) {
660 mib[3] = i;
661 if (sysctl(mib, 4, &vfc, &miblen, NULL, 0) == 0) {
662 if (!(vfc.vfc_flags & MNT_LOCAL)) {
663 listptr[cnt++] = strdup(vfc.vfc_name);
664 if (listptr[cnt-1] == NULL) {
665 warnx("malloc failed");
666 return (NULL);
667 }
668 }
669 }
670 }
671 #endif
672
673 if (cnt == 0 ||
674 (str = malloc(sizeof(char) * (32 * cnt + cnt + 2))) == NULL) {
675 if (cnt > 0)
676 warnx("malloc failed");
677 free(listptr);
678 return (NULL);
679 }
680
681 *str = 'n'; *(str + 1) = 'o';
682 for (i = 0, strptr = str + 2; i < cnt; i++, strptr++) {
683 strncpy(strptr, listptr[i], 32);
684 strptr += strlen(listptr[i]);
685 *strptr = ',';
686 free(listptr[i]);
687 }
688 *(--strptr) = '\0';
689
690 free(listptr);
691 return (str);
692 }