Fix of memory leak in TreeStore::check_name destruction.
[midnight-commander.git] / src / filemanager / mountlist.c
blob171bfbd4aeab6b9254d7901e239e7b8f80a14883
1 /*
2 Return a list of mounted file systems
4 Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
5 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
7 Copyright (C) 1991, 1992, 2011
8 The Free Software Foundation, Inc.
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 /** \file mountlist.c
27 * \brief Source: list of mounted filesystems
30 #include <config.h>
32 #include <limits.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdint.h> /* SIZE_MAX */
37 #include <sys/types.h>
39 #include <errno.h>
41 /* This header needs to be included before sys/mount.h on *BSD */
42 #ifdef HAVE_SYS_PARAM_H
43 #include <sys/param.h>
44 #endif
46 #if defined STAT_STATVFS || defined STAT_STATVFS64 /* POSIX 1003.1-2001 (and later) with XSI */
47 #include <sys/statvfs.h>
48 #else
49 /* Don't include backward-compatibility files unless they're needed.
50 Eventually we'd like to remove all this cruft. */
51 #include <fcntl.h>
52 #include <unistd.h>
53 #include <sys/stat.h>
55 #ifdef MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
56 #ifdef HAVE_SYS_UCRED_H
57 #include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
58 NGROUPS is used as an array dimension in ucred.h */
59 #include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
60 #endif
61 #ifdef HAVE_SYS_MOUNT_H
62 #include <sys/mount.h>
63 #endif
64 #ifdef HAVE_SYS_FS_TYPES_H
65 #include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
66 #endif
67 #ifdef HAVE_STRUCT_FSSTAT_F_FSTYPENAME
68 #define FS_TYPE(Ent) ((Ent).f_fstypename)
69 #else
70 #define FS_TYPE(Ent) mnt_names[(Ent).f_type]
71 #endif
72 #endif /* MOUNTED_GETFSSTAT */
73 #endif /* STAT_STATVFS || STAT_STATVFS64 */
75 #ifdef HAVE_SYS_VFS_H
76 #include <sys/vfs.h>
77 #endif
78 #ifdef HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */
79 #include <sys/fs/s5param.h>
80 #endif
81 #if defined HAVE_SYS_FILSYS_H && !defined _CRAY
82 #include <sys/filsys.h> /* SVR2 */
83 #endif
84 #ifdef HAVE_SYS_STATFS_H
85 #include <sys/statfs.h>
86 #endif
87 #ifdef HAVE_DUSTAT_H /* AIX PS/2 */
88 #include <sys/dustat.h>
89 #endif
91 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
92 #include <mntent.h>
93 #ifndef MOUNTED
94 #ifdef _PATH_MOUNTED /* GNU libc */
95 #define MOUNTED _PATH_MOUNTED
96 #endif
97 #ifdef MNT_MNTTAB /* HP-UX. */
98 #define MOUNTED MNT_MNTTAB
99 #endif
100 #ifdef MNTTABNAME /* Dynix. */
101 #define MOUNTED MNTTABNAME
102 #endif
103 #endif
104 #endif
106 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
107 #include <sys/mount.h>
108 #endif
110 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
111 #include <sys/statvfs.h>
112 #endif
114 #ifdef MOUNTED_GETMNT /* Ultrix. */
115 #include <sys/mount.h>
116 #include <sys/fs_types.h>
117 #endif
119 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
120 #include <fs_info.h>
121 #include <dirent.h>
122 #endif
124 #ifdef MOUNTED_FREAD /* SVR2. */
125 #include <mnttab.h>
126 #endif
128 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
129 #include <mnttab.h>
130 #include <sys/fstyp.h>
131 #include <sys/statfs.h>
132 #endif
134 #ifdef MOUNTED_LISTMNTENT
135 #include <mntent.h>
136 #endif
138 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
139 #include <sys/mnttab.h>
140 #endif
142 #ifdef MOUNTED_VMOUNT /* AIX. */
143 #include <fshelp.h>
144 #include <sys/vfs.h>
145 #endif
147 #ifdef MOUNTED_INTERIX_STATVFS /* Interix. */
148 #include <sys/statvfs.h>
149 #include <dirent.h>
150 #endif
152 #ifdef DOLPHIN
153 /* So special that it's not worth putting this in autoconf. */
154 #undef MOUNTED_FREAD_FSTYP
155 #define MOUNTED_GETMNTTBL
156 #endif
158 #ifdef HAVE_SYS_MNTENT_H
159 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
160 #include <sys/mntent.h>
161 #endif
163 #undef MNT_IGNORE
164 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
165 #define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
166 #else
167 #define MNT_IGNORE(M) 0
168 #endif
170 #ifdef HAVE_INFOMOUNT_QNX
171 #include <sys/disk.h>
172 #include <sys/fsys.h>
173 #endif
175 #ifdef HAVE_SYS_STATVFS_H /* SVR4. */
176 #include <sys/statvfs.h>
177 #endif
179 #include "lib/global.h"
180 #include "mountlist.h"
182 /*** global variables ****************************************************************************/
184 /*** file scope macro definitions ****************************************************************/
186 #if defined (__QNX__) && !defined(__QNXNTO__) && !defined (HAVE_INFOMOUNT_LIST)
187 #define HAVE_INFOMOUNT_QNX
188 #endif
190 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
191 #define HAVE_INFOMOUNT
192 #endif
194 /* The results of open() in this file are not used with fchdir,
195 therefore save some unnecessary work in fchdir.c. */
196 #undef open
197 #undef close
199 /* The results of opendir() in this file are not used with dirfd and fchdir,
200 therefore save some unnecessary work in fchdir.c. */
201 #undef opendir
202 #undef closedir
204 #ifndef ME_DUMMY
205 #define ME_DUMMY(Fs_name, Fs_type) \
206 (strcmp (Fs_type, "autofs") == 0 \
207 || strcmp (Fs_type, "none") == 0 \
208 || strcmp (Fs_type, "proc") == 0 \
209 || strcmp (Fs_type, "subfs") == 0 \
210 /* for NetBSD 3.0 */ \
211 || strcmp (Fs_type, "kernfs") == 0 \
212 /* for Irix 6.5 */ \
213 || strcmp (Fs_type, "ignore") == 0)
214 #endif
216 #ifdef __CYGWIN__
217 #include <windows.h>
218 #define ME_REMOTE me_remote
219 /* All cygwin mount points include `:' or start with `//'; so it
220 requires a native Windows call to determine remote disks. */
221 static int
222 me_remote (char const *fs_name, char const *fs_type _GL_UNUSED)
224 if (fs_name[0] && fs_name[1] == ':')
226 char drive[4];
227 sprintf (drive, "%c:\\", fs_name[0]);
228 switch (GetDriveType (drive))
230 case DRIVE_REMOVABLE:
231 case DRIVE_FIXED:
232 case DRIVE_CDROM:
233 case DRIVE_RAMDISK:
234 return 0;
237 return 1;
239 #endif
240 #ifndef ME_REMOTE
241 /* A file system is `remote' if its Fs_name contains a `:'
242 or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */
243 #define ME_REMOTE(Fs_name, Fs_type) \
244 (strchr (Fs_name, ':') != NULL \
245 || ((Fs_name)[0] == '/' \
246 && (Fs_name)[1] == '/' \
247 && (strcmp (Fs_type, "smbfs") == 0 || strcmp (Fs_type, "cifs") == 0)))
248 #endif
250 /* Many space usage primitives use all 1 bits to denote a value that is
251 not applicable or unknown. Propagate this information by returning
252 a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
253 is unsigned and narrower than uintmax_t. */
254 #define PROPAGATE_ALL_ONES(x) \
255 ((sizeof (x) < sizeof (uintmax_t) \
256 && (~ (x) == (sizeof (x) < sizeof (int) \
257 ? - (1 << (sizeof (x) * CHAR_BIT)) \
258 : 0))) \
259 ? UINTMAX_MAX : (uintmax_t) (x))
261 /* Extract the top bit of X as an uintmax_t value. */
262 #define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
264 /* If a value is negative, many space usage primitives store it into an
265 integer variable by assignment, even if the variable's type is unsigned.
266 So, if a space usage variable X's top bit is set, convert X to the
267 uintmax_t value V such that (- (uintmax_t) V) is the negative of
268 the original value. If X's top bit is clear, just yield X.
269 Use PROPAGATE_TOP_BIT if the original value might be negative;
270 otherwise, use PROPAGATE_ALL_ONES. */
271 #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
273 #ifdef STAT_READ_FILSYS /* SVR2 */
274 /* Set errno to zero upon EOF. */
275 #define ZERO_BYTE_TRANSFER_ERRNO 0
277 #ifdef EINTR
278 #define IS_EINTR(x) ((x) == EINTR)
279 #else
280 #define IS_EINTR(x) 0
281 #endif
282 #endif /* STAT_READ_FILSYS */
284 /*** file scope type declarations ****************************************************************/
286 /* A mount table entry. */
287 struct mount_entry
289 char *me_devname; /* Device node name, including "/dev/". */
290 char *me_mountdir; /* Mount point directory name. */
291 char *me_type; /* "nfs", "4.2", etc. */
292 dev_t me_dev; /* Device number of me_mountdir. */
293 unsigned int me_dummy:1; /* Nonzero for dummy file systems. */
294 unsigned int me_remote:1; /* Nonzero for remote fileystems. */
295 unsigned int me_type_malloced:1; /* Nonzero if me_type was malloced. */
296 struct mount_entry *me_next;
299 struct fs_usage
301 uintmax_t fsu_blocksize; /* Size of a block. */
302 uintmax_t fsu_blocks; /* Total blocks. */
303 uintmax_t fsu_bfree; /* Free blocks available to superuser. */
304 uintmax_t fsu_bavail; /* Free blocks available to non-superuser. */
305 int fsu_bavail_top_bit_set; /* 1 if fsu_bavail represents a value < 0. */
306 uintmax_t fsu_files; /* Total file nodes. */
307 uintmax_t fsu_ffree; /* Free file nodes. */
310 /*** file scope variables ************************************************************************/
312 #ifdef HAVE_INFOMOUNT_LIST
313 static struct mount_entry *mc_mount_list = NULL;
314 #endif /* HAVE_INFOMOUNT_LIST */
316 /*** file scope functions ************************************************************************/
317 /* --------------------------------------------------------------------------------------------- */
319 #ifdef HAVE_INFOMOUNT_LIST
320 static void
321 free_mount_entry (struct mount_entry *me)
323 if (!me)
324 return;
325 if (me->me_devname)
326 free (me->me_devname);
327 if (me->me_mountdir)
328 free (me->me_mountdir);
329 if (me->me_type && me->me_type_malloced)
330 free (me->me_type);
331 free (me);
334 /* --------------------------------------------------------------------------------------------- */
336 #ifdef MOUNTED_GETMNTINFO
338 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
339 static char *
340 fstype_to_string (short int t)
342 switch (t)
344 #ifdef MOUNT_PC
345 case MOUNT_PC:
346 return "pc";
347 #endif
348 #ifdef MOUNT_MFS
349 case MOUNT_MFS:
350 return "mfs";
351 #endif
352 #ifdef MOUNT_LO
353 case MOUNT_LO:
354 return "lo";
355 #endif
356 #ifdef MOUNT_TFS
357 case MOUNT_TFS:
358 return "tfs";
359 #endif
360 #ifdef MOUNT_TMP
361 case MOUNT_TMP:
362 return "tmp";
363 #endif
364 #ifdef MOUNT_UFS
365 case MOUNT_UFS:
366 return "ufs";
367 #endif
368 #ifdef MOUNT_NFS
369 case MOUNT_NFS:
370 return "nfs";
371 #endif
372 #ifdef MOUNT_MSDOS
373 case MOUNT_MSDOS:
374 return "msdos";
375 #endif
376 #ifdef MOUNT_LFS
377 case MOUNT_LFS:
378 return "lfs";
379 #endif
380 #ifdef MOUNT_LOFS
381 case MOUNT_LOFS:
382 return "lofs";
383 #endif
384 #ifdef MOUNT_FDESC
385 case MOUNT_FDESC:
386 return "fdesc";
387 #endif
388 #ifdef MOUNT_PORTAL
389 case MOUNT_PORTAL:
390 return "portal";
391 #endif
392 #ifdef MOUNT_NULL
393 case MOUNT_NULL:
394 return "null";
395 #endif
396 #ifdef MOUNT_UMAP
397 case MOUNT_UMAP:
398 return "umap";
399 #endif
400 #ifdef MOUNT_KERNFS
401 case MOUNT_KERNFS:
402 return "kernfs";
403 #endif
404 #ifdef MOUNT_PROCFS
405 case MOUNT_PROCFS:
406 return "procfs";
407 #endif
408 #ifdef MOUNT_AFS
409 case MOUNT_AFS:
410 return "afs";
411 #endif
412 #ifdef MOUNT_CD9660
413 case MOUNT_CD9660:
414 return "cd9660";
415 #endif
416 #ifdef MOUNT_UNION
417 case MOUNT_UNION:
418 return "union";
419 #endif
420 #ifdef MOUNT_DEVFS
421 case MOUNT_DEVFS:
422 return "devfs";
423 #endif
424 #ifdef MOUNT_EXT2FS
425 case MOUNT_EXT2FS:
426 return "ext2fs";
427 #endif
428 default:
429 return "?";
432 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
434 /* --------------------------------------------------------------------------------------------- */
436 static char *
437 fsp_to_string (const struct statfs *fsp)
439 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
440 return (char *) (fsp->f_fstypename);
441 #else
442 return fstype_to_string (fsp->f_type);
443 #endif
445 #endif /* MOUNTED_GETMNTINFO */
447 /* --------------------------------------------------------------------------------------------- */
449 #ifdef MOUNTED_VMOUNT /* AIX. */
450 static char *
451 fstype_to_string (int t)
453 struct vfs_ent *e;
455 e = getvfsbytype (t);
456 if (!e || !e->vfsent_name)
457 return "none";
458 else
459 return e->vfsent_name;
461 #endif /* MOUNTED_VMOUNT */
463 /* --------------------------------------------------------------------------------------------- */
465 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
467 /* Return the device number from MOUNT_OPTIONS, if possible.
468 Otherwise return (dev_t) -1. */
470 /* --------------------------------------------------------------------------------------------- */
472 static dev_t
473 dev_from_mount_options (char const *mount_options)
475 /* GNU/Linux allows file system implementations to define their own
476 meaning for "dev=" mount options, so don't trust the meaning
477 here. */
478 #ifndef __linux__
479 static char const dev_pattern[] = ",dev=";
480 char const *devopt = strstr (mount_options, dev_pattern);
482 if (devopt)
484 char const *optval = devopt + sizeof (dev_pattern) - 1;
485 char *optvalend;
486 unsigned long int dev;
487 errno = 0;
488 dev = strtoul (optval, &optvalend, 16);
489 if (optval != optvalend
490 && (*optvalend == '\0' || *optvalend == ',')
491 && !(dev == ULONG_MAX && errno == ERANGE) && dev == (dev_t) dev)
492 return dev;
494 #endif
496 (void) mount_options;
497 return -1;
500 #endif
502 /* --------------------------------------------------------------------------------------------- */
504 #if defined _AIX && defined _I386
505 /* AIX PS/2 does not supply statfs. */
507 static int
508 statfs (char *file, struct statfs *fsb)
510 struct stat stats;
511 struct dustat fsd;
513 if (stat (file, &stats) != 0)
514 return -1;
515 if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
516 return -1;
517 fsb->f_type = 0;
518 fsb->f_bsize = fsd.du_bsize;
519 fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
520 fsb->f_bfree = fsd.du_tfree;
521 fsb->f_bavail = fsd.du_tfree;
522 fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
523 fsb->f_ffree = fsd.du_tinode;
524 fsb->f_fsid.val[0] = fsd.du_site;
525 fsb->f_fsid.val[1] = fsd.du_pckno;
526 return 0;
529 #endif /* _AIX && _I386 */
531 /* --------------------------------------------------------------------------------------------- */
533 /* Return a list of the currently mounted file systems, or NULL on error.
534 Add each entry to the tail of the list so that they stay in order.
535 If NEED_FS_TYPE is true, ensure that the file system type fields in
536 the returned list are valid. Otherwise, they might not be. */
538 static struct mount_entry *
539 read_file_system_list (int need_fs_type)
541 struct mount_entry *mount_list;
542 struct mount_entry *me;
543 struct mount_entry **mtail = &mount_list;
545 #ifdef MOUNTED_LISTMNTENT
547 struct tabmntent *mntlist, *p;
548 struct mntent *mnt;
549 struct mount_entry *me;
551 /* the third and fourth arguments could be used to filter mounts,
552 but Crays doesn't seem to have any mounts that we want to
553 remove. Specifically, automount create normal NFS mounts.
556 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
557 return NULL;
558 for (p = mntlist; p; p = p->next)
560 mnt = p->ment;
561 me = malloc (sizeof (*me));
562 me->me_devname = strdup (mnt->mnt_fsname);
563 me->me_mountdir = strdup (mnt->mnt_dir);
564 me->me_type = strdup (mnt->mnt_type);
565 me->me_type_malloced = 1;
566 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
567 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
568 me->me_dev = -1;
569 *mtail = me;
570 mtail = &me->me_next;
572 freemntlist (mntlist);
574 #endif
576 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
578 struct mntent *mnt;
579 const char *table = MOUNTED;
580 FILE *fp;
582 fp = setmntent (table, "r");
583 if (fp == NULL)
584 return NULL;
586 while ((mnt = getmntent (fp)))
588 me = malloc (sizeof (*me));
589 me->me_devname = strdup (mnt->mnt_fsname);
590 me->me_mountdir = strdup (mnt->mnt_dir);
591 me->me_type = strdup (mnt->mnt_type);
592 me->me_type_malloced = 1;
593 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
594 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
595 me->me_dev = dev_from_mount_options (mnt->mnt_opts);
597 /* Add to the linked list. */
598 *mtail = me;
599 mtail = &me->me_next;
602 if (endmntent (fp) == 0)
603 goto free_then_fail;
605 #endif /* MOUNTED_GETMNTENT1. */
607 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
609 struct statfs *fsp;
610 int entries;
612 entries = getmntinfo (&fsp, MNT_NOWAIT);
613 if (entries < 0)
614 return NULL;
615 for (; entries-- > 0; fsp++)
617 char *fs_type = fsp_to_string (fsp);
619 me = malloc (sizeof (*me));
620 me->me_devname = strdup (fsp->f_mntfromname);
621 me->me_mountdir = strdup (fsp->f_mntonname);
622 me->me_type = fs_type;
623 me->me_type_malloced = 0;
624 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
625 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
626 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
628 /* Add to the linked list. */
629 *mtail = me;
630 mtail = &me->me_next;
633 #endif /* MOUNTED_GETMNTINFO */
635 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
637 struct statvfs *fsp;
638 int entries;
640 entries = getmntinfo (&fsp, MNT_NOWAIT);
641 if (entries < 0)
642 return NULL;
643 for (; entries-- > 0; fsp++)
645 me = malloc (sizeof (*me));
646 me->me_devname = strdup (fsp->f_mntfromname);
647 me->me_mountdir = strdup (fsp->f_mntonname);
648 me->me_type = strdup (fsp->f_fstypename);
649 me->me_type_malloced = 1;
650 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
651 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
652 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
654 /* Add to the linked list. */
655 *mtail = me;
656 mtail = &me->me_next;
659 #endif /* MOUNTED_GETMNTINFO2 */
661 #ifdef MOUNTED_GETMNT /* Ultrix. */
663 int offset = 0;
664 int val;
665 struct fs_data fsd;
667 while (errno = 0, 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, (char *) 0)))
669 me = malloc (sizeof (*me));
670 me->me_devname = strdup (fsd.fd_req.devname);
671 me->me_mountdir = strdup (fsd.fd_req.path);
672 me->me_type = gt_names[fsd.fd_req.fstype];
673 me->me_type_malloced = 0;
674 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
675 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
676 me->me_dev = fsd.fd_req.dev;
678 /* Add to the linked list. */
679 *mtail = me;
680 mtail = &me->me_next;
682 if (val < 0)
683 goto free_then_fail;
685 #endif /* MOUNTED_GETMNT. */
687 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
689 /* The next_dev() and fs_stat_dev() system calls give the list of
690 all file systems, including the information returned by statvfs()
691 (fs type, total blocks, free blocks etc.), but without the mount
692 point. But on BeOS all file systems except / are mounted in the
693 rootfs, directly under /.
694 The directory name of the mount point is often, but not always,
695 identical to the volume name of the device.
696 We therefore get the list of subdirectories of /, and the list
697 of all file systems, and match the two lists. */
699 DIR *dirp;
700 struct rootdir_entry
702 char *name;
703 dev_t dev;
704 ino_t ino;
705 struct rootdir_entry *next;
707 struct rootdir_entry *rootdir_list;
708 struct rootdir_entry **rootdir_tail;
709 int32 pos;
710 dev_t dev;
711 fs_info fi;
713 /* All volumes are mounted in the rootfs, directly under /. */
714 rootdir_list = NULL;
715 rootdir_tail = &rootdir_list;
716 dirp = opendir ("/");
717 if (dirp)
719 struct dirent *d;
721 while ((d = readdir (dirp)) != NULL)
723 char *name;
724 struct stat statbuf;
726 if (strcmp (d->d_name, "..") == 0)
727 continue;
729 if (strcmp (d->d_name, ".") == 0)
730 name = strdup ("/");
731 else
733 name = malloc (1 + strlen (d->d_name) + 1);
734 name[0] = '/';
735 strcpy (name + 1, d->d_name);
738 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
740 struct rootdir_entry *re = malloc (sizeof (*re));
741 re->name = name;
742 re->dev = statbuf.st_dev;
743 re->ino = statbuf.st_ino;
745 /* Add to the linked list. */
746 *rootdir_tail = re;
747 rootdir_tail = &re->next;
749 else
750 free (name);
752 closedir (dirp);
754 *rootdir_tail = NULL;
756 for (pos = 0; (dev = next_dev (&pos)) >= 0;)
757 if (fs_stat_dev (dev, &fi) >= 0)
759 /* Note: fi.dev == dev. */
760 struct rootdir_entry *re;
762 for (re = rootdir_list; re; re = re->next)
763 if (re->dev == fi.dev && re->ino == fi.root)
764 break;
766 me = malloc (sizeof (*me));
767 me->me_devname = strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
768 me->me_mountdir = strdup (re != NULL ? re->name : fi.fsh_name);
769 me->me_type = strdup (fi.fsh_name);
770 me->me_type_malloced = 1;
771 me->me_dev = fi.dev;
772 me->me_dummy = 0;
773 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
775 /* Add to the linked list. */
776 *mtail = me;
777 mtail = &me->me_next;
779 *mtail = NULL;
781 while (rootdir_list != NULL)
783 struct rootdir_entry *re = rootdir_list;
784 rootdir_list = re->next;
785 free (re->name);
786 free (re);
789 #endif /* MOUNTED_FS_STAT_DEV */
791 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
793 int numsys, counter;
794 size_t bufsize;
795 struct statfs *stats;
797 numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
798 if (numsys < 0)
799 return NULL;
800 if (SIZE_MAX / sizeof (*stats) <= numsys)
802 fprintf (stderr, "%s\n", _("Memory exhausted!"));
803 exit (EXIT_FAILURE);
806 bufsize = (1 + numsys) * sizeof (*stats);
807 stats = malloc (bufsize);
808 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
810 if (numsys < 0)
812 free (stats);
813 return NULL;
816 for (counter = 0; counter < numsys; counter++)
818 me = malloc (sizeof (*me));
819 me->me_devname = strdup (stats[counter].f_mntfromname);
820 me->me_mountdir = strdup (stats[counter].f_mntonname);
821 me->me_type = strdup (FS_TYPE (stats[counter]));
822 me->me_type_malloced = 1;
823 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
824 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
825 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
827 /* Add to the linked list. */
828 *mtail = me;
829 mtail = &me->me_next;
832 free (stats);
834 #endif /* MOUNTED_GETFSSTAT */
836 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
838 struct mnttab mnt;
839 char *table = "/etc/mnttab";
840 FILE *fp;
842 fp = fopen (table, "r");
843 if (fp == NULL)
844 return NULL;
846 while (fread (&mnt, sizeof (mnt), 1, fp) > 0)
848 me = malloc (sizeof (*me));
849 #ifdef GETFSTYP /* SVR3. */
850 me->me_devname = strdup (mnt.mt_dev);
851 #else
852 me->me_devname = malloc (strlen (mnt.mt_dev) + 6);
853 strcpy (me->me_devname, "/dev/");
854 strcpy (me->me_devname + 5, mnt.mt_dev);
855 #endif
856 me->me_mountdir = strdup (mnt.mt_filsys);
857 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
858 me->me_type = "";
859 me->me_type_malloced = 0;
860 #ifdef GETFSTYP /* SVR3. */
861 if (need_fs_type)
863 struct statfs fsd;
864 char typebuf[FSTYPSZ];
866 if (statfs (me->me_mountdir, &fsd, sizeof (fsd), 0) != -1
867 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
869 me->me_type = strdup (typebuf);
870 me->me_type_malloced = 1;
873 #endif
874 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
875 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
877 /* Add to the linked list. */
878 *mtail = me;
879 mtail = &me->me_next;
882 if (ferror (fp))
884 /* The last fread() call must have failed. */
885 int saved_errno = errno;
886 fclose (fp);
887 errno = saved_errno;
888 goto free_then_fail;
891 if (fclose (fp) == EOF)
892 goto free_then_fail;
894 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
896 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
898 struct mntent **mnttbl = getmnttbl (), **ent;
899 for (ent = mnttbl; *ent; ent++)
901 me = malloc (sizeof (*me));
902 me->me_devname = strdup ((*ent)->mt_resource);
903 me->me_mountdir = strdup ((*ent)->mt_directory);
904 me->me_type = strdup ((*ent)->mt_fstype);
905 me->me_type_malloced = 1;
906 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
907 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
908 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
910 /* Add to the linked list. */
911 *mtail = me;
912 mtail = &me->me_next;
914 endmnttbl ();
916 #endif
918 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
920 struct mnttab mnt;
921 char *table = MNTTAB;
922 FILE *fp;
923 int ret;
924 int lockfd = -1;
926 #if defined F_RDLCK && defined F_SETLKW
927 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
928 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
929 for this file name, we should use their macro name instead.
930 (Why not just lock MNTTAB directly? We don't know.) */
931 #ifndef MNTTAB_LOCK
932 #define MNTTAB_LOCK "/etc/.mnttab.lock"
933 #endif
934 lockfd = open (MNTTAB_LOCK, O_RDONLY);
935 if (0 <= lockfd)
937 struct flock flock;
938 flock.l_type = F_RDLCK;
939 flock.l_whence = SEEK_SET;
940 flock.l_start = 0;
941 flock.l_len = 0;
942 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
943 if (errno != EINTR)
945 int saved_errno = errno;
946 close (lockfd);
947 errno = saved_errno;
948 return NULL;
951 else if (errno != ENOENT)
952 return NULL;
953 #endif
955 errno = 0;
956 fp = fopen (table, "r");
957 if (fp == NULL)
958 ret = errno;
959 else
961 while ((ret = getmntent (fp, &mnt)) == 0)
963 me = malloc (sizeof (*me));
964 me->me_devname = strdup (mnt.mnt_special);
965 me->me_mountdir = strdup (mnt.mnt_mountp);
966 me->me_type = strdup (mnt.mnt_fstype);
967 me->me_type_malloced = 1;
968 me->me_dummy = MNT_IGNORE (&mnt) != 0;
969 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
970 me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
972 /* Add to the linked list. */
973 *mtail = me;
974 mtail = &me->me_next;
977 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
980 if (0 <= lockfd && close (lockfd) != 0)
981 ret = errno;
983 if (0 <= ret)
985 errno = ret;
986 goto free_then_fail;
989 #endif /* MOUNTED_GETMNTENT2. */
991 #ifdef MOUNTED_VMOUNT /* AIX. */
993 int bufsize;
994 char *entries, *thisent;
995 struct vmount *vmp;
996 int n_entries;
997 int i;
999 /* Ask how many bytes to allocate for the mounted file system info. */
1000 if (mntctl (MCTL_QUERY, sizeof (bufsize), (struct vmount *) &bufsize) != 0)
1001 return NULL;
1002 entries = malloc (bufsize);
1004 /* Get the list of mounted file systems. */
1005 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
1006 if (n_entries < 0)
1008 int saved_errno = errno;
1009 free (entries);
1010 errno = saved_errno;
1011 return NULL;
1014 for (i = 0, thisent = entries; i < n_entries; i++, thisent += vmp->vmt_length)
1016 char *options, *ignore;
1018 vmp = (struct vmount *) thisent;
1019 me = malloc (sizeof (*me));
1020 if (vmp->vmt_flags & MNT_REMOTE)
1022 char *host, *dir;
1024 me->me_remote = 1;
1025 /* Prepend the remote dirname. */
1026 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
1027 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
1028 me->me_devname = malloc (strlen (host) + strlen (dir) + 2);
1029 strcpy (me->me_devname, host);
1030 strcat (me->me_devname, ":");
1031 strcat (me->me_devname, dir);
1033 else
1035 me->me_remote = 0;
1036 me->me_devname = strdup (thisent + vmp->vmt_data[VMT_OBJECT].vmt_off);
1038 me->me_mountdir = strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
1039 me->me_type = strdup (fstype_to_string (vmp->vmt_gfstype));
1040 me->me_type_malloced = 1;
1041 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
1042 ignore = strstr (options, "ignore");
1043 me->me_dummy = (ignore
1044 && (ignore == options || ignore[-1] == ',')
1045 && (ignore[sizeof ("ignore") - 1] == ','
1046 || ignore[sizeof ("ignore") - 1] == '\0'));
1047 me->me_dev = (dev_t) (-1); /* vmt_fsid might be the info we want. */
1049 /* Add to the linked list. */
1050 *mtail = me;
1051 mtail = &me->me_next;
1053 free (entries);
1055 #endif /* MOUNTED_VMOUNT. */
1058 #ifdef MOUNTED_INTERIX_STATVFS
1060 DIR *dirp = opendir ("/dev/fs");
1061 char node[9 + NAME_MAX];
1063 if (!dirp)
1064 goto free_then_fail;
1066 while (1)
1068 struct statvfs dev;
1069 struct dirent entry;
1070 struct dirent *result;
1072 if (readdir_r (dirp, &entry, &result) || result == NULL)
1073 break;
1075 strcpy (node, "/dev/fs/");
1076 strcat (node, entry.d_name);
1078 if (statvfs (node, &dev) == 0)
1080 me = malloc (sizeof *me);
1081 me->me_devname = strdup (dev.f_mntfromname);
1082 me->me_mountdir = strdup (dev.f_mntonname);
1083 me->me_type = strdup (dev.f_fstypename);
1084 me->me_type_malloced = 1;
1085 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1086 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1087 me->me_dev = (dev_t) - 1; /* Magic; means not known yet. */
1089 /* Add to the linked list. */
1090 *mtail = me;
1091 mtail = &me->me_next;
1095 #endif /* MOUNTED_INTERIX_STATVFS */
1097 (void) need_fs_type; /* avoid argument-unused warning */
1098 *mtail = NULL;
1099 return mount_list;
1102 free_then_fail:
1104 int saved_errno = errno;
1105 *mtail = NULL;
1107 while (mount_list)
1109 me = mount_list->me_next;
1110 free (mount_list->me_devname);
1111 free (mount_list->me_mountdir);
1112 if (mount_list->me_type_malloced)
1113 free (mount_list->me_type);
1114 free (mount_list);
1115 mount_list = me;
1118 errno = saved_errno;
1119 return NULL;
1123 #endif /* HAVE_INFOMOUNT_LIST */
1125 /* --------------------------------------------------------------------------------------------- */
1127 #ifdef HAVE_INFOMOUNT_QNX
1129 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1130 ** this via the following code.
1131 ** Note that, as this is based on CWD, it only fills one mount_entry
1132 ** structure. See my_statfs() in utilunix.c for the "other side" of
1133 ** this hack.
1136 static struct mount_entry *
1137 read_file_system_list (int need_fs_type, int all_fs)
1139 struct _disk_entry de;
1140 struct statfs fs;
1141 int i, fd;
1142 char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
1144 static struct mount_entry *me = NULL;
1146 if (me)
1148 if (me->me_devname)
1149 free (me->me_devname);
1150 if (me->me_mountdir)
1151 free (me->me_mountdir);
1152 if (me->me_type)
1153 free (me->me_type);
1155 else
1156 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
1158 if (!getcwd (dir, _POSIX_PATH_MAX))
1159 return (NULL);
1161 fd = open (dir, O_RDONLY);
1162 if (fd == -1)
1163 return (NULL);
1165 i = disk_get_entry (fd, &de);
1167 close (fd);
1169 if (i == -1)
1170 return (NULL);
1172 switch (de.disk_type)
1174 case _UNMOUNTED:
1175 tp = "unmounted";
1176 break;
1177 case _FLOPPY:
1178 tp = "Floppy";
1179 break;
1180 case _HARD:
1181 tp = "Hard";
1182 break;
1183 case _RAMDISK:
1184 tp = "Ram";
1185 break;
1186 case _REMOVABLE:
1187 tp = "Removable";
1188 break;
1189 case _TAPE:
1190 tp = "Tape";
1191 break;
1192 case _CDROM:
1193 tp = "CDROM";
1194 break;
1195 default:
1196 tp = "unknown";
1199 if (fsys_get_mount_dev (dir, &dev) == -1)
1200 return (NULL);
1202 if (fsys_get_mount_pt (dev, &dir) == -1)
1203 return (NULL);
1205 me->me_devname = strdup (dev);
1206 me->me_mountdir = strdup (dir);
1207 me->me_type = strdup (tp);
1208 me->me_dev = de.disk_type;
1210 #ifdef DEBUG
1211 fprintf (stderr,
1212 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1213 de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
1214 fprintf (stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
1215 fprintf (stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
1216 #endif /* DEBUG */
1218 return (me);
1220 #endif /* HAVE_INFOMOUNT_QNX */
1222 /* --------------------------------------------------------------------------------------------- */
1224 #ifdef STAT_READ_FILSYS /* SVR2 */
1226 /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
1227 interrupted. Return the actual number of bytes read(written), zero for EOF,
1228 or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */
1229 static size_t
1230 safe_read (int fd, void *buf, size_t count)
1232 /* Work around a bug in Tru64 5.1. Attempting to read more than
1233 INT_MAX bytes fails with errno == EINVAL. See
1234 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
1235 When decreasing COUNT, keep it block-aligned. */
1236 /* *INDENT-OFF* */
1237 enum { BUGGY_READ_MAXIMUM = INT_MAX & ~8191 };
1238 /* *INDENT-ON* */
1240 for (;;)
1242 ssize_t result = read (fd, buf, count);
1244 if (0 <= result)
1245 return result;
1246 else if (IS_EINTR (errno))
1247 continue;
1248 else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count)
1249 count = BUGGY_READ_MAXIMUM;
1250 else
1251 return result;
1255 /* --------------------------------------------------------------------------------------------- */
1257 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1258 interrupted or if a partial write(read) occurs. Return the number
1259 of bytes transferred.
1260 When writing, set errno if fewer than COUNT bytes are written.
1261 When reading, if fewer than COUNT bytes are read, you must examine
1262 errno to distinguish failure from EOF (errno == 0). */
1264 static size_t
1265 full_read (int fd, void *buf, size_t count)
1267 size_t total = 0;
1268 char *ptr = (char *) buf;
1270 while (count > 0)
1272 size_t n_rw = safe_read (fd, ptr, count);
1273 if (n_rw == (size_t) (-1))
1274 break;
1275 if (n_rw == 0)
1277 errno = ZERO_BYTE_TRANSFER_ERRNO;
1278 break;
1280 total += n_rw;
1281 ptr += n_rw;
1282 count -= n_rw;
1285 return total;
1288 #endif /* STAT_READ_FILSYS */
1290 /* --------------------------------------------------------------------------------------------- */
1292 #ifdef HAVE_INFOMOUNT
1293 /* Fill in the fields of FSP with information about space usage for
1294 the file system on which FILE resides.
1295 DISK is the device on which FILE is mounted, for space-getting
1296 methods that need to know it.
1297 Return 0 if successful, -1 if not. When returning -1, ensure that
1298 ERRNO is either a system error value, or zero if DISK is NULL
1299 on a system that requires a non-NULL value. */
1300 static int
1301 get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
1303 #ifdef STAT_STATVFS /* POSIX, except glibc/Linux */
1305 struct statvfs fsd;
1307 if (statvfs (file, &fsd) < 0)
1308 return -1;
1310 /* f_frsize isn't guaranteed to be supported. */
1311 fsp->fsu_blocksize = (fsd.f_frsize
1312 ? PROPAGATE_ALL_ONES (fsd.f_frsize) : PROPAGATE_ALL_ONES (fsd.f_bsize));
1314 #elif defined STAT_STATVFS64 /* AIX */
1316 struct statvfs64 fsd;
1318 if (statvfs64 (file, &fsd) < 0)
1319 return -1;
1321 /* f_frsize isn't guaranteed to be supported. */
1322 fsp->fsu_blocksize = (fsd.f_frsize
1323 ? PROPAGATE_ALL_ONES (fsd.f_frsize) : PROPAGATE_ALL_ONES (fsd.f_bsize));
1325 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1327 struct fs_data fsd;
1329 if (statfs (file, &fsd) != 1)
1330 return -1;
1332 fsp->fsu_blocksize = 1024;
1333 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot);
1334 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree);
1335 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen);
1336 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0;
1337 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
1338 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
1340 #elif defined STAT_READ_FILSYS /* SVR2 */
1341 #ifndef SUPERBOFF
1342 #define SUPERBOFF (SUPERB * 512)
1343 #endif
1345 struct filsys fsd;
1346 int fd;
1348 if (!disk)
1350 errno = 0;
1351 return -1;
1354 fd = open (disk, O_RDONLY);
1355 if (fd < 0)
1356 return -1;
1357 lseek (fd, (off_t) SUPERBOFF, 0);
1358 if (full_read (fd, (char *) &fsd, sizeof (fsd)) != sizeof (fsd))
1360 close (fd);
1361 return -1;
1363 close (fd);
1365 fsp->fsu_blocksize = (fsd.s_type == Fs2b ? 1024 : 512);
1366 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.s_fsize);
1367 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.s_tfree);
1368 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree);
1369 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0;
1370 fsp->fsu_files = (fsd.s_isize == -1
1371 ? UINTMAX_MAX : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1));
1372 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode);
1374 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1376 struct statfs fsd;
1378 if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
1379 return -1;
1381 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1383 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux, 4.3BSD, SunOS 4, \
1384 Mac OS X < 10.4, FreeBSD < 5.0, \
1385 NetBSD < 3.0, OpenBSD < 4.4 */
1387 struct statfs fsd;
1389 if (statfs (file, &fsd) < 0)
1390 return -1;
1392 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1394 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1396 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1397 struct statfs are truncated to 2GB. These conditions detect that
1398 truncation, presumably without botching the 4.1.1 case, in which
1399 the values are not truncated. The correct counts are stored in
1400 undocumented spare fields. */
1401 if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
1403 fsd.f_blocks = fsd.f_spare[0];
1404 fsd.f_bfree = fsd.f_spare[1];
1405 fsd.f_bavail = fsd.f_spare[2];
1407 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1409 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1411 struct statfs fsd;
1413 if (statfs (file, &fsd) < 0)
1414 return -1;
1416 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1418 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1419 Dolphin */
1421 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1422 #define f_bavail f_bfree
1423 #endif
1425 struct statfs fsd;
1427 if (statfs (file, &fsd, sizeof (fsd), 0) < 0)
1428 return -1;
1430 /* Empirically, the block counts on most SVR3 and SVR3-derived
1431 systems seem to always be in terms of 512-byte blocks,
1432 no matter what value f_bsize has. */
1433 #if defined _AIX || defined _CRAY
1434 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1435 #else
1436 fsp->fsu_blocksize = 512;
1437 #endif
1439 #endif
1441 #if (defined STAT_STATVFS || defined STAT_STATVFS64 \
1442 || (!defined STAT_STATFS2_FS_DATA && !defined STAT_READ_FILSYS))
1444 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
1445 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
1446 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
1447 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
1448 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
1449 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
1451 #endif
1453 (void) disk; /* avoid argument-unused warning */
1454 return 0;
1456 #endif /* HAVE_INFOMOUNT */
1458 /* --------------------------------------------------------------------------------------------- */
1459 /*** public functions ****************************************************************************/
1460 /* --------------------------------------------------------------------------------------------- */
1462 void
1463 free_my_statfs (void)
1465 #ifdef HAVE_INFOMOUNT_LIST
1466 while (mc_mount_list != NULL)
1468 struct mount_entry *next;
1470 next = mc_mount_list->me_next;
1471 free_mount_entry (mc_mount_list);
1472 mc_mount_list = next;
1475 mc_mount_list = NULL;
1476 #endif /* HAVE_INFOMOUNT_LIST */
1479 /* --------------------------------------------------------------------------------------------- */
1481 void
1482 init_my_statfs (void)
1484 #ifdef HAVE_INFOMOUNT_LIST
1485 free_my_statfs ();
1486 mc_mount_list = read_file_system_list (1);
1487 #endif /* HAVE_INFOMOUNT_LIST */
1490 /* --------------------------------------------------------------------------------------------- */
1492 void
1493 my_statfs (struct my_statfs *myfs_stats, const char *path)
1495 #ifdef HAVE_INFOMOUNT_LIST
1496 size_t i, len = 0;
1497 struct mount_entry *entry = NULL;
1498 struct mount_entry *temp = mc_mount_list;
1499 struct fs_usage fs_use;
1501 while (temp)
1503 i = strlen (temp->me_mountdir);
1504 if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
1505 if (!entry || (path[i] == PATH_SEP || path[i] == '\0'))
1507 len = i;
1508 entry = temp;
1510 temp = temp->me_next;
1513 if (entry)
1515 memset (&fs_use, 0, sizeof (struct fs_usage));
1516 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1518 myfs_stats->type = entry->me_dev;
1519 myfs_stats->typename = entry->me_type;
1520 myfs_stats->mpoint = entry->me_mountdir;
1521 myfs_stats->device = entry->me_devname;
1522 myfs_stats->avail =
1523 ((uintmax_t) (getuid ()? fs_use.fsu_bavail : fs_use.fsu_bfree) *
1524 fs_use.fsu_blocksize) >> 10;
1525 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1526 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1527 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1529 else
1530 #endif /* HAVE_INFOMOUNT_LIST */
1532 #ifdef HAVE_INFOMOUNT_QNX
1534 ** This is the "other side" of the hack to read_file_system_list() in
1535 ** mountlist.c.
1536 ** It's not the most efficient approach, but consumes less memory. It
1537 ** also accomodates QNX's ability to mount filesystems on the fly.
1539 struct mount_entry *entry;
1540 struct fs_usage fs_use;
1542 entry = read_file_system_list (0, 0);
1543 if (entry != NULL)
1545 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1547 myfs_stats->type = entry->me_dev;
1548 myfs_stats->typename = entry->me_type;
1549 myfs_stats->mpoint = entry->me_mountdir;
1550 myfs_stats->device = entry->me_devname;
1552 myfs_stats->avail = ((uintmax_t) fs_use.fsu_bfree * fs_use.fsu_blocksize) >> 10;
1553 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1554 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1555 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1557 else
1558 #endif /* HAVE_INFOMOUNT_QNX */
1560 myfs_stats->type = 0;
1561 myfs_stats->mpoint = "unknown";
1562 myfs_stats->device = "unknown";
1563 myfs_stats->avail = 0;
1564 myfs_stats->total = 0;
1565 myfs_stats->nfree = 0;
1566 myfs_stats->nodes = 0;
1570 /* --------------------------------------------------------------------------------------------- */