src/filemanager/mountlist.c: apply mc code indentation policy.
[midnight-commander.git] / src / filemanager / mountlist.c
blob2be1a87e1eb92fa152794b8ed24610db922b929f
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_READ_FILSYS /* SVR2 */
274 /* Set errno to zero upon EOF. */
275 #define ZERO_BYTE_TRANSFER_ERRNO 0
277 #ifdef EINTR
278 #define IS_EINTR(x) ((x) == EINTR)
279 #else
280 #define IS_EINTR(x) 0
281 #endif
282 #endif /* STAT_READ_FILSYS */
284 /*** file scope type declarations ****************************************************************/
286 /* A mount table entry. */
287 struct mount_entry
289 char *me_devname; /* Device node name, including "/dev/". */
290 char *me_mountdir; /* Mount point directory name. */
291 char *me_type; /* "nfs", "4.2", etc. */
292 dev_t me_dev; /* Device number of me_mountdir. */
293 unsigned int me_dummy:1; /* Nonzero for dummy file systems. */
294 unsigned int me_remote:1; /* Nonzero for remote fileystems. */
295 unsigned int me_type_malloced:1; /* Nonzero if me_type was malloced. */
296 struct mount_entry *me_next;
299 struct fs_usage
301 uintmax_t fsu_blocksize; /* Size of a block. */
302 uintmax_t fsu_blocks; /* Total blocks. */
303 uintmax_t fsu_bfree; /* Free blocks available to superuser. */
304 uintmax_t fsu_bavail; /* Free blocks available to non-superuser. */
305 int fsu_bavail_top_bit_set; /* 1 if fsu_bavail represents a value < 0. */
306 uintmax_t fsu_files; /* Total file nodes. */
307 uintmax_t fsu_ffree; /* Free file nodes. */
310 /*** file scope variables ************************************************************************/
312 #ifdef HAVE_INFOMOUNT_LIST
313 static struct mount_entry *mc_mount_list = NULL;
314 #endif /* HAVE_INFOMOUNT_LIST */
316 /*** file scope functions ************************************************************************/
317 /* --------------------------------------------------------------------------------------------- */
319 #ifdef HAVE_INFOMOUNT_LIST
320 static void
321 free_mount_entry (struct mount_entry *me)
323 if (!me)
324 return;
325 if (me->me_devname)
326 free (me->me_devname);
327 if (me->me_mountdir)
328 free (me->me_mountdir);
329 if (me->me_type && me->me_type_malloced)
330 free (me->me_type);
331 free (me);
334 /* --------------------------------------------------------------------------------------------- */
336 #ifdef MOUNTED_GETMNTINFO
338 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
339 static char *
340 fstype_to_string (short int t)
342 switch (t)
344 #ifdef MOUNT_PC
345 case MOUNT_PC:
346 return "pc";
347 #endif
348 #ifdef MOUNT_MFS
349 case MOUNT_MFS:
350 return "mfs";
351 #endif
352 #ifdef MOUNT_LO
353 case MOUNT_LO:
354 return "lo";
355 #endif
356 #ifdef MOUNT_TFS
357 case MOUNT_TFS:
358 return "tfs";
359 #endif
360 #ifdef MOUNT_TMP
361 case MOUNT_TMP:
362 return "tmp";
363 #endif
364 #ifdef MOUNT_UFS
365 case MOUNT_UFS:
366 return "ufs";
367 #endif
368 #ifdef MOUNT_NFS
369 case MOUNT_NFS:
370 return "nfs";
371 #endif
372 #ifdef MOUNT_MSDOS
373 case MOUNT_MSDOS:
374 return "msdos";
375 #endif
376 #ifdef MOUNT_LFS
377 case MOUNT_LFS:
378 return "lfs";
379 #endif
380 #ifdef MOUNT_LOFS
381 case MOUNT_LOFS:
382 return "lofs";
383 #endif
384 #ifdef MOUNT_FDESC
385 case MOUNT_FDESC:
386 return "fdesc";
387 #endif
388 #ifdef MOUNT_PORTAL
389 case MOUNT_PORTAL:
390 return "portal";
391 #endif
392 #ifdef MOUNT_NULL
393 case MOUNT_NULL:
394 return "null";
395 #endif
396 #ifdef MOUNT_UMAP
397 case MOUNT_UMAP:
398 return "umap";
399 #endif
400 #ifdef MOUNT_KERNFS
401 case MOUNT_KERNFS:
402 return "kernfs";
403 #endif
404 #ifdef MOUNT_PROCFS
405 case MOUNT_PROCFS:
406 return "procfs";
407 #endif
408 #ifdef MOUNT_AFS
409 case MOUNT_AFS:
410 return "afs";
411 #endif
412 #ifdef MOUNT_CD9660
413 case MOUNT_CD9660:
414 return "cd9660";
415 #endif
416 #ifdef MOUNT_UNION
417 case MOUNT_UNION:
418 return "union";
419 #endif
420 #ifdef MOUNT_DEVFS
421 case MOUNT_DEVFS:
422 return "devfs";
423 #endif
424 #ifdef MOUNT_EXT2FS
425 case MOUNT_EXT2FS:
426 return "ext2fs";
427 #endif
428 default:
429 return "?";
432 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
434 /* --------------------------------------------------------------------------------------------- */
436 static char *
437 fsp_to_string (const struct statfs *fsp)
439 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
440 return (char *) (fsp->f_fstypename);
441 #else
442 return fstype_to_string (fsp->f_type);
443 #endif
445 #endif /* MOUNTED_GETMNTINFO */
447 /* --------------------------------------------------------------------------------------------- */
449 #ifdef MOUNTED_VMOUNT /* AIX. */
450 static char *
451 fstype_to_string (int t)
453 struct vfs_ent *e;
455 e = getvfsbytype (t);
456 if (!e || !e->vfsent_name)
457 return "none";
458 else
459 return e->vfsent_name;
461 #endif /* MOUNTED_VMOUNT */
463 /* --------------------------------------------------------------------------------------------- */
465 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
467 /* Return the device number from MOUNT_OPTIONS, if possible.
468 Otherwise return (dev_t) -1. */
470 /* --------------------------------------------------------------------------------------------- */
472 static dev_t
473 dev_from_mount_options (char const *mount_options)
475 /* GNU/Linux allows file system implementations to define their own
476 meaning for "dev=" mount options, so don't trust the meaning
477 here. */
478 #ifndef __linux__
479 static char const dev_pattern[] = ",dev=";
480 char const *devopt = strstr (mount_options, dev_pattern);
482 if (devopt)
484 char const *optval = devopt + sizeof (dev_pattern) - 1;
485 char *optvalend;
486 unsigned long int dev;
487 errno = 0;
488 dev = strtoul (optval, &optvalend, 16);
489 if (optval != optvalend
490 && (*optvalend == '\0' || *optvalend == ',')
491 && !(dev == ULONG_MAX && errno == ERANGE) && dev == (dev_t) dev)
492 return dev;
494 #endif
496 (void) mount_options;
497 return -1;
500 #endif
502 /* --------------------------------------------------------------------------------------------- */
504 #if defined _AIX && defined _I386
505 /* AIX PS/2 does not supply statfs. */
507 static int
508 statfs (char *file, struct statfs *fsb)
510 struct stat stats;
511 struct dustat fsd;
513 if (stat (file, &stats) != 0)
514 return -1;
515 if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
516 return -1;
517 fsb->f_type = 0;
518 fsb->f_bsize = fsd.du_bsize;
519 fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
520 fsb->f_bfree = fsd.du_tfree;
521 fsb->f_bavail = fsd.du_tfree;
522 fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
523 fsb->f_ffree = fsd.du_tinode;
524 fsb->f_fsid.val[0] = fsd.du_site;
525 fsb->f_fsid.val[1] = fsd.du_pckno;
526 return 0;
529 #endif /* _AIX && _I386 */
531 /* --------------------------------------------------------------------------------------------- */
533 /* Return a list of the currently mounted file systems, or NULL on error.
534 Add each entry to the tail of the list so that they stay in order.
535 If NEED_FS_TYPE is true, ensure that the file system type fields in
536 the returned list are valid. Otherwise, they might not be. */
538 static struct mount_entry *
539 read_file_system_list (int need_fs_type)
541 struct mount_entry *mount_list;
542 struct mount_entry *me;
543 struct mount_entry **mtail = &mount_list;
545 #ifdef MOUNTED_LISTMNTENT
547 struct tabmntent *mntlist, *p;
548 struct mntent *mnt;
549 struct mount_entry *me;
551 /* the third and fourth arguments could be used to filter mounts,
552 but Crays doesn't seem to have any mounts that we want to
553 remove. Specifically, automount create normal NFS mounts.
556 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
557 return NULL;
558 for (p = mntlist; p; p = p->next)
560 mnt = p->ment;
561 me = malloc (sizeof (*me));
562 me->me_devname = strdup (mnt->mnt_fsname);
563 me->me_mountdir = strdup (mnt->mnt_dir);
564 me->me_type = strdup (mnt->mnt_type);
565 me->me_type_malloced = 1;
566 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
567 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
568 me->me_dev = -1;
569 *mtail = me;
570 mtail = &me->me_next;
572 freemntlist (mntlist);
574 #endif
576 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
578 struct mntent *mnt;
579 const char *table = MOUNTED;
580 FILE *fp;
582 fp = setmntent (table, "r");
583 if (fp == NULL)
584 return NULL;
586 while ((mnt = getmntent (fp)))
588 me = malloc (sizeof (*me));
589 me->me_devname = strdup (mnt->mnt_fsname);
590 me->me_mountdir = strdup (mnt->mnt_dir);
591 me->me_type = strdup (mnt->mnt_type);
592 me->me_type_malloced = 1;
593 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
594 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
595 me->me_dev = dev_from_mount_options (mnt->mnt_opts);
597 /* Add to the linked list. */
598 *mtail = me;
599 mtail = &me->me_next;
602 if (endmntent (fp) == 0)
603 goto free_then_fail;
605 #endif /* MOUNTED_GETMNTENT1. */
607 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
609 struct statfs *fsp;
610 int entries;
612 entries = getmntinfo (&fsp, MNT_NOWAIT);
613 if (entries < 0)
614 return NULL;
615 for (; entries-- > 0; fsp++)
617 char *fs_type = fsp_to_string (fsp);
619 me = malloc (sizeof (*me));
620 me->me_devname = strdup (fsp->f_mntfromname);
621 me->me_mountdir = strdup (fsp->f_mntonname);
622 me->me_type = fs_type;
623 me->me_type_malloced = 0;
624 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
625 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
626 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
628 /* Add to the linked list. */
629 *mtail = me;
630 mtail = &me->me_next;
633 #endif /* MOUNTED_GETMNTINFO */
635 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
637 struct statvfs *fsp;
638 int entries;
640 entries = getmntinfo (&fsp, MNT_NOWAIT);
641 if (entries < 0)
642 return NULL;
643 for (; entries-- > 0; fsp++)
645 me = malloc (sizeof (*me));
646 me->me_devname = strdup (fsp->f_mntfromname);
647 me->me_mountdir = strdup (fsp->f_mntonname);
648 me->me_type = strdup (fsp->f_fstypename);
649 me->me_type_malloced = 1;
650 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
651 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
652 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
654 /* Add to the linked list. */
655 *mtail = me;
656 mtail = &me->me_next;
659 #endif /* MOUNTED_GETMNTINFO2 */
661 #ifdef MOUNTED_GETMNT /* Ultrix. */
663 int offset = 0;
664 int val;
665 struct fs_data fsd;
667 while (errno = 0, 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, (char *) 0)))
669 me = malloc (sizeof (*me));
670 me->me_devname = strdup (fsd.fd_req.devname);
671 me->me_mountdir = strdup (fsd.fd_req.path);
672 me->me_type = gt_names[fsd.fd_req.fstype];
673 me->me_type_malloced = 0;
674 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
675 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
676 me->me_dev = fsd.fd_req.dev;
678 /* Add to the linked list. */
679 *mtail = me;
680 mtail = &me->me_next;
682 if (val < 0)
683 goto free_then_fail;
685 #endif /* MOUNTED_GETMNT. */
687 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
689 /* The next_dev() and fs_stat_dev() system calls give the list of
690 all file systems, including the information returned by statvfs()
691 (fs type, total blocks, free blocks etc.), but without the mount
692 point. But on BeOS all file systems except / are mounted in the
693 rootfs, directly under /.
694 The directory name of the mount point is often, but not always,
695 identical to the volume name of the device.
696 We therefore get the list of subdirectories of /, and the list
697 of all file systems, and match the two lists. */
699 DIR *dirp;
700 struct rootdir_entry
702 char *name;
703 dev_t dev;
704 ino_t ino;
705 struct rootdir_entry *next;
707 struct rootdir_entry *rootdir_list;
708 struct rootdir_entry **rootdir_tail;
709 int32 pos;
710 dev_t dev;
711 fs_info fi;
713 /* All volumes are mounted in the rootfs, directly under /. */
714 rootdir_list = NULL;
715 rootdir_tail = &rootdir_list;
716 dirp = opendir ("/");
717 if (dirp)
719 struct dirent *d;
721 while ((d = readdir (dirp)) != NULL)
723 char *name;
724 struct stat statbuf;
726 if (strcmp (d->d_name, "..") == 0)
727 continue;
729 if (strcmp (d->d_name, ".") == 0)
730 name = strdup ("/");
731 else
733 name = malloc (1 + strlen (d->d_name) + 1);
734 name[0] = '/';
735 strcpy (name + 1, d->d_name);
738 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
740 struct rootdir_entry *re = malloc (sizeof (*re));
741 re->name = name;
742 re->dev = statbuf.st_dev;
743 re->ino = statbuf.st_ino;
745 /* Add to the linked list. */
746 *rootdir_tail = re;
747 rootdir_tail = &re->next;
749 else
750 free (name);
752 closedir (dirp);
754 *rootdir_tail = NULL;
756 for (pos = 0; (dev = next_dev (&pos)) >= 0;)
757 if (fs_stat_dev (dev, &fi) >= 0)
759 /* Note: fi.dev == dev. */
760 struct rootdir_entry *re;
762 for (re = rootdir_list; re; re = re->next)
763 if (re->dev == fi.dev && re->ino == fi.root)
764 break;
766 me = malloc (sizeof (*me));
767 me->me_devname = strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
768 me->me_mountdir = strdup (re != NULL ? re->name : fi.fsh_name);
769 me->me_type = strdup (fi.fsh_name);
770 me->me_type_malloced = 1;
771 me->me_dev = fi.dev;
772 me->me_dummy = 0;
773 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
775 /* Add to the linked list. */
776 *mtail = me;
777 mtail = &me->me_next;
779 *mtail = NULL;
781 while (rootdir_list != NULL)
783 struct rootdir_entry *re = rootdir_list;
784 rootdir_list = re->next;
785 free (re->name);
786 free (re);
789 #endif /* MOUNTED_FS_STAT_DEV */
791 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
793 int numsys, counter;
794 size_t bufsize;
795 struct statfs *stats;
797 numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
798 if (numsys < 0)
799 return NULL;
800 if (SIZE_MAX / sizeof (*stats) <= numsys)
802 fprintf (stderr, "%s\n", _("Memory exhausted!"));
803 exit (EXIT_FAILURE);
806 bufsize = (1 + numsys) * sizeof (*stats);
807 stats = malloc (bufsize);
808 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
810 if (numsys < 0)
812 free (stats);
813 return NULL;
816 for (counter = 0; counter < numsys; counter++)
818 me = malloc (sizeof (*me));
819 me->me_devname = strdup (stats[counter].f_mntfromname);
820 me->me_mountdir = strdup (stats[counter].f_mntonname);
821 me->me_type = strdup (FS_TYPE (stats[counter]));
822 me->me_type_malloced = 1;
823 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
824 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
825 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
827 /* Add to the linked list. */
828 *mtail = me;
829 mtail = &me->me_next;
832 free (stats);
834 #endif /* MOUNTED_GETFSSTAT */
836 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
838 struct mnttab mnt;
839 char *table = "/etc/mnttab";
840 FILE *fp;
842 fp = fopen (table, "r");
843 if (fp == NULL)
844 return NULL;
846 while (fread (&mnt, sizeof (mnt), 1, fp) > 0)
848 me = malloc (sizeof (*me));
849 #ifdef GETFSTYP /* SVR3. */
850 me->me_devname = strdup (mnt.mt_dev);
851 #else
852 me->me_devname = malloc (strlen (mnt.mt_dev) + 6);
853 strcpy (me->me_devname, "/dev/");
854 strcpy (me->me_devname + 5, mnt.mt_dev);
855 #endif
856 me->me_mountdir = strdup (mnt.mt_filsys);
857 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
858 me->me_type = "";
859 me->me_type_malloced = 0;
860 #ifdef GETFSTYP /* SVR3. */
861 if (need_fs_type)
863 struct statfs fsd;
864 char typebuf[FSTYPSZ];
866 if (statfs (me->me_mountdir, &fsd, sizeof (fsd), 0) != -1
867 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
869 me->me_type = strdup (typebuf);
870 me->me_type_malloced = 1;
873 #endif
874 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
875 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
877 /* Add to the linked list. */
878 *mtail = me;
879 mtail = &me->me_next;
882 if (ferror (fp))
884 /* The last fread() call must have failed. */
885 int saved_errno = errno;
886 fclose (fp);
887 errno = saved_errno;
888 goto free_then_fail;
891 if (fclose (fp) == EOF)
892 goto free_then_fail;
894 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
896 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
898 struct mntent **mnttbl = getmnttbl (), **ent;
899 for (ent = mnttbl; *ent; ent++)
901 me = malloc (sizeof (*me));
902 me->me_devname = strdup ((*ent)->mt_resource);
903 me->me_mountdir = strdup ((*ent)->mt_directory);
904 me->me_type = strdup ((*ent)->mt_fstype);
905 me->me_type_malloced = 1;
906 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
907 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
908 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
910 /* Add to the linked list. */
911 *mtail = me;
912 mtail = &me->me_next;
914 endmnttbl ();
916 #endif
918 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
920 struct mnttab mnt;
921 char *table = MNTTAB;
922 FILE *fp;
923 int ret;
924 int lockfd = -1;
926 #if defined F_RDLCK && defined F_SETLKW
927 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
928 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
929 for this file name, we should use their macro name instead.
930 (Why not just lock MNTTAB directly? We don't know.) */
931 #ifndef MNTTAB_LOCK
932 #define MNTTAB_LOCK "/etc/.mnttab.lock"
933 #endif
934 lockfd = open (MNTTAB_LOCK, O_RDONLY);
935 if (0 <= lockfd)
937 struct flock flock;
938 flock.l_type = F_RDLCK;
939 flock.l_whence = SEEK_SET;
940 flock.l_start = 0;
941 flock.l_len = 0;
942 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
943 if (errno != EINTR)
945 int saved_errno = errno;
946 close (lockfd);
947 errno = saved_errno;
948 return NULL;
951 else if (errno != ENOENT)
952 return NULL;
953 #endif
955 errno = 0;
956 fp = fopen (table, "r");
957 if (fp == NULL)
958 ret = errno;
959 else
961 while ((ret = getmntent (fp, &mnt)) == 0)
963 me = malloc (sizeof (*me));
964 me->me_devname = strdup (mnt.mnt_special);
965 me->me_mountdir = strdup (mnt.mnt_mountp);
966 me->me_type = strdup (mnt.mnt_fstype);
967 me->me_type_malloced = 1;
968 me->me_dummy = MNT_IGNORE (&mnt) != 0;
969 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
970 me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
972 /* Add to the linked list. */
973 *mtail = me;
974 mtail = &me->me_next;
977 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
980 if (0 <= lockfd && close (lockfd) != 0)
981 ret = errno;
983 if (0 <= ret)
985 errno = ret;
986 goto free_then_fail;
989 #endif /* MOUNTED_GETMNTENT2. */
991 #ifdef MOUNTED_VMOUNT /* AIX. */
993 int bufsize;
994 char *entries, *thisent;
995 struct vmount *vmp;
996 int n_entries;
997 int i;
999 /* Ask how many bytes to allocate for the mounted file system info. */
1000 if (mntctl (MCTL_QUERY, sizeof (bufsize), (struct vmount *) &bufsize) != 0)
1001 return NULL;
1002 entries = malloc (bufsize);
1004 /* Get the list of mounted file systems. */
1005 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
1006 if (n_entries < 0)
1008 int saved_errno = errno;
1009 free (entries);
1010 errno = saved_errno;
1011 return NULL;
1014 for (i = 0, thisent = entries; i < n_entries; i++, thisent += vmp->vmt_length)
1016 char *options, *ignore;
1018 vmp = (struct vmount *) thisent;
1019 me = malloc (sizeof (*me));
1020 if (vmp->vmt_flags & MNT_REMOTE)
1022 char *host, *dir;
1024 me->me_remote = 1;
1025 /* Prepend the remote dirname. */
1026 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
1027 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
1028 me->me_devname = malloc (strlen (host) + strlen (dir) + 2);
1029 strcpy (me->me_devname, host);
1030 strcat (me->me_devname, ":");
1031 strcat (me->me_devname, dir);
1033 else
1035 me->me_remote = 0;
1036 me->me_devname = strdup (thisent + vmp->vmt_data[VMT_OBJECT].vmt_off);
1038 me->me_mountdir = strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
1039 me->me_type = strdup (fstype_to_string (vmp->vmt_gfstype));
1040 me->me_type_malloced = 1;
1041 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
1042 ignore = strstr (options, "ignore");
1043 me->me_dummy = (ignore
1044 && (ignore == options || ignore[-1] == ',')
1045 && (ignore[sizeof ("ignore") - 1] == ','
1046 || ignore[sizeof ("ignore") - 1] == '\0'));
1047 me->me_dev = (dev_t) (-1); /* vmt_fsid might be the info we want. */
1049 /* Add to the linked list. */
1050 *mtail = me;
1051 mtail = &me->me_next;
1053 free (entries);
1055 #endif /* MOUNTED_VMOUNT. */
1058 #ifdef MOUNTED_INTERIX_STATVFS
1060 DIR *dirp = opendir ("/dev/fs");
1061 char node[9 + NAME_MAX];
1063 if (!dirp)
1064 goto free_then_fail;
1066 while (1)
1068 struct statvfs dev;
1069 struct dirent entry;
1070 struct dirent *result;
1072 if (readdir_r (dirp, &entry, &result) || result == NULL)
1073 break;
1075 strcpy (node, "/dev/fs/");
1076 strcat (node, entry.d_name);
1078 if (statvfs (node, &dev) == 0)
1080 me = malloc (sizeof *me);
1081 me->me_devname = strdup (dev.f_mntfromname);
1082 me->me_mountdir = strdup (dev.f_mntonname);
1083 me->me_type = strdup (dev.f_fstypename);
1084 me->me_type_malloced = 1;
1085 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1086 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1087 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
1089 /* Add to the linked list. */
1090 *mtail = me;
1091 mtail = &me->me_next;
1095 #endif /* MOUNTED_INTERIX_STATVFS */
1097 (void) need_fs_type; /* avoid argument-unused warning */
1098 *mtail = NULL;
1099 return mount_list;
1102 free_then_fail:
1104 int saved_errno = errno;
1105 *mtail = NULL;
1107 while (mount_list)
1109 me = mount_list->me_next;
1110 free (mount_list->me_devname);
1111 free (mount_list->me_mountdir);
1112 if (mount_list->me_type_malloced)
1113 free (mount_list->me_type);
1114 free (mount_list);
1115 mount_list = me;
1118 errno = saved_errno;
1119 return NULL;
1123 #endif /* HAVE_INFOMOUNT_LIST */
1125 /* --------------------------------------------------------------------------------------------- */
1127 #ifdef HAVE_INFOMOUNT_QNX
1129 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1130 ** this via the following code.
1131 ** Note that, as this is based on CWD, it only fills one mount_entry
1132 ** structure. See my_statfs() in utilunix.c for the "other side" of
1133 ** this hack.
1136 static struct mount_entry *
1137 read_file_system_list (int need_fs_type, int all_fs)
1139 struct _disk_entry de;
1140 struct statfs fs;
1141 int i, fd;
1142 char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
1144 static struct mount_entry *me = NULL;
1146 if (me)
1148 if (me->me_devname)
1149 free (me->me_devname);
1150 if (me->me_mountdir)
1151 free (me->me_mountdir);
1152 if (me->me_type)
1153 free (me->me_type);
1155 else
1156 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
1158 if (!getcwd (dir, _POSIX_PATH_MAX))
1159 return (NULL);
1161 fd = open (dir, O_RDONLY);
1162 if (fd == -1)
1163 return (NULL);
1165 i = disk_get_entry (fd, &de);
1167 close (fd);
1169 if (i == -1)
1170 return (NULL);
1172 switch (de.disk_type)
1174 case _UNMOUNTED:
1175 tp = "unmounted";
1176 break;
1177 case _FLOPPY:
1178 tp = "Floppy";
1179 break;
1180 case _HARD:
1181 tp = "Hard";
1182 break;
1183 case _RAMDISK:
1184 tp = "Ram";
1185 break;
1186 case _REMOVABLE:
1187 tp = "Removable";
1188 break;
1189 case _TAPE:
1190 tp = "Tape";
1191 break;
1192 case _CDROM:
1193 tp = "CDROM";
1194 break;
1195 default:
1196 tp = "unknown";
1199 if (fsys_get_mount_dev (dir, &dev) == -1)
1200 return (NULL);
1202 if (fsys_get_mount_pt (dev, &dir) == -1)
1203 return (NULL);
1205 me->me_devname = strdup (dev);
1206 me->me_mountdir = strdup (dir);
1207 me->me_type = strdup (tp);
1208 me->me_dev = de.disk_type;
1210 #ifdef DEBUG
1211 fprintf (stderr,
1212 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1213 de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
1214 fprintf (stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
1215 fprintf (stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
1216 #endif /* DEBUG */
1218 return (me);
1220 #endif /* HAVE_INFOMOUNT_QNX */
1222 /* --------------------------------------------------------------------------------------------- */
1224 #ifdef STAT_READ_FILSYS /* SVR2 */
1226 /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
1227 interrupted. Return the actual number of bytes read(written), zero for EOF,
1228 or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */
1229 static size_t
1230 safe_read (int fd, void *buf, size_t count)
1232 /* Work around a bug in Tru64 5.1. Attempting to read more than
1233 INT_MAX bytes fails with errno == EINVAL. See
1234 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
1235 When decreasing COUNT, keep it block-aligned. */
1236 /* *INDENT-OFF* */
1237 enum { BUGGY_READ_MAXIMUM = INT_MAX & ~8191 };
1238 /* *INDENT-ON* */
1240 for (;;)
1242 ssize_t result = read (fd, buf, count);
1244 if (0 <= result)
1245 return result;
1246 else if (IS_EINTR (errno))
1247 continue;
1248 else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count)
1249 count = BUGGY_READ_MAXIMUM;
1250 else
1251 return result;
1255 /* --------------------------------------------------------------------------------------------- */
1257 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1258 interrupted or if a partial write(read) occurs. Return the number
1259 of bytes transferred.
1260 When writing, set errno if fewer than COUNT bytes are written.
1261 When reading, if fewer than COUNT bytes are read, you must examine
1262 errno to distinguish failure from EOF (errno == 0). */
1264 static size_t
1265 full_read (int fd, void *buf, size_t count)
1267 size_t total = 0;
1268 char *ptr = (char *) buf;
1270 while (count > 0)
1272 size_t n_rw = safe_read (fd, ptr, count);
1273 if (n_rw == (size_t) (-1))
1274 break;
1275 if (n_rw == 0)
1277 errno = ZERO_BYTE_TRANSFER_ERRNO;
1278 break;
1280 total += n_rw;
1281 ptr += n_rw;
1282 count -= n_rw;
1285 return total;
1288 #endif /* STAT_READ_FILSYS */
1290 /* --------------------------------------------------------------------------------------------- */
1292 #ifdef HAVE_INFOMOUNT
1293 /* Fill in the fields of FSP with information about space usage for
1294 the file system on which FILE resides.
1295 DISK is the device on which FILE is mounted, for space-getting
1296 methods that need to know it.
1297 Return 0 if successful, -1 if not. When returning -1, ensure that
1298 ERRNO is either a system error value, or zero if DISK is NULL
1299 on a system that requires a non-NULL value. */
1300 static int
1301 get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
1303 #ifdef STAT_STATVFS /* POSIX, except glibc/Linux */
1305 struct statvfs fsd;
1307 if (statvfs (file, &fsd) < 0)
1308 return -1;
1310 /* f_frsize isn't guaranteed to be supported. */
1311 /* *INDENT-OFF* */
1312 fsp->fsu_blocksize = fsd.f_frsize
1313 ? PROPAGATE_ALL_ONES (fsd.f_frsize)
1314 : PROPAGATE_ALL_ONES (fsd.f_bsize);
1315 /* *INDENT-ON* */
1317 #elif defined STAT_STATVFS64 /* AIX */
1319 struct statvfs64 fsd;
1321 if (statvfs64 (file, &fsd) < 0)
1322 return -1;
1324 /* f_frsize isn't guaranteed to be supported. */
1325 /* *INDENT-OFF* */
1326 fsp->fsu_blocksize = fsd.f_frsize
1327 ? PROPAGATE_ALL_ONES (fsd.f_frsize)
1328 : PROPAGATE_ALL_ONES (fsd.f_bsize);
1329 /* *INDENT-ON* */
1331 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1333 struct fs_data fsd;
1335 if (statfs (file, &fsd) != 1)
1336 return -1;
1338 fsp->fsu_blocksize = 1024;
1339 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot);
1340 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree);
1341 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen);
1342 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0;
1343 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
1344 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
1346 #elif defined STAT_READ_FILSYS /* SVR2 */
1347 #ifndef SUPERBOFF
1348 #define SUPERBOFF (SUPERB * 512)
1349 #endif
1351 struct filsys fsd;
1352 int fd;
1354 if (!disk)
1356 errno = 0;
1357 return -1;
1360 fd = open (disk, O_RDONLY);
1361 if (fd < 0)
1362 return -1;
1363 lseek (fd, (off_t) SUPERBOFF, 0);
1364 if (full_read (fd, (char *) &fsd, sizeof (fsd)) != sizeof (fsd))
1366 close (fd);
1367 return -1;
1369 close (fd);
1371 fsp->fsu_blocksize = (fsd.s_type == Fs2b ? 1024 : 512);
1372 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.s_fsize);
1373 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.s_tfree);
1374 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree);
1375 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0;
1376 fsp->fsu_files = (fsd.s_isize == -1
1377 ? UINTMAX_MAX : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1));
1378 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode);
1380 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1382 struct statfs fsd;
1384 if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
1385 return -1;
1387 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1389 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux, 4.3BSD, SunOS 4, \
1390 Mac OS X < 10.4, FreeBSD < 5.0, \
1391 NetBSD < 3.0, OpenBSD < 4.4 */
1393 struct statfs fsd;
1395 if (statfs (file, &fsd) < 0)
1396 return -1;
1398 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1400 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1402 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1403 struct statfs are truncated to 2GB. These conditions detect that
1404 truncation, presumably without botching the 4.1.1 case, in which
1405 the values are not truncated. The correct counts are stored in
1406 undocumented spare fields. */
1407 if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
1409 fsd.f_blocks = fsd.f_spare[0];
1410 fsd.f_bfree = fsd.f_spare[1];
1411 fsd.f_bavail = fsd.f_spare[2];
1413 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1415 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1417 struct statfs fsd;
1419 if (statfs (file, &fsd) < 0)
1420 return -1;
1422 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1424 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1425 Dolphin */
1427 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1428 #define f_bavail f_bfree
1429 #endif
1431 struct statfs fsd;
1433 if (statfs (file, &fsd, sizeof (fsd), 0) < 0)
1434 return -1;
1436 /* Empirically, the block counts on most SVR3 and SVR3-derived
1437 systems seem to always be in terms of 512-byte blocks,
1438 no matter what value f_bsize has. */
1439 #if defined _AIX || defined _CRAY
1440 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1441 #else
1442 fsp->fsu_blocksize = 512;
1443 #endif
1445 #endif
1447 #if (defined STAT_STATVFS || defined STAT_STATVFS64 \
1448 || (!defined STAT_STATFS2_FS_DATA && !defined STAT_READ_FILSYS))
1450 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
1451 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
1452 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
1453 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
1454 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
1455 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
1457 #endif
1458 (void) disk; /* avoid argument-unused warning */
1459 return 0;
1461 #endif /* HAVE_INFOMOUNT */
1463 /* --------------------------------------------------------------------------------------------- */
1464 /*** public functions ****************************************************************************/
1465 /* --------------------------------------------------------------------------------------------- */
1467 void
1468 free_my_statfs (void)
1470 #ifdef HAVE_INFOMOUNT_LIST
1471 while (mc_mount_list != NULL)
1473 struct mount_entry *next;
1475 next = mc_mount_list->me_next;
1476 free_mount_entry (mc_mount_list);
1477 mc_mount_list = next;
1480 mc_mount_list = NULL;
1481 #endif /* HAVE_INFOMOUNT_LIST */
1484 /* --------------------------------------------------------------------------------------------- */
1486 void
1487 init_my_statfs (void)
1489 #ifdef HAVE_INFOMOUNT_LIST
1490 free_my_statfs ();
1491 mc_mount_list = read_file_system_list (1);
1492 #endif /* HAVE_INFOMOUNT_LIST */
1495 /* --------------------------------------------------------------------------------------------- */
1497 void
1498 my_statfs (struct my_statfs *myfs_stats, const char *path)
1500 #ifdef HAVE_INFOMOUNT_LIST
1501 size_t i, len = 0;
1502 struct mount_entry *entry = NULL;
1503 struct mount_entry *temp = mc_mount_list;
1504 struct fs_usage fs_use;
1506 while (temp)
1508 i = strlen (temp->me_mountdir);
1509 if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
1510 if (!entry || (path[i] == PATH_SEP || path[i] == '\0'))
1512 len = i;
1513 entry = temp;
1515 temp = temp->me_next;
1518 if (entry)
1520 memset (&fs_use, 0, sizeof (struct fs_usage));
1521 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1523 myfs_stats->type = entry->me_dev;
1524 myfs_stats->typename = entry->me_type;
1525 myfs_stats->mpoint = entry->me_mountdir;
1526 myfs_stats->device = entry->me_devname;
1527 myfs_stats->avail =
1528 ((uintmax_t) (getuid ()? fs_use.fsu_bavail : fs_use.fsu_bfree) *
1529 fs_use.fsu_blocksize) >> 10;
1530 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1531 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1532 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1534 else
1535 #endif /* HAVE_INFOMOUNT_LIST */
1537 #ifdef HAVE_INFOMOUNT_QNX
1539 ** This is the "other side" of the hack to read_file_system_list() in
1540 ** mountlist.c.
1541 ** It's not the most efficient approach, but consumes less memory. It
1542 ** also accomodates QNX's ability to mount filesystems on the fly.
1544 struct mount_entry *entry;
1545 struct fs_usage fs_use;
1547 entry = read_file_system_list (0, 0);
1548 if (entry != NULL)
1550 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1552 myfs_stats->type = entry->me_dev;
1553 myfs_stats->typename = entry->me_type;
1554 myfs_stats->mpoint = entry->me_mountdir;
1555 myfs_stats->device = entry->me_devname;
1557 myfs_stats->avail = ((uintmax_t) fs_use.fsu_bfree * fs_use.fsu_blocksize) >> 10;
1558 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1559 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1560 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1562 else
1563 #endif /* HAVE_INFOMOUNT_QNX */
1565 myfs_stats->type = 0;
1566 myfs_stats->mpoint = "unknown";
1567 myfs_stats->device = "unknown";
1568 myfs_stats->avail = 0;
1569 myfs_stats->total = 0;
1570 myfs_stats->nfree = 0;
1571 myfs_stats->nodes = 0;
1575 /* --------------------------------------------------------------------------------------------- */