Sync with gnulib b1fac377605c0eef8844fc8d3818d360f37d6fa4:
[midnight-commander.git] / src / filemanager / mountlist.c
blob739ff7f9e568f98dca0442aea03284a41556526c
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 static int
280 statvfs_works (void)
282 return 1;
284 #else
285 #include <string.h> /* for strverscmp */
286 #include <sys/utsname.h>
287 #include <sys/statfs.h>
288 #define STAT_STATFS2_BSIZE 1
290 static int
291 statvfs_works (void)
293 static int statvfs_works_cache = -1;
294 struct utsname name;
296 if (statvfs_works_cache < 0)
297 statvfs_works_cache = (uname (&name) == 0 && 0 <= strverscmp (name.release, "2.6.36"));
298 return statvfs_works_cache;
300 #endif
301 #endif
303 #ifdef STAT_READ_FILSYS /* SVR2 */
304 /* Set errno to zero upon EOF. */
305 #define ZERO_BYTE_TRANSFER_ERRNO 0
307 #ifdef EINTR
308 #define IS_EINTR(x) ((x) == EINTR)
309 #else
310 #define IS_EINTR(x) 0
311 #endif
312 #endif /* STAT_READ_FILSYS */
314 /*** file scope type declarations ****************************************************************/
316 /* A mount table entry. */
317 struct mount_entry
319 char *me_devname; /* Device node name, including "/dev/". */
320 char *me_mountdir; /* Mount point directory name. */
321 char *me_type; /* "nfs", "4.2", etc. */
322 dev_t me_dev; /* Device number of me_mountdir. */
323 unsigned int me_dummy:1; /* Nonzero for dummy file systems. */
324 unsigned int me_remote:1; /* Nonzero for remote fileystems. */
325 unsigned int me_type_malloced:1; /* Nonzero if me_type was malloced. */
326 struct mount_entry *me_next;
329 struct fs_usage
331 uintmax_t fsu_blocksize; /* Size of a block. */
332 uintmax_t fsu_blocks; /* Total blocks. */
333 uintmax_t fsu_bfree; /* Free blocks available to superuser. */
334 uintmax_t fsu_bavail; /* Free blocks available to non-superuser. */
335 int fsu_bavail_top_bit_set; /* 1 if fsu_bavail represents a value < 0. */
336 uintmax_t fsu_files; /* Total file nodes. */
337 uintmax_t fsu_ffree; /* Free file nodes. */
340 /*** file scope variables ************************************************************************/
342 #ifdef HAVE_INFOMOUNT_LIST
343 static struct mount_entry *mc_mount_list = NULL;
344 #endif /* HAVE_INFOMOUNT_LIST */
346 /*** file scope functions ************************************************************************/
347 /* --------------------------------------------------------------------------------------------- */
349 #ifdef HAVE_INFOMOUNT_LIST
350 static void
351 free_mount_entry (struct mount_entry *me)
353 if (!me)
354 return;
355 if (me->me_devname)
356 free (me->me_devname);
357 if (me->me_mountdir)
358 free (me->me_mountdir);
359 if (me->me_type && me->me_type_malloced)
360 free (me->me_type);
361 free (me);
364 /* --------------------------------------------------------------------------------------------- */
366 #ifdef MOUNTED_GETMNTINFO
368 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
369 static char *
370 fstype_to_string (short int t)
372 switch (t)
374 #ifdef MOUNT_PC
375 case MOUNT_PC:
376 return "pc";
377 #endif
378 #ifdef MOUNT_MFS
379 case MOUNT_MFS:
380 return "mfs";
381 #endif
382 #ifdef MOUNT_LO
383 case MOUNT_LO:
384 return "lo";
385 #endif
386 #ifdef MOUNT_TFS
387 case MOUNT_TFS:
388 return "tfs";
389 #endif
390 #ifdef MOUNT_TMP
391 case MOUNT_TMP:
392 return "tmp";
393 #endif
394 #ifdef MOUNT_UFS
395 case MOUNT_UFS:
396 return "ufs";
397 #endif
398 #ifdef MOUNT_NFS
399 case MOUNT_NFS:
400 return "nfs";
401 #endif
402 #ifdef MOUNT_MSDOS
403 case MOUNT_MSDOS:
404 return "msdos";
405 #endif
406 #ifdef MOUNT_LFS
407 case MOUNT_LFS:
408 return "lfs";
409 #endif
410 #ifdef MOUNT_LOFS
411 case MOUNT_LOFS:
412 return "lofs";
413 #endif
414 #ifdef MOUNT_FDESC
415 case MOUNT_FDESC:
416 return "fdesc";
417 #endif
418 #ifdef MOUNT_PORTAL
419 case MOUNT_PORTAL:
420 return "portal";
421 #endif
422 #ifdef MOUNT_NULL
423 case MOUNT_NULL:
424 return "null";
425 #endif
426 #ifdef MOUNT_UMAP
427 case MOUNT_UMAP:
428 return "umap";
429 #endif
430 #ifdef MOUNT_KERNFS
431 case MOUNT_KERNFS:
432 return "kernfs";
433 #endif
434 #ifdef MOUNT_PROCFS
435 case MOUNT_PROCFS:
436 return "procfs";
437 #endif
438 #ifdef MOUNT_AFS
439 case MOUNT_AFS:
440 return "afs";
441 #endif
442 #ifdef MOUNT_CD9660
443 case MOUNT_CD9660:
444 return "cd9660";
445 #endif
446 #ifdef MOUNT_UNION
447 case MOUNT_UNION:
448 return "union";
449 #endif
450 #ifdef MOUNT_DEVFS
451 case MOUNT_DEVFS:
452 return "devfs";
453 #endif
454 #ifdef MOUNT_EXT2FS
455 case MOUNT_EXT2FS:
456 return "ext2fs";
457 #endif
458 default:
459 return "?";
462 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
464 /* --------------------------------------------------------------------------------------------- */
466 static char *
467 fsp_to_string (const struct statfs *fsp)
469 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
470 return (char *) (fsp->f_fstypename);
471 #else
472 return fstype_to_string (fsp->f_type);
473 #endif
475 #endif /* MOUNTED_GETMNTINFO */
477 /* --------------------------------------------------------------------------------------------- */
479 #ifdef MOUNTED_VMOUNT /* AIX. */
480 static char *
481 fstype_to_string (int t)
483 struct vfs_ent *e;
485 e = getvfsbytype (t);
486 if (!e || !e->vfsent_name)
487 return "none";
488 else
489 return e->vfsent_name;
491 #endif /* MOUNTED_VMOUNT */
493 /* --------------------------------------------------------------------------------------------- */
495 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
497 /* Return the device number from MOUNT_OPTIONS, if possible.
498 Otherwise return (dev_t) -1. */
500 /* --------------------------------------------------------------------------------------------- */
502 static dev_t
503 dev_from_mount_options (char const *mount_options)
505 /* GNU/Linux allows file system implementations to define their own
506 meaning for "dev=" mount options, so don't trust the meaning
507 here. */
508 #ifndef __linux__
509 static char const dev_pattern[] = ",dev=";
510 char const *devopt = strstr (mount_options, dev_pattern);
512 if (devopt)
514 char const *optval = devopt + sizeof (dev_pattern) - 1;
515 char *optvalend;
516 unsigned long int dev;
517 errno = 0;
518 dev = strtoul (optval, &optvalend, 16);
519 if (optval != optvalend
520 && (*optvalend == '\0' || *optvalend == ',')
521 && !(dev == ULONG_MAX && errno == ERANGE) && dev == (dev_t) dev)
522 return dev;
524 #endif
526 (void) mount_options;
527 return -1;
530 #endif
532 /* --------------------------------------------------------------------------------------------- */
534 #if defined _AIX && defined _I386
535 /* AIX PS/2 does not supply statfs. */
537 static int
538 statfs (char *file, struct statfs *fsb)
540 struct stat stats;
541 struct dustat fsd;
543 if (stat (file, &stats) != 0)
544 return -1;
545 if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
546 return -1;
547 fsb->f_type = 0;
548 fsb->f_bsize = fsd.du_bsize;
549 fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
550 fsb->f_bfree = fsd.du_tfree;
551 fsb->f_bavail = fsd.du_tfree;
552 fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
553 fsb->f_ffree = fsd.du_tinode;
554 fsb->f_fsid.val[0] = fsd.du_site;
555 fsb->f_fsid.val[1] = fsd.du_pckno;
556 return 0;
559 #endif /* _AIX && _I386 */
561 /* --------------------------------------------------------------------------------------------- */
563 /* Return a list of the currently mounted file systems, or NULL on error.
564 Add each entry to the tail of the list so that they stay in order.
565 If NEED_FS_TYPE is true, ensure that the file system type fields in
566 the returned list are valid. Otherwise, they might not be. */
568 static struct mount_entry *
569 read_file_system_list (int need_fs_type)
571 struct mount_entry *mount_list;
572 struct mount_entry *me;
573 struct mount_entry **mtail = &mount_list;
575 #ifdef MOUNTED_LISTMNTENT
577 struct tabmntent *mntlist, *p;
578 struct mntent *mnt;
579 struct mount_entry *me;
581 /* the third and fourth arguments could be used to filter mounts,
582 but Crays doesn't seem to have any mounts that we want to
583 remove. Specifically, automount create normal NFS mounts.
586 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
587 return NULL;
588 for (p = mntlist; p; p = p->next)
590 mnt = p->ment;
591 me = malloc (sizeof (*me));
592 me->me_devname = strdup (mnt->mnt_fsname);
593 me->me_mountdir = strdup (mnt->mnt_dir);
594 me->me_type = strdup (mnt->mnt_type);
595 me->me_type_malloced = 1;
596 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
597 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
598 me->me_dev = -1;
599 *mtail = me;
600 mtail = &me->me_next;
602 freemntlist (mntlist);
604 #endif
606 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
608 struct mntent *mnt;
609 const char *table = MOUNTED;
610 FILE *fp;
612 fp = setmntent (table, "r");
613 if (fp == NULL)
614 return NULL;
616 while ((mnt = getmntent (fp)))
618 me = malloc (sizeof (*me));
619 me->me_devname = strdup (mnt->mnt_fsname);
620 me->me_mountdir = strdup (mnt->mnt_dir);
621 me->me_type = strdup (mnt->mnt_type);
622 me->me_type_malloced = 1;
623 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
624 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
625 me->me_dev = dev_from_mount_options (mnt->mnt_opts);
627 /* Add to the linked list. */
628 *mtail = me;
629 mtail = &me->me_next;
632 if (endmntent (fp) == 0)
633 goto free_then_fail;
635 #endif /* MOUNTED_GETMNTENT1. */
637 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
639 struct statfs *fsp;
640 int entries;
642 entries = getmntinfo (&fsp, MNT_NOWAIT);
643 if (entries < 0)
644 return NULL;
645 for (; entries-- > 0; fsp++)
647 char *fs_type = fsp_to_string (fsp);
649 me = malloc (sizeof (*me));
650 me->me_devname = strdup (fsp->f_mntfromname);
651 me->me_mountdir = strdup (fsp->f_mntonname);
652 me->me_type = fs_type;
653 me->me_type_malloced = 0;
654 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
655 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
656 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
658 /* Add to the linked list. */
659 *mtail = me;
660 mtail = &me->me_next;
663 #endif /* MOUNTED_GETMNTINFO */
665 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
667 struct statvfs *fsp;
668 int entries;
670 entries = getmntinfo (&fsp, MNT_NOWAIT);
671 if (entries < 0)
672 return NULL;
673 for (; entries-- > 0; fsp++)
675 me = malloc (sizeof (*me));
676 me->me_devname = strdup (fsp->f_mntfromname);
677 me->me_mountdir = strdup (fsp->f_mntonname);
678 me->me_type = strdup (fsp->f_fstypename);
679 me->me_type_malloced = 1;
680 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
681 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
682 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
684 /* Add to the linked list. */
685 *mtail = me;
686 mtail = &me->me_next;
689 #endif /* MOUNTED_GETMNTINFO2 */
691 #ifdef MOUNTED_GETMNT /* Ultrix. */
693 int offset = 0;
694 int val;
695 struct fs_data fsd;
697 while (errno = 0, 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, (char *) 0)))
699 me = malloc (sizeof (*me));
700 me->me_devname = strdup (fsd.fd_req.devname);
701 me->me_mountdir = strdup (fsd.fd_req.path);
702 me->me_type = gt_names[fsd.fd_req.fstype];
703 me->me_type_malloced = 0;
704 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
705 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
706 me->me_dev = fsd.fd_req.dev;
708 /* Add to the linked list. */
709 *mtail = me;
710 mtail = &me->me_next;
712 if (val < 0)
713 goto free_then_fail;
715 #endif /* MOUNTED_GETMNT. */
717 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
719 /* The next_dev() and fs_stat_dev() system calls give the list of
720 all file systems, including the information returned by statvfs()
721 (fs type, total blocks, free blocks etc.), but without the mount
722 point. But on BeOS all file systems except / are mounted in the
723 rootfs, directly under /.
724 The directory name of the mount point is often, but not always,
725 identical to the volume name of the device.
726 We therefore get the list of subdirectories of /, and the list
727 of all file systems, and match the two lists. */
729 DIR *dirp;
730 struct rootdir_entry
732 char *name;
733 dev_t dev;
734 ino_t ino;
735 struct rootdir_entry *next;
737 struct rootdir_entry *rootdir_list;
738 struct rootdir_entry **rootdir_tail;
739 int32 pos;
740 dev_t dev;
741 fs_info fi;
743 /* All volumes are mounted in the rootfs, directly under /. */
744 rootdir_list = NULL;
745 rootdir_tail = &rootdir_list;
746 dirp = opendir ("/");
747 if (dirp)
749 struct dirent *d;
751 while ((d = readdir (dirp)) != NULL)
753 char *name;
754 struct stat statbuf;
756 if (strcmp (d->d_name, "..") == 0)
757 continue;
759 if (strcmp (d->d_name, ".") == 0)
760 name = strdup ("/");
761 else
763 name = malloc (1 + strlen (d->d_name) + 1);
764 name[0] = '/';
765 strcpy (name + 1, d->d_name);
768 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
770 struct rootdir_entry *re = malloc (sizeof (*re));
771 re->name = name;
772 re->dev = statbuf.st_dev;
773 re->ino = statbuf.st_ino;
775 /* Add to the linked list. */
776 *rootdir_tail = re;
777 rootdir_tail = &re->next;
779 else
780 free (name);
782 closedir (dirp);
784 *rootdir_tail = NULL;
786 for (pos = 0; (dev = next_dev (&pos)) >= 0;)
787 if (fs_stat_dev (dev, &fi) >= 0)
789 /* Note: fi.dev == dev. */
790 struct rootdir_entry *re;
792 for (re = rootdir_list; re; re = re->next)
793 if (re->dev == fi.dev && re->ino == fi.root)
794 break;
796 me = malloc (sizeof (*me));
797 me->me_devname = strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
798 me->me_mountdir = strdup (re != NULL ? re->name : fi.fsh_name);
799 me->me_type = strdup (fi.fsh_name);
800 me->me_type_malloced = 1;
801 me->me_dev = fi.dev;
802 me->me_dummy = 0;
803 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
805 /* Add to the linked list. */
806 *mtail = me;
807 mtail = &me->me_next;
809 *mtail = NULL;
811 while (rootdir_list != NULL)
813 struct rootdir_entry *re = rootdir_list;
814 rootdir_list = re->next;
815 free (re->name);
816 free (re);
819 #endif /* MOUNTED_FS_STAT_DEV */
821 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
823 int numsys, counter;
824 size_t bufsize;
825 struct statfs *stats;
827 numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
828 if (numsys < 0)
829 return NULL;
830 if (SIZE_MAX / sizeof (*stats) <= numsys)
832 fprintf (stderr, "%s\n", _("Memory exhausted!"));
833 exit (EXIT_FAILURE);
836 bufsize = (1 + numsys) * sizeof (*stats);
837 stats = malloc (bufsize);
838 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
840 if (numsys < 0)
842 free (stats);
843 return NULL;
846 for (counter = 0; counter < numsys; counter++)
848 me = malloc (sizeof (*me));
849 me->me_devname = strdup (stats[counter].f_mntfromname);
850 me->me_mountdir = strdup (stats[counter].f_mntonname);
851 me->me_type = strdup (FS_TYPE (stats[counter]));
852 me->me_type_malloced = 1;
853 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
854 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
855 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
857 /* Add to the linked list. */
858 *mtail = me;
859 mtail = &me->me_next;
862 free (stats);
864 #endif /* MOUNTED_GETFSSTAT */
866 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
868 struct mnttab mnt;
869 char *table = "/etc/mnttab";
870 FILE *fp;
872 fp = fopen (table, "r");
873 if (fp == NULL)
874 return NULL;
876 while (fread (&mnt, sizeof (mnt), 1, fp) > 0)
878 me = malloc (sizeof (*me));
879 #ifdef GETFSTYP /* SVR3. */
880 me->me_devname = strdup (mnt.mt_dev);
881 #else
882 me->me_devname = malloc (strlen (mnt.mt_dev) + 6);
883 strcpy (me->me_devname, "/dev/");
884 strcpy (me->me_devname + 5, mnt.mt_dev);
885 #endif
886 me->me_mountdir = strdup (mnt.mt_filsys);
887 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
888 me->me_type = "";
889 me->me_type_malloced = 0;
890 #ifdef GETFSTYP /* SVR3. */
891 if (need_fs_type)
893 struct statfs fsd;
894 char typebuf[FSTYPSZ];
896 if (statfs (me->me_mountdir, &fsd, sizeof (fsd), 0) != -1
897 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
899 me->me_type = strdup (typebuf);
900 me->me_type_malloced = 1;
903 #endif
904 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
905 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
907 /* Add to the linked list. */
908 *mtail = me;
909 mtail = &me->me_next;
912 if (ferror (fp))
914 /* The last fread() call must have failed. */
915 int saved_errno = errno;
916 fclose (fp);
917 errno = saved_errno;
918 goto free_then_fail;
921 if (fclose (fp) == EOF)
922 goto free_then_fail;
924 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
926 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
928 struct mntent **mnttbl = getmnttbl (), **ent;
929 for (ent = mnttbl; *ent; ent++)
931 me = malloc (sizeof (*me));
932 me->me_devname = strdup ((*ent)->mt_resource);
933 me->me_mountdir = strdup ((*ent)->mt_directory);
934 me->me_type = strdup ((*ent)->mt_fstype);
935 me->me_type_malloced = 1;
936 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
937 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
938 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
940 /* Add to the linked list. */
941 *mtail = me;
942 mtail = &me->me_next;
944 endmnttbl ();
946 #endif
948 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
950 struct mnttab mnt;
951 char *table = MNTTAB;
952 FILE *fp;
953 int ret;
954 int lockfd = -1;
956 #if defined F_RDLCK && defined F_SETLKW
957 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
958 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
959 for this file name, we should use their macro name instead.
960 (Why not just lock MNTTAB directly? We don't know.) */
961 #ifndef MNTTAB_LOCK
962 #define MNTTAB_LOCK "/etc/.mnttab.lock"
963 #endif
964 lockfd = open (MNTTAB_LOCK, O_RDONLY);
965 if (0 <= lockfd)
967 struct flock flock;
968 flock.l_type = F_RDLCK;
969 flock.l_whence = SEEK_SET;
970 flock.l_start = 0;
971 flock.l_len = 0;
972 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
973 if (errno != EINTR)
975 int saved_errno = errno;
976 close (lockfd);
977 errno = saved_errno;
978 return NULL;
981 else if (errno != ENOENT)
982 return NULL;
983 #endif
985 errno = 0;
986 fp = fopen (table, "r");
987 if (fp == NULL)
988 ret = errno;
989 else
991 while ((ret = getmntent (fp, &mnt)) == 0)
993 me = malloc (sizeof (*me));
994 me->me_devname = strdup (mnt.mnt_special);
995 me->me_mountdir = strdup (mnt.mnt_mountp);
996 me->me_type = strdup (mnt.mnt_fstype);
997 me->me_type_malloced = 1;
998 me->me_dummy = MNT_IGNORE (&mnt) != 0;
999 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1000 me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
1002 /* Add to the linked list. */
1003 *mtail = me;
1004 mtail = &me->me_next;
1007 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
1010 if (0 <= lockfd && close (lockfd) != 0)
1011 ret = errno;
1013 if (0 <= ret)
1015 errno = ret;
1016 goto free_then_fail;
1019 #endif /* MOUNTED_GETMNTENT2. */
1021 #ifdef MOUNTED_VMOUNT /* AIX. */
1023 int bufsize;
1024 char *entries, *thisent;
1025 struct vmount *vmp;
1026 int n_entries;
1027 int i;
1029 /* Ask how many bytes to allocate for the mounted file system info. */
1030 if (mntctl (MCTL_QUERY, sizeof (bufsize), (struct vmount *) &bufsize) != 0)
1031 return NULL;
1032 entries = malloc (bufsize);
1034 /* Get the list of mounted file systems. */
1035 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
1036 if (n_entries < 0)
1038 int saved_errno = errno;
1039 free (entries);
1040 errno = saved_errno;
1041 return NULL;
1044 for (i = 0, thisent = entries; i < n_entries; i++, thisent += vmp->vmt_length)
1046 char *options, *ignore;
1048 vmp = (struct vmount *) thisent;
1049 me = malloc (sizeof (*me));
1050 if (vmp->vmt_flags & MNT_REMOTE)
1052 char *host, *dir;
1054 me->me_remote = 1;
1055 /* Prepend the remote dirname. */
1056 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
1057 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
1058 me->me_devname = malloc (strlen (host) + strlen (dir) + 2);
1059 strcpy (me->me_devname, host);
1060 strcat (me->me_devname, ":");
1061 strcat (me->me_devname, dir);
1063 else
1065 me->me_remote = 0;
1066 me->me_devname = strdup (thisent + vmp->vmt_data[VMT_OBJECT].vmt_off);
1068 me->me_mountdir = strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
1069 me->me_type = strdup (fstype_to_string (vmp->vmt_gfstype));
1070 me->me_type_malloced = 1;
1071 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
1072 ignore = strstr (options, "ignore");
1073 me->me_dummy = (ignore
1074 && (ignore == options || ignore[-1] == ',')
1075 && (ignore[sizeof ("ignore") - 1] == ','
1076 || ignore[sizeof ("ignore") - 1] == '\0'));
1077 me->me_dev = (dev_t) (-1); /* vmt_fsid might be the info we want. */
1079 /* Add to the linked list. */
1080 *mtail = me;
1081 mtail = &me->me_next;
1083 free (entries);
1085 #endif /* MOUNTED_VMOUNT. */
1088 #ifdef MOUNTED_INTERIX_STATVFS
1090 DIR *dirp = opendir ("/dev/fs");
1091 char node[9 + NAME_MAX];
1093 if (!dirp)
1094 goto free_then_fail;
1096 while (1)
1098 struct statvfs dev;
1099 struct dirent entry;
1100 struct dirent *result;
1102 if (readdir_r (dirp, &entry, &result) || result == NULL)
1103 break;
1105 strcpy (node, "/dev/fs/");
1106 strcat (node, entry.d_name);
1108 if (statvfs (node, &dev) == 0)
1110 me = malloc (sizeof *me);
1111 me->me_devname = strdup (dev.f_mntfromname);
1112 me->me_mountdir = strdup (dev.f_mntonname);
1113 me->me_type = strdup (dev.f_fstypename);
1114 me->me_type_malloced = 1;
1115 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1116 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1117 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
1119 /* Add to the linked list. */
1120 *mtail = me;
1121 mtail = &me->me_next;
1125 #endif /* MOUNTED_INTERIX_STATVFS */
1127 (void) need_fs_type; /* avoid argument-unused warning */
1128 *mtail = NULL;
1129 return mount_list;
1132 free_then_fail:
1134 int saved_errno = errno;
1135 *mtail = NULL;
1137 while (mount_list)
1139 me = mount_list->me_next;
1140 free (mount_list->me_devname);
1141 free (mount_list->me_mountdir);
1142 if (mount_list->me_type_malloced)
1143 free (mount_list->me_type);
1144 free (mount_list);
1145 mount_list = me;
1148 errno = saved_errno;
1149 return NULL;
1153 #endif /* HAVE_INFOMOUNT_LIST */
1155 /* --------------------------------------------------------------------------------------------- */
1157 #ifdef HAVE_INFOMOUNT_QNX
1159 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1160 ** this via the following code.
1161 ** Note that, as this is based on CWD, it only fills one mount_entry
1162 ** structure. See my_statfs() in utilunix.c for the "other side" of
1163 ** this hack.
1166 static struct mount_entry *
1167 read_file_system_list (int need_fs_type, int all_fs)
1169 struct _disk_entry de;
1170 struct statfs fs;
1171 int i, fd;
1172 char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
1174 static struct mount_entry *me = NULL;
1176 if (me)
1178 if (me->me_devname)
1179 free (me->me_devname);
1180 if (me->me_mountdir)
1181 free (me->me_mountdir);
1182 if (me->me_type)
1183 free (me->me_type);
1185 else
1186 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
1188 if (!getcwd (dir, _POSIX_PATH_MAX))
1189 return (NULL);
1191 fd = open (dir, O_RDONLY);
1192 if (fd == -1)
1193 return (NULL);
1195 i = disk_get_entry (fd, &de);
1197 close (fd);
1199 if (i == -1)
1200 return (NULL);
1202 switch (de.disk_type)
1204 case _UNMOUNTED:
1205 tp = "unmounted";
1206 break;
1207 case _FLOPPY:
1208 tp = "Floppy";
1209 break;
1210 case _HARD:
1211 tp = "Hard";
1212 break;
1213 case _RAMDISK:
1214 tp = "Ram";
1215 break;
1216 case _REMOVABLE:
1217 tp = "Removable";
1218 break;
1219 case _TAPE:
1220 tp = "Tape";
1221 break;
1222 case _CDROM:
1223 tp = "CDROM";
1224 break;
1225 default:
1226 tp = "unknown";
1229 if (fsys_get_mount_dev (dir, &dev) == -1)
1230 return (NULL);
1232 if (fsys_get_mount_pt (dev, &dir) == -1)
1233 return (NULL);
1235 me->me_devname = strdup (dev);
1236 me->me_mountdir = strdup (dir);
1237 me->me_type = strdup (tp);
1238 me->me_dev = de.disk_type;
1240 #ifdef DEBUG
1241 fprintf (stderr,
1242 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1243 de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
1244 fprintf (stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
1245 fprintf (stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
1246 #endif /* DEBUG */
1248 return (me);
1250 #endif /* HAVE_INFOMOUNT_QNX */
1252 /* --------------------------------------------------------------------------------------------- */
1254 #ifdef STAT_READ_FILSYS /* SVR2 */
1256 /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
1257 interrupted. Return the actual number of bytes read(written), zero for EOF,
1258 or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */
1259 static size_t
1260 safe_read (int fd, void *buf, size_t count)
1262 /* Work around a bug in Tru64 5.1. Attempting to read more than
1263 INT_MAX bytes fails with errno == EINVAL. See
1264 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
1265 When decreasing COUNT, keep it block-aligned. */
1266 /* *INDENT-OFF* */
1267 enum { BUGGY_READ_MAXIMUM = INT_MAX & ~8191 };
1268 /* *INDENT-ON* */
1270 for (;;)
1272 ssize_t result = read (fd, buf, count);
1274 if (0 <= result)
1275 return result;
1276 else if (IS_EINTR (errno))
1277 continue;
1278 else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count)
1279 count = BUGGY_READ_MAXIMUM;
1280 else
1281 return result;
1285 /* --------------------------------------------------------------------------------------------- */
1287 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1288 interrupted or if a partial write(read) occurs. Return the number
1289 of bytes transferred.
1290 When writing, set errno if fewer than COUNT bytes are written.
1291 When reading, if fewer than COUNT bytes are read, you must examine
1292 errno to distinguish failure from EOF (errno == 0). */
1294 static size_t
1295 full_read (int fd, void *buf, size_t count)
1297 size_t total = 0;
1298 char *ptr = (char *) buf;
1300 while (count > 0)
1302 size_t n_rw = safe_read (fd, ptr, count);
1303 if (n_rw == (size_t) (-1))
1304 break;
1305 if (n_rw == 0)
1307 errno = ZERO_BYTE_TRANSFER_ERRNO;
1308 break;
1310 total += n_rw;
1311 ptr += n_rw;
1312 count -= n_rw;
1315 return total;
1318 #endif /* STAT_READ_FILSYS */
1320 /* --------------------------------------------------------------------------------------------- */
1322 #ifdef HAVE_INFOMOUNT
1323 /* Fill in the fields of FSP with information about space usage for
1324 the file system on which FILE resides.
1325 DISK is the device on which FILE is mounted, for space-getting
1326 methods that need to know it.
1327 Return 0 if successful, -1 if not. When returning -1, ensure that
1328 ERRNO is either a system error value, or zero if DISK is NULL
1329 on a system that requires a non-NULL value. */
1330 static int
1331 get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
1333 #ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
1335 if (statvfs_works ())
1337 struct statvfs vfsd;
1339 if (statvfs (file, &vfsd) < 0)
1340 return -1;
1342 /* f_frsize isn't guaranteed to be supported. */
1343 fsp->fsu_blocksize = (vfsd.f_frsize
1344 ? PROPAGATE_ALL_ONES (vfsd.f_frsize)
1345 : PROPAGATE_ALL_ONES (vfsd.f_bsize));
1347 fsp->fsu_blocks = PROPAGATE_ALL_ONES (vfsd.f_blocks);
1348 fsp->fsu_bfree = PROPAGATE_ALL_ONES (vfsd.f_bfree);
1349 fsp->fsu_bavail = PROPAGATE_TOP_BIT (vfsd.f_bavail);
1350 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (vfsd.f_bavail) != 0;
1351 fsp->fsu_files = PROPAGATE_ALL_ONES (vfsd.f_files);
1352 fsp->fsu_ffree = PROPAGATE_ALL_ONES (vfsd.f_ffree);
1353 return 0;
1356 #endif
1358 #if defined STAT_STATVFS64 /* AIX */
1360 struct statvfs64 fsd;
1362 if (statvfs64 (file, &fsd) < 0)
1363 return -1;
1365 /* f_frsize isn't guaranteed to be supported. */
1366 /* *INDENT-OFF* */
1367 fsp->fsu_blocksize = fsd.f_frsize
1368 ? PROPAGATE_ALL_ONES (fsd.f_frsize)
1369 : PROPAGATE_ALL_ONES (fsd.f_bsize);
1370 /* *INDENT-ON* */
1372 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1374 struct fs_data fsd;
1376 if (statfs (file, &fsd) != 1)
1377 return -1;
1379 fsp->fsu_blocksize = 1024;
1380 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot);
1381 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree);
1382 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen);
1383 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0;
1384 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
1385 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
1387 #elif defined STAT_READ_FILSYS /* SVR2 */
1388 #ifndef SUPERBOFF
1389 #define SUPERBOFF (SUPERB * 512)
1390 #endif
1392 struct filsys fsd;
1393 int fd;
1395 if (!disk)
1397 errno = 0;
1398 return -1;
1401 fd = open (disk, O_RDONLY);
1402 if (fd < 0)
1403 return -1;
1404 lseek (fd, (off_t) SUPERBOFF, 0);
1405 if (full_read (fd, (char *) &fsd, sizeof (fsd)) != sizeof (fsd))
1407 close (fd);
1408 return -1;
1410 close (fd);
1412 fsp->fsu_blocksize = (fsd.s_type == Fs2b ? 1024 : 512);
1413 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.s_fsize);
1414 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.s_tfree);
1415 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree);
1416 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0;
1417 fsp->fsu_files = (fsd.s_isize == -1
1418 ? UINTMAX_MAX : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1));
1419 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode);
1421 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1423 struct statfs fsd;
1425 if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
1426 return -1;
1428 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1430 #elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
1432 struct statfs fsd;
1434 if (statfs (file, &fsd) < 0)
1435 return -1;
1437 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_frsize);
1439 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
1440 Mac OS X < 10.4, FreeBSD < 5.0, \
1441 NetBSD < 3.0, OpenBSD < 4.4 */
1443 struct statfs fsd;
1445 if (statfs (file, &fsd) < 0)
1446 return -1;
1448 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1450 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1452 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1453 struct statfs are truncated to 2GB. These conditions detect that
1454 truncation, presumably without botching the 4.1.1 case, in which
1455 the values are not truncated. The correct counts are stored in
1456 undocumented spare fields. */
1457 if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
1459 fsd.f_blocks = fsd.f_spare[0];
1460 fsd.f_bfree = fsd.f_spare[1];
1461 fsd.f_bavail = fsd.f_spare[2];
1463 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1465 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1467 struct statfs fsd;
1469 if (statfs (file, &fsd) < 0)
1470 return -1;
1472 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1474 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1475 Dolphin */
1477 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1478 #define f_bavail f_bfree
1479 #endif
1481 struct statfs fsd;
1483 if (statfs (file, &fsd, sizeof (fsd), 0) < 0)
1484 return -1;
1486 /* Empirically, the block counts on most SVR3 and SVR3-derived
1487 systems seem to always be in terms of 512-byte blocks,
1488 no matter what value f_bsize has. */
1489 #if defined _AIX || defined _CRAY
1490 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1491 #else
1492 fsp->fsu_blocksize = 512;
1493 #endif
1495 #endif
1497 #if (defined STAT_STATVFS64 \
1498 || (!defined STAT_STATFS2_FS_DATA && !defined STAT_READ_FILSYS))
1500 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
1501 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
1502 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
1503 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
1504 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
1505 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
1507 #endif
1508 (void) disk; /* avoid argument-unused warning */
1509 return 0;
1511 #endif /* HAVE_INFOMOUNT */
1513 /* --------------------------------------------------------------------------------------------- */
1514 /*** public functions ****************************************************************************/
1515 /* --------------------------------------------------------------------------------------------- */
1517 void
1518 free_my_statfs (void)
1520 #ifdef HAVE_INFOMOUNT_LIST
1521 while (mc_mount_list != NULL)
1523 struct mount_entry *next;
1525 next = mc_mount_list->me_next;
1526 free_mount_entry (mc_mount_list);
1527 mc_mount_list = next;
1530 mc_mount_list = NULL;
1531 #endif /* HAVE_INFOMOUNT_LIST */
1534 /* --------------------------------------------------------------------------------------------- */
1536 void
1537 init_my_statfs (void)
1539 #ifdef HAVE_INFOMOUNT_LIST
1540 free_my_statfs ();
1541 mc_mount_list = read_file_system_list (1);
1542 #endif /* HAVE_INFOMOUNT_LIST */
1545 /* --------------------------------------------------------------------------------------------- */
1547 void
1548 my_statfs (struct my_statfs *myfs_stats, const char *path)
1550 #ifdef HAVE_INFOMOUNT_LIST
1551 size_t i, len = 0;
1552 struct mount_entry *entry = NULL;
1553 struct mount_entry *temp = mc_mount_list;
1554 struct fs_usage fs_use;
1556 while (temp)
1558 i = strlen (temp->me_mountdir);
1559 if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
1560 if (!entry || (path[i] == PATH_SEP || path[i] == '\0'))
1562 len = i;
1563 entry = temp;
1565 temp = temp->me_next;
1568 if (entry)
1570 memset (&fs_use, 0, sizeof (struct fs_usage));
1571 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1573 myfs_stats->type = entry->me_dev;
1574 myfs_stats->typename = entry->me_type;
1575 myfs_stats->mpoint = entry->me_mountdir;
1576 myfs_stats->device = entry->me_devname;
1577 myfs_stats->avail =
1578 ((uintmax_t) (getuid ()? fs_use.fsu_bavail : fs_use.fsu_bfree) *
1579 fs_use.fsu_blocksize) >> 10;
1580 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1581 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1582 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1584 else
1585 #endif /* HAVE_INFOMOUNT_LIST */
1587 #ifdef HAVE_INFOMOUNT_QNX
1589 ** This is the "other side" of the hack to read_file_system_list() in
1590 ** mountlist.c.
1591 ** It's not the most efficient approach, but consumes less memory. It
1592 ** also accomodates QNX's ability to mount filesystems on the fly.
1594 struct mount_entry *entry;
1595 struct fs_usage fs_use;
1597 entry = read_file_system_list (0, 0);
1598 if (entry != NULL)
1600 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1602 myfs_stats->type = entry->me_dev;
1603 myfs_stats->typename = entry->me_type;
1604 myfs_stats->mpoint = entry->me_mountdir;
1605 myfs_stats->device = entry->me_devname;
1607 myfs_stats->avail = ((uintmax_t) fs_use.fsu_bfree * fs_use.fsu_blocksize) >> 10;
1608 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1609 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1610 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1612 else
1613 #endif /* HAVE_INFOMOUNT_QNX */
1615 myfs_stats->type = 0;
1616 myfs_stats->mpoint = "unknown";
1617 myfs_stats->device = "unknown";
1618 myfs_stats->avail = 0;
1619 myfs_stats->total = 0;
1620 myfs_stats->nfree = 0;
1621 myfs_stats->nodes = 0;
1625 /* --------------------------------------------------------------------------------------------- */