eac0e12baa0ed9f06a853a84985ad0012cca11a1
[midnight-commander.git] / src / filemanager / mountlist.c
blobeac0e12baa0ed9f06a853a84985ad0012cca11a1
1 /*
2 Return a list of mounted file systems
4 Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
5 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
7 Copyright (C) 1991, 1992, 2011
8 The Free Software Foundation, Inc.
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 /** \file mountlist.c
27 * \brief Source: list of mounted filesystems
30 #include <config.h>
32 #include <limits.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdint.h> /* SIZE_MAX */
37 #include <sys/types.h>
39 #include <errno.h>
41 /* This header needs to be included before sys/mount.h on *BSD */
42 #ifdef HAVE_SYS_PARAM_H
43 #include <sys/param.h>
44 #endif
46 #if defined STAT_STATVFS || defined STAT_STATVFS64 /* POSIX 1003.1-2001 (and later) with XSI */
47 #include <sys/statvfs.h>
48 #else
49 /* Don't include backward-compatibility files unless they're needed.
50 Eventually we'd like to remove all this cruft. */
51 #include <fcntl.h>
52 #include <unistd.h>
53 #include <sys/stat.h>
55 #ifdef MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
56 #ifdef HAVE_SYS_UCRED_H
57 #include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
58 NGROUPS is used as an array dimension in ucred.h */
59 #include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
60 #endif
61 #ifdef HAVE_SYS_MOUNT_H
62 #include <sys/mount.h>
63 #endif
64 #ifdef HAVE_SYS_FS_TYPES_H
65 #include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
66 #endif
67 #ifdef HAVE_STRUCT_FSSTAT_F_FSTYPENAME
68 #define FS_TYPE(Ent) ((Ent).f_fstypename)
69 #else
70 #define FS_TYPE(Ent) mnt_names[(Ent).f_type]
71 #endif
72 #endif /* MOUNTED_GETFSSTAT */
73 #endif /* STAT_STATVFS || STAT_STATVFS64 */
75 #ifdef HAVE_SYS_VFS_H
76 #include <sys/vfs.h>
77 #endif
78 #ifdef HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */
79 #include <sys/fs/s5param.h>
80 #endif
81 #if defined HAVE_SYS_FILSYS_H && !defined _CRAY
82 #include <sys/filsys.h> /* SVR2 */
83 #endif
84 #ifdef HAVE_SYS_STATFS_H
85 #include <sys/statfs.h>
86 #endif
87 #ifdef HAVE_DUSTAT_H /* AIX PS/2 */
88 #include <sys/dustat.h>
89 #endif
91 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
92 #include <mntent.h>
93 #ifndef MOUNTED
94 #ifdef _PATH_MOUNTED /* GNU libc */
95 #define MOUNTED _PATH_MOUNTED
96 #endif
97 #ifdef MNT_MNTTAB /* HP-UX. */
98 #define MOUNTED MNT_MNTTAB
99 #endif
100 #ifdef MNTTABNAME /* Dynix. */
101 #define MOUNTED MNTTABNAME
102 #endif
103 #endif
104 #endif
106 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
107 #include <sys/mount.h>
108 #endif
110 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
111 #include <sys/statvfs.h>
112 #endif
114 #ifdef MOUNTED_GETMNT /* Ultrix. */
115 #include <sys/mount.h>
116 #include <sys/fs_types.h>
117 #endif
119 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
120 #include <fs_info.h>
121 #include <dirent.h>
122 #endif
124 #ifdef MOUNTED_FREAD /* SVR2. */
125 #include <mnttab.h>
126 #endif
128 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
129 #include <mnttab.h>
130 #include <sys/fstyp.h>
131 #include <sys/statfs.h>
132 #endif
134 #ifdef MOUNTED_LISTMNTENT
135 #include <mntent.h>
136 #endif
138 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
139 #include <sys/mnttab.h>
140 #endif
142 #ifdef MOUNTED_VMOUNT /* AIX. */
143 #include <fshelp.h>
144 #include <sys/vfs.h>
145 #endif
147 #ifdef MOUNTED_INTERIX_STATVFS /* Interix. */
148 #include <sys/statvfs.h>
149 #include <dirent.h>
150 #endif
152 #ifdef DOLPHIN
153 /* So special that it's not worth putting this in autoconf. */
154 #undef MOUNTED_FREAD_FSTYP
155 #define MOUNTED_GETMNTTBL
156 #endif
158 #ifdef HAVE_SYS_MNTENT_H
159 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
160 #include <sys/mntent.h>
161 #endif
163 #undef MNT_IGNORE
164 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
165 #define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
166 #else
167 #define MNT_IGNORE(M) 0
168 #endif
170 #ifdef HAVE_INFOMOUNT_QNX
171 #include <sys/disk.h>
172 #include <sys/fsys.h>
173 #endif
175 #ifdef HAVE_SYS_STATVFS_H /* SVR4. */
176 #include <sys/statvfs.h>
177 #endif
179 #include "lib/global.h"
180 #include "mountlist.h"
182 /*** global variables ****************************************************************************/
184 /*** file scope macro definitions ****************************************************************/
186 #if defined (__QNX__) && !defined(__QNXNTO__) && !defined (HAVE_INFOMOUNT_LIST)
187 #define HAVE_INFOMOUNT_QNX
188 #endif
190 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
191 #define HAVE_INFOMOUNT
192 #endif
194 /* The results of open() in this file are not used with fchdir,
195 therefore save some unnecessary work in fchdir.c. */
196 #undef open
197 #undef close
199 /* The results of opendir() in this file are not used with dirfd and fchdir,
200 therefore save some unnecessary work in fchdir.c. */
201 #undef opendir
202 #undef closedir
204 #define ME_DUMMY_0(Fs_name, Fs_type) \
205 (strcmp (Fs_type, "autofs") == 0 \
206 || strcmp (Fs_type, "proc") == 0 \
207 || strcmp (Fs_type, "subfs") == 0 \
208 /* for Linux 2.6/3.x */ \
209 || strcmp (Fs_type, "debugfs") == 0 \
210 || strcmp (Fs_type, "devpts") == 0 \
211 || strcmp (Fs_type, "devtmpfs") == 0 \
212 || strcmp (Fs_type, "fusectl") == 0 \
213 || strcmp (Fs_type, "mqueue") == 0 \
214 || strcmp (Fs_type, "rpc_pipefs") == 0 \
215 || strcmp (Fs_type, "sysfs") == 0 \
216 /* FreeBSD, Linux 2.4 */ \
217 || strcmp (Fs_type, "devfs") == 0 \
218 /* for NetBSD 3.0 */ \
219 || strcmp (Fs_type, "kernfs") == 0 \
220 /* for Irix 6.5 */ \
221 || strcmp (Fs_type, "ignore") == 0)
223 /* Historically, we have marked as "dummy" any file system of type "none",
224 but now that programs like du need to know about bind-mounted directories,
225 we grant an exception to any with "bind" in its list of mount options.
226 I.e., those are *not* dummy entries. */
227 #ifdef MOUNTED_GETMNTENT1
228 #define ME_DUMMY(Fs_name, Fs_type, Fs_ent) \
229 (ME_DUMMY_0 (Fs_name, Fs_type) \
230 || (strcmp (Fs_type, "none") == 0 \
231 && !hasmntopt (Fs_ent, "bind")))
232 #else
233 #define ME_DUMMY(Fs_name, Fs_type) \
234 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
235 #endif
237 #ifdef __CYGWIN__
238 #include <windows.h>
239 #define ME_REMOTE me_remote
240 /* All cygwin mount points include `:' or start with `//'; so it
241 requires a native Windows call to determine remote disks. */
242 static int
243 me_remote (char const *fs_name, char const *fs_type _GL_UNUSED)
245 if (fs_name[0] && fs_name[1] == ':')
247 char drive[4];
248 sprintf (drive, "%c:\\", fs_name[0]);
249 switch (GetDriveType (drive))
251 case DRIVE_REMOVABLE:
252 case DRIVE_FIXED:
253 case DRIVE_CDROM:
254 case DRIVE_RAMDISK:
255 return 0;
258 return 1;
260 #endif
261 #ifndef ME_REMOTE
262 /* A file system is `remote' if its Fs_name contains a `:'
263 or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */
264 #define ME_REMOTE(Fs_name, Fs_type) \
265 (strchr (Fs_name, ':') != NULL \
266 || ((Fs_name)[0] == '/' \
267 && (Fs_name)[1] == '/' \
268 && (strcmp (Fs_type, "smbfs") == 0 || strcmp (Fs_type, "cifs") == 0)))
269 #endif
271 /* Many space usage primitives use all 1 bits to denote a value that is
272 not applicable or unknown. Propagate this information by returning
273 a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
274 is unsigned and narrower than uintmax_t. */
275 #define PROPAGATE_ALL_ONES(x) \
276 ((sizeof (x) < sizeof (uintmax_t) \
277 && (~ (x) == (sizeof (x) < sizeof (int) \
278 ? - (1 << (sizeof (x) * CHAR_BIT)) \
279 : 0))) \
280 ? UINTMAX_MAX : (uintmax_t) (x))
282 /* Extract the top bit of X as an uintmax_t value. */
283 #define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
285 /* If a value is negative, many space usage primitives store it into an
286 integer variable by assignment, even if the variable's type is unsigned.
287 So, if a space usage variable X's top bit is set, convert X to the
288 uintmax_t value V such that (- (uintmax_t) V) is the negative of
289 the original value. If X's top bit is clear, just yield X.
290 Use PROPAGATE_TOP_BIT if the original value might be negative;
291 otherwise, use PROPAGATE_ALL_ONES. */
292 #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
294 #ifdef STAT_STATVFS
295 /* Return true if statvfs works. This is false for statvfs on systems
296 with GNU libc on Linux kernels before 2.6.36, which stats all
297 preceding entries in /proc/mounts; that makes df hang if even one
298 of the corresponding file systems is hard-mounted but not available. */
299 #if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
300 /* The FRSIZE fallback is not required in this case. */
301 #undef STAT_STATFS2_FRSIZE
302 static int
303 statvfs_works (void)
305 return 1;
307 #else
308 #include <string.h> /* for strverscmp */
309 #include <sys/utsname.h>
310 #include <sys/statfs.h>
311 #define STAT_STATFS2_BSIZE 1
313 static int
314 statvfs_works (void)
316 static int statvfs_works_cache = -1;
317 struct utsname name;
319 if (statvfs_works_cache < 0)
320 statvfs_works_cache = (uname (&name) == 0 && 0 <= strverscmp (name.release, "2.6.36"));
321 return statvfs_works_cache;
323 #endif
324 #endif
326 #ifdef STAT_READ_FILSYS /* SVR2 */
327 /* Set errno to zero upon EOF. */
328 #define ZERO_BYTE_TRANSFER_ERRNO 0
330 #ifdef EINTR
331 #define IS_EINTR(x) ((x) == EINTR)
332 #else
333 #define IS_EINTR(x) 0
334 #endif
335 #endif /* STAT_READ_FILSYS */
337 /*** file scope type declarations ****************************************************************/
339 /* A mount table entry. */
340 struct mount_entry
342 char *me_devname; /* Device node name, including "/dev/". */
343 char *me_mountdir; /* Mount point directory name. */
344 char *me_type; /* "nfs", "4.2", etc. */
345 dev_t me_dev; /* Device number of me_mountdir. */
346 unsigned int me_dummy:1; /* Nonzero for dummy file systems. */
347 unsigned int me_remote:1; /* Nonzero for remote fileystems. */
348 unsigned int me_type_malloced:1; /* Nonzero if me_type was malloced. */
349 struct mount_entry *me_next;
352 struct fs_usage
354 uintmax_t fsu_blocksize; /* Size of a block. */
355 uintmax_t fsu_blocks; /* Total blocks. */
356 uintmax_t fsu_bfree; /* Free blocks available to superuser. */
357 uintmax_t fsu_bavail; /* Free blocks available to non-superuser. */
358 int fsu_bavail_top_bit_set; /* 1 if fsu_bavail represents a value < 0. */
359 uintmax_t fsu_files; /* Total file nodes. */
360 uintmax_t fsu_ffree; /* Free file nodes. */
363 /*** file scope variables ************************************************************************/
365 #ifdef HAVE_INFOMOUNT_LIST
366 static struct mount_entry *mc_mount_list = NULL;
367 #endif /* HAVE_INFOMOUNT_LIST */
369 /*** file scope functions ************************************************************************/
370 /* --------------------------------------------------------------------------------------------- */
372 #ifdef HAVE_INFOMOUNT_LIST
373 static void
374 free_mount_entry (struct mount_entry *me)
376 if (!me)
377 return;
378 g_free (me->me_devname);
379 g_free (me->me_mountdir);
380 if (me->me_type_malloced)
381 g_free (me->me_type);
382 g_free (me);
385 /* --------------------------------------------------------------------------------------------- */
387 #ifdef MOUNTED_GETMNTINFO
389 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
390 static char *
391 fstype_to_string (short int t)
393 switch (t)
395 #ifdef MOUNT_PC
396 case MOUNT_PC:
397 return "pc";
398 #endif
399 #ifdef MOUNT_MFS
400 case MOUNT_MFS:
401 return "mfs";
402 #endif
403 #ifdef MOUNT_LO
404 case MOUNT_LO:
405 return "lo";
406 #endif
407 #ifdef MOUNT_TFS
408 case MOUNT_TFS:
409 return "tfs";
410 #endif
411 #ifdef MOUNT_TMP
412 case MOUNT_TMP:
413 return "tmp";
414 #endif
415 #ifdef MOUNT_UFS
416 case MOUNT_UFS:
417 return "ufs";
418 #endif
419 #ifdef MOUNT_NFS
420 case MOUNT_NFS:
421 return "nfs";
422 #endif
423 #ifdef MOUNT_MSDOS
424 case MOUNT_MSDOS:
425 return "msdos";
426 #endif
427 #ifdef MOUNT_LFS
428 case MOUNT_LFS:
429 return "lfs";
430 #endif
431 #ifdef MOUNT_LOFS
432 case MOUNT_LOFS:
433 return "lofs";
434 #endif
435 #ifdef MOUNT_FDESC
436 case MOUNT_FDESC:
437 return "fdesc";
438 #endif
439 #ifdef MOUNT_PORTAL
440 case MOUNT_PORTAL:
441 return "portal";
442 #endif
443 #ifdef MOUNT_NULL
444 case MOUNT_NULL:
445 return "null";
446 #endif
447 #ifdef MOUNT_UMAP
448 case MOUNT_UMAP:
449 return "umap";
450 #endif
451 #ifdef MOUNT_KERNFS
452 case MOUNT_KERNFS:
453 return "kernfs";
454 #endif
455 #ifdef MOUNT_PROCFS
456 case MOUNT_PROCFS:
457 return "procfs";
458 #endif
459 #ifdef MOUNT_AFS
460 case MOUNT_AFS:
461 return "afs";
462 #endif
463 #ifdef MOUNT_CD9660
464 case MOUNT_CD9660:
465 return "cd9660";
466 #endif
467 #ifdef MOUNT_UNION
468 case MOUNT_UNION:
469 return "union";
470 #endif
471 #ifdef MOUNT_DEVFS
472 case MOUNT_DEVFS:
473 return "devfs";
474 #endif
475 #ifdef MOUNT_EXT2FS
476 case MOUNT_EXT2FS:
477 return "ext2fs";
478 #endif
479 default:
480 return "?";
483 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
485 /* --------------------------------------------------------------------------------------------- */
487 static char *
488 fsp_to_string (const struct statfs *fsp)
490 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
491 return (char *) (fsp->f_fstypename);
492 #else
493 return fstype_to_string (fsp->f_type);
494 #endif
496 #endif /* MOUNTED_GETMNTINFO */
498 /* --------------------------------------------------------------------------------------------- */
500 #ifdef MOUNTED_VMOUNT /* AIX. */
501 static char *
502 fstype_to_string (int t)
504 struct vfs_ent *e;
506 e = getvfsbytype (t);
507 if (!e || !e->vfsent_name)
508 return "none";
509 else
510 return e->vfsent_name;
512 #endif /* MOUNTED_VMOUNT */
514 /* --------------------------------------------------------------------------------------------- */
516 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
518 /* Return the device number from MOUNT_OPTIONS, if possible.
519 Otherwise return (dev_t) -1. */
521 /* --------------------------------------------------------------------------------------------- */
523 static dev_t
524 dev_from_mount_options (char const *mount_options)
526 /* GNU/Linux allows file system implementations to define their own
527 meaning for "dev=" mount options, so don't trust the meaning
528 here. */
529 #ifndef __linux__
530 static char const dev_pattern[] = ",dev=";
531 char const *devopt = strstr (mount_options, dev_pattern);
533 if (devopt)
535 char const *optval = devopt + sizeof (dev_pattern) - 1;
536 char *optvalend;
537 unsigned long int dev;
538 errno = 0;
539 dev = strtoul (optval, &optvalend, 16);
540 if (optval != optvalend
541 && (*optvalend == '\0' || *optvalend == ',')
542 && !(dev == ULONG_MAX && errno == ERANGE) && dev == (dev_t) dev)
543 return dev;
545 #endif
547 (void) mount_options;
548 return -1;
551 #endif
553 /* --------------------------------------------------------------------------------------------- */
555 #if defined _AIX && defined _I386
556 /* AIX PS/2 does not supply statfs. */
558 static int
559 statfs (char *file, struct statfs *fsb)
561 struct stat stats;
562 struct dustat fsd;
564 if (stat (file, &stats) != 0)
565 return -1;
566 if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
567 return -1;
568 fsb->f_type = 0;
569 fsb->f_bsize = fsd.du_bsize;
570 fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
571 fsb->f_bfree = fsd.du_tfree;
572 fsb->f_bavail = fsd.du_tfree;
573 fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
574 fsb->f_ffree = fsd.du_tinode;
575 fsb->f_fsid.val[0] = fsd.du_site;
576 fsb->f_fsid.val[1] = fsd.du_pckno;
577 return 0;
580 #endif /* _AIX && _I386 */
582 /* --------------------------------------------------------------------------------------------- */
584 /* Return a list of the currently mounted file systems, or NULL on error.
585 Add each entry to the tail of the list so that they stay in order.
586 If NEED_FS_TYPE is true, ensure that the file system type fields in
587 the returned list are valid. Otherwise, they might not be. */
589 static struct mount_entry *
590 read_file_system_list (int need_fs_type)
592 struct mount_entry *mount_list;
593 struct mount_entry *me;
594 struct mount_entry **mtail = &mount_list;
596 #ifdef MOUNTED_LISTMNTENT
598 struct tabmntent *mntlist, *p;
599 struct mntent *mnt;
600 struct mount_entry *me;
602 /* the third and fourth arguments could be used to filter mounts,
603 but Crays doesn't seem to have any mounts that we want to
604 remove. Specifically, automount create normal NFS mounts.
607 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
608 return NULL;
609 for (p = mntlist; p; p = p->next)
611 mnt = p->ment;
612 me = g_malloc (sizeof (*me));
613 me->me_devname = g_strdup (mnt->mnt_fsname);
614 me->me_mountdir = g_strdup (mnt->mnt_dir);
615 me->me_type = g_strdup (mnt->mnt_type);
616 me->me_type_malloced = 1;
617 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
618 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
619 me->me_dev = -1;
620 *mtail = me;
621 mtail = &me->me_next;
623 freemntlist (mntlist);
625 #endif
627 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
629 struct mntent *mnt;
630 const char *table = MOUNTED;
631 FILE *fp;
633 fp = setmntent (table, "r");
634 if (fp == NULL)
635 return NULL;
637 while ((mnt = getmntent (fp)))
639 me = g_malloc (sizeof (*me));
640 me->me_devname = g_strdup (mnt->mnt_fsname);
641 me->me_mountdir = g_strdup (mnt->mnt_dir);
642 me->me_type = g_strdup (mnt->mnt_type);
643 me->me_type_malloced = 1;
644 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, mnt);
645 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
646 me->me_dev = dev_from_mount_options (mnt->mnt_opts);
648 /* Add to the linked list. */
649 *mtail = me;
650 mtail = &me->me_next;
653 if (endmntent (fp) == 0)
654 goto free_then_fail;
656 #endif /* MOUNTED_GETMNTENT1. */
658 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
660 struct statfs *fsp;
661 int entries;
663 entries = getmntinfo (&fsp, MNT_NOWAIT);
664 if (entries < 0)
665 return NULL;
666 for (; entries-- > 0; fsp++)
668 char *fs_type = fsp_to_string (fsp);
670 me = g_malloc (sizeof (*me));
671 me->me_devname = g_strdup (fsp->f_mntfromname);
672 me->me_mountdir = g_strdup (fsp->f_mntonname);
673 me->me_type = fs_type;
674 me->me_type_malloced = 0;
675 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
676 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
677 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
679 /* Add to the linked list. */
680 *mtail = me;
681 mtail = &me->me_next;
684 #endif /* MOUNTED_GETMNTINFO */
686 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
688 struct statvfs *fsp;
689 int entries;
691 entries = getmntinfo (&fsp, MNT_NOWAIT);
692 if (entries < 0)
693 return NULL;
694 for (; entries-- > 0; fsp++)
696 me = g_malloc (sizeof (*me));
697 me->me_devname = g_strdup (fsp->f_mntfromname);
698 me->me_mountdir = g_strdup (fsp->f_mntonname);
699 me->me_type = g_strdup (fsp->f_fstypename);
700 me->me_type_malloced = 1;
701 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
702 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
703 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
705 /* Add to the linked list. */
706 *mtail = me;
707 mtail = &me->me_next;
710 #endif /* MOUNTED_GETMNTINFO2 */
712 #ifdef MOUNTED_GETMNT /* Ultrix. */
714 int offset = 0;
715 int val;
716 struct fs_data fsd;
718 while (errno = 0, 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, (char *) 0)))
720 me = g_malloc (sizeof (*me));
721 me->me_devname = g_strdup (fsd.fd_req.devname);
722 me->me_mountdir = g_strdup (fsd.fd_req.path);
723 me->me_type = gt_names[fsd.fd_req.fstype];
724 me->me_type_malloced = 0;
725 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
726 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
727 me->me_dev = fsd.fd_req.dev;
729 /* Add to the linked list. */
730 *mtail = me;
731 mtail = &me->me_next;
733 if (val < 0)
734 goto free_then_fail;
736 #endif /* MOUNTED_GETMNT. */
738 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
740 /* The next_dev() and fs_stat_dev() system calls give the list of
741 all file systems, including the information returned by statvfs()
742 (fs type, total blocks, free blocks etc.), but without the mount
743 point. But on BeOS all file systems except / are mounted in the
744 rootfs, directly under /.
745 The directory name of the mount point is often, but not always,
746 identical to the volume name of the device.
747 We therefore get the list of subdirectories of /, and the list
748 of all file systems, and match the two lists. */
750 DIR *dirp;
751 struct rootdir_entry
753 char *name;
754 dev_t dev;
755 ino_t ino;
756 struct rootdir_entry *next;
758 struct rootdir_entry *rootdir_list;
759 struct rootdir_entry **rootdir_tail;
760 int32 pos;
761 dev_t dev;
762 fs_info fi;
764 /* All volumes are mounted in the rootfs, directly under /. */
765 rootdir_list = NULL;
766 rootdir_tail = &rootdir_list;
767 dirp = opendir ("/");
768 if (dirp)
770 struct dirent *d;
772 while ((d = readdir (dirp)) != NULL)
774 char *name;
775 struct stat statbuf;
777 if (strcmp (d->d_name, "..") == 0)
778 continue;
780 if (strcmp (d->d_name, ".") == 0)
781 name = g_strdup ("/");
782 else
783 name = g_strconcat ("/", d->d_name, (char *) NULL);
785 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
787 struct rootdir_entry *re = g_malloc (sizeof (*re));
788 re->name = name;
789 re->dev = statbuf.st_dev;
790 re->ino = statbuf.st_ino;
792 /* Add to the linked list. */
793 *rootdir_tail = re;
794 rootdir_tail = &re->next;
796 else
797 g_free (name);
799 closedir (dirp);
801 *rootdir_tail = NULL;
803 for (pos = 0; (dev = next_dev (&pos)) >= 0;)
804 if (fs_stat_dev (dev, &fi) >= 0)
806 /* Note: fi.dev == dev. */
807 struct rootdir_entry *re;
809 for (re = rootdir_list; re; re = re->next)
810 if (re->dev == fi.dev && re->ino == fi.root)
811 break;
813 me = g_malloc (sizeof (*me));
814 me->me_devname = g_strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
815 me->me_mountdir = g_strdup (re != NULL ? re->name : fi.fsh_name);
816 me->me_type = g_strdup (fi.fsh_name);
817 me->me_type_malloced = 1;
818 me->me_dev = fi.dev;
819 me->me_dummy = 0;
820 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
822 /* Add to the linked list. */
823 *mtail = me;
824 mtail = &me->me_next;
826 *mtail = NULL;
828 while (rootdir_list != NULL)
830 struct rootdir_entry *re = rootdir_list;
831 rootdir_list = re->next;
832 g_free (re->name);
833 g_free (re);
836 #endif /* MOUNTED_FS_STAT_DEV */
838 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
840 int numsys, counter;
841 size_t bufsize;
842 struct statfs *stats;
844 numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
845 if (numsys < 0)
846 return NULL;
847 if (SIZE_MAX / sizeof (*stats) <= numsys)
849 fprintf (stderr, "%s\n", _("Memory exhausted!"));
850 exit (EXIT_FAILURE);
853 bufsize = (1 + numsys) * sizeof (*stats);
854 stats = g_malloc (bufsize);
855 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
857 if (numsys < 0)
859 g_free (stats);
860 return NULL;
863 for (counter = 0; counter < numsys; counter++)
865 me = g_malloc (sizeof (*me));
866 me->me_devname = g_strdup (stats[counter].f_mntfromname);
867 me->me_mountdir = g_strdup (stats[counter].f_mntonname);
868 me->me_type = g_strdup (FS_TYPE (stats[counter]));
869 me->me_type_malloced = 1;
870 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
871 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
872 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
874 /* Add to the linked list. */
875 *mtail = me;
876 mtail = &me->me_next;
879 g_free (stats);
881 #endif /* MOUNTED_GETFSSTAT */
883 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
885 struct mnttab mnt;
886 char *table = "/etc/mnttab";
887 FILE *fp;
889 fp = fopen (table, "r");
890 if (fp == NULL)
891 return NULL;
893 while (fread (&mnt, sizeof (mnt), 1, fp) > 0)
895 me = g_malloc (sizeof (*me));
896 #ifdef GETFSTYP /* SVR3. */
897 me->me_devname = g_strdup (mnt.mt_dev);
898 #else
899 me->me_devname = g_strconcat ("/dev/", mnt.mt_dev, (char *) NULL);
900 #endif
901 me->me_mountdir = g_strdup (mnt.mt_filsys);
902 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
903 me->me_type = "";
904 me->me_type_malloced = 0;
905 #ifdef GETFSTYP /* SVR3. */
906 if (need_fs_type)
908 struct statfs fsd;
909 char typebuf[FSTYPSZ];
911 if (statfs (me->me_mountdir, &fsd, sizeof (fsd), 0) != -1
912 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
914 me->me_type = g_strdup (typebuf);
915 me->me_type_malloced = 1;
918 #endif
919 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
920 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
922 /* Add to the linked list. */
923 *mtail = me;
924 mtail = &me->me_next;
927 if (ferror (fp))
929 /* The last fread() call must have failed. */
930 int saved_errno = errno;
931 fclose (fp);
932 errno = saved_errno;
933 goto free_then_fail;
936 if (fclose (fp) == EOF)
937 goto free_then_fail;
939 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
941 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
943 struct mntent **mnttbl = getmnttbl (), **ent;
944 for (ent = mnttbl; *ent; ent++)
946 me = g_malloc (sizeof (*me));
947 me->me_devname = g_strdup ((*ent)->mt_resource);
948 me->me_mountdir = g_strdup ((*ent)->mt_directory);
949 me->me_type = g_strdup ((*ent)->mt_fstype);
950 me->me_type_malloced = 1;
951 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
952 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
953 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
955 /* Add to the linked list. */
956 *mtail = me;
957 mtail = &me->me_next;
959 endmnttbl ();
961 #endif
963 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
965 struct mnttab mnt;
966 char *table = MNTTAB;
967 FILE *fp;
968 int ret;
969 int lockfd = -1;
971 #if defined F_RDLCK && defined F_SETLKW
972 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
973 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
974 for this file name, we should use their macro name instead.
975 (Why not just lock MNTTAB directly? We don't know.) */
976 #ifndef MNTTAB_LOCK
977 #define MNTTAB_LOCK "/etc/.mnttab.lock"
978 #endif
979 lockfd = open (MNTTAB_LOCK, O_RDONLY);
980 if (0 <= lockfd)
982 struct flock flock;
983 flock.l_type = F_RDLCK;
984 flock.l_whence = SEEK_SET;
985 flock.l_start = 0;
986 flock.l_len = 0;
987 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
988 if (errno != EINTR)
990 int saved_errno = errno;
991 close (lockfd);
992 errno = saved_errno;
993 return NULL;
996 else if (errno != ENOENT)
997 return NULL;
998 #endif
1000 errno = 0;
1001 fp = fopen (table, "r");
1002 if (fp == NULL)
1003 ret = errno;
1004 else
1006 while ((ret = getmntent (fp, &mnt)) == 0)
1008 me = g_malloc (sizeof (*me));
1009 me->me_devname = g_strdup (mnt.mnt_special);
1010 me->me_mountdir = g_strdup (mnt.mnt_mountp);
1011 me->me_type = g_strdup (mnt.mnt_fstype);
1012 me->me_type_malloced = 1;
1013 me->me_dummy = MNT_IGNORE (&mnt) != 0;
1014 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1015 me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
1017 /* Add to the linked list. */
1018 *mtail = me;
1019 mtail = &me->me_next;
1022 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
1025 if (0 <= lockfd && close (lockfd) != 0)
1026 ret = errno;
1028 if (0 <= ret)
1030 errno = ret;
1031 goto free_then_fail;
1034 #endif /* MOUNTED_GETMNTENT2. */
1036 #ifdef MOUNTED_VMOUNT /* AIX. */
1038 int bufsize;
1039 char *entries, *thisent;
1040 struct vmount *vmp;
1041 int n_entries;
1042 int i;
1044 /* Ask how many bytes to allocate for the mounted file system info. */
1045 if (mntctl (MCTL_QUERY, sizeof (bufsize), (struct vmount *) &bufsize) != 0)
1046 return NULL;
1047 entries = g_malloc (bufsize);
1049 /* Get the list of mounted file systems. */
1050 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
1051 if (n_entries < 0)
1053 int saved_errno = errno;
1054 g_free (entries);
1055 errno = saved_errno;
1056 return NULL;
1059 for (i = 0, thisent = entries; i < n_entries; i++, thisent += vmp->vmt_length)
1061 char *options, *ignore;
1063 vmp = (struct vmount *) thisent;
1064 me = g_malloc (sizeof (*me));
1065 if (vmp->vmt_flags & MNT_REMOTE)
1067 char *host, *dir;
1069 me->me_remote = 1;
1070 /* Prepend the remote dirname. */
1071 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
1072 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
1073 me->me_devname = g_strconcat (host, ":", dir, (char *) NULL);
1075 else
1077 me->me_remote = 0;
1078 me->me_devname = g_strdup (thisent + vmp->vmt_data[VMT_OBJECT].vmt_off);
1080 me->me_mountdir = g_strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
1081 me->me_type = g_strdup (fstype_to_string (vmp->vmt_gfstype));
1082 me->me_type_malloced = 1;
1083 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
1084 ignore = strstr (options, "ignore");
1085 me->me_dummy = (ignore
1086 && (ignore == options || ignore[-1] == ',')
1087 && (ignore[sizeof ("ignore") - 1] == ','
1088 || ignore[sizeof ("ignore") - 1] == '\0'));
1089 me->me_dev = (dev_t) (-1); /* vmt_fsid might be the info we want. */
1091 /* Add to the linked list. */
1092 *mtail = me;
1093 mtail = &me->me_next;
1095 g_free (entries);
1097 #endif /* MOUNTED_VMOUNT. */
1100 #ifdef MOUNTED_INTERIX_STATVFS
1102 DIR *dirp = opendir ("/dev/fs");
1103 char node[9 + NAME_MAX];
1105 if (!dirp)
1106 goto free_then_fail;
1108 while (1)
1110 struct statvfs dev;
1111 struct dirent entry;
1112 struct dirent *result;
1114 if (readdir_r (dirp, &entry, &result) || result == NULL)
1115 break;
1117 strcpy (node, "/dev/fs/");
1118 strcat (node, entry.d_name);
1120 if (statvfs (node, &dev) == 0)
1122 me = g_malloc (sizeof *me);
1123 me->me_devname = g_strdup (dev.f_mntfromname);
1124 me->me_mountdir = g_strdup (dev.f_mntonname);
1125 me->me_type = g_strdup (dev.f_fstypename);
1126 me->me_type_malloced = 1;
1127 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1128 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1129 me->me_dev = (dev_t) (-1); /* Magic; means not known yet. */
1131 /* Add to the linked list. */
1132 *mtail = me;
1133 mtail = &me->me_next;
1137 #endif /* MOUNTED_INTERIX_STATVFS */
1139 (void) need_fs_type; /* avoid argument-unused warning */
1140 *mtail = NULL;
1141 return mount_list;
1144 free_then_fail:
1146 int saved_errno = errno;
1147 *mtail = NULL;
1149 while (mount_list)
1151 me = mount_list->me_next;
1152 g_free (mount_list->me_devname);
1153 g_free (mount_list->me_mountdir);
1154 if (mount_list->me_type_malloced)
1155 g_free (mount_list->me_type);
1156 g_free (mount_list);
1157 mount_list = me;
1160 errno = saved_errno;
1161 return NULL;
1165 #endif /* HAVE_INFOMOUNT_LIST */
1167 /* --------------------------------------------------------------------------------------------- */
1169 #ifdef HAVE_INFOMOUNT_QNX
1171 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1172 ** this via the following code.
1173 ** Note that, as this is based on CWD, it only fills one mount_entry
1174 ** structure. See my_statfs() in utilunix.c for the "other side" of
1175 ** this hack.
1178 static struct mount_entry *
1179 read_file_system_list (int need_fs_type, int all_fs)
1181 struct _disk_entry de;
1182 struct statfs fs;
1183 int i, fd;
1184 char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
1186 static struct mount_entry *me = NULL;
1188 if (me)
1190 g_free (me->me_devname);
1191 g_free (me->me_mountdir);
1192 g_free (me->me_type);
1194 else
1195 me = (struct mount_entry *) g_malloc (sizeof (struct mount_entry));
1197 if (!getcwd (dir, _POSIX_PATH_MAX))
1198 return (NULL);
1200 fd = open (dir, O_RDONLY);
1201 if (fd == -1)
1202 return (NULL);
1204 i = disk_get_entry (fd, &de);
1206 close (fd);
1208 if (i == -1)
1209 return (NULL);
1211 switch (de.disk_type)
1213 case _UNMOUNTED:
1214 tp = "unmounted";
1215 break;
1216 case _FLOPPY:
1217 tp = "Floppy";
1218 break;
1219 case _HARD:
1220 tp = "Hard";
1221 break;
1222 case _RAMDISK:
1223 tp = "Ram";
1224 break;
1225 case _REMOVABLE:
1226 tp = "Removable";
1227 break;
1228 case _TAPE:
1229 tp = "Tape";
1230 break;
1231 case _CDROM:
1232 tp = "CDROM";
1233 break;
1234 default:
1235 tp = "unknown";
1238 if (fsys_get_mount_dev (dir, &dev) == -1)
1239 return (NULL);
1241 if (fsys_get_mount_pt (dev, &dir) == -1)
1242 return (NULL);
1244 me->me_devname = g_strdup (dev);
1245 me->me_mountdir = g_strdup (dir);
1246 me->me_type = g_strdup (tp);
1247 me->me_dev = de.disk_type;
1249 #ifdef DEBUG
1250 fprintf (stderr,
1251 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1252 de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
1253 fprintf (stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
1254 fprintf (stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
1255 #endif /* DEBUG */
1257 return (me);
1259 #endif /* HAVE_INFOMOUNT_QNX */
1261 /* --------------------------------------------------------------------------------------------- */
1263 #ifdef STAT_READ_FILSYS /* SVR2 */
1265 /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
1266 interrupted. Return the actual number of bytes read(written), zero for EOF,
1267 or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */
1268 static size_t
1269 safe_read (int fd, void *buf, size_t count)
1271 /* Work around a bug in Tru64 5.1. Attempting to read more than
1272 INT_MAX bytes fails with errno == EINVAL. See
1273 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
1274 When decreasing COUNT, keep it block-aligned. */
1275 /* *INDENT-OFF* */
1276 enum { BUGGY_READ_MAXIMUM = INT_MAX & ~8191 };
1277 /* *INDENT-ON* */
1279 while (TRUE)
1281 ssize_t result;
1283 result = read (fd, buf, count);
1285 if (0 <= result)
1286 return result;
1287 else if (IS_EINTR (errno))
1288 continue;
1289 else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count)
1290 count = BUGGY_READ_MAXIMUM;
1291 else
1292 return result;
1296 /* --------------------------------------------------------------------------------------------- */
1298 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1299 interrupted or if a partial write(read) occurs. Return the number
1300 of bytes transferred.
1301 When writing, set errno if fewer than COUNT bytes are written.
1302 When reading, if fewer than COUNT bytes are read, you must examine
1303 errno to distinguish failure from EOF (errno == 0). */
1305 static size_t
1306 full_read (int fd, void *buf, size_t count)
1308 size_t total = 0;
1309 char *ptr = (char *) buf;
1311 while (count > 0)
1313 size_t n_rw = safe_read (fd, ptr, count);
1314 if (n_rw == (size_t) (-1))
1315 break;
1316 if (n_rw == 0)
1318 errno = ZERO_BYTE_TRANSFER_ERRNO;
1319 break;
1321 total += n_rw;
1322 ptr += n_rw;
1323 count -= n_rw;
1326 return total;
1329 #endif /* STAT_READ_FILSYS */
1331 /* --------------------------------------------------------------------------------------------- */
1333 #ifdef HAVE_INFOMOUNT
1334 /* Fill in the fields of FSP with information about space usage for
1335 the file system on which FILE resides.
1336 DISK is the device on which FILE is mounted, for space-getting
1337 methods that need to know it.
1338 Return 0 if successful, -1 if not. When returning -1, ensure that
1339 ERRNO is either a system error value, or zero if DISK is NULL
1340 on a system that requires a non-NULL value. */
1341 static int
1342 get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
1344 #ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
1346 if (statvfs_works ())
1348 struct statvfs vfsd;
1350 if (statvfs (file, &vfsd) < 0)
1351 return -1;
1353 /* f_frsize isn't guaranteed to be supported. */
1354 fsp->fsu_blocksize = (vfsd.f_frsize
1355 ? PROPAGATE_ALL_ONES (vfsd.f_frsize)
1356 : PROPAGATE_ALL_ONES (vfsd.f_bsize));
1358 fsp->fsu_blocks = PROPAGATE_ALL_ONES (vfsd.f_blocks);
1359 fsp->fsu_bfree = PROPAGATE_ALL_ONES (vfsd.f_bfree);
1360 fsp->fsu_bavail = PROPAGATE_TOP_BIT (vfsd.f_bavail);
1361 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (vfsd.f_bavail) != 0;
1362 fsp->fsu_files = PROPAGATE_ALL_ONES (vfsd.f_files);
1363 fsp->fsu_ffree = PROPAGATE_ALL_ONES (vfsd.f_ffree);
1365 else
1366 #endif
1369 #if defined STAT_STATVFS64 /* AIX */
1371 struct statvfs64 fsd;
1373 if (statvfs64 (file, &fsd) < 0)
1374 return -1;
1376 /* f_frsize isn't guaranteed to be supported. */
1377 /* *INDENT-OFF* */
1378 fsp->fsu_blocksize = fsd.f_frsize
1379 ? PROPAGATE_ALL_ONES (fsd.f_frsize)
1380 : PROPAGATE_ALL_ONES (fsd.f_bsize);
1381 /* *INDENT-ON* */
1383 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1385 struct fs_data fsd;
1387 if (statfs (file, &fsd) != 1)
1388 return -1;
1390 fsp->fsu_blocksize = 1024;
1391 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot);
1392 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree);
1393 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen);
1394 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0;
1395 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
1396 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
1398 #elif defined STAT_READ_FILSYS /* SVR2 */
1399 #ifndef SUPERBOFF
1400 #define SUPERBOFF (SUPERB * 512)
1401 #endif
1403 struct filsys fsd;
1404 int fd;
1406 if (!disk)
1408 errno = 0;
1409 return -1;
1412 fd = open (disk, O_RDONLY);
1413 if (fd < 0)
1414 return -1;
1415 lseek (fd, (off_t) SUPERBOFF, 0);
1416 if (full_read (fd, (char *) &fsd, sizeof (fsd)) != sizeof (fsd))
1418 close (fd);
1419 return -1;
1421 close (fd);
1423 fsp->fsu_blocksize = (fsd.s_type == Fs2b ? 1024 : 512);
1424 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.s_fsize);
1425 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.s_tfree);
1426 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree);
1427 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0;
1428 fsp->fsu_files = (fsd.s_isize == -1
1429 ? UINTMAX_MAX : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1));
1430 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode);
1432 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1434 struct statfs fsd;
1436 if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
1437 return -1;
1439 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1441 #elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
1443 struct statfs fsd;
1445 if (statfs (file, &fsd) < 0)
1446 return -1;
1448 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_frsize);
1450 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
1451 Mac OS X < 10.4, FreeBSD < 5.0, \
1452 NetBSD < 3.0, OpenBSD < 4.4 */
1454 struct statfs fsd;
1456 if (statfs (file, &fsd) < 0)
1457 return -1;
1459 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1461 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1463 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1464 struct statfs are truncated to 2GB. These conditions detect that
1465 truncation, presumably without botching the 4.1.1 case, in which
1466 the values are not truncated. The correct counts are stored in
1467 undocumented spare fields. */
1468 if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
1470 fsd.f_blocks = fsd.f_spare[0];
1471 fsd.f_bfree = fsd.f_spare[1];
1472 fsd.f_bavail = fsd.f_spare[2];
1474 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1476 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1478 struct statfs fsd;
1480 if (statfs (file, &fsd) < 0)
1481 return -1;
1483 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1485 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1486 Dolphin */
1488 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1489 #define f_bavail f_bfree
1490 #endif
1492 struct statfs fsd;
1494 if (statfs (file, &fsd, sizeof (fsd), 0) < 0)
1495 return -1;
1497 /* Empirically, the block counts on most SVR3 and SVR3-derived
1498 systems seem to always be in terms of 512-byte blocks,
1499 no matter what value f_bsize has. */
1500 #if defined _AIX || defined _CRAY
1501 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1502 #else
1503 fsp->fsu_blocksize = 512;
1504 #endif
1506 #endif
1508 #if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 \
1509 || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE \
1510 || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
1512 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
1513 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
1514 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
1515 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
1516 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
1517 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
1519 #endif
1522 (void) disk; /* avoid argument-unused warning */
1524 return 0;
1526 #endif /* HAVE_INFOMOUNT */
1528 /* --------------------------------------------------------------------------------------------- */
1529 /*** public functions ****************************************************************************/
1530 /* --------------------------------------------------------------------------------------------- */
1532 void
1533 free_my_statfs (void)
1535 #ifdef HAVE_INFOMOUNT_LIST
1536 while (mc_mount_list != NULL)
1538 struct mount_entry *next;
1540 next = mc_mount_list->me_next;
1541 free_mount_entry (mc_mount_list);
1542 mc_mount_list = next;
1545 mc_mount_list = NULL;
1546 #endif /* HAVE_INFOMOUNT_LIST */
1549 /* --------------------------------------------------------------------------------------------- */
1551 void
1552 init_my_statfs (void)
1554 #ifdef HAVE_INFOMOUNT_LIST
1555 free_my_statfs ();
1556 mc_mount_list = read_file_system_list (1);
1557 #endif /* HAVE_INFOMOUNT_LIST */
1560 /* --------------------------------------------------------------------------------------------- */
1562 void
1563 my_statfs (struct my_statfs *myfs_stats, const char *path)
1565 #ifdef HAVE_INFOMOUNT_LIST
1566 size_t i, len = 0;
1567 struct mount_entry *entry = NULL;
1568 struct mount_entry *temp = mc_mount_list;
1569 struct fs_usage fs_use;
1571 while (temp)
1573 i = strlen (temp->me_mountdir);
1574 if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
1575 if (!entry || (path[i] == PATH_SEP || path[i] == '\0'))
1577 len = i;
1578 entry = temp;
1580 temp = temp->me_next;
1583 if (entry)
1585 memset (&fs_use, 0, sizeof (struct fs_usage));
1586 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1588 myfs_stats->type = entry->me_dev;
1589 myfs_stats->typename = entry->me_type;
1590 myfs_stats->mpoint = entry->me_mountdir;
1591 myfs_stats->device = entry->me_devname;
1592 myfs_stats->avail =
1593 ((uintmax_t) (getuid ()? fs_use.fsu_bavail : fs_use.fsu_bfree) *
1594 fs_use.fsu_blocksize) >> 10;
1595 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1596 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1597 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1599 else
1600 #endif /* HAVE_INFOMOUNT_LIST */
1602 #ifdef HAVE_INFOMOUNT_QNX
1604 ** This is the "other side" of the hack to read_file_system_list() in
1605 ** mountlist.c.
1606 ** It's not the most efficient approach, but consumes less memory. It
1607 ** also accomodates QNX's ability to mount filesystems on the fly.
1609 struct mount_entry *entry;
1610 struct fs_usage fs_use;
1612 entry = read_file_system_list (0, 0);
1613 if (entry != NULL)
1615 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1617 myfs_stats->type = entry->me_dev;
1618 myfs_stats->typename = entry->me_type;
1619 myfs_stats->mpoint = entry->me_mountdir;
1620 myfs_stats->device = entry->me_devname;
1622 myfs_stats->avail = ((uintmax_t) fs_use.fsu_bfree * fs_use.fsu_blocksize) >> 10;
1623 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1624 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1625 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1627 else
1628 #endif /* HAVE_INFOMOUNT_QNX */
1630 myfs_stats->type = 0;
1631 myfs_stats->mpoint = "unknown";
1632 myfs_stats->device = "unknown";
1633 myfs_stats->avail = 0;
1634 myfs_stats->total = 0;
1635 myfs_stats->nfree = 0;
1636 myfs_stats->nodes = 0;
1640 /* --------------------------------------------------------------------------------------------- */