Add IS_PATH_SEP macro and use it.
[midnight-commander.git] / src / filemanager / mountlist.c
blob991ebc399f1161d25c265ff5778183918b557e20
1 /*
2 Return a list of mounted file systems
4 Copyright (C) 1991-2015
5 Free Software Foundation, Inc.
7 This file is part of the Midnight Commander.
9 The Midnight Commander is free software: you can redistribute it
10 and/or modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation, either version 3 of the License,
12 or (at your option) any later version.
14 The Midnight Commander is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /** \file mountlist.c
24 * \brief Source: list of mounted filesystems
27 #include <config.h>
29 #include <limits.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdint.h> /* SIZE_MAX */
34 #include <sys/types.h>
36 #include <errno.h>
38 /* This header needs to be included before sys/mount.h on *BSD */
39 #ifdef HAVE_SYS_PARAM_H
40 #include <sys/param.h>
41 #endif
43 #if defined STAT_STATVFS || defined STAT_STATVFS64 /* POSIX 1003.1-2001 (and later) with XSI */
44 #include <sys/statvfs.h>
45 #else
46 /* Don't include backward-compatibility files unless they're needed.
47 Eventually we'd like to remove all this cruft. */
48 #include <fcntl.h>
49 #include <unistd.h>
50 #include <sys/stat.h>
52 #ifdef MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
53 #ifdef HAVE_SYS_UCRED_H
54 #include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
55 NGROUPS is used as an array dimension in ucred.h */
56 #include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
57 #endif
58 #ifdef HAVE_SYS_MOUNT_H
59 #include <sys/mount.h>
60 #endif
61 #ifdef HAVE_SYS_FS_TYPES_H
62 #include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
63 #endif
64 #ifdef HAVE_STRUCT_FSSTAT_F_FSTYPENAME
65 #define FS_TYPE(Ent) ((Ent).f_fstypename)
66 #else
67 #define FS_TYPE(Ent) mnt_names[(Ent).f_type]
68 #endif
69 #endif /* MOUNTED_GETFSSTAT */
70 #endif /* STAT_STATVFS || STAT_STATVFS64 */
72 #ifdef HAVE_SYS_VFS_H
73 #include <sys/vfs.h>
74 #endif
75 #ifdef HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */
76 #include <sys/fs/s5param.h>
77 #endif
78 #if defined HAVE_SYS_FILSYS_H && !defined _CRAY
79 #include <sys/filsys.h> /* SVR2 */
80 #endif
81 #ifdef HAVE_SYS_STATFS_H
82 #include <sys/statfs.h>
83 #endif
84 #ifdef HAVE_DUSTAT_H /* AIX PS/2 */
85 #include <sys/dustat.h>
86 #endif
88 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
89 #include <mntent.h>
90 #ifndef MOUNTED
91 #ifdef _PATH_MOUNTED /* GNU libc */
92 #define MOUNTED _PATH_MOUNTED
93 #endif
94 #ifdef MNT_MNTTAB /* HP-UX. */
95 #define MOUNTED MNT_MNTTAB
96 #endif
97 #ifdef MNTTABNAME /* Dynix. */
98 #define MOUNTED MNTTABNAME
99 #endif
100 #endif
101 #endif
103 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
104 #include <sys/mount.h>
105 #endif
107 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
108 #include <sys/statvfs.h>
109 #endif
111 #ifdef MOUNTED_GETMNT /* Ultrix. */
112 #include <sys/mount.h>
113 #include <sys/fs_types.h>
114 #endif
116 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
117 #include <fs_info.h>
118 #include <dirent.h>
119 #endif
121 #ifdef MOUNTED_FREAD /* SVR2. */
122 #include <mnttab.h>
123 #endif
125 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
126 #include <mnttab.h>
127 #include <sys/fstyp.h>
128 #include <sys/statfs.h>
129 #endif
131 #ifdef MOUNTED_LISTMNTENT
132 #include <mntent.h>
133 #endif
135 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
136 #include <sys/mnttab.h>
137 #endif
139 #ifdef MOUNTED_VMOUNT /* AIX. */
140 #include <fshelp.h>
141 #include <sys/vfs.h>
142 #endif
144 #ifdef MOUNTED_INTERIX_STATVFS /* Interix. */
145 #include <sys/statvfs.h>
146 #include <dirent.h>
147 #endif
149 #ifdef DOLPHIN
150 /* So special that it's not worth putting this in autoconf. */
151 #undef MOUNTED_FREAD_FSTYP
152 #define MOUNTED_GETMNTTBL
153 #endif
155 #ifdef HAVE_SYS_MNTENT_H
156 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
157 #include <sys/mntent.h>
158 #endif
160 #ifdef MOUNTED_PROC_MOUNTINFO
161 /* Use /proc/self/mountinfo instead of /proc/self/mounts (/etc/mtab)
162 * on Linux, if available */
163 #include <libmount/libmount.h>
164 #endif
166 #ifndef HAVE_HASMNTOPT
167 #define hasmntopt(mnt, opt) ((char *) 0)
168 #endif
170 #undef MNT_IGNORE
171 #ifdef MNTOPT_IGNORE
172 #if defined __sun && defined __SVR4
173 /* Solaris defines hasmntopt(struct mnttab *, char *)
174 while it is otherwise hasmntopt(struct mnttab *, const char *). */
175 #define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
176 #else
177 #define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
178 #endif
179 #else
180 #define MNT_IGNORE(M) 0
181 #endif
183 #ifdef HAVE_INFOMOUNT_QNX
184 #include <sys/disk.h>
185 #include <sys/fsys.h>
186 #endif
188 #ifdef HAVE_SYS_STATVFS_H /* SVR4. */
189 #include <sys/statvfs.h>
190 #endif
192 #include "lib/global.h"
193 #include "lib/strutil.h" /* str_verscmp() */
194 #include "mountlist.h"
196 /*** global variables ****************************************************************************/
198 /*** file scope macro definitions ****************************************************************/
200 #if defined (__QNX__) && !defined(__QNXNTO__) && !defined (HAVE_INFOMOUNT_LIST)
201 #define HAVE_INFOMOUNT_QNX
202 #endif
204 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
205 #define HAVE_INFOMOUNT
206 #endif
208 /* The results of opendir() in this file are not used with dirfd and fchdir,
209 therefore save some unnecessary work in fchdir.c. */
210 #undef opendir
211 #undef closedir
213 #define ME_DUMMY_0(Fs_name, Fs_type) \
214 (strcmp (Fs_type, "autofs") == 0 \
215 || strcmp (Fs_type, "proc") == 0 \
216 || strcmp (Fs_type, "subfs") == 0 \
217 /* for Linux 2.6/3.x */ \
218 || strcmp (Fs_type, "debugfs") == 0 \
219 || strcmp (Fs_type, "devpts") == 0 \
220 || strcmp (Fs_type, "fusectl") == 0 \
221 || strcmp (Fs_type, "mqueue") == 0 \
222 || strcmp (Fs_type, "rpc_pipefs") == 0 \
223 || strcmp (Fs_type, "sysfs") == 0 \
224 /* FreeBSD, Linux 2.4 */ \
225 || strcmp (Fs_type, "devfs") == 0 \
226 /* for NetBSD 3.0 */ \
227 || strcmp (Fs_type, "kernfs") == 0 \
228 /* for Irix 6.5 */ \
229 || strcmp (Fs_type, "ignore") == 0)
231 /* Historically, we have marked as "dummy" any file system of type "none",
232 but now that programs like du need to know about bind-mounted directories,
233 we grant an exception to any with "bind" in its list of mount options.
234 I.e., those are *not* dummy entries. */
235 #ifdef MOUNTED_GETMNTENT1
236 #define ME_DUMMY(Fs_name, Fs_type, Bind) \
237 (ME_DUMMY_0 (Fs_name, Fs_type) \
238 || (strcmp (Fs_type, "none") == 0 && !Bind))
239 #else
240 #define ME_DUMMY(Fs_name, Fs_type) \
241 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
242 #endif
244 #ifdef __CYGWIN__
245 #include <windows.h>
246 #define ME_REMOTE me_remote
247 /* All cygwin mount points include ':' or start with '//'; so it
248 requires a native Windows call to determine remote disks. */
249 static int
250 me_remote (char const *fs_name, char const *fs_type)
252 (void) fs_type;
254 if (fs_name[0] && fs_name[1] == ':')
256 char drive[4];
257 sprintf (drive, "%c:\\", fs_name[0]);
258 switch (GetDriveType (drive))
260 case DRIVE_REMOVABLE:
261 case DRIVE_FIXED:
262 case DRIVE_CDROM:
263 case DRIVE_RAMDISK:
264 return 0;
267 return 1;
269 #endif
270 #ifndef ME_REMOTE
271 /* A file system is 'remote' if its Fs_name contains a ':'
272 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//'). */
273 #define ME_REMOTE(Fs_name, Fs_type) \
274 (strchr (Fs_name, ':') != NULL \
275 || ((Fs_name)[0] == '/' \
276 && (Fs_name)[1] == '/' \
277 && (strcmp (Fs_type, "smbfs") == 0 || strcmp (Fs_type, "cifs") == 0)))
278 #endif
280 /* Many space usage primitives use all 1 bits to denote a value that is
281 not applicable or unknown. Propagate this information by returning
282 a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
283 is unsigned and narrower than uintmax_t. */
284 #define PROPAGATE_ALL_ONES(x) \
285 ((sizeof (x) < sizeof (uintmax_t) \
286 && (~ (x) == (sizeof (x) < sizeof (int) \
287 ? - (1 << (sizeof (x) * CHAR_BIT)) \
288 : 0))) \
289 ? UINTMAX_MAX : (uintmax_t) (x))
291 /* Extract the top bit of X as an uintmax_t value. */
292 #define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
294 /* If a value is negative, many space usage primitives store it into an
295 integer variable by assignment, even if the variable's type is unsigned.
296 So, if a space usage variable X's top bit is set, convert X to the
297 uintmax_t value V such that (- (uintmax_t) V) is the negative of
298 the original value. If X's top bit is clear, just yield X.
299 Use PROPAGATE_TOP_BIT if the original value might be negative;
300 otherwise, use PROPAGATE_ALL_ONES. */
301 #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
303 #ifdef STAT_STATVFS
304 #if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
305 /* The FRSIZE fallback is not required in this case. */
306 #undef STAT_STATFS2_FRSIZE
307 #else
308 #include <sys/utsname.h>
309 #include <sys/statfs.h>
310 #define STAT_STATFS2_BSIZE 1
311 #endif
312 #endif
314 #ifdef STAT_READ_FILSYS /* SVR2 */
315 /* Set errno to zero upon EOF. */
316 #define ZERO_BYTE_TRANSFER_ERRNO 0
318 #ifdef EINTR
319 #define IS_EINTR(x) ((x) == EINTR)
320 #else
321 #define IS_EINTR(x) 0
322 #endif
323 #endif /* STAT_READ_FILSYS */
325 /*** file scope type declarations ****************************************************************/
327 /* A mount table entry. */
328 struct mount_entry
330 char *me_devname; /* Device node name, including "/dev/". */
331 char *me_mountdir; /* Mount point directory name. */
332 char *me_type; /* "nfs", "4.2", etc. */
333 dev_t me_dev; /* Device number of me_mountdir. */
334 unsigned int me_dummy:1; /* Nonzero for dummy file systems. */
335 unsigned int me_remote:1; /* Nonzero for remote fileystems. */
336 unsigned int me_type_malloced:1; /* Nonzero if me_type was malloced. */
337 struct mount_entry *me_next;
340 struct fs_usage
342 uintmax_t fsu_blocksize; /* Size of a block. */
343 uintmax_t fsu_blocks; /* Total blocks. */
344 uintmax_t fsu_bfree; /* Free blocks available to superuser. */
345 uintmax_t fsu_bavail; /* Free blocks available to non-superuser. */
346 int fsu_bavail_top_bit_set; /* 1 if fsu_bavail represents a value < 0. */
347 uintmax_t fsu_files; /* Total file nodes. */
348 uintmax_t fsu_ffree; /* Free file nodes. */
351 /*** file scope variables ************************************************************************/
353 #ifdef HAVE_INFOMOUNT_LIST
354 static struct mount_entry *mc_mount_list = NULL;
355 #endif /* HAVE_INFOMOUNT_LIST */
357 /*** file scope functions ************************************************************************/
358 /* --------------------------------------------------------------------------------------------- */
360 #ifdef STAT_STATVFS
361 /* Return true if statvfs works. This is false for statvfs on systems
362 with GNU libc on Linux kernels before 2.6.36, which stats all
363 preceding entries in /proc/mounts; that makes df hang if even one
364 of the corresponding file systems is hard-mounted but not available. */
365 static int
366 statvfs_works (void)
368 #if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
369 return 1;
370 #else
371 static int statvfs_works_cache = -1;
372 struct utsname name;
374 if (statvfs_works_cache < 0)
375 statvfs_works_cache = (uname (&name) == 0 && 0 <= str_verscmp (name.release, "2.6.36"));
376 return statvfs_works_cache;
377 #endif
379 #endif
381 /* --------------------------------------------------------------------------------------------- */
383 #ifdef HAVE_INFOMOUNT_LIST
384 static void
385 free_mount_entry (struct mount_entry *me)
387 if (!me)
388 return;
389 g_free (me->me_devname);
390 g_free (me->me_mountdir);
391 if (me->me_type_malloced)
392 g_free (me->me_type);
393 g_free (me);
396 /* --------------------------------------------------------------------------------------------- */
398 #ifdef MOUNTED_GETMNTINFO
400 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
401 static char *
402 fstype_to_string (short int t)
404 switch (t)
406 #ifdef MOUNT_PC
407 /* cppcheck-suppress syntaxError */
408 case MOUNT_PC:
409 return "pc";
410 #endif
411 #ifdef MOUNT_MFS
412 /* cppcheck-suppress syntaxError */
413 case MOUNT_MFS:
414 return "mfs";
415 #endif
416 #ifdef MOUNT_LO
417 /* cppcheck-suppress syntaxError */
418 case MOUNT_LO:
419 return "lo";
420 #endif
421 #ifdef MOUNT_TFS
422 /* cppcheck-suppress syntaxError */
423 case MOUNT_TFS:
424 return "tfs";
425 #endif
426 #ifdef MOUNT_TMP
427 /* cppcheck-suppress syntaxError */
428 case MOUNT_TMP:
429 return "tmp";
430 #endif
431 #ifdef MOUNT_UFS
432 /* cppcheck-suppress syntaxError */
433 case MOUNT_UFS:
434 return "ufs";
435 #endif
436 #ifdef MOUNT_NFS
437 /* cppcheck-suppress syntaxError */
438 case MOUNT_NFS:
439 return "nfs";
440 #endif
441 #ifdef MOUNT_MSDOS
442 /* cppcheck-suppress syntaxError */
443 case MOUNT_MSDOS:
444 return "msdos";
445 #endif
446 #ifdef MOUNT_LFS
447 /* cppcheck-suppress syntaxError */
448 case MOUNT_LFS:
449 return "lfs";
450 #endif
451 #ifdef MOUNT_LOFS
452 /* cppcheck-suppress syntaxError */
453 case MOUNT_LOFS:
454 return "lofs";
455 #endif
456 #ifdef MOUNT_FDESC
457 /* cppcheck-suppress syntaxError */
458 case MOUNT_FDESC:
459 return "fdesc";
460 #endif
461 #ifdef MOUNT_PORTAL
462 /* cppcheck-suppress syntaxError */
463 case MOUNT_PORTAL:
464 return "portal";
465 #endif
466 #ifdef MOUNT_NULL
467 /* cppcheck-suppress syntaxError */
468 case MOUNT_NULL:
469 return "null";
470 #endif
471 #ifdef MOUNT_UMAP
472 /* cppcheck-suppress syntaxError */
473 case MOUNT_UMAP:
474 return "umap";
475 #endif
476 #ifdef MOUNT_KERNFS
477 /* cppcheck-suppress syntaxError */
478 case MOUNT_KERNFS:
479 return "kernfs";
480 #endif
481 #ifdef MOUNT_PROCFS
482 /* cppcheck-suppress syntaxError */
483 case MOUNT_PROCFS:
484 return "procfs";
485 #endif
486 #ifdef MOUNT_AFS
487 /* cppcheck-suppress syntaxError */
488 case MOUNT_AFS:
489 return "afs";
490 #endif
491 #ifdef MOUNT_CD9660
492 /* cppcheck-suppress syntaxError */
493 case MOUNT_CD9660:
494 return "cd9660";
495 #endif
496 #ifdef MOUNT_UNION
497 /* cppcheck-suppress syntaxError */
498 case MOUNT_UNION:
499 return "union";
500 #endif
501 #ifdef MOUNT_DEVFS
502 /* cppcheck-suppress syntaxError */
503 case MOUNT_DEVFS:
504 return "devfs";
505 #endif
506 #ifdef MOUNT_EXT2FS
507 /* cppcheck-suppress syntaxError */
508 case MOUNT_EXT2FS:
509 return "ext2fs";
510 #endif
511 default:
512 return "?";
515 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
517 /* --------------------------------------------------------------------------------------------- */
519 static char *
520 fsp_to_string (const struct statfs *fsp)
522 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
523 return (char *) (fsp->f_fstypename);
524 #else
525 return fstype_to_string (fsp->f_type);
526 #endif
528 #endif /* MOUNTED_GETMNTINFO */
530 /* --------------------------------------------------------------------------------------------- */
532 #ifdef MOUNTED_VMOUNT /* AIX. */
533 static char *
534 fstype_to_string (int t)
536 struct vfs_ent *e;
538 e = getvfsbytype (t);
539 if (!e || !e->vfsent_name)
540 return "none";
541 else
542 return e->vfsent_name;
544 #endif /* MOUNTED_VMOUNT */
546 /* --------------------------------------------------------------------------------------------- */
548 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
550 /* Return the device number from MOUNT_OPTIONS, if possible.
551 Otherwise return (dev_t) -1. */
553 /* --------------------------------------------------------------------------------------------- */
555 static dev_t
556 dev_from_mount_options (char const *mount_options)
558 /* GNU/Linux allows file system implementations to define their own
559 meaning for "dev=" mount options, so don't trust the meaning
560 here. */
561 #ifndef __linux__
562 static char const dev_pattern[] = ",dev=";
563 char const *devopt = strstr (mount_options, dev_pattern);
565 if (devopt)
567 char const *optval = devopt + sizeof (dev_pattern) - 1;
568 char *optvalend;
569 unsigned long int dev;
570 errno = 0;
571 dev = strtoul (optval, &optvalend, 16);
572 if (optval != optvalend
573 && (*optvalend == '\0' || *optvalend == ',')
574 && !(dev == ULONG_MAX && errno == ERANGE) && dev == (dev_t) dev)
575 return dev;
577 #endif
579 (void) mount_options;
580 return -1;
583 #endif
585 /* --------------------------------------------------------------------------------------------- */
587 #if defined _AIX && defined _I386
588 /* AIX PS/2 does not supply statfs. */
590 static int
591 statfs (char *file, struct statfs *fsb)
593 struct stat stats;
594 struct dustat fsd;
596 if (stat (file, &stats) != 0)
597 return -1;
598 if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
599 return -1;
600 fsb->f_type = 0;
601 fsb->f_bsize = fsd.du_bsize;
602 fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
603 fsb->f_bfree = fsd.du_tfree;
604 fsb->f_bavail = fsd.du_tfree;
605 fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
606 fsb->f_ffree = fsd.du_tinode;
607 fsb->f_fsid.val[0] = fsd.du_site;
608 fsb->f_fsid.val[1] = fsd.du_pckno;
609 return 0;
612 #endif /* _AIX && _I386 */
614 /* --------------------------------------------------------------------------------------------- */
616 /* Return a list of the currently mounted file systems, or NULL on error.
617 Add each entry to the tail of the list so that they stay in order.
618 If NEED_FS_TYPE is true, ensure that the file system type fields in
619 the returned list are valid. Otherwise, they might not be. */
621 static struct mount_entry *
622 read_file_system_list (int need_fs_type)
624 struct mount_entry *mount_list;
625 struct mount_entry *me;
626 struct mount_entry **mtail = &mount_list;
628 #ifdef MOUNTED_LISTMNTENT
630 struct tabmntent *mntlist, *p;
631 struct mount_entry *me;
633 /* the third and fourth arguments could be used to filter mounts,
634 but Crays doesn't seem to have any mounts that we want to
635 remove. Specifically, automount create normal NFS mounts.
638 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
639 return NULL;
640 for (p = mntlist; p; p = p->next)
642 struct mntent *mnt = p->ment;
644 me = g_malloc (sizeof (*me));
645 me->me_devname = g_strdup (mnt->mnt_fsname);
646 me->me_mountdir = g_strdup (mnt->mnt_dir);
647 me->me_type = g_strdup (mnt->mnt_type);
648 me->me_type_malloced = 1;
649 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
650 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
651 me->me_dev = -1;
652 *mtail = me;
653 mtail = &me->me_next;
655 freemntlist (mntlist);
657 #endif
659 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
661 #ifdef MOUNTED_PROC_MOUNTINFO
662 struct libmnt_table *fstable = NULL;
664 fstable = mnt_new_table_from_file ("/proc/self/mountinfo");
666 if (fstable != NULL)
668 struct libmnt_fs *fs;
669 struct libmnt_iter *iter;
671 iter = mnt_new_iter (MNT_ITER_FORWARD);
673 while (iter && mnt_table_next_fs (fstable, iter, &fs) == 0)
675 me = g_malloc (sizeof *me);
677 me->me_devname = g_strdup (mnt_fs_get_source (fs));
678 me->me_mountdir = g_strdup (mnt_fs_get_target (fs));
679 me->me_type = g_strdup (mnt_fs_get_fstype (fs));
680 me->me_type_malloced = 1;
681 me->me_dev = mnt_fs_get_devno (fs);
682 /* Note we don't use mnt_fs_is_pseudofs() or mnt_fs_is_netfs() here
683 as libmount's classification is non-compatible currently.
684 Also we pass "false" for the "Bind" option as that's only
685 significant when the Fs_type is "none" which will not be
686 the case when parsing "/proc/self/mountinfo", and only
687 applies for static /etc/mtab files. */
688 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, FALSE);
689 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
691 /* Add to the linked list. */
692 *mtail = me;
693 mtail = &me->me_next;
696 mnt_free_iter (iter);
697 mnt_free_table (fstable);
700 else /* fallback to /proc/self/mounts (/etc/mtab) if anything failed */
701 #endif /* MOUNTED_PROC_MOUNTINFO */
703 FILE *fp;
704 struct mntent *mnt;
705 const char *table = MOUNTED;
707 fp = setmntent (table, "r");
708 if (fp == NULL)
709 return NULL;
711 while ((mnt = getmntent (fp)) != NULL)
713 gboolean bind;
715 bind = hasmntopt (mnt, "bind") != NULL;
717 me = g_malloc (sizeof (*me));
718 me->me_devname = g_strdup (mnt->mnt_fsname);
719 me->me_mountdir = g_strdup (mnt->mnt_dir);
720 me->me_type = g_strdup (mnt->mnt_type);
721 me->me_type_malloced = 1;
722 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, bind);
723 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
724 me->me_dev = dev_from_mount_options (mnt->mnt_opts);
726 /* Add to the linked list. */
727 *mtail = me;
728 mtail = &me->me_next;
731 if (endmntent (fp) == 0)
732 goto free_then_fail;
735 #endif /* MOUNTED_GETMNTENT1. */
737 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
739 struct statfs *fsp;
740 int entries;
742 entries = getmntinfo (&fsp, MNT_NOWAIT);
743 if (entries < 0)
744 return NULL;
745 for (; entries-- > 0; fsp++)
747 char *fs_type = fsp_to_string (fsp);
749 me = g_malloc (sizeof (*me));
750 me->me_devname = g_strdup (fsp->f_mntfromname);
751 me->me_mountdir = g_strdup (fsp->f_mntonname);
752 me->me_type = fs_type;
753 me->me_type_malloced = 0;
754 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
755 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
756 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
758 /* Add to the linked list. */
759 *mtail = me;
760 mtail = &me->me_next;
763 #endif /* MOUNTED_GETMNTINFO */
765 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
767 struct statvfs *fsp;
768 int entries;
770 entries = getmntinfo (&fsp, MNT_NOWAIT);
771 if (entries < 0)
772 return NULL;
773 for (; entries-- > 0; fsp++)
775 me = g_malloc (sizeof (*me));
776 me->me_devname = g_strdup (fsp->f_mntfromname);
777 me->me_mountdir = g_strdup (fsp->f_mntonname);
778 me->me_type = g_strdup (fsp->f_fstypename);
779 me->me_type_malloced = 1;
780 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
781 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
782 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
784 /* Add to the linked list. */
785 *mtail = me;
786 mtail = &me->me_next;
789 #endif /* MOUNTED_GETMNTINFO2 */
791 #ifdef MOUNTED_GETMNT /* Ultrix. */
793 int offset = 0;
794 int val;
795 struct fs_data fsd;
797 while (TRUE)
799 errno = 0;
800 val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, (char *) NULL);
801 if (val < 0)
802 goto free_then_fail;
803 if (val == 0)
804 break;
806 me = g_malloc (sizeof (*me));
807 me->me_devname = g_strdup (fsd.fd_req.devname);
808 me->me_mountdir = g_strdup (fsd.fd_req.path);
809 me->me_type = gt_names[fsd.fd_req.fstype];
810 me->me_type_malloced = 0;
811 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
812 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
813 me->me_dev = fsd.fd_req.dev;
815 /* Add to the linked list. */
816 *mtail = me;
817 mtail = &me->me_next;
820 #endif /* MOUNTED_GETMNT. */
822 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
824 /* The next_dev() and fs_stat_dev() system calls give the list of
825 all file systems, including the information returned by statvfs()
826 (fs type, total blocks, free blocks etc.), but without the mount
827 point. But on BeOS all file systems except / are mounted in the
828 rootfs, directly under /.
829 The directory name of the mount point is often, but not always,
830 identical to the volume name of the device.
831 We therefore get the list of subdirectories of /, and the list
832 of all file systems, and match the two lists. */
834 DIR *dirp;
835 struct rootdir_entry
837 char *name;
838 dev_t dev;
839 ino_t ino;
840 struct rootdir_entry *next;
842 struct rootdir_entry *rootdir_list;
843 struct rootdir_entry **rootdir_tail;
844 int32 pos;
845 dev_t dev;
846 fs_info fi;
848 /* All volumes are mounted in the rootfs, directly under /. */
849 rootdir_list = NULL;
850 rootdir_tail = &rootdir_list;
851 dirp = opendir (PATH_SEP_STR);
852 if (dirp)
854 struct dirent *d;
856 while ((d = readdir (dirp)) != NULL)
858 char *name;
859 struct stat statbuf;
861 if (DIR_IS_DOT (d->d_name))
862 continue;
864 if (DIR_IS_DOTDOT (d->d_name))
865 name = g_strdup (PATH_SEP_STR);
866 else
867 name = g_strconcat (PATH_SEP_STR, d->d_name, (char *) NULL);
869 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
871 struct rootdir_entry *re = g_malloc (sizeof (*re));
872 re->name = name;
873 re->dev = statbuf.st_dev;
874 re->ino = statbuf.st_ino;
876 /* Add to the linked list. */
877 *rootdir_tail = re;
878 rootdir_tail = &re->next;
880 else
881 g_free (name);
883 closedir (dirp);
885 *rootdir_tail = NULL;
887 for (pos = 0; (dev = next_dev (&pos)) >= 0;)
888 if (fs_stat_dev (dev, &fi) >= 0)
890 /* Note: fi.dev == dev. */
891 struct rootdir_entry *re;
893 for (re = rootdir_list; re; re = re->next)
894 if (re->dev == fi.dev && re->ino == fi.root)
895 break;
897 me = g_malloc (sizeof (*me));
898 me->me_devname =
899 g_strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
900 me->me_mountdir = g_strdup (re != NULL ? re->name : fi.fsh_name);
901 me->me_type = g_strdup (fi.fsh_name);
902 me->me_type_malloced = 1;
903 me->me_dev = fi.dev;
904 me->me_dummy = 0;
905 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
907 /* Add to the linked list. */
908 *mtail = me;
909 mtail = &me->me_next;
911 *mtail = NULL;
913 while (rootdir_list != NULL)
915 struct rootdir_entry *re = rootdir_list;
916 rootdir_list = re->next;
917 g_free (re->name);
918 g_free (re);
921 #endif /* MOUNTED_FS_STAT_DEV */
923 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
925 int numsys, counter;
926 size_t bufsize;
927 struct statfs *stats;
929 numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
930 if (numsys < 0)
931 return NULL;
932 if (SIZE_MAX / sizeof (*stats) <= numsys)
934 fprintf (stderr, "%s\n", _("Memory exhausted!"));
935 exit (EXIT_FAILURE);
938 bufsize = (1 + numsys) * sizeof (*stats);
939 stats = g_malloc (bufsize);
940 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
942 if (numsys < 0)
944 g_free (stats);
945 return NULL;
948 for (counter = 0; counter < numsys; counter++)
950 me = g_malloc (sizeof (*me));
951 me->me_devname = g_strdup (stats[counter].f_mntfromname);
952 me->me_mountdir = g_strdup (stats[counter].f_mntonname);
953 me->me_type = g_strdup (FS_TYPE (stats[counter]));
954 me->me_type_malloced = 1;
955 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
956 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
957 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
959 /* Add to the linked list. */
960 *mtail = me;
961 mtail = &me->me_next;
964 g_free (stats);
966 #endif /* MOUNTED_GETFSSTAT */
968 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
970 struct mnttab mnt;
971 char *table = "/etc/mnttab";
972 FILE *fp;
974 fp = fopen (table, "r");
975 if (fp == NULL)
976 return NULL;
978 while (fread (&mnt, sizeof (mnt), 1, fp) > 0)
980 me = g_malloc (sizeof (*me));
981 #ifdef GETFSTYP /* SVR3. */
982 me->me_devname = g_strdup (mnt.mt_dev);
983 #else
984 me->me_devname = g_strconcat ("/dev/", mnt.mt_dev, (char *) NULL);
985 #endif
986 me->me_mountdir = g_strdup (mnt.mt_filsys);
987 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
988 me->me_type = "";
989 me->me_type_malloced = 0;
990 #ifdef GETFSTYP /* SVR3. */
991 if (need_fs_type)
993 struct statfs fsd;
994 char typebuf[FSTYPSZ];
996 if (statfs (me->me_mountdir, &fsd, sizeof (fsd), 0) != -1
997 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
999 me->me_type = g_strdup (typebuf);
1000 me->me_type_malloced = 1;
1003 #endif
1004 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1005 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1007 /* Add to the linked list. */
1008 *mtail = me;
1009 mtail = &me->me_next;
1012 if (ferror (fp))
1014 /* The last fread() call must have failed. */
1015 int saved_errno = errno;
1016 fclose (fp);
1017 errno = saved_errno;
1018 goto free_then_fail;
1021 if (fclose (fp) == EOF)
1022 goto free_then_fail;
1024 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
1026 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
1028 struct mntent **mnttbl = getmnttbl (), **ent;
1029 for (ent = mnttbl; *ent; ent++)
1031 me = g_malloc (sizeof (*me));
1032 me->me_devname = g_strdup ((*ent)->mt_resource);
1033 me->me_mountdir = g_strdup ((*ent)->mt_directory);
1034 me->me_type = g_strdup ((*ent)->mt_fstype);
1035 me->me_type_malloced = 1;
1036 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1037 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1038 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
1040 /* Add to the linked list. */
1041 *mtail = me;
1042 mtail = &me->me_next;
1044 endmnttbl ();
1046 #endif
1048 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
1050 struct mnttab mnt;
1051 char *table = MNTTAB;
1052 FILE *fp;
1053 int ret;
1054 int lockfd = -1;
1056 #if defined F_RDLCK && defined F_SETLKW
1057 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
1058 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
1059 for this file name, we should use their macro name instead.
1060 (Why not just lock MNTTAB directly? We don't know.) */
1061 #ifndef MNTTAB_LOCK
1062 #define MNTTAB_LOCK "/etc/.mnttab.lock"
1063 #endif
1064 lockfd = open (MNTTAB_LOCK, O_RDONLY);
1065 if (lockfd >= 0)
1067 struct flock flock;
1069 flock.l_type = F_RDLCK;
1070 flock.l_whence = SEEK_SET;
1071 flock.l_start = 0;
1072 flock.l_len = 0;
1073 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
1074 if (errno != EINTR)
1076 int saved_errno = errno;
1077 close (lockfd);
1078 errno = saved_errno;
1079 return NULL;
1082 else if (errno != ENOENT)
1083 return NULL;
1084 #endif
1086 errno = 0;
1087 fp = fopen (table, "r");
1088 if (fp == NULL)
1089 ret = errno;
1090 else
1092 while ((ret = getmntent (fp, &mnt)) == 0)
1094 me = g_malloc (sizeof (*me));
1095 me->me_devname = g_strdup (mnt.mnt_special);
1096 me->me_mountdir = g_strdup (mnt.mnt_mountp);
1097 me->me_type = g_strdup (mnt.mnt_fstype);
1098 me->me_type_malloced = 1;
1099 me->me_dummy = MNT_IGNORE (&mnt) != 0;
1100 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1101 me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
1103 /* Add to the linked list. */
1104 *mtail = me;
1105 mtail = &me->me_next;
1108 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
1111 if (lockfd >= 0 && close (lockfd) != 0)
1112 ret = errno;
1114 if (ret >= 0)
1116 errno = ret;
1117 goto free_then_fail;
1120 #endif /* MOUNTED_GETMNTENT2. */
1122 #ifdef MOUNTED_VMOUNT /* AIX. */
1124 int bufsize;
1125 char *entries, *thisent;
1126 struct vmount *vmp;
1127 int n_entries;
1128 int i;
1130 /* Ask how many bytes to allocate for the mounted file system info. */
1131 if (mntctl (MCTL_QUERY, sizeof (bufsize), (struct vmount *) &bufsize) != 0)
1132 return NULL;
1133 entries = g_malloc (bufsize);
1135 /* Get the list of mounted file systems. */
1136 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
1137 if (n_entries < 0)
1139 int saved_errno = errno;
1140 g_free (entries);
1141 errno = saved_errno;
1142 return NULL;
1145 for (i = 0, thisent = entries; i < n_entries; i++, thisent += vmp->vmt_length)
1147 char *options, *ignore;
1149 vmp = (struct vmount *) thisent;
1150 me = g_malloc (sizeof (*me));
1151 if (vmp->vmt_flags & MNT_REMOTE)
1153 char *host, *dir;
1155 me->me_remote = 1;
1156 /* Prepend the remote dirname. */
1157 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
1158 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
1159 me->me_devname = g_strconcat (host, ":", dir, (char *) NULL);
1161 else
1163 me->me_remote = 0;
1164 me->me_devname = g_strdup (thisent + vmp->vmt_data[VMT_OBJECT].vmt_off);
1166 me->me_mountdir = g_strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
1167 me->me_type = g_strdup (fstype_to_string (vmp->vmt_gfstype));
1168 me->me_type_malloced = 1;
1169 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
1170 ignore = strstr (options, "ignore");
1171 me->me_dummy = (ignore
1172 && (ignore == options || ignore[-1] == ',')
1173 && (ignore[sizeof ("ignore") - 1] == ','
1174 || ignore[sizeof ("ignore") - 1] == '\0'));
1175 me->me_dev = (dev_t) (-1); /* vmt_fsid might be the info we want. */
1177 /* Add to the linked list. */
1178 *mtail = me;
1179 mtail = &me->me_next;
1181 g_free (entries);
1183 #endif /* MOUNTED_VMOUNT. */
1186 #ifdef MOUNTED_INTERIX_STATVFS
1188 DIR *dirp = opendir ("/dev/fs");
1189 char node[9 + NAME_MAX];
1191 if (!dirp)
1192 goto free_then_fail;
1194 while (1)
1196 struct statvfs dev;
1197 struct dirent entry;
1198 struct dirent *result;
1200 if (readdir_r (dirp, &entry, &result) || result == NULL)
1201 break;
1203 strcpy (node, "/dev/fs/");
1204 strcat (node, entry.d_name);
1206 if (statvfs (node, &dev) == 0)
1208 me = g_malloc (sizeof *me);
1209 me->me_devname = g_strdup (dev.f_mntfromname);
1210 me->me_mountdir = g_strdup (dev.f_mntonname);
1211 me->me_type = g_strdup (dev.f_fstypename);
1212 me->me_type_malloced = 1;
1213 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1214 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1215 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
1217 /* Add to the linked list. */
1218 *mtail = me;
1219 mtail = &me->me_next;
1222 closedir (dirp);
1224 #endif /* MOUNTED_INTERIX_STATVFS */
1226 (void) need_fs_type; /* avoid argument-unused warning */
1227 *mtail = NULL;
1228 return mount_list;
1231 free_then_fail:
1233 int saved_errno = errno;
1234 *mtail = NULL;
1236 while (mount_list)
1238 me = mount_list->me_next;
1239 g_free (mount_list->me_devname);
1240 g_free (mount_list->me_mountdir);
1241 if (mount_list->me_type_malloced)
1242 g_free (mount_list->me_type);
1243 g_free (mount_list);
1244 mount_list = me;
1247 errno = saved_errno;
1248 return NULL;
1252 #endif /* HAVE_INFOMOUNT_LIST */
1254 /* --------------------------------------------------------------------------------------------- */
1256 #ifdef HAVE_INFOMOUNT_QNX
1258 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1259 ** this via the following code.
1260 ** Note that, as this is based on CWD, it only fills one mount_entry
1261 ** structure. See my_statfs() in utilunix.c for the "other side" of
1262 ** this hack.
1265 static struct mount_entry *
1266 read_file_system_list (int need_fs_type, int all_fs)
1268 struct _disk_entry de;
1269 struct statfs fs;
1270 int i, fd;
1271 char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
1273 static struct mount_entry *me = NULL;
1275 if (me)
1277 g_free (me->me_devname);
1278 g_free (me->me_mountdir);
1279 g_free (me->me_type);
1281 else
1282 me = (struct mount_entry *) g_malloc (sizeof (struct mount_entry));
1284 if (!getcwd (dir, _POSIX_PATH_MAX))
1285 return (NULL);
1287 fd = open (dir, O_RDONLY);
1288 if (fd == -1)
1289 return (NULL);
1291 i = disk_get_entry (fd, &de);
1293 close (fd);
1295 if (i == -1)
1296 return (NULL);
1298 switch (de.disk_type)
1300 case _UNMOUNTED:
1301 tp = "unmounted";
1302 break;
1303 case _FLOPPY:
1304 tp = "Floppy";
1305 break;
1306 case _HARD:
1307 tp = "Hard";
1308 break;
1309 case _RAMDISK:
1310 tp = "Ram";
1311 break;
1312 case _REMOVABLE:
1313 tp = "Removable";
1314 break;
1315 case _TAPE:
1316 tp = "Tape";
1317 break;
1318 case _CDROM:
1319 tp = "CDROM";
1320 break;
1321 default:
1322 tp = "unknown";
1325 if (fsys_get_mount_dev (dir, &dev) == -1)
1326 return (NULL);
1328 if (fsys_get_mount_pt (dev, &dir) == -1)
1329 return (NULL);
1331 me->me_devname = g_strdup (dev);
1332 me->me_mountdir = g_strdup (dir);
1333 me->me_type = g_strdup (tp);
1334 me->me_dev = de.disk_type;
1336 #ifdef DEBUG
1337 fprintf (stderr,
1338 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1339 de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
1340 fprintf (stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
1341 fprintf (stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
1342 #endif /* DEBUG */
1344 return (me);
1346 #endif /* HAVE_INFOMOUNT_QNX */
1348 /* --------------------------------------------------------------------------------------------- */
1350 #ifdef STAT_READ_FILSYS /* SVR2 */
1352 /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
1353 interrupted. Return the actual number of bytes read(written), zero for EOF,
1354 or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */
1355 static size_t
1356 safe_read (int fd, void *buf, size_t count)
1358 /* Work around a bug in Tru64 5.1. Attempting to read more than
1359 INT_MAX bytes fails with errno == EINVAL. See
1360 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
1361 When decreasing COUNT, keep it block-aligned. */
1362 /* *INDENT-OFF* */
1363 enum { BUGGY_READ_MAXIMUM = INT_MAX & ~8191 };
1364 /* *INDENT-ON* */
1366 while (TRUE)
1368 ssize_t result;
1370 result = read (fd, buf, count);
1372 if (0 <= result)
1373 return result;
1374 else if (IS_EINTR (errno))
1375 continue;
1376 else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count)
1377 count = BUGGY_READ_MAXIMUM;
1378 else
1379 return result;
1383 /* --------------------------------------------------------------------------------------------- */
1385 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1386 interrupted or if a partial write(read) occurs. Return the number
1387 of bytes transferred.
1388 When writing, set errno if fewer than COUNT bytes are written.
1389 When reading, if fewer than COUNT bytes are read, you must examine
1390 errno to distinguish failure from EOF (errno == 0). */
1392 static size_t
1393 full_read (int fd, void *buf, size_t count)
1395 size_t total = 0;
1396 char *ptr = (char *) buf;
1398 while (count > 0)
1400 size_t n_rw = safe_read (fd, ptr, count);
1401 if (n_rw == (size_t) (-1))
1402 break;
1403 if (n_rw == 0)
1405 errno = ZERO_BYTE_TRANSFER_ERRNO;
1406 break;
1408 total += n_rw;
1409 ptr += n_rw;
1410 count -= n_rw;
1413 return total;
1416 #endif /* STAT_READ_FILSYS */
1418 /* --------------------------------------------------------------------------------------------- */
1420 #ifdef HAVE_INFOMOUNT
1421 /* Fill in the fields of FSP with information about space usage for
1422 the file system on which FILE resides.
1423 DISK is the device on which FILE is mounted, for space-getting
1424 methods that need to know it.
1425 Return 0 if successful, -1 if not. When returning -1, ensure that
1426 ERRNO is either a system error value, or zero if DISK is NULL
1427 on a system that requires a non-NULL value. */
1428 static int
1429 get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
1431 #ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
1433 if (statvfs_works ())
1435 struct statvfs vfsd;
1437 if (statvfs (file, &vfsd) < 0)
1438 return -1;
1440 /* f_frsize isn't guaranteed to be supported. */
1441 fsp->fsu_blocksize = (vfsd.f_frsize
1442 ? PROPAGATE_ALL_ONES (vfsd.f_frsize)
1443 : PROPAGATE_ALL_ONES (vfsd.f_bsize));
1445 fsp->fsu_blocks = PROPAGATE_ALL_ONES (vfsd.f_blocks);
1446 fsp->fsu_bfree = PROPAGATE_ALL_ONES (vfsd.f_bfree);
1447 fsp->fsu_bavail = PROPAGATE_TOP_BIT (vfsd.f_bavail);
1448 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (vfsd.f_bavail) != 0;
1449 fsp->fsu_files = PROPAGATE_ALL_ONES (vfsd.f_files);
1450 fsp->fsu_ffree = PROPAGATE_ALL_ONES (vfsd.f_ffree);
1452 else
1453 #endif
1456 #if defined STAT_STATVFS64 /* AIX */
1458 struct statvfs64 fsd;
1460 if (statvfs64 (file, &fsd) < 0)
1461 return -1;
1463 /* f_frsize isn't guaranteed to be supported. */
1464 /* *INDENT-OFF* */
1465 fsp->fsu_blocksize = fsd.f_frsize
1466 ? PROPAGATE_ALL_ONES (fsd.f_frsize)
1467 : PROPAGATE_ALL_ONES (fsd.f_bsize);
1468 /* *INDENT-ON* */
1470 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1472 struct fs_data fsd;
1474 if (statfs (file, &fsd) != 1)
1475 return -1;
1477 fsp->fsu_blocksize = 1024;
1478 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot);
1479 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree);
1480 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen);
1481 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0;
1482 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
1483 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
1485 #elif defined STAT_READ_FILSYS /* SVR2 */
1486 #ifndef SUPERBOFF
1487 #define SUPERBOFF (SUPERB * 512)
1488 #endif
1490 struct filsys fsd;
1491 int fd;
1493 if (!disk)
1495 errno = 0;
1496 return -1;
1499 fd = open (disk, O_RDONLY);
1500 if (fd < 0)
1501 return -1;
1502 lseek (fd, (off_t) SUPERBOFF, 0);
1503 if (full_read (fd, (char *) &fsd, sizeof (fsd)) != sizeof (fsd))
1505 close (fd);
1506 return -1;
1508 close (fd);
1510 fsp->fsu_blocksize = (fsd.s_type == Fs2b ? 1024 : 512);
1511 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.s_fsize);
1512 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.s_tfree);
1513 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree);
1514 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0;
1515 fsp->fsu_files = (fsd.s_isize == -1
1516 ? UINTMAX_MAX : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1));
1517 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode);
1519 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1521 struct statfs fsd;
1523 if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
1524 return -1;
1526 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1528 #elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
1530 struct statfs fsd;
1532 if (statfs (file, &fsd) < 0)
1533 return -1;
1535 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_frsize);
1537 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
1538 Mac OS X < 10.4, FreeBSD < 5.0, \
1539 NetBSD < 3.0, OpenBSD < 4.4 */
1541 struct statfs fsd;
1543 if (statfs (file, &fsd) < 0)
1544 return -1;
1546 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1548 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1550 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1551 struct statfs are truncated to 2GB. These conditions detect that
1552 truncation, presumably without botching the 4.1.1 case, in which
1553 the values are not truncated. The correct counts are stored in
1554 undocumented spare fields. */
1555 if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
1557 fsd.f_blocks = fsd.f_spare[0];
1558 fsd.f_bfree = fsd.f_spare[1];
1559 fsd.f_bavail = fsd.f_spare[2];
1561 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1563 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1565 struct statfs fsd;
1567 if (statfs (file, &fsd) < 0)
1568 return -1;
1570 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1572 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1573 Dolphin */
1575 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1576 #define f_bavail f_bfree
1577 #endif
1579 struct statfs fsd;
1581 if (statfs (file, &fsd, sizeof (fsd), 0) < 0)
1582 return -1;
1584 /* Empirically, the block counts on most SVR3 and SVR3-derived
1585 systems seem to always be in terms of 512-byte blocks,
1586 no matter what value f_bsize has. */
1587 #if defined _AIX || defined _CRAY
1588 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1589 #else
1590 fsp->fsu_blocksize = 512;
1591 #endif
1593 #endif
1595 #if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 \
1596 || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE \
1597 || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
1599 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
1600 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
1601 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
1602 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
1603 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
1604 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
1606 #endif
1609 (void) disk; /* avoid argument-unused warning */
1611 return 0;
1613 #endif /* HAVE_INFOMOUNT */
1615 /* --------------------------------------------------------------------------------------------- */
1616 /*** public functions ****************************************************************************/
1617 /* --------------------------------------------------------------------------------------------- */
1619 void
1620 free_my_statfs (void)
1622 #ifdef HAVE_INFOMOUNT_LIST
1623 while (mc_mount_list != NULL)
1625 struct mount_entry *next;
1627 next = mc_mount_list->me_next;
1628 free_mount_entry (mc_mount_list);
1629 mc_mount_list = next;
1632 mc_mount_list = NULL;
1633 #endif /* HAVE_INFOMOUNT_LIST */
1636 /* --------------------------------------------------------------------------------------------- */
1638 void
1639 init_my_statfs (void)
1641 #ifdef HAVE_INFOMOUNT_LIST
1642 free_my_statfs ();
1643 mc_mount_list = read_file_system_list (1);
1644 #endif /* HAVE_INFOMOUNT_LIST */
1647 /* --------------------------------------------------------------------------------------------- */
1649 void
1650 my_statfs (struct my_statfs *myfs_stats, const char *path)
1652 #ifdef HAVE_INFOMOUNT_LIST
1653 size_t len = 0;
1654 struct mount_entry *entry = NULL;
1655 struct mount_entry *temp = mc_mount_list;
1656 struct fs_usage fs_use;
1658 while (temp)
1660 size_t i;
1662 i = strlen (temp->me_mountdir);
1663 if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
1664 if (entry == NULL || IS_PATH_SEP (path[i]) || path[i] == '\0')
1666 len = i;
1667 entry = temp;
1669 temp = temp->me_next;
1672 if (entry)
1674 memset (&fs_use, 0, sizeof (struct fs_usage));
1675 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1677 myfs_stats->type = entry->me_dev;
1678 myfs_stats->typename = entry->me_type;
1679 myfs_stats->mpoint = entry->me_mountdir;
1680 myfs_stats->device = entry->me_devname;
1681 myfs_stats->avail =
1682 ((uintmax_t) (getuid ()? fs_use.fsu_bavail : fs_use.fsu_bfree) *
1683 fs_use.fsu_blocksize) >> 10;
1684 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1685 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1686 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1688 else
1689 #endif /* HAVE_INFOMOUNT_LIST */
1691 #ifdef HAVE_INFOMOUNT_QNX
1693 ** This is the "other side" of the hack to read_file_system_list() in
1694 ** mountlist.c.
1695 ** It's not the most efficient approach, but consumes less memory. It
1696 ** also accommodates QNX's ability to mount filesystems on the fly.
1698 struct mount_entry *entry;
1699 struct fs_usage fs_use;
1701 entry = read_file_system_list (0, 0);
1702 if (entry != NULL)
1704 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1706 myfs_stats->type = entry->me_dev;
1707 myfs_stats->typename = entry->me_type;
1708 myfs_stats->mpoint = entry->me_mountdir;
1709 myfs_stats->device = entry->me_devname;
1711 myfs_stats->avail = ((uintmax_t) fs_use.fsu_bfree * fs_use.fsu_blocksize) >> 10;
1712 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1713 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1714 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1716 else
1717 #endif /* HAVE_INFOMOUNT_QNX */
1719 myfs_stats->type = 0;
1720 myfs_stats->mpoint = "unknown";
1721 myfs_stats->device = "unknown";
1722 myfs_stats->avail = 0;
1723 myfs_stats->total = 0;
1724 myfs_stats->nfree = 0;
1725 myfs_stats->nodes = 0;
1729 /* --------------------------------------------------------------------------------------------- */