(get_fs_usage): avoid compile warning about mixed declarations and code.
[midnight-commander.git] / src / filemanager / mountlist.c
blob74a6dc6a8e467f044d5d59bd151f1b868aa92358
1 /*
2 Return a list of mounted file systems
4 Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
5 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
7 Copyright (C) 1991, 1992, 2011
8 The Free Software Foundation, Inc.
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 /** \file mountlist.c
27 * \brief Source: list of mounted filesystems
30 #include <config.h>
32 #include <limits.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdint.h> /* SIZE_MAX */
37 #include <sys/types.h>
39 #include <errno.h>
41 /* This header needs to be included before sys/mount.h on *BSD */
42 #ifdef HAVE_SYS_PARAM_H
43 #include <sys/param.h>
44 #endif
46 #if defined STAT_STATVFS || defined STAT_STATVFS64 /* POSIX 1003.1-2001 (and later) with XSI */
47 #include <sys/statvfs.h>
48 #else
49 /* Don't include backward-compatibility files unless they're needed.
50 Eventually we'd like to remove all this cruft. */
51 #include <fcntl.h>
52 #include <unistd.h>
53 #include <sys/stat.h>
55 #ifdef MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
56 #ifdef HAVE_SYS_UCRED_H
57 #include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
58 NGROUPS is used as an array dimension in ucred.h */
59 #include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
60 #endif
61 #ifdef HAVE_SYS_MOUNT_H
62 #include <sys/mount.h>
63 #endif
64 #ifdef HAVE_SYS_FS_TYPES_H
65 #include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
66 #endif
67 #ifdef HAVE_STRUCT_FSSTAT_F_FSTYPENAME
68 #define FS_TYPE(Ent) ((Ent).f_fstypename)
69 #else
70 #define FS_TYPE(Ent) mnt_names[(Ent).f_type]
71 #endif
72 #endif /* MOUNTED_GETFSSTAT */
73 #endif /* STAT_STATVFS || STAT_STATVFS64 */
75 #ifdef HAVE_SYS_VFS_H
76 #include <sys/vfs.h>
77 #endif
78 #ifdef HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */
79 #include <sys/fs/s5param.h>
80 #endif
81 #if defined HAVE_SYS_FILSYS_H && !defined _CRAY
82 #include <sys/filsys.h> /* SVR2 */
83 #endif
84 #ifdef HAVE_SYS_STATFS_H
85 #include <sys/statfs.h>
86 #endif
87 #ifdef HAVE_DUSTAT_H /* AIX PS/2 */
88 #include <sys/dustat.h>
89 #endif
91 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
92 #include <mntent.h>
93 #ifndef MOUNTED
94 #ifdef _PATH_MOUNTED /* GNU libc */
95 #define MOUNTED _PATH_MOUNTED
96 #endif
97 #ifdef MNT_MNTTAB /* HP-UX. */
98 #define MOUNTED MNT_MNTTAB
99 #endif
100 #ifdef MNTTABNAME /* Dynix. */
101 #define MOUNTED MNTTABNAME
102 #endif
103 #endif
104 #endif
106 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
107 #include <sys/mount.h>
108 #endif
110 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
111 #include <sys/statvfs.h>
112 #endif
114 #ifdef MOUNTED_GETMNT /* Ultrix. */
115 #include <sys/mount.h>
116 #include <sys/fs_types.h>
117 #endif
119 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
120 #include <fs_info.h>
121 #include <dirent.h>
122 #endif
124 #ifdef MOUNTED_FREAD /* SVR2. */
125 #include <mnttab.h>
126 #endif
128 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
129 #include <mnttab.h>
130 #include <sys/fstyp.h>
131 #include <sys/statfs.h>
132 #endif
134 #ifdef MOUNTED_LISTMNTENT
135 #include <mntent.h>
136 #endif
138 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
139 #include <sys/mnttab.h>
140 #endif
142 #ifdef MOUNTED_VMOUNT /* AIX. */
143 #include <fshelp.h>
144 #include <sys/vfs.h>
145 #endif
147 #ifdef MOUNTED_INTERIX_STATVFS /* Interix. */
148 #include <sys/statvfs.h>
149 #include <dirent.h>
150 #endif
152 #ifdef DOLPHIN
153 /* So special that it's not worth putting this in autoconf. */
154 #undef MOUNTED_FREAD_FSTYP
155 #define MOUNTED_GETMNTTBL
156 #endif
158 #ifdef HAVE_SYS_MNTENT_H
159 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
160 #include <sys/mntent.h>
161 #endif
163 #undef MNT_IGNORE
164 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
165 #define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
166 #else
167 #define MNT_IGNORE(M) 0
168 #endif
170 #ifdef HAVE_INFOMOUNT_QNX
171 #include <sys/disk.h>
172 #include <sys/fsys.h>
173 #endif
175 #ifdef HAVE_SYS_STATVFS_H /* SVR4. */
176 #include <sys/statvfs.h>
177 #endif
179 #include "lib/global.h"
180 #include "mountlist.h"
182 /*** global variables ****************************************************************************/
184 /*** file scope macro definitions ****************************************************************/
186 #if defined (__QNX__) && !defined(__QNXNTO__) && !defined (HAVE_INFOMOUNT_LIST)
187 #define HAVE_INFOMOUNT_QNX
188 #endif
190 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
191 #define HAVE_INFOMOUNT
192 #endif
194 /* The results of open() in this file are not used with fchdir,
195 therefore save some unnecessary work in fchdir.c. */
196 #undef open
197 #undef close
199 /* The results of opendir() in this file are not used with dirfd and fchdir,
200 therefore save some unnecessary work in fchdir.c. */
201 #undef opendir
202 #undef closedir
204 #ifndef ME_DUMMY
205 #define ME_DUMMY(Fs_name, Fs_type) \
206 (strcmp (Fs_type, "autofs") == 0 \
207 || strcmp (Fs_type, "none") == 0 \
208 || strcmp (Fs_type, "proc") == 0 \
209 || strcmp (Fs_type, "subfs") == 0 \
210 /* for NetBSD 3.0 */ \
211 || strcmp (Fs_type, "kernfs") == 0 \
212 /* for Irix 6.5 */ \
213 || strcmp (Fs_type, "ignore") == 0)
214 #endif
216 #ifdef __CYGWIN__
217 #include <windows.h>
218 #define ME_REMOTE me_remote
219 /* All cygwin mount points include `:' or start with `//'; so it
220 requires a native Windows call to determine remote disks. */
221 static int
222 me_remote (char const *fs_name, char const *fs_type _GL_UNUSED)
224 if (fs_name[0] && fs_name[1] == ':')
226 char drive[4];
227 sprintf (drive, "%c:\\", fs_name[0]);
228 switch (GetDriveType (drive))
230 case DRIVE_REMOVABLE:
231 case DRIVE_FIXED:
232 case DRIVE_CDROM:
233 case DRIVE_RAMDISK:
234 return 0;
237 return 1;
239 #endif
240 #ifndef ME_REMOTE
241 /* A file system is `remote' if its Fs_name contains a `:'
242 or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */
243 #define ME_REMOTE(Fs_name, Fs_type) \
244 (strchr (Fs_name, ':') != NULL \
245 || ((Fs_name)[0] == '/' \
246 && (Fs_name)[1] == '/' \
247 && (strcmp (Fs_type, "smbfs") == 0 || strcmp (Fs_type, "cifs") == 0)))
248 #endif
250 /* Many space usage primitives use all 1 bits to denote a value that is
251 not applicable or unknown. Propagate this information by returning
252 a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
253 is unsigned and narrower than uintmax_t. */
254 #define PROPAGATE_ALL_ONES(x) \
255 ((sizeof (x) < sizeof (uintmax_t) \
256 && (~ (x) == (sizeof (x) < sizeof (int) \
257 ? - (1 << (sizeof (x) * CHAR_BIT)) \
258 : 0))) \
259 ? UINTMAX_MAX : (uintmax_t) (x))
261 /* Extract the top bit of X as an uintmax_t value. */
262 #define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
264 /* If a value is negative, many space usage primitives store it into an
265 integer variable by assignment, even if the variable's type is unsigned.
266 So, if a space usage variable X's top bit is set, convert X to the
267 uintmax_t value V such that (- (uintmax_t) V) is the negative of
268 the original value. If X's top bit is clear, just yield X.
269 Use PROPAGATE_TOP_BIT if the original value might be negative;
270 otherwise, use PROPAGATE_ALL_ONES. */
271 #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
273 #ifdef STAT_STATVFS
274 /* Return true if statvfs works. This is false for statvfs on systems
275 with GNU libc on Linux kernels before 2.6.36, which stats all
276 preceding entries in /proc/mounts; that makes df hang if even one
277 of the corresponding file systems is hard-mounted but not available. */
278 # if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
279 /* The FRSIZE fallback is not required in this case. */
280 #undef STAT_STATFS2_FRSIZE
281 static int
282 statvfs_works (void)
284 return 1;
286 #else
287 #include <string.h> /* for strverscmp */
288 #include <sys/utsname.h>
289 #include <sys/statfs.h>
290 #define STAT_STATFS2_BSIZE 1
292 static int
293 statvfs_works (void)
295 static int statvfs_works_cache = -1;
296 struct utsname name;
298 if (statvfs_works_cache < 0)
299 statvfs_works_cache = (uname (&name) == 0 && 0 <= strverscmp (name.release, "2.6.36"));
300 return statvfs_works_cache;
302 #endif
303 #endif
305 #ifdef STAT_READ_FILSYS /* SVR2 */
306 /* Set errno to zero upon EOF. */
307 #define ZERO_BYTE_TRANSFER_ERRNO 0
309 #ifdef EINTR
310 #define IS_EINTR(x) ((x) == EINTR)
311 #else
312 #define IS_EINTR(x) 0
313 #endif
314 #endif /* STAT_READ_FILSYS */
316 /*** file scope type declarations ****************************************************************/
318 /* A mount table entry. */
319 struct mount_entry
321 char *me_devname; /* Device node name, including "/dev/". */
322 char *me_mountdir; /* Mount point directory name. */
323 char *me_type; /* "nfs", "4.2", etc. */
324 dev_t me_dev; /* Device number of me_mountdir. */
325 unsigned int me_dummy:1; /* Nonzero for dummy file systems. */
326 unsigned int me_remote:1; /* Nonzero for remote fileystems. */
327 unsigned int me_type_malloced:1; /* Nonzero if me_type was malloced. */
328 struct mount_entry *me_next;
331 struct fs_usage
333 uintmax_t fsu_blocksize; /* Size of a block. */
334 uintmax_t fsu_blocks; /* Total blocks. */
335 uintmax_t fsu_bfree; /* Free blocks available to superuser. */
336 uintmax_t fsu_bavail; /* Free blocks available to non-superuser. */
337 int fsu_bavail_top_bit_set; /* 1 if fsu_bavail represents a value < 0. */
338 uintmax_t fsu_files; /* Total file nodes. */
339 uintmax_t fsu_ffree; /* Free file nodes. */
342 /*** file scope variables ************************************************************************/
344 #ifdef HAVE_INFOMOUNT_LIST
345 static struct mount_entry *mc_mount_list = NULL;
346 #endif /* HAVE_INFOMOUNT_LIST */
348 /*** file scope functions ************************************************************************/
349 /* --------------------------------------------------------------------------------------------- */
351 #ifdef HAVE_INFOMOUNT_LIST
352 static void
353 free_mount_entry (struct mount_entry *me)
355 if (!me)
356 return;
357 if (me->me_devname)
358 free (me->me_devname);
359 if (me->me_mountdir)
360 free (me->me_mountdir);
361 if (me->me_type && me->me_type_malloced)
362 free (me->me_type);
363 free (me);
366 /* --------------------------------------------------------------------------------------------- */
368 #ifdef MOUNTED_GETMNTINFO
370 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
371 static char *
372 fstype_to_string (short int t)
374 switch (t)
376 #ifdef MOUNT_PC
377 case MOUNT_PC:
378 return "pc";
379 #endif
380 #ifdef MOUNT_MFS
381 case MOUNT_MFS:
382 return "mfs";
383 #endif
384 #ifdef MOUNT_LO
385 case MOUNT_LO:
386 return "lo";
387 #endif
388 #ifdef MOUNT_TFS
389 case MOUNT_TFS:
390 return "tfs";
391 #endif
392 #ifdef MOUNT_TMP
393 case MOUNT_TMP:
394 return "tmp";
395 #endif
396 #ifdef MOUNT_UFS
397 case MOUNT_UFS:
398 return "ufs";
399 #endif
400 #ifdef MOUNT_NFS
401 case MOUNT_NFS:
402 return "nfs";
403 #endif
404 #ifdef MOUNT_MSDOS
405 case MOUNT_MSDOS:
406 return "msdos";
407 #endif
408 #ifdef MOUNT_LFS
409 case MOUNT_LFS:
410 return "lfs";
411 #endif
412 #ifdef MOUNT_LOFS
413 case MOUNT_LOFS:
414 return "lofs";
415 #endif
416 #ifdef MOUNT_FDESC
417 case MOUNT_FDESC:
418 return "fdesc";
419 #endif
420 #ifdef MOUNT_PORTAL
421 case MOUNT_PORTAL:
422 return "portal";
423 #endif
424 #ifdef MOUNT_NULL
425 case MOUNT_NULL:
426 return "null";
427 #endif
428 #ifdef MOUNT_UMAP
429 case MOUNT_UMAP:
430 return "umap";
431 #endif
432 #ifdef MOUNT_KERNFS
433 case MOUNT_KERNFS:
434 return "kernfs";
435 #endif
436 #ifdef MOUNT_PROCFS
437 case MOUNT_PROCFS:
438 return "procfs";
439 #endif
440 #ifdef MOUNT_AFS
441 case MOUNT_AFS:
442 return "afs";
443 #endif
444 #ifdef MOUNT_CD9660
445 case MOUNT_CD9660:
446 return "cd9660";
447 #endif
448 #ifdef MOUNT_UNION
449 case MOUNT_UNION:
450 return "union";
451 #endif
452 #ifdef MOUNT_DEVFS
453 case MOUNT_DEVFS:
454 return "devfs";
455 #endif
456 #ifdef MOUNT_EXT2FS
457 case MOUNT_EXT2FS:
458 return "ext2fs";
459 #endif
460 default:
461 return "?";
464 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
466 /* --------------------------------------------------------------------------------------------- */
468 static char *
469 fsp_to_string (const struct statfs *fsp)
471 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
472 return (char *) (fsp->f_fstypename);
473 #else
474 return fstype_to_string (fsp->f_type);
475 #endif
477 #endif /* MOUNTED_GETMNTINFO */
479 /* --------------------------------------------------------------------------------------------- */
481 #ifdef MOUNTED_VMOUNT /* AIX. */
482 static char *
483 fstype_to_string (int t)
485 struct vfs_ent *e;
487 e = getvfsbytype (t);
488 if (!e || !e->vfsent_name)
489 return "none";
490 else
491 return e->vfsent_name;
493 #endif /* MOUNTED_VMOUNT */
495 /* --------------------------------------------------------------------------------------------- */
497 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
499 /* Return the device number from MOUNT_OPTIONS, if possible.
500 Otherwise return (dev_t) -1. */
502 /* --------------------------------------------------------------------------------------------- */
504 static dev_t
505 dev_from_mount_options (char const *mount_options)
507 /* GNU/Linux allows file system implementations to define their own
508 meaning for "dev=" mount options, so don't trust the meaning
509 here. */
510 #ifndef __linux__
511 static char const dev_pattern[] = ",dev=";
512 char const *devopt = strstr (mount_options, dev_pattern);
514 if (devopt)
516 char const *optval = devopt + sizeof (dev_pattern) - 1;
517 char *optvalend;
518 unsigned long int dev;
519 errno = 0;
520 dev = strtoul (optval, &optvalend, 16);
521 if (optval != optvalend
522 && (*optvalend == '\0' || *optvalend == ',')
523 && !(dev == ULONG_MAX && errno == ERANGE) && dev == (dev_t) dev)
524 return dev;
526 #endif
528 (void) mount_options;
529 return -1;
532 #endif
534 /* --------------------------------------------------------------------------------------------- */
536 #if defined _AIX && defined _I386
537 /* AIX PS/2 does not supply statfs. */
539 static int
540 statfs (char *file, struct statfs *fsb)
542 struct stat stats;
543 struct dustat fsd;
545 if (stat (file, &stats) != 0)
546 return -1;
547 if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
548 return -1;
549 fsb->f_type = 0;
550 fsb->f_bsize = fsd.du_bsize;
551 fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
552 fsb->f_bfree = fsd.du_tfree;
553 fsb->f_bavail = fsd.du_tfree;
554 fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
555 fsb->f_ffree = fsd.du_tinode;
556 fsb->f_fsid.val[0] = fsd.du_site;
557 fsb->f_fsid.val[1] = fsd.du_pckno;
558 return 0;
561 #endif /* _AIX && _I386 */
563 /* --------------------------------------------------------------------------------------------- */
565 /* Return a list of the currently mounted file systems, or NULL on error.
566 Add each entry to the tail of the list so that they stay in order.
567 If NEED_FS_TYPE is true, ensure that the file system type fields in
568 the returned list are valid. Otherwise, they might not be. */
570 static struct mount_entry *
571 read_file_system_list (int need_fs_type)
573 struct mount_entry *mount_list;
574 struct mount_entry *me;
575 struct mount_entry **mtail = &mount_list;
577 #ifdef MOUNTED_LISTMNTENT
579 struct tabmntent *mntlist, *p;
580 struct mntent *mnt;
581 struct mount_entry *me;
583 /* the third and fourth arguments could be used to filter mounts,
584 but Crays doesn't seem to have any mounts that we want to
585 remove. Specifically, automount create normal NFS mounts.
588 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
589 return NULL;
590 for (p = mntlist; p; p = p->next)
592 mnt = p->ment;
593 me = malloc (sizeof (*me));
594 me->me_devname = strdup (mnt->mnt_fsname);
595 me->me_mountdir = strdup (mnt->mnt_dir);
596 me->me_type = strdup (mnt->mnt_type);
597 me->me_type_malloced = 1;
598 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
599 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
600 me->me_dev = -1;
601 *mtail = me;
602 mtail = &me->me_next;
604 freemntlist (mntlist);
606 #endif
608 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
610 struct mntent *mnt;
611 const char *table = MOUNTED;
612 FILE *fp;
614 fp = setmntent (table, "r");
615 if (fp == NULL)
616 return NULL;
618 while ((mnt = getmntent (fp)))
620 me = malloc (sizeof (*me));
621 me->me_devname = strdup (mnt->mnt_fsname);
622 me->me_mountdir = strdup (mnt->mnt_dir);
623 me->me_type = strdup (mnt->mnt_type);
624 me->me_type_malloced = 1;
625 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
626 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
627 me->me_dev = dev_from_mount_options (mnt->mnt_opts);
629 /* Add to the linked list. */
630 *mtail = me;
631 mtail = &me->me_next;
634 if (endmntent (fp) == 0)
635 goto free_then_fail;
637 #endif /* MOUNTED_GETMNTENT1. */
639 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
641 struct statfs *fsp;
642 int entries;
644 entries = getmntinfo (&fsp, MNT_NOWAIT);
645 if (entries < 0)
646 return NULL;
647 for (; entries-- > 0; fsp++)
649 char *fs_type = fsp_to_string (fsp);
651 me = malloc (sizeof (*me));
652 me->me_devname = strdup (fsp->f_mntfromname);
653 me->me_mountdir = strdup (fsp->f_mntonname);
654 me->me_type = fs_type;
655 me->me_type_malloced = 0;
656 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
657 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
658 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
660 /* Add to the linked list. */
661 *mtail = me;
662 mtail = &me->me_next;
665 #endif /* MOUNTED_GETMNTINFO */
667 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
669 struct statvfs *fsp;
670 int entries;
672 entries = getmntinfo (&fsp, MNT_NOWAIT);
673 if (entries < 0)
674 return NULL;
675 for (; entries-- > 0; fsp++)
677 me = malloc (sizeof (*me));
678 me->me_devname = strdup (fsp->f_mntfromname);
679 me->me_mountdir = strdup (fsp->f_mntonname);
680 me->me_type = strdup (fsp->f_fstypename);
681 me->me_type_malloced = 1;
682 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
683 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
684 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
686 /* Add to the linked list. */
687 *mtail = me;
688 mtail = &me->me_next;
691 #endif /* MOUNTED_GETMNTINFO2 */
693 #ifdef MOUNTED_GETMNT /* Ultrix. */
695 int offset = 0;
696 int val;
697 struct fs_data fsd;
699 while (errno = 0, 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, (char *) 0)))
701 me = malloc (sizeof (*me));
702 me->me_devname = strdup (fsd.fd_req.devname);
703 me->me_mountdir = strdup (fsd.fd_req.path);
704 me->me_type = gt_names[fsd.fd_req.fstype];
705 me->me_type_malloced = 0;
706 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
707 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
708 me->me_dev = fsd.fd_req.dev;
710 /* Add to the linked list. */
711 *mtail = me;
712 mtail = &me->me_next;
714 if (val < 0)
715 goto free_then_fail;
717 #endif /* MOUNTED_GETMNT. */
719 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
721 /* The next_dev() and fs_stat_dev() system calls give the list of
722 all file systems, including the information returned by statvfs()
723 (fs type, total blocks, free blocks etc.), but without the mount
724 point. But on BeOS all file systems except / are mounted in the
725 rootfs, directly under /.
726 The directory name of the mount point is often, but not always,
727 identical to the volume name of the device.
728 We therefore get the list of subdirectories of /, and the list
729 of all file systems, and match the two lists. */
731 DIR *dirp;
732 struct rootdir_entry
734 char *name;
735 dev_t dev;
736 ino_t ino;
737 struct rootdir_entry *next;
739 struct rootdir_entry *rootdir_list;
740 struct rootdir_entry **rootdir_tail;
741 int32 pos;
742 dev_t dev;
743 fs_info fi;
745 /* All volumes are mounted in the rootfs, directly under /. */
746 rootdir_list = NULL;
747 rootdir_tail = &rootdir_list;
748 dirp = opendir ("/");
749 if (dirp)
751 struct dirent *d;
753 while ((d = readdir (dirp)) != NULL)
755 char *name;
756 struct stat statbuf;
758 if (strcmp (d->d_name, "..") == 0)
759 continue;
761 if (strcmp (d->d_name, ".") == 0)
762 name = strdup ("/");
763 else
765 name = malloc (1 + strlen (d->d_name) + 1);
766 name[0] = '/';
767 strcpy (name + 1, d->d_name);
770 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
772 struct rootdir_entry *re = malloc (sizeof (*re));
773 re->name = name;
774 re->dev = statbuf.st_dev;
775 re->ino = statbuf.st_ino;
777 /* Add to the linked list. */
778 *rootdir_tail = re;
779 rootdir_tail = &re->next;
781 else
782 free (name);
784 closedir (dirp);
786 *rootdir_tail = NULL;
788 for (pos = 0; (dev = next_dev (&pos)) >= 0;)
789 if (fs_stat_dev (dev, &fi) >= 0)
791 /* Note: fi.dev == dev. */
792 struct rootdir_entry *re;
794 for (re = rootdir_list; re; re = re->next)
795 if (re->dev == fi.dev && re->ino == fi.root)
796 break;
798 me = malloc (sizeof (*me));
799 me->me_devname = strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
800 me->me_mountdir = strdup (re != NULL ? re->name : fi.fsh_name);
801 me->me_type = strdup (fi.fsh_name);
802 me->me_type_malloced = 1;
803 me->me_dev = fi.dev;
804 me->me_dummy = 0;
805 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
807 /* Add to the linked list. */
808 *mtail = me;
809 mtail = &me->me_next;
811 *mtail = NULL;
813 while (rootdir_list != NULL)
815 struct rootdir_entry *re = rootdir_list;
816 rootdir_list = re->next;
817 free (re->name);
818 free (re);
821 #endif /* MOUNTED_FS_STAT_DEV */
823 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
825 int numsys, counter;
826 size_t bufsize;
827 struct statfs *stats;
829 numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
830 if (numsys < 0)
831 return NULL;
832 if (SIZE_MAX / sizeof (*stats) <= numsys)
834 fprintf (stderr, "%s\n", _("Memory exhausted!"));
835 exit (EXIT_FAILURE);
838 bufsize = (1 + numsys) * sizeof (*stats);
839 stats = malloc (bufsize);
840 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
842 if (numsys < 0)
844 free (stats);
845 return NULL;
848 for (counter = 0; counter < numsys; counter++)
850 me = malloc (sizeof (*me));
851 me->me_devname = strdup (stats[counter].f_mntfromname);
852 me->me_mountdir = strdup (stats[counter].f_mntonname);
853 me->me_type = strdup (FS_TYPE (stats[counter]));
854 me->me_type_malloced = 1;
855 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
856 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
857 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
859 /* Add to the linked list. */
860 *mtail = me;
861 mtail = &me->me_next;
864 free (stats);
866 #endif /* MOUNTED_GETFSSTAT */
868 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
870 struct mnttab mnt;
871 char *table = "/etc/mnttab";
872 FILE *fp;
874 fp = fopen (table, "r");
875 if (fp == NULL)
876 return NULL;
878 while (fread (&mnt, sizeof (mnt), 1, fp) > 0)
880 me = malloc (sizeof (*me));
881 #ifdef GETFSTYP /* SVR3. */
882 me->me_devname = strdup (mnt.mt_dev);
883 #else
884 me->me_devname = malloc (strlen (mnt.mt_dev) + 6);
885 strcpy (me->me_devname, "/dev/");
886 strcpy (me->me_devname + 5, mnt.mt_dev);
887 #endif
888 me->me_mountdir = strdup (mnt.mt_filsys);
889 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
890 me->me_type = "";
891 me->me_type_malloced = 0;
892 #ifdef GETFSTYP /* SVR3. */
893 if (need_fs_type)
895 struct statfs fsd;
896 char typebuf[FSTYPSZ];
898 if (statfs (me->me_mountdir, &fsd, sizeof (fsd), 0) != -1
899 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
901 me->me_type = strdup (typebuf);
902 me->me_type_malloced = 1;
905 #endif
906 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
907 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
909 /* Add to the linked list. */
910 *mtail = me;
911 mtail = &me->me_next;
914 if (ferror (fp))
916 /* The last fread() call must have failed. */
917 int saved_errno = errno;
918 fclose (fp);
919 errno = saved_errno;
920 goto free_then_fail;
923 if (fclose (fp) == EOF)
924 goto free_then_fail;
926 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
928 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
930 struct mntent **mnttbl = getmnttbl (), **ent;
931 for (ent = mnttbl; *ent; ent++)
933 me = malloc (sizeof (*me));
934 me->me_devname = strdup ((*ent)->mt_resource);
935 me->me_mountdir = strdup ((*ent)->mt_directory);
936 me->me_type = strdup ((*ent)->mt_fstype);
937 me->me_type_malloced = 1;
938 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
939 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
940 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
942 /* Add to the linked list. */
943 *mtail = me;
944 mtail = &me->me_next;
946 endmnttbl ();
948 #endif
950 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
952 struct mnttab mnt;
953 char *table = MNTTAB;
954 FILE *fp;
955 int ret;
956 int lockfd = -1;
958 #if defined F_RDLCK && defined F_SETLKW
959 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
960 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
961 for this file name, we should use their macro name instead.
962 (Why not just lock MNTTAB directly? We don't know.) */
963 #ifndef MNTTAB_LOCK
964 #define MNTTAB_LOCK "/etc/.mnttab.lock"
965 #endif
966 lockfd = open (MNTTAB_LOCK, O_RDONLY);
967 if (0 <= lockfd)
969 struct flock flock;
970 flock.l_type = F_RDLCK;
971 flock.l_whence = SEEK_SET;
972 flock.l_start = 0;
973 flock.l_len = 0;
974 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
975 if (errno != EINTR)
977 int saved_errno = errno;
978 close (lockfd);
979 errno = saved_errno;
980 return NULL;
983 else if (errno != ENOENT)
984 return NULL;
985 #endif
987 errno = 0;
988 fp = fopen (table, "r");
989 if (fp == NULL)
990 ret = errno;
991 else
993 while ((ret = getmntent (fp, &mnt)) == 0)
995 me = malloc (sizeof (*me));
996 me->me_devname = strdup (mnt.mnt_special);
997 me->me_mountdir = strdup (mnt.mnt_mountp);
998 me->me_type = strdup (mnt.mnt_fstype);
999 me->me_type_malloced = 1;
1000 me->me_dummy = MNT_IGNORE (&mnt) != 0;
1001 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1002 me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
1004 /* Add to the linked list. */
1005 *mtail = me;
1006 mtail = &me->me_next;
1009 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
1012 if (0 <= lockfd && close (lockfd) != 0)
1013 ret = errno;
1015 if (0 <= ret)
1017 errno = ret;
1018 goto free_then_fail;
1021 #endif /* MOUNTED_GETMNTENT2. */
1023 #ifdef MOUNTED_VMOUNT /* AIX. */
1025 int bufsize;
1026 char *entries, *thisent;
1027 struct vmount *vmp;
1028 int n_entries;
1029 int i;
1031 /* Ask how many bytes to allocate for the mounted file system info. */
1032 if (mntctl (MCTL_QUERY, sizeof (bufsize), (struct vmount *) &bufsize) != 0)
1033 return NULL;
1034 entries = malloc (bufsize);
1036 /* Get the list of mounted file systems. */
1037 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
1038 if (n_entries < 0)
1040 int saved_errno = errno;
1041 free (entries);
1042 errno = saved_errno;
1043 return NULL;
1046 for (i = 0, thisent = entries; i < n_entries; i++, thisent += vmp->vmt_length)
1048 char *options, *ignore;
1050 vmp = (struct vmount *) thisent;
1051 me = malloc (sizeof (*me));
1052 if (vmp->vmt_flags & MNT_REMOTE)
1054 char *host, *dir;
1056 me->me_remote = 1;
1057 /* Prepend the remote dirname. */
1058 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
1059 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
1060 me->me_devname = malloc (strlen (host) + strlen (dir) + 2);
1061 strcpy (me->me_devname, host);
1062 strcat (me->me_devname, ":");
1063 strcat (me->me_devname, dir);
1065 else
1067 me->me_remote = 0;
1068 me->me_devname = strdup (thisent + vmp->vmt_data[VMT_OBJECT].vmt_off);
1070 me->me_mountdir = strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
1071 me->me_type = strdup (fstype_to_string (vmp->vmt_gfstype));
1072 me->me_type_malloced = 1;
1073 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
1074 ignore = strstr (options, "ignore");
1075 me->me_dummy = (ignore
1076 && (ignore == options || ignore[-1] == ',')
1077 && (ignore[sizeof ("ignore") - 1] == ','
1078 || ignore[sizeof ("ignore") - 1] == '\0'));
1079 me->me_dev = (dev_t) (-1); /* vmt_fsid might be the info we want. */
1081 /* Add to the linked list. */
1082 *mtail = me;
1083 mtail = &me->me_next;
1085 free (entries);
1087 #endif /* MOUNTED_VMOUNT. */
1090 #ifdef MOUNTED_INTERIX_STATVFS
1092 DIR *dirp = opendir ("/dev/fs");
1093 char node[9 + NAME_MAX];
1095 if (!dirp)
1096 goto free_then_fail;
1098 while (1)
1100 struct statvfs dev;
1101 struct dirent entry;
1102 struct dirent *result;
1104 if (readdir_r (dirp, &entry, &result) || result == NULL)
1105 break;
1107 strcpy (node, "/dev/fs/");
1108 strcat (node, entry.d_name);
1110 if (statvfs (node, &dev) == 0)
1112 me = malloc (sizeof *me);
1113 me->me_devname = strdup (dev.f_mntfromname);
1114 me->me_mountdir = strdup (dev.f_mntonname);
1115 me->me_type = strdup (dev.f_fstypename);
1116 me->me_type_malloced = 1;
1117 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1118 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1119 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
1121 /* Add to the linked list. */
1122 *mtail = me;
1123 mtail = &me->me_next;
1127 #endif /* MOUNTED_INTERIX_STATVFS */
1129 (void) need_fs_type; /* avoid argument-unused warning */
1130 *mtail = NULL;
1131 return mount_list;
1134 free_then_fail:
1136 int saved_errno = errno;
1137 *mtail = NULL;
1139 while (mount_list)
1141 me = mount_list->me_next;
1142 free (mount_list->me_devname);
1143 free (mount_list->me_mountdir);
1144 if (mount_list->me_type_malloced)
1145 free (mount_list->me_type);
1146 free (mount_list);
1147 mount_list = me;
1150 errno = saved_errno;
1151 return NULL;
1155 #endif /* HAVE_INFOMOUNT_LIST */
1157 /* --------------------------------------------------------------------------------------------- */
1159 #ifdef HAVE_INFOMOUNT_QNX
1161 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1162 ** this via the following code.
1163 ** Note that, as this is based on CWD, it only fills one mount_entry
1164 ** structure. See my_statfs() in utilunix.c for the "other side" of
1165 ** this hack.
1168 static struct mount_entry *
1169 read_file_system_list (int need_fs_type, int all_fs)
1171 struct _disk_entry de;
1172 struct statfs fs;
1173 int i, fd;
1174 char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
1176 static struct mount_entry *me = NULL;
1178 if (me)
1180 if (me->me_devname)
1181 free (me->me_devname);
1182 if (me->me_mountdir)
1183 free (me->me_mountdir);
1184 if (me->me_type)
1185 free (me->me_type);
1187 else
1188 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
1190 if (!getcwd (dir, _POSIX_PATH_MAX))
1191 return (NULL);
1193 fd = open (dir, O_RDONLY);
1194 if (fd == -1)
1195 return (NULL);
1197 i = disk_get_entry (fd, &de);
1199 close (fd);
1201 if (i == -1)
1202 return (NULL);
1204 switch (de.disk_type)
1206 case _UNMOUNTED:
1207 tp = "unmounted";
1208 break;
1209 case _FLOPPY:
1210 tp = "Floppy";
1211 break;
1212 case _HARD:
1213 tp = "Hard";
1214 break;
1215 case _RAMDISK:
1216 tp = "Ram";
1217 break;
1218 case _REMOVABLE:
1219 tp = "Removable";
1220 break;
1221 case _TAPE:
1222 tp = "Tape";
1223 break;
1224 case _CDROM:
1225 tp = "CDROM";
1226 break;
1227 default:
1228 tp = "unknown";
1231 if (fsys_get_mount_dev (dir, &dev) == -1)
1232 return (NULL);
1234 if (fsys_get_mount_pt (dev, &dir) == -1)
1235 return (NULL);
1237 me->me_devname = strdup (dev);
1238 me->me_mountdir = strdup (dir);
1239 me->me_type = strdup (tp);
1240 me->me_dev = de.disk_type;
1242 #ifdef DEBUG
1243 fprintf (stderr,
1244 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1245 de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
1246 fprintf (stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
1247 fprintf (stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
1248 #endif /* DEBUG */
1250 return (me);
1252 #endif /* HAVE_INFOMOUNT_QNX */
1254 /* --------------------------------------------------------------------------------------------- */
1256 #ifdef STAT_READ_FILSYS /* SVR2 */
1258 /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
1259 interrupted. Return the actual number of bytes read(written), zero for EOF,
1260 or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */
1261 static size_t
1262 safe_read (int fd, void *buf, size_t count)
1264 /* Work around a bug in Tru64 5.1. Attempting to read more than
1265 INT_MAX bytes fails with errno == EINVAL. See
1266 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
1267 When decreasing COUNT, keep it block-aligned. */
1268 /* *INDENT-OFF* */
1269 enum { BUGGY_READ_MAXIMUM = INT_MAX & ~8191 };
1270 /* *INDENT-ON* */
1272 for (;;)
1274 ssize_t result = read (fd, buf, count);
1276 if (0 <= result)
1277 return result;
1278 else if (IS_EINTR (errno))
1279 continue;
1280 else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count)
1281 count = BUGGY_READ_MAXIMUM;
1282 else
1283 return result;
1287 /* --------------------------------------------------------------------------------------------- */
1289 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1290 interrupted or if a partial write(read) occurs. Return the number
1291 of bytes transferred.
1292 When writing, set errno if fewer than COUNT bytes are written.
1293 When reading, if fewer than COUNT bytes are read, you must examine
1294 errno to distinguish failure from EOF (errno == 0). */
1296 static size_t
1297 full_read (int fd, void *buf, size_t count)
1299 size_t total = 0;
1300 char *ptr = (char *) buf;
1302 while (count > 0)
1304 size_t n_rw = safe_read (fd, ptr, count);
1305 if (n_rw == (size_t) (-1))
1306 break;
1307 if (n_rw == 0)
1309 errno = ZERO_BYTE_TRANSFER_ERRNO;
1310 break;
1312 total += n_rw;
1313 ptr += n_rw;
1314 count -= n_rw;
1317 return total;
1320 #endif /* STAT_READ_FILSYS */
1322 /* --------------------------------------------------------------------------------------------- */
1324 #ifdef HAVE_INFOMOUNT
1325 /* Fill in the fields of FSP with information about space usage for
1326 the file system on which FILE resides.
1327 DISK is the device on which FILE is mounted, for space-getting
1328 methods that need to know it.
1329 Return 0 if successful, -1 if not. When returning -1, ensure that
1330 ERRNO is either a system error value, or zero if DISK is NULL
1331 on a system that requires a non-NULL value. */
1332 static int
1333 get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
1335 #ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
1337 if (statvfs_works ())
1339 struct statvfs vfsd;
1341 if (statvfs (file, &vfsd) < 0)
1342 return -1;
1344 /* f_frsize isn't guaranteed to be supported. */
1345 fsp->fsu_blocksize = (vfsd.f_frsize
1346 ? PROPAGATE_ALL_ONES (vfsd.f_frsize)
1347 : PROPAGATE_ALL_ONES (vfsd.f_bsize));
1349 fsp->fsu_blocks = PROPAGATE_ALL_ONES (vfsd.f_blocks);
1350 fsp->fsu_bfree = PROPAGATE_ALL_ONES (vfsd.f_bfree);
1351 fsp->fsu_bavail = PROPAGATE_TOP_BIT (vfsd.f_bavail);
1352 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (vfsd.f_bavail) != 0;
1353 fsp->fsu_files = PROPAGATE_ALL_ONES (vfsd.f_files);
1354 fsp->fsu_ffree = PROPAGATE_ALL_ONES (vfsd.f_ffree);
1356 else
1357 #endif
1360 #if defined STAT_STATVFS64 /* AIX */
1362 struct statvfs64 fsd;
1364 if (statvfs64 (file, &fsd) < 0)
1365 return -1;
1367 /* f_frsize isn't guaranteed to be supported. */
1368 /* *INDENT-OFF* */
1369 fsp->fsu_blocksize = fsd.f_frsize
1370 ? PROPAGATE_ALL_ONES (fsd.f_frsize)
1371 : PROPAGATE_ALL_ONES (fsd.f_bsize);
1372 /* *INDENT-ON* */
1374 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1376 struct fs_data fsd;
1378 if (statfs (file, &fsd) != 1)
1379 return -1;
1381 fsp->fsu_blocksize = 1024;
1382 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot);
1383 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree);
1384 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen);
1385 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0;
1386 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
1387 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
1389 #elif defined STAT_READ_FILSYS /* SVR2 */
1390 #ifndef SUPERBOFF
1391 #define SUPERBOFF (SUPERB * 512)
1392 #endif
1394 struct filsys fsd;
1395 int fd;
1397 if (!disk)
1399 errno = 0;
1400 return -1;
1403 fd = open (disk, O_RDONLY);
1404 if (fd < 0)
1405 return -1;
1406 lseek (fd, (off_t) SUPERBOFF, 0);
1407 if (full_read (fd, (char *) &fsd, sizeof (fsd)) != sizeof (fsd))
1409 close (fd);
1410 return -1;
1412 close (fd);
1414 fsp->fsu_blocksize = (fsd.s_type == Fs2b ? 1024 : 512);
1415 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.s_fsize);
1416 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.s_tfree);
1417 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree);
1418 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0;
1419 fsp->fsu_files = (fsd.s_isize == -1
1420 ? UINTMAX_MAX : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1));
1421 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode);
1423 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1425 struct statfs fsd;
1427 if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
1428 return -1;
1430 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1432 #elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
1434 struct statfs fsd;
1436 if (statfs (file, &fsd) < 0)
1437 return -1;
1439 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_frsize);
1441 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
1442 Mac OS X < 10.4, FreeBSD < 5.0, \
1443 NetBSD < 3.0, OpenBSD < 4.4 */
1445 struct statfs fsd;
1447 if (statfs (file, &fsd) < 0)
1448 return -1;
1450 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1452 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1454 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1455 struct statfs are truncated to 2GB. These conditions detect that
1456 truncation, presumably without botching the 4.1.1 case, in which
1457 the values are not truncated. The correct counts are stored in
1458 undocumented spare fields. */
1459 if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
1461 fsd.f_blocks = fsd.f_spare[0];
1462 fsd.f_bfree = fsd.f_spare[1];
1463 fsd.f_bavail = fsd.f_spare[2];
1465 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1467 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1469 struct statfs fsd;
1471 if (statfs (file, &fsd) < 0)
1472 return -1;
1474 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1476 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1477 Dolphin */
1479 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1480 #define f_bavail f_bfree
1481 #endif
1483 struct statfs fsd;
1485 if (statfs (file, &fsd, sizeof (fsd), 0) < 0)
1486 return -1;
1488 /* Empirically, the block counts on most SVR3 and SVR3-derived
1489 systems seem to always be in terms of 512-byte blocks,
1490 no matter what value f_bsize has. */
1491 #if defined _AIX || defined _CRAY
1492 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1493 #else
1494 fsp->fsu_blocksize = 512;
1495 #endif
1497 #endif
1499 #if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 \
1500 || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE \
1501 || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
1503 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
1504 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
1505 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
1506 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
1507 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
1508 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
1510 #endif
1513 (void) disk; /* avoid argument-unused warning */
1515 return 0;
1517 #endif /* HAVE_INFOMOUNT */
1519 /* --------------------------------------------------------------------------------------------- */
1520 /*** public functions ****************************************************************************/
1521 /* --------------------------------------------------------------------------------------------- */
1523 void
1524 free_my_statfs (void)
1526 #ifdef HAVE_INFOMOUNT_LIST
1527 while (mc_mount_list != NULL)
1529 struct mount_entry *next;
1531 next = mc_mount_list->me_next;
1532 free_mount_entry (mc_mount_list);
1533 mc_mount_list = next;
1536 mc_mount_list = NULL;
1537 #endif /* HAVE_INFOMOUNT_LIST */
1540 /* --------------------------------------------------------------------------------------------- */
1542 void
1543 init_my_statfs (void)
1545 #ifdef HAVE_INFOMOUNT_LIST
1546 free_my_statfs ();
1547 mc_mount_list = read_file_system_list (1);
1548 #endif /* HAVE_INFOMOUNT_LIST */
1551 /* --------------------------------------------------------------------------------------------- */
1553 void
1554 my_statfs (struct my_statfs *myfs_stats, const char *path)
1556 #ifdef HAVE_INFOMOUNT_LIST
1557 size_t i, len = 0;
1558 struct mount_entry *entry = NULL;
1559 struct mount_entry *temp = mc_mount_list;
1560 struct fs_usage fs_use;
1562 while (temp)
1564 i = strlen (temp->me_mountdir);
1565 if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
1566 if (!entry || (path[i] == PATH_SEP || path[i] == '\0'))
1568 len = i;
1569 entry = temp;
1571 temp = temp->me_next;
1574 if (entry)
1576 memset (&fs_use, 0, sizeof (struct fs_usage));
1577 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1579 myfs_stats->type = entry->me_dev;
1580 myfs_stats->typename = entry->me_type;
1581 myfs_stats->mpoint = entry->me_mountdir;
1582 myfs_stats->device = entry->me_devname;
1583 myfs_stats->avail =
1584 ((uintmax_t) (getuid ()? fs_use.fsu_bavail : fs_use.fsu_bfree) *
1585 fs_use.fsu_blocksize) >> 10;
1586 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1587 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1588 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1590 else
1591 #endif /* HAVE_INFOMOUNT_LIST */
1593 #ifdef HAVE_INFOMOUNT_QNX
1595 ** This is the "other side" of the hack to read_file_system_list() in
1596 ** mountlist.c.
1597 ** It's not the most efficient approach, but consumes less memory. It
1598 ** also accomodates QNX's ability to mount filesystems on the fly.
1600 struct mount_entry *entry;
1601 struct fs_usage fs_use;
1603 entry = read_file_system_list (0, 0);
1604 if (entry != NULL)
1606 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1608 myfs_stats->type = entry->me_dev;
1609 myfs_stats->typename = entry->me_type;
1610 myfs_stats->mpoint = entry->me_mountdir;
1611 myfs_stats->device = entry->me_devname;
1613 myfs_stats->avail = ((uintmax_t) fs_use.fsu_bfree * fs_use.fsu_blocksize) >> 10;
1614 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1615 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1616 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1618 else
1619 #endif /* HAVE_INFOMOUNT_QNX */
1621 myfs_stats->type = 0;
1622 myfs_stats->mpoint = "unknown";
1623 myfs_stats->device = "unknown";
1624 myfs_stats->avail = 0;
1625 myfs_stats->total = 0;
1626 myfs_stats->nfree = 0;
1627 myfs_stats->nodes = 0;
1631 /* --------------------------------------------------------------------------------------------- */