Sync with gnulib 62bb7a8bf95807d6339e1e17fc0d21c319b280a2.
[midnight-commander.git] / src / filemanager / mountlist.c
blobf06a6ac1fccb057e0e5e5699ca9c60065d4533a5
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 #ifndef HAVE_HASMNTOPT
164 #define hasmntopt(mnt, opt) ((char *) 0)
165 #endif
167 #undef MNT_IGNORE
168 #ifdef MNTOPT_IGNORE
169 #define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
170 #else
171 #define MNT_IGNORE(M) 0
172 #endif
174 #ifdef HAVE_INFOMOUNT_QNX
175 #include <sys/disk.h>
176 #include <sys/fsys.h>
177 #endif
179 #ifdef HAVE_SYS_STATVFS_H /* SVR4. */
180 #include <sys/statvfs.h>
181 #endif
183 #include "lib/global.h"
184 #include "mountlist.h"
186 /*** global variables ****************************************************************************/
188 /*** file scope macro definitions ****************************************************************/
190 #if defined (__QNX__) && !defined(__QNXNTO__) && !defined (HAVE_INFOMOUNT_LIST)
191 #define HAVE_INFOMOUNT_QNX
192 #endif
194 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
195 #define HAVE_INFOMOUNT
196 #endif
198 /* The results of open() in this file are not used with fchdir,
199 therefore save some unnecessary work in fchdir.c. */
200 #undef open
201 #undef close
203 /* The results of opendir() in this file are not used with dirfd and fchdir,
204 therefore save some unnecessary work in fchdir.c. */
205 #undef opendir
206 #undef closedir
208 #define ME_DUMMY_0(Fs_name, Fs_type) \
209 (strcmp (Fs_type, "autofs") == 0 \
210 || strcmp (Fs_type, "proc") == 0 \
211 || strcmp (Fs_type, "subfs") == 0 \
212 /* for Linux 2.6/3.x */ \
213 || strcmp (Fs_type, "debugfs") == 0 \
214 || strcmp (Fs_type, "devpts") == 0 \
215 || strcmp (Fs_type, "fusectl") == 0 \
216 || strcmp (Fs_type, "mqueue") == 0 \
217 || strcmp (Fs_type, "rpc_pipefs") == 0 \
218 || strcmp (Fs_type, "sysfs") == 0 \
219 /* FreeBSD, Linux 2.4 */ \
220 || strcmp (Fs_type, "devfs") == 0 \
221 /* for NetBSD 3.0 */ \
222 || strcmp (Fs_type, "kernfs") == 0 \
223 /* for Irix 6.5 */ \
224 || strcmp (Fs_type, "ignore") == 0)
226 /* Historically, we have marked as "dummy" any file system of type "none",
227 but now that programs like du need to know about bind-mounted directories,
228 we grant an exception to any with "bind" in its list of mount options.
229 I.e., those are *not* dummy entries. */
230 #ifdef MOUNTED_GETMNTENT1
231 #define ME_DUMMY(Fs_name, Fs_type, Fs_ent) \
232 (ME_DUMMY_0 (Fs_name, Fs_type) \
233 || (strcmp (Fs_type, "none") == 0 \
234 && !hasmntopt (Fs_ent, "bind")))
235 #else
236 #define ME_DUMMY(Fs_name, Fs_type) \
237 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
238 #endif
240 #ifdef __CYGWIN__
241 #include <windows.h>
242 #define ME_REMOTE me_remote
243 /* All cygwin mount points include `:' or start with `//'; so it
244 requires a native Windows call to determine remote disks. */
245 static int
246 me_remote (char const *fs_name, char const *fs_type _GL_UNUSED)
248 if (fs_name[0] && fs_name[1] == ':')
250 char drive[4];
251 sprintf (drive, "%c:\\", fs_name[0]);
252 switch (GetDriveType (drive))
254 case DRIVE_REMOVABLE:
255 case DRIVE_FIXED:
256 case DRIVE_CDROM:
257 case DRIVE_RAMDISK:
258 return 0;
261 return 1;
263 #endif
264 #ifndef ME_REMOTE
265 /* A file system is `remote' if its Fs_name contains a `:'
266 or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */
267 #define ME_REMOTE(Fs_name, Fs_type) \
268 (strchr (Fs_name, ':') != NULL \
269 || ((Fs_name)[0] == '/' \
270 && (Fs_name)[1] == '/' \
271 && (strcmp (Fs_type, "smbfs") == 0 || strcmp (Fs_type, "cifs") == 0)))
272 #endif
274 /* Many space usage primitives use all 1 bits to denote a value that is
275 not applicable or unknown. Propagate this information by returning
276 a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
277 is unsigned and narrower than uintmax_t. */
278 #define PROPAGATE_ALL_ONES(x) \
279 ((sizeof (x) < sizeof (uintmax_t) \
280 && (~ (x) == (sizeof (x) < sizeof (int) \
281 ? - (1 << (sizeof (x) * CHAR_BIT)) \
282 : 0))) \
283 ? UINTMAX_MAX : (uintmax_t) (x))
285 /* Extract the top bit of X as an uintmax_t value. */
286 #define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
288 /* If a value is negative, many space usage primitives store it into an
289 integer variable by assignment, even if the variable's type is unsigned.
290 So, if a space usage variable X's top bit is set, convert X to the
291 uintmax_t value V such that (- (uintmax_t) V) is the negative of
292 the original value. If X's top bit is clear, just yield X.
293 Use PROPAGATE_TOP_BIT if the original value might be negative;
294 otherwise, use PROPAGATE_ALL_ONES. */
295 #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
297 #ifdef STAT_STATVFS
298 /* Return true if statvfs works. This is false for statvfs on systems
299 with GNU libc on Linux kernels before 2.6.36, which stats all
300 preceding entries in /proc/mounts; that makes df hang if even one
301 of the corresponding file systems is hard-mounted but not available. */
302 #if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
303 /* The FRSIZE fallback is not required in this case. */
304 #undef STAT_STATFS2_FRSIZE
305 static int
306 statvfs_works (void)
308 return 1;
310 #else
311 #include <string.h> /* for strverscmp */
312 #include <sys/utsname.h>
313 #include <sys/statfs.h>
314 #define STAT_STATFS2_BSIZE 1
316 static int
317 statvfs_works (void)
319 static int statvfs_works_cache = -1;
320 struct utsname name;
322 if (statvfs_works_cache < 0)
323 statvfs_works_cache = (uname (&name) == 0 && 0 <= strverscmp (name.release, "2.6.36"));
324 return statvfs_works_cache;
326 #endif
327 #endif
329 #ifdef STAT_READ_FILSYS /* SVR2 */
330 /* Set errno to zero upon EOF. */
331 #define ZERO_BYTE_TRANSFER_ERRNO 0
333 #ifdef EINTR
334 #define IS_EINTR(x) ((x) == EINTR)
335 #else
336 #define IS_EINTR(x) 0
337 #endif
338 #endif /* STAT_READ_FILSYS */
340 /*** file scope type declarations ****************************************************************/
342 /* A mount table entry. */
343 struct mount_entry
345 char *me_devname; /* Device node name, including "/dev/". */
346 char *me_mountdir; /* Mount point directory name. */
347 char *me_type; /* "nfs", "4.2", etc. */
348 dev_t me_dev; /* Device number of me_mountdir. */
349 unsigned int me_dummy:1; /* Nonzero for dummy file systems. */
350 unsigned int me_remote:1; /* Nonzero for remote fileystems. */
351 unsigned int me_type_malloced:1; /* Nonzero if me_type was malloced. */
352 struct mount_entry *me_next;
355 struct fs_usage
357 uintmax_t fsu_blocksize; /* Size of a block. */
358 uintmax_t fsu_blocks; /* Total blocks. */
359 uintmax_t fsu_bfree; /* Free blocks available to superuser. */
360 uintmax_t fsu_bavail; /* Free blocks available to non-superuser. */
361 int fsu_bavail_top_bit_set; /* 1 if fsu_bavail represents a value < 0. */
362 uintmax_t fsu_files; /* Total file nodes. */
363 uintmax_t fsu_ffree; /* Free file nodes. */
366 /*** file scope variables ************************************************************************/
368 #ifdef HAVE_INFOMOUNT_LIST
369 static struct mount_entry *mc_mount_list = NULL;
370 #endif /* HAVE_INFOMOUNT_LIST */
372 /*** file scope functions ************************************************************************/
373 /* --------------------------------------------------------------------------------------------- */
375 #ifdef HAVE_INFOMOUNT_LIST
376 static void
377 free_mount_entry (struct mount_entry *me)
379 if (!me)
380 return;
381 g_free (me->me_devname);
382 g_free (me->me_mountdir);
383 if (me->me_type_malloced)
384 g_free (me->me_type);
385 g_free (me);
388 /* --------------------------------------------------------------------------------------------- */
390 #ifdef MOUNTED_GETMNTINFO
392 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
393 static char *
394 fstype_to_string (short int t)
396 switch (t)
398 #ifdef MOUNT_PC
399 case MOUNT_PC:
400 return "pc";
401 #endif
402 #ifdef MOUNT_MFS
403 case MOUNT_MFS:
404 return "mfs";
405 #endif
406 #ifdef MOUNT_LO
407 case MOUNT_LO:
408 return "lo";
409 #endif
410 #ifdef MOUNT_TFS
411 case MOUNT_TFS:
412 return "tfs";
413 #endif
414 #ifdef MOUNT_TMP
415 case MOUNT_TMP:
416 return "tmp";
417 #endif
418 #ifdef MOUNT_UFS
419 case MOUNT_UFS:
420 return "ufs";
421 #endif
422 #ifdef MOUNT_NFS
423 case MOUNT_NFS:
424 return "nfs";
425 #endif
426 #ifdef MOUNT_MSDOS
427 case MOUNT_MSDOS:
428 return "msdos";
429 #endif
430 #ifdef MOUNT_LFS
431 case MOUNT_LFS:
432 return "lfs";
433 #endif
434 #ifdef MOUNT_LOFS
435 case MOUNT_LOFS:
436 return "lofs";
437 #endif
438 #ifdef MOUNT_FDESC
439 case MOUNT_FDESC:
440 return "fdesc";
441 #endif
442 #ifdef MOUNT_PORTAL
443 case MOUNT_PORTAL:
444 return "portal";
445 #endif
446 #ifdef MOUNT_NULL
447 case MOUNT_NULL:
448 return "null";
449 #endif
450 #ifdef MOUNT_UMAP
451 case MOUNT_UMAP:
452 return "umap";
453 #endif
454 #ifdef MOUNT_KERNFS
455 case MOUNT_KERNFS:
456 return "kernfs";
457 #endif
458 #ifdef MOUNT_PROCFS
459 case MOUNT_PROCFS:
460 return "procfs";
461 #endif
462 #ifdef MOUNT_AFS
463 case MOUNT_AFS:
464 return "afs";
465 #endif
466 #ifdef MOUNT_CD9660
467 case MOUNT_CD9660:
468 return "cd9660";
469 #endif
470 #ifdef MOUNT_UNION
471 case MOUNT_UNION:
472 return "union";
473 #endif
474 #ifdef MOUNT_DEVFS
475 case MOUNT_DEVFS:
476 return "devfs";
477 #endif
478 #ifdef MOUNT_EXT2FS
479 case MOUNT_EXT2FS:
480 return "ext2fs";
481 #endif
482 default:
483 return "?";
486 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
488 /* --------------------------------------------------------------------------------------------- */
490 static char *
491 fsp_to_string (const struct statfs *fsp)
493 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
494 return (char *) (fsp->f_fstypename);
495 #else
496 return fstype_to_string (fsp->f_type);
497 #endif
499 #endif /* MOUNTED_GETMNTINFO */
501 /* --------------------------------------------------------------------------------------------- */
503 #ifdef MOUNTED_VMOUNT /* AIX. */
504 static char *
505 fstype_to_string (int t)
507 struct vfs_ent *e;
509 e = getvfsbytype (t);
510 if (!e || !e->vfsent_name)
511 return "none";
512 else
513 return e->vfsent_name;
515 #endif /* MOUNTED_VMOUNT */
517 /* --------------------------------------------------------------------------------------------- */
519 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
521 /* Return the device number from MOUNT_OPTIONS, if possible.
522 Otherwise return (dev_t) -1. */
524 /* --------------------------------------------------------------------------------------------- */
526 static dev_t
527 dev_from_mount_options (char const *mount_options)
529 /* GNU/Linux allows file system implementations to define their own
530 meaning for "dev=" mount options, so don't trust the meaning
531 here. */
532 #ifndef __linux__
533 static char const dev_pattern[] = ",dev=";
534 char const *devopt = strstr (mount_options, dev_pattern);
536 if (devopt)
538 char const *optval = devopt + sizeof (dev_pattern) - 1;
539 char *optvalend;
540 unsigned long int dev;
541 errno = 0;
542 dev = strtoul (optval, &optvalend, 16);
543 if (optval != optvalend
544 && (*optvalend == '\0' || *optvalend == ',')
545 && !(dev == ULONG_MAX && errno == ERANGE) && dev == (dev_t) dev)
546 return dev;
548 #endif
550 (void) mount_options;
551 return -1;
554 #endif
556 /* --------------------------------------------------------------------------------------------- */
558 #if defined _AIX && defined _I386
559 /* AIX PS/2 does not supply statfs. */
561 static int
562 statfs (char *file, struct statfs *fsb)
564 struct stat stats;
565 struct dustat fsd;
567 if (stat (file, &stats) != 0)
568 return -1;
569 if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
570 return -1;
571 fsb->f_type = 0;
572 fsb->f_bsize = fsd.du_bsize;
573 fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
574 fsb->f_bfree = fsd.du_tfree;
575 fsb->f_bavail = fsd.du_tfree;
576 fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
577 fsb->f_ffree = fsd.du_tinode;
578 fsb->f_fsid.val[0] = fsd.du_site;
579 fsb->f_fsid.val[1] = fsd.du_pckno;
580 return 0;
583 #endif /* _AIX && _I386 */
585 /* --------------------------------------------------------------------------------------------- */
587 /* Return a list of the currently mounted file systems, or NULL on error.
588 Add each entry to the tail of the list so that they stay in order.
589 If NEED_FS_TYPE is true, ensure that the file system type fields in
590 the returned list are valid. Otherwise, they might not be. */
592 static struct mount_entry *
593 read_file_system_list (int need_fs_type)
595 struct mount_entry *mount_list;
596 struct mount_entry *me;
597 struct mount_entry **mtail = &mount_list;
599 #ifdef MOUNTED_LISTMNTENT
601 struct tabmntent *mntlist, *p;
602 struct mntent *mnt;
603 struct mount_entry *me;
605 /* the third and fourth arguments could be used to filter mounts,
606 but Crays doesn't seem to have any mounts that we want to
607 remove. Specifically, automount create normal NFS mounts.
610 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
611 return NULL;
612 for (p = mntlist; p; p = p->next)
614 mnt = p->ment;
615 me = g_malloc (sizeof (*me));
616 me->me_devname = g_strdup (mnt->mnt_fsname);
617 me->me_mountdir = g_strdup (mnt->mnt_dir);
618 me->me_type = g_strdup (mnt->mnt_type);
619 me->me_type_malloced = 1;
620 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
621 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
622 me->me_dev = -1;
623 *mtail = me;
624 mtail = &me->me_next;
626 freemntlist (mntlist);
628 #endif
630 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
632 struct mntent *mnt;
633 const char *table = MOUNTED;
634 FILE *fp;
636 fp = setmntent (table, "r");
637 if (fp == NULL)
638 return NULL;
640 while ((mnt = getmntent (fp)))
642 me = g_malloc (sizeof (*me));
643 me->me_devname = g_strdup (mnt->mnt_fsname);
644 me->me_mountdir = g_strdup (mnt->mnt_dir);
645 me->me_type = g_strdup (mnt->mnt_type);
646 me->me_type_malloced = 1;
647 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, mnt);
648 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
649 me->me_dev = dev_from_mount_options (mnt->mnt_opts);
651 /* Add to the linked list. */
652 *mtail = me;
653 mtail = &me->me_next;
656 if (endmntent (fp) == 0)
657 goto free_then_fail;
659 #endif /* MOUNTED_GETMNTENT1. */
661 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
663 struct statfs *fsp;
664 int entries;
666 entries = getmntinfo (&fsp, MNT_NOWAIT);
667 if (entries < 0)
668 return NULL;
669 for (; entries-- > 0; fsp++)
671 char *fs_type = fsp_to_string (fsp);
673 me = g_malloc (sizeof (*me));
674 me->me_devname = g_strdup (fsp->f_mntfromname);
675 me->me_mountdir = g_strdup (fsp->f_mntonname);
676 me->me_type = fs_type;
677 me->me_type_malloced = 0;
678 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
679 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
680 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
682 /* Add to the linked list. */
683 *mtail = me;
684 mtail = &me->me_next;
687 #endif /* MOUNTED_GETMNTINFO */
689 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
691 struct statvfs *fsp;
692 int entries;
694 entries = getmntinfo (&fsp, MNT_NOWAIT);
695 if (entries < 0)
696 return NULL;
697 for (; entries-- > 0; fsp++)
699 me = g_malloc (sizeof (*me));
700 me->me_devname = g_strdup (fsp->f_mntfromname);
701 me->me_mountdir = g_strdup (fsp->f_mntonname);
702 me->me_type = g_strdup (fsp->f_fstypename);
703 me->me_type_malloced = 1;
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 = (dev_t) (-1); /* Magic; means not known yet. */
708 /* Add to the linked list. */
709 *mtail = me;
710 mtail = &me->me_next;
713 #endif /* MOUNTED_GETMNTINFO2 */
715 #ifdef MOUNTED_GETMNT /* Ultrix. */
717 int offset = 0;
718 int val;
719 struct fs_data fsd;
721 while (errno = 0, 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, (char *) 0)))
723 me = g_malloc (sizeof (*me));
724 me->me_devname = g_strdup (fsd.fd_req.devname);
725 me->me_mountdir = g_strdup (fsd.fd_req.path);
726 me->me_type = gt_names[fsd.fd_req.fstype];
727 me->me_type_malloced = 0;
728 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
729 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
730 me->me_dev = fsd.fd_req.dev;
732 /* Add to the linked list. */
733 *mtail = me;
734 mtail = &me->me_next;
736 if (val < 0)
737 goto free_then_fail;
739 #endif /* MOUNTED_GETMNT. */
741 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
743 /* The next_dev() and fs_stat_dev() system calls give the list of
744 all file systems, including the information returned by statvfs()
745 (fs type, total blocks, free blocks etc.), but without the mount
746 point. But on BeOS all file systems except / are mounted in the
747 rootfs, directly under /.
748 The directory name of the mount point is often, but not always,
749 identical to the volume name of the device.
750 We therefore get the list of subdirectories of /, and the list
751 of all file systems, and match the two lists. */
753 DIR *dirp;
754 struct rootdir_entry
756 char *name;
757 dev_t dev;
758 ino_t ino;
759 struct rootdir_entry *next;
761 struct rootdir_entry *rootdir_list;
762 struct rootdir_entry **rootdir_tail;
763 int32 pos;
764 dev_t dev;
765 fs_info fi;
767 /* All volumes are mounted in the rootfs, directly under /. */
768 rootdir_list = NULL;
769 rootdir_tail = &rootdir_list;
770 dirp = opendir ("/");
771 if (dirp)
773 struct dirent *d;
775 while ((d = readdir (dirp)) != NULL)
777 char *name;
778 struct stat statbuf;
780 if (strcmp (d->d_name, "..") == 0)
781 continue;
783 if (strcmp (d->d_name, ".") == 0)
784 name = g_strdup ("/");
785 else
786 name = g_strconcat ("/", d->d_name, (char *) NULL);
788 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
790 struct rootdir_entry *re = g_malloc (sizeof (*re));
791 re->name = name;
792 re->dev = statbuf.st_dev;
793 re->ino = statbuf.st_ino;
795 /* Add to the linked list. */
796 *rootdir_tail = re;
797 rootdir_tail = &re->next;
799 else
800 g_free (name);
802 closedir (dirp);
804 *rootdir_tail = NULL;
806 for (pos = 0; (dev = next_dev (&pos)) >= 0;)
807 if (fs_stat_dev (dev, &fi) >= 0)
809 /* Note: fi.dev == dev. */
810 struct rootdir_entry *re;
812 for (re = rootdir_list; re; re = re->next)
813 if (re->dev == fi.dev && re->ino == fi.root)
814 break;
816 me = g_malloc (sizeof (*me));
817 me->me_devname =
818 g_strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
819 me->me_mountdir = g_strdup (re != NULL ? re->name : fi.fsh_name);
820 me->me_type = g_strdup (fi.fsh_name);
821 me->me_type_malloced = 1;
822 me->me_dev = fi.dev;
823 me->me_dummy = 0;
824 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
826 /* Add to the linked list. */
827 *mtail = me;
828 mtail = &me->me_next;
830 *mtail = NULL;
832 while (rootdir_list != NULL)
834 struct rootdir_entry *re = rootdir_list;
835 rootdir_list = re->next;
836 g_free (re->name);
837 g_free (re);
840 #endif /* MOUNTED_FS_STAT_DEV */
842 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
844 int numsys, counter;
845 size_t bufsize;
846 struct statfs *stats;
848 numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
849 if (numsys < 0)
850 return NULL;
851 if (SIZE_MAX / sizeof (*stats) <= numsys)
853 fprintf (stderr, "%s\n", _("Memory exhausted!"));
854 exit (EXIT_FAILURE);
857 bufsize = (1 + numsys) * sizeof (*stats);
858 stats = g_malloc (bufsize);
859 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
861 if (numsys < 0)
863 g_free (stats);
864 return NULL;
867 for (counter = 0; counter < numsys; counter++)
869 me = g_malloc (sizeof (*me));
870 me->me_devname = g_strdup (stats[counter].f_mntfromname);
871 me->me_mountdir = g_strdup (stats[counter].f_mntonname);
872 me->me_type = g_strdup (FS_TYPE (stats[counter]));
873 me->me_type_malloced = 1;
874 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
875 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
876 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
878 /* Add to the linked list. */
879 *mtail = me;
880 mtail = &me->me_next;
883 g_free (stats);
885 #endif /* MOUNTED_GETFSSTAT */
887 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
889 struct mnttab mnt;
890 char *table = "/etc/mnttab";
891 FILE *fp;
893 fp = fopen (table, "r");
894 if (fp == NULL)
895 return NULL;
897 while (fread (&mnt, sizeof (mnt), 1, fp) > 0)
899 me = g_malloc (sizeof (*me));
900 #ifdef GETFSTYP /* SVR3. */
901 me->me_devname = g_strdup (mnt.mt_dev);
902 #else
903 me->me_devname = g_strconcat ("/dev/", mnt.mt_dev, (char *) NULL);
904 #endif
905 me->me_mountdir = g_strdup (mnt.mt_filsys);
906 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
907 me->me_type = "";
908 me->me_type_malloced = 0;
909 #ifdef GETFSTYP /* SVR3. */
910 if (need_fs_type)
912 struct statfs fsd;
913 char typebuf[FSTYPSZ];
915 if (statfs (me->me_mountdir, &fsd, sizeof (fsd), 0) != -1
916 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
918 me->me_type = g_strdup (typebuf);
919 me->me_type_malloced = 1;
922 #endif
923 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
924 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
926 /* Add to the linked list. */
927 *mtail = me;
928 mtail = &me->me_next;
931 if (ferror (fp))
933 /* The last fread() call must have failed. */
934 int saved_errno = errno;
935 fclose (fp);
936 errno = saved_errno;
937 goto free_then_fail;
940 if (fclose (fp) == EOF)
941 goto free_then_fail;
943 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
945 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
947 struct mntent **mnttbl = getmnttbl (), **ent;
948 for (ent = mnttbl; *ent; ent++)
950 me = g_malloc (sizeof (*me));
951 me->me_devname = g_strdup ((*ent)->mt_resource);
952 me->me_mountdir = g_strdup ((*ent)->mt_directory);
953 me->me_type = g_strdup ((*ent)->mt_fstype);
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;
963 endmnttbl ();
965 #endif
967 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
969 struct mnttab mnt;
970 char *table = MNTTAB;
971 FILE *fp;
972 int ret;
973 int lockfd = -1;
975 #if defined F_RDLCK && defined F_SETLKW
976 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
977 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
978 for this file name, we should use their macro name instead.
979 (Why not just lock MNTTAB directly? We don't know.) */
980 #ifndef MNTTAB_LOCK
981 #define MNTTAB_LOCK "/etc/.mnttab.lock"
982 #endif
983 lockfd = open (MNTTAB_LOCK, O_RDONLY);
984 if (0 <= lockfd)
986 struct flock flock;
987 flock.l_type = F_RDLCK;
988 flock.l_whence = SEEK_SET;
989 flock.l_start = 0;
990 flock.l_len = 0;
991 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
992 if (errno != EINTR)
994 int saved_errno = errno;
995 close (lockfd);
996 errno = saved_errno;
997 return NULL;
1000 else if (errno != ENOENT)
1001 return NULL;
1002 #endif
1004 errno = 0;
1005 fp = fopen (table, "r");
1006 if (fp == NULL)
1007 ret = errno;
1008 else
1010 while ((ret = getmntent (fp, &mnt)) == 0)
1012 me = g_malloc (sizeof (*me));
1013 me->me_devname = g_strdup (mnt.mnt_special);
1014 me->me_mountdir = g_strdup (mnt.mnt_mountp);
1015 me->me_type = g_strdup (mnt.mnt_fstype);
1016 me->me_type_malloced = 1;
1017 me->me_dummy = MNT_IGNORE (&mnt) != 0;
1018 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1019 me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
1021 /* Add to the linked list. */
1022 *mtail = me;
1023 mtail = &me->me_next;
1026 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
1029 if (0 <= lockfd && close (lockfd) != 0)
1030 ret = errno;
1032 if (0 <= ret)
1034 errno = ret;
1035 goto free_then_fail;
1038 #endif /* MOUNTED_GETMNTENT2. */
1040 #ifdef MOUNTED_VMOUNT /* AIX. */
1042 int bufsize;
1043 char *entries, *thisent;
1044 struct vmount *vmp;
1045 int n_entries;
1046 int i;
1048 /* Ask how many bytes to allocate for the mounted file system info. */
1049 if (mntctl (MCTL_QUERY, sizeof (bufsize), (struct vmount *) &bufsize) != 0)
1050 return NULL;
1051 entries = g_malloc (bufsize);
1053 /* Get the list of mounted file systems. */
1054 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
1055 if (n_entries < 0)
1057 int saved_errno = errno;
1058 g_free (entries);
1059 errno = saved_errno;
1060 return NULL;
1063 for (i = 0, thisent = entries; i < n_entries; i++, thisent += vmp->vmt_length)
1065 char *options, *ignore;
1067 vmp = (struct vmount *) thisent;
1068 me = g_malloc (sizeof (*me));
1069 if (vmp->vmt_flags & MNT_REMOTE)
1071 char *host, *dir;
1073 me->me_remote = 1;
1074 /* Prepend the remote dirname. */
1075 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
1076 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
1077 me->me_devname = g_strconcat (host, ":", dir, (char *) NULL);
1079 else
1081 me->me_remote = 0;
1082 me->me_devname = g_strdup (thisent + vmp->vmt_data[VMT_OBJECT].vmt_off);
1084 me->me_mountdir = g_strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
1085 me->me_type = g_strdup (fstype_to_string (vmp->vmt_gfstype));
1086 me->me_type_malloced = 1;
1087 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
1088 ignore = strstr (options, "ignore");
1089 me->me_dummy = (ignore
1090 && (ignore == options || ignore[-1] == ',')
1091 && (ignore[sizeof ("ignore") - 1] == ','
1092 || ignore[sizeof ("ignore") - 1] == '\0'));
1093 me->me_dev = (dev_t) (-1); /* vmt_fsid might be the info we want. */
1095 /* Add to the linked list. */
1096 *mtail = me;
1097 mtail = &me->me_next;
1099 g_free (entries);
1101 #endif /* MOUNTED_VMOUNT. */
1104 #ifdef MOUNTED_INTERIX_STATVFS
1106 DIR *dirp = opendir ("/dev/fs");
1107 char node[9 + NAME_MAX];
1109 if (!dirp)
1110 goto free_then_fail;
1112 while (1)
1114 struct statvfs dev;
1115 struct dirent entry;
1116 struct dirent *result;
1118 if (readdir_r (dirp, &entry, &result) || result == NULL)
1119 break;
1121 strcpy (node, "/dev/fs/");
1122 strcat (node, entry.d_name);
1124 if (statvfs (node, &dev) == 0)
1126 me = g_malloc (sizeof *me);
1127 me->me_devname = g_strdup (dev.f_mntfromname);
1128 me->me_mountdir = g_strdup (dev.f_mntonname);
1129 me->me_type = g_strdup (dev.f_fstypename);
1130 me->me_type_malloced = 1;
1131 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1132 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1133 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
1135 /* Add to the linked list. */
1136 *mtail = me;
1137 mtail = &me->me_next;
1141 #endif /* MOUNTED_INTERIX_STATVFS */
1143 (void) need_fs_type; /* avoid argument-unused warning */
1144 *mtail = NULL;
1145 return mount_list;
1148 free_then_fail:
1150 int saved_errno = errno;
1151 *mtail = NULL;
1153 while (mount_list)
1155 me = mount_list->me_next;
1156 g_free (mount_list->me_devname);
1157 g_free (mount_list->me_mountdir);
1158 if (mount_list->me_type_malloced)
1159 g_free (mount_list->me_type);
1160 g_free (mount_list);
1161 mount_list = me;
1164 errno = saved_errno;
1165 return NULL;
1169 #endif /* HAVE_INFOMOUNT_LIST */
1171 /* --------------------------------------------------------------------------------------------- */
1173 #ifdef HAVE_INFOMOUNT_QNX
1175 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1176 ** this via the following code.
1177 ** Note that, as this is based on CWD, it only fills one mount_entry
1178 ** structure. See my_statfs() in utilunix.c for the "other side" of
1179 ** this hack.
1182 static struct mount_entry *
1183 read_file_system_list (int need_fs_type, int all_fs)
1185 struct _disk_entry de;
1186 struct statfs fs;
1187 int i, fd;
1188 char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
1190 static struct mount_entry *me = NULL;
1192 if (me)
1194 g_free (me->me_devname);
1195 g_free (me->me_mountdir);
1196 g_free (me->me_type);
1198 else
1199 me = (struct mount_entry *) g_malloc (sizeof (struct mount_entry));
1201 if (!getcwd (dir, _POSIX_PATH_MAX))
1202 return (NULL);
1204 fd = open (dir, O_RDONLY);
1205 if (fd == -1)
1206 return (NULL);
1208 i = disk_get_entry (fd, &de);
1210 close (fd);
1212 if (i == -1)
1213 return (NULL);
1215 switch (de.disk_type)
1217 case _UNMOUNTED:
1218 tp = "unmounted";
1219 break;
1220 case _FLOPPY:
1221 tp = "Floppy";
1222 break;
1223 case _HARD:
1224 tp = "Hard";
1225 break;
1226 case _RAMDISK:
1227 tp = "Ram";
1228 break;
1229 case _REMOVABLE:
1230 tp = "Removable";
1231 break;
1232 case _TAPE:
1233 tp = "Tape";
1234 break;
1235 case _CDROM:
1236 tp = "CDROM";
1237 break;
1238 default:
1239 tp = "unknown";
1242 if (fsys_get_mount_dev (dir, &dev) == -1)
1243 return (NULL);
1245 if (fsys_get_mount_pt (dev, &dir) == -1)
1246 return (NULL);
1248 me->me_devname = g_strdup (dev);
1249 me->me_mountdir = g_strdup (dir);
1250 me->me_type = g_strdup (tp);
1251 me->me_dev = de.disk_type;
1253 #ifdef DEBUG
1254 fprintf (stderr,
1255 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1256 de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
1257 fprintf (stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
1258 fprintf (stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
1259 #endif /* DEBUG */
1261 return (me);
1263 #endif /* HAVE_INFOMOUNT_QNX */
1265 /* --------------------------------------------------------------------------------------------- */
1267 #ifdef STAT_READ_FILSYS /* SVR2 */
1269 /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
1270 interrupted. Return the actual number of bytes read(written), zero for EOF,
1271 or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */
1272 static size_t
1273 safe_read (int fd, void *buf, size_t count)
1275 /* Work around a bug in Tru64 5.1. Attempting to read more than
1276 INT_MAX bytes fails with errno == EINVAL. See
1277 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
1278 When decreasing COUNT, keep it block-aligned. */
1279 /* *INDENT-OFF* */
1280 enum { BUGGY_READ_MAXIMUM = INT_MAX & ~8191 };
1281 /* *INDENT-ON* */
1283 while (TRUE)
1285 ssize_t result;
1287 result = read (fd, buf, count);
1289 if (0 <= result)
1290 return result;
1291 else if (IS_EINTR (errno))
1292 continue;
1293 else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count)
1294 count = BUGGY_READ_MAXIMUM;
1295 else
1296 return result;
1300 /* --------------------------------------------------------------------------------------------- */
1302 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1303 interrupted or if a partial write(read) occurs. Return the number
1304 of bytes transferred.
1305 When writing, set errno if fewer than COUNT bytes are written.
1306 When reading, if fewer than COUNT bytes are read, you must examine
1307 errno to distinguish failure from EOF (errno == 0). */
1309 static size_t
1310 full_read (int fd, void *buf, size_t count)
1312 size_t total = 0;
1313 char *ptr = (char *) buf;
1315 while (count > 0)
1317 size_t n_rw = safe_read (fd, ptr, count);
1318 if (n_rw == (size_t) (-1))
1319 break;
1320 if (n_rw == 0)
1322 errno = ZERO_BYTE_TRANSFER_ERRNO;
1323 break;
1325 total += n_rw;
1326 ptr += n_rw;
1327 count -= n_rw;
1330 return total;
1333 #endif /* STAT_READ_FILSYS */
1335 /* --------------------------------------------------------------------------------------------- */
1337 #ifdef HAVE_INFOMOUNT
1338 /* Fill in the fields of FSP with information about space usage for
1339 the file system on which FILE resides.
1340 DISK is the device on which FILE is mounted, for space-getting
1341 methods that need to know it.
1342 Return 0 if successful, -1 if not. When returning -1, ensure that
1343 ERRNO is either a system error value, or zero if DISK is NULL
1344 on a system that requires a non-NULL value. */
1345 static int
1346 get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
1348 #ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
1350 if (statvfs_works ())
1352 struct statvfs vfsd;
1354 if (statvfs (file, &vfsd) < 0)
1355 return -1;
1357 /* f_frsize isn't guaranteed to be supported. */
1358 fsp->fsu_blocksize = (vfsd.f_frsize
1359 ? PROPAGATE_ALL_ONES (vfsd.f_frsize)
1360 : PROPAGATE_ALL_ONES (vfsd.f_bsize));
1362 fsp->fsu_blocks = PROPAGATE_ALL_ONES (vfsd.f_blocks);
1363 fsp->fsu_bfree = PROPAGATE_ALL_ONES (vfsd.f_bfree);
1364 fsp->fsu_bavail = PROPAGATE_TOP_BIT (vfsd.f_bavail);
1365 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (vfsd.f_bavail) != 0;
1366 fsp->fsu_files = PROPAGATE_ALL_ONES (vfsd.f_files);
1367 fsp->fsu_ffree = PROPAGATE_ALL_ONES (vfsd.f_ffree);
1369 else
1370 #endif
1373 #if defined STAT_STATVFS64 /* AIX */
1375 struct statvfs64 fsd;
1377 if (statvfs64 (file, &fsd) < 0)
1378 return -1;
1380 /* f_frsize isn't guaranteed to be supported. */
1381 /* *INDENT-OFF* */
1382 fsp->fsu_blocksize = fsd.f_frsize
1383 ? PROPAGATE_ALL_ONES (fsd.f_frsize)
1384 : PROPAGATE_ALL_ONES (fsd.f_bsize);
1385 /* *INDENT-ON* */
1387 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1389 struct fs_data fsd;
1391 if (statfs (file, &fsd) != 1)
1392 return -1;
1394 fsp->fsu_blocksize = 1024;
1395 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot);
1396 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree);
1397 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen);
1398 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0;
1399 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
1400 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
1402 #elif defined STAT_READ_FILSYS /* SVR2 */
1403 #ifndef SUPERBOFF
1404 #define SUPERBOFF (SUPERB * 512)
1405 #endif
1407 struct filsys fsd;
1408 int fd;
1410 if (!disk)
1412 errno = 0;
1413 return -1;
1416 fd = open (disk, O_RDONLY);
1417 if (fd < 0)
1418 return -1;
1419 lseek (fd, (off_t) SUPERBOFF, 0);
1420 if (full_read (fd, (char *) &fsd, sizeof (fsd)) != sizeof (fsd))
1422 close (fd);
1423 return -1;
1425 close (fd);
1427 fsp->fsu_blocksize = (fsd.s_type == Fs2b ? 1024 : 512);
1428 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.s_fsize);
1429 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.s_tfree);
1430 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree);
1431 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0;
1432 fsp->fsu_files = (fsd.s_isize == -1
1433 ? UINTMAX_MAX : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1));
1434 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode);
1436 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1438 struct statfs fsd;
1440 if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
1441 return -1;
1443 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1445 #elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
1447 struct statfs fsd;
1449 if (statfs (file, &fsd) < 0)
1450 return -1;
1452 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_frsize);
1454 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
1455 Mac OS X < 10.4, FreeBSD < 5.0, \
1456 NetBSD < 3.0, OpenBSD < 4.4 */
1458 struct statfs fsd;
1460 if (statfs (file, &fsd) < 0)
1461 return -1;
1463 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1465 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1467 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1468 struct statfs are truncated to 2GB. These conditions detect that
1469 truncation, presumably without botching the 4.1.1 case, in which
1470 the values are not truncated. The correct counts are stored in
1471 undocumented spare fields. */
1472 if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
1474 fsd.f_blocks = fsd.f_spare[0];
1475 fsd.f_bfree = fsd.f_spare[1];
1476 fsd.f_bavail = fsd.f_spare[2];
1478 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1480 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1482 struct statfs fsd;
1484 if (statfs (file, &fsd) < 0)
1485 return -1;
1487 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1489 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1490 Dolphin */
1492 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1493 #define f_bavail f_bfree
1494 #endif
1496 struct statfs fsd;
1498 if (statfs (file, &fsd, sizeof (fsd), 0) < 0)
1499 return -1;
1501 /* Empirically, the block counts on most SVR3 and SVR3-derived
1502 systems seem to always be in terms of 512-byte blocks,
1503 no matter what value f_bsize has. */
1504 #if defined _AIX || defined _CRAY
1505 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1506 #else
1507 fsp->fsu_blocksize = 512;
1508 #endif
1510 #endif
1512 #if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 \
1513 || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE \
1514 || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
1516 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
1517 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
1518 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
1519 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
1520 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
1521 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
1523 #endif
1526 (void) disk; /* avoid argument-unused warning */
1528 return 0;
1530 #endif /* HAVE_INFOMOUNT */
1532 /* --------------------------------------------------------------------------------------------- */
1533 /*** public functions ****************************************************************************/
1534 /* --------------------------------------------------------------------------------------------- */
1536 void
1537 free_my_statfs (void)
1539 #ifdef HAVE_INFOMOUNT_LIST
1540 while (mc_mount_list != NULL)
1542 struct mount_entry *next;
1544 next = mc_mount_list->me_next;
1545 free_mount_entry (mc_mount_list);
1546 mc_mount_list = next;
1549 mc_mount_list = NULL;
1550 #endif /* HAVE_INFOMOUNT_LIST */
1553 /* --------------------------------------------------------------------------------------------- */
1555 void
1556 init_my_statfs (void)
1558 #ifdef HAVE_INFOMOUNT_LIST
1559 free_my_statfs ();
1560 mc_mount_list = read_file_system_list (1);
1561 #endif /* HAVE_INFOMOUNT_LIST */
1564 /* --------------------------------------------------------------------------------------------- */
1566 void
1567 my_statfs (struct my_statfs *myfs_stats, const char *path)
1569 #ifdef HAVE_INFOMOUNT_LIST
1570 size_t i, len = 0;
1571 struct mount_entry *entry = NULL;
1572 struct mount_entry *temp = mc_mount_list;
1573 struct fs_usage fs_use;
1575 while (temp)
1577 i = strlen (temp->me_mountdir);
1578 if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
1579 if (!entry || (path[i] == PATH_SEP || path[i] == '\0'))
1581 len = i;
1582 entry = temp;
1584 temp = temp->me_next;
1587 if (entry)
1589 memset (&fs_use, 0, sizeof (struct fs_usage));
1590 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1592 myfs_stats->type = entry->me_dev;
1593 myfs_stats->typename = entry->me_type;
1594 myfs_stats->mpoint = entry->me_mountdir;
1595 myfs_stats->device = entry->me_devname;
1596 myfs_stats->avail =
1597 ((uintmax_t) (getuid ()? fs_use.fsu_bavail : fs_use.fsu_bfree) *
1598 fs_use.fsu_blocksize) >> 10;
1599 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1600 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1601 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1603 else
1604 #endif /* HAVE_INFOMOUNT_LIST */
1606 #ifdef HAVE_INFOMOUNT_QNX
1608 ** This is the "other side" of the hack to read_file_system_list() in
1609 ** mountlist.c.
1610 ** It's not the most efficient approach, but consumes less memory. It
1611 ** also accomodates QNX's ability to mount filesystems on the fly.
1613 struct mount_entry *entry;
1614 struct fs_usage fs_use;
1616 entry = read_file_system_list (0, 0);
1617 if (entry != NULL)
1619 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1621 myfs_stats->type = entry->me_dev;
1622 myfs_stats->typename = entry->me_type;
1623 myfs_stats->mpoint = entry->me_mountdir;
1624 myfs_stats->device = entry->me_devname;
1626 myfs_stats->avail = ((uintmax_t) fs_use.fsu_bfree * fs_use.fsu_blocksize) >> 10;
1627 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1628 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1629 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1631 else
1632 #endif /* HAVE_INFOMOUNT_QNX */
1634 myfs_stats->type = 0;
1635 myfs_stats->mpoint = "unknown";
1636 myfs_stats->device = "unknown";
1637 myfs_stats->avail = 0;
1638 myfs_stats->total = 0;
1639 myfs_stats->nfree = 0;
1640 myfs_stats->nodes = 0;
1644 /* --------------------------------------------------------------------------------------------- */