fsusage, mountlist, getloadavg: Remove support for Dynix/ptx.
[gnulib.git] / lib / mountlist.c
blob01ad309f3fee3b43c11765e6defac7de64fba44e
1 /* mountlist.c -- return a list of mounted file systems
3 Copyright (C) 1991-1992, 1997-2018 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 #include <config.h>
20 #include "mountlist.h"
22 #include <limits.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdint.h>
28 #include "xalloc.h"
30 #include <errno.h>
32 #include <fcntl.h>
34 #include <unistd.h>
36 #if HAVE_SYS_PARAM_H
37 # include <sys/param.h>
38 #endif
40 #if MAJOR_IN_MKDEV
41 # include <sys/mkdev.h>
42 #elif MAJOR_IN_SYSMACROS
43 # include <sys/sysmacros.h>
44 #endif
46 #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
47 # if HAVE_SYS_UCRED_H
48 # include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
49 NGROUPS is used as an array dimension in ucred.h */
50 # include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
51 # endif
52 # if HAVE_SYS_MOUNT_H
53 # include <sys/mount.h>
54 # endif
55 # if HAVE_SYS_FS_TYPES_H
56 # include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
57 # endif
58 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
59 # define FS_TYPE(Ent) ((Ent).f_fstypename)
60 # else
61 # define FS_TYPE(Ent) mnt_names[(Ent).f_type]
62 # endif
63 #endif /* MOUNTED_GETFSSTAT */
65 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
66 also (obsolete) 4.3BSD, SunOS */
67 # include <mntent.h>
68 # include <sys/types.h>
69 # if !defined MOUNTED
70 # if defined _PATH_MOUNTED /* GNU libc */
71 # define MOUNTED _PATH_MOUNTED
72 # endif
73 # if defined MNT_MNTTAB /* HP-UX. */
74 # define MOUNTED MNT_MNTTAB
75 # endif
76 # endif
77 #endif
79 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
80 # include <sys/mount.h>
81 #endif
83 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
84 # include <sys/statvfs.h>
85 #endif
87 #ifdef MOUNTED_GETMNT /* (obsolete) Ultrix */
88 # include <sys/mount.h>
89 # include <sys/fs_types.h>
90 #endif
92 #ifdef MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
93 # include <fs_info.h>
94 # include <dirent.h>
95 #endif
97 #ifdef MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
98 # include <mnttab.h>
99 # include <sys/fstyp.h>
100 # include <sys/statfs.h>
101 #endif
103 #ifdef MOUNTED_LISTMNTENT /* (obsolete) Cray UNICOS 9 */
104 # include <mntent.h>
105 #endif
107 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
108 # include <sys/mnttab.h>
109 #endif
111 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
112 # include <sys/mnttab.h>
113 #endif
115 #ifdef MOUNTED_VMOUNT /* AIX */
116 # include <fshelp.h>
117 # include <sys/vfs.h>
118 #endif
120 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
121 # include <sys/statvfs.h>
122 # include <dirent.h>
123 #endif
125 #if HAVE_SYS_MNTENT_H
126 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
127 # include <sys/mntent.h>
128 #endif
130 #ifndef HAVE_HASMNTOPT
131 # define hasmntopt(mnt, opt) ((char *) 0)
132 #endif
134 #undef MNT_IGNORE
135 #ifdef MNTOPT_IGNORE
136 # if defined __sun && defined __SVR4
137 /* Solaris defines hasmntopt(struct mnttab *, char *)
138 while it is otherwise hasmntopt(struct mnttab *, const char *). */
139 # define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
140 # else
141 # define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
142 # endif
143 #else
144 # define MNT_IGNORE(M) 0
145 #endif
147 #if USE_UNLOCKED_IO
148 # include "unlocked-io.h"
149 #endif
151 /* The results of opendir() in this file are not used with dirfd and fchdir,
152 therefore save some unnecessary work in fchdir.c. */
153 #ifdef GNULIB_defined_opendir
154 # undef opendir
155 #endif
156 #ifdef GNULIB_defined_closedir
157 # undef closedir
158 #endif
160 #define ME_DUMMY_0(Fs_name, Fs_type) \
161 (strcmp (Fs_type, "autofs") == 0 \
162 || strcmp (Fs_type, "proc") == 0 \
163 || strcmp (Fs_type, "subfs") == 0 \
164 /* for Linux 2.6/3.x */ \
165 || strcmp (Fs_type, "debugfs") == 0 \
166 || strcmp (Fs_type, "devpts") == 0 \
167 || strcmp (Fs_type, "fusectl") == 0 \
168 || strcmp (Fs_type, "mqueue") == 0 \
169 || strcmp (Fs_type, "rpc_pipefs") == 0 \
170 || strcmp (Fs_type, "sysfs") == 0 \
171 /* FreeBSD, Linux 2.4 */ \
172 || strcmp (Fs_type, "devfs") == 0 \
173 /* for NetBSD 3.0 */ \
174 || strcmp (Fs_type, "kernfs") == 0 \
175 /* for Irix 6.5 */ \
176 || strcmp (Fs_type, "ignore") == 0)
178 /* Historically, we have marked as "dummy" any file system of type "none",
179 but now that programs like du need to know about bind-mounted directories,
180 we grant an exception to any with "bind" in its list of mount options.
181 I.e., those are *not* dummy entries. */
182 #ifdef MOUNTED_GETMNTENT1
183 # define ME_DUMMY(Fs_name, Fs_type, Bind) \
184 (ME_DUMMY_0 (Fs_name, Fs_type) \
185 || (strcmp (Fs_type, "none") == 0 && !Bind))
186 #else
187 # define ME_DUMMY(Fs_name, Fs_type) \
188 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
189 #endif
191 #ifdef __CYGWIN__
192 # include <windows.h>
193 # define ME_REMOTE me_remote
194 /* All cygwin mount points include ':' or start with '//'; so it
195 requires a native Windows call to determine remote disks. */
196 static bool
197 me_remote (char const *fs_name, char const *fs_type _GL_UNUSED)
199 if (fs_name[0] && fs_name[1] == ':')
201 char drive[4];
202 sprintf (drive, "%c:\\", fs_name[0]);
203 switch (GetDriveType (drive))
205 case DRIVE_REMOVABLE:
206 case DRIVE_FIXED:
207 case DRIVE_CDROM:
208 case DRIVE_RAMDISK:
209 return false;
212 return true;
214 #endif
216 #ifndef ME_REMOTE
217 /* A file system is "remote" if its Fs_name contains a ':'
218 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//')
219 or Fs_name is equal to "-hosts" (used by autofs to mount remote fs). */
220 # define ME_REMOTE(Fs_name, Fs_type) \
221 (strchr (Fs_name, ':') != NULL \
222 || ((Fs_name)[0] == '/' \
223 && (Fs_name)[1] == '/' \
224 && (strcmp (Fs_type, "smbfs") == 0 \
225 || strcmp (Fs_type, "cifs") == 0)) \
226 || (strcmp("-hosts", Fs_name) == 0))
227 #endif
229 #if MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
231 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
232 static char *
233 fstype_to_string (short int t)
235 switch (t)
237 # ifdef MOUNT_PC
238 case MOUNT_PC:
239 return "pc";
240 # endif
241 # ifdef MOUNT_MFS
242 case MOUNT_MFS:
243 return "mfs";
244 # endif
245 # ifdef MOUNT_LO
246 case MOUNT_LO:
247 return "lo";
248 # endif
249 # ifdef MOUNT_TFS
250 case MOUNT_TFS:
251 return "tfs";
252 # endif
253 # ifdef MOUNT_TMP
254 case MOUNT_TMP:
255 return "tmp";
256 # endif
257 # ifdef MOUNT_UFS
258 case MOUNT_UFS:
259 return "ufs" ;
260 # endif
261 # ifdef MOUNT_NFS
262 case MOUNT_NFS:
263 return "nfs" ;
264 # endif
265 # ifdef MOUNT_MSDOS
266 case MOUNT_MSDOS:
267 return "msdos" ;
268 # endif
269 # ifdef MOUNT_LFS
270 case MOUNT_LFS:
271 return "lfs" ;
272 # endif
273 # ifdef MOUNT_LOFS
274 case MOUNT_LOFS:
275 return "lofs" ;
276 # endif
277 # ifdef MOUNT_FDESC
278 case MOUNT_FDESC:
279 return "fdesc" ;
280 # endif
281 # ifdef MOUNT_PORTAL
282 case MOUNT_PORTAL:
283 return "portal" ;
284 # endif
285 # ifdef MOUNT_NULL
286 case MOUNT_NULL:
287 return "null" ;
288 # endif
289 # ifdef MOUNT_UMAP
290 case MOUNT_UMAP:
291 return "umap" ;
292 # endif
293 # ifdef MOUNT_KERNFS
294 case MOUNT_KERNFS:
295 return "kernfs" ;
296 # endif
297 # ifdef MOUNT_PROCFS
298 case MOUNT_PROCFS:
299 return "procfs" ;
300 # endif
301 # ifdef MOUNT_AFS
302 case MOUNT_AFS:
303 return "afs" ;
304 # endif
305 # ifdef MOUNT_CD9660
306 case MOUNT_CD9660:
307 return "cd9660" ;
308 # endif
309 # ifdef MOUNT_UNION
310 case MOUNT_UNION:
311 return "union" ;
312 # endif
313 # ifdef MOUNT_DEVFS
314 case MOUNT_DEVFS:
315 return "devfs" ;
316 # endif
317 # ifdef MOUNT_EXT2FS
318 case MOUNT_EXT2FS:
319 return "ext2fs" ;
320 # endif
321 default:
322 return "?";
325 # endif
327 static char *
328 fsp_to_string (const struct statfs *fsp)
330 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
331 return (char *) (fsp->f_fstypename);
332 # else
333 return fstype_to_string (fsp->f_type);
334 # endif
337 #endif /* MOUNTED_GETMNTINFO */
339 #ifdef MOUNTED_VMOUNT /* AIX */
340 static char *
341 fstype_to_string (int t)
343 struct vfs_ent *e;
345 e = getvfsbytype (t);
346 if (!e || !e->vfsent_name)
347 return "none";
348 else
349 return e->vfsent_name;
351 #endif /* MOUNTED_VMOUNT */
354 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
356 /* Return the device number from MOUNT_OPTIONS, if possible.
357 Otherwise return (dev_t) -1. */
358 static dev_t
359 dev_from_mount_options (char const *mount_options)
361 /* GNU/Linux allows file system implementations to define their own
362 meaning for "dev=" mount options, so don't trust the meaning
363 here. */
364 # ifndef __linux__
366 static char const dev_pattern[] = ",dev=";
367 char const *devopt = strstr (mount_options, dev_pattern);
369 if (devopt)
371 char const *optval = devopt + sizeof dev_pattern - 1;
372 char *optvalend;
373 unsigned long int dev;
374 errno = 0;
375 dev = strtoul (optval, &optvalend, 16);
376 if (optval != optvalend
377 && (*optvalend == '\0' || *optvalend == ',')
378 && ! (dev == ULONG_MAX && errno == ERANGE)
379 && dev == (dev_t) dev)
380 return dev;
383 # endif
384 (void) mount_options;
385 return -1;
388 #endif
390 #if defined MOUNTED_GETMNTENT1 && defined __linux__ /* GNU/Linux, Android */
392 /* Unescape the paths in mount tables.
393 STR is updated in place. */
395 static void
396 unescape_tab (char *str)
398 size_t i, j = 0;
399 size_t len = strlen (str) + 1;
400 for (i = 0; i < len; i++)
402 if (str[i] == '\\' && (i + 4 < len)
403 && str[i + 1] >= '0' && str[i + 1] <= '3'
404 && str[i + 2] >= '0' && str[i + 2] <= '7'
405 && str[i + 3] >= '0' && str[i + 3] <= '7')
407 str[j++] = (str[i + 1] - '0') * 64 +
408 (str[i + 2] - '0') * 8 +
409 (str[i + 3] - '0');
410 i += 3;
412 else
413 str[j++] = str[i];
416 #endif
418 /* Return a list of the currently mounted file systems, or NULL on error.
419 Add each entry to the tail of the list so that they stay in order.
420 If NEED_FS_TYPE is true, ensure that the file system type fields in
421 the returned list are valid. Otherwise, they might not be. */
423 struct mount_entry *
424 read_file_system_list (bool need_fs_type)
426 struct mount_entry *mount_list;
427 struct mount_entry *me;
428 struct mount_entry **mtail = &mount_list;
429 (void) need_fs_type;
431 #ifdef MOUNTED_LISTMNTENT /* (obsolete) Cray UNICOS 9 */
433 struct tabmntent *mntlist, *p;
434 struct mntent *mnt;
436 /* the third and fourth arguments could be used to filter mounts,
437 but Crays doesn't seem to have any mounts that we want to
438 remove. Specifically, automount create normal NFS mounts.
441 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
442 return NULL;
443 for (p = mntlist; p; p = p->next)
445 mnt = p->ment;
446 me = xmalloc (sizeof *me);
447 me->me_devname = xstrdup (mnt->mnt_fsname);
448 me->me_mountdir = xstrdup (mnt->mnt_dir);
449 me->me_mntroot = NULL;
450 me->me_type = xstrdup (mnt->mnt_type);
451 me->me_type_malloced = 1;
452 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
453 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
454 me->me_dev = -1;
455 *mtail = me;
456 mtail = &me->me_next;
458 freemntlist (mntlist);
460 #endif
462 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
463 also (obsolete) 4.3BSD, SunOS */
465 FILE *fp;
467 # ifdef __linux__
468 /* Try parsing mountinfo first, as that make device IDs available.
469 Note we could use libmount routines to simplify this parsing a little
470 (and that code is in previous versions of this function), however
471 libmount depends on libselinux which pulls in many dependencies. */
472 char const *mountinfo = "/proc/self/mountinfo";
473 fp = fopen (mountinfo, "r");
474 if (fp != NULL)
476 char *line = NULL;
477 size_t buf_size = 0;
479 while (getline (&line, &buf_size, fp) != -1)
481 unsigned int devmaj, devmin;
482 int target_s, target_e, type_s, type_e;
483 int source_s, source_e, mntroot_s, mntroot_e;
484 char test;
485 char *dash;
486 int rc;
488 rc = sscanf(line, "%*u " /* id - discarded */
489 "%*u " /* parent - discarded */
490 "%u:%u " /* dev major:minor */
491 "%n%*s%n " /* mountroot */
492 "%n%*s%n" /* target, start and end */
493 "%c", /* more data... */
494 &devmaj, &devmin,
495 &mntroot_s, &mntroot_e,
496 &target_s, &target_e,
497 &test);
499 if (rc != 3 && rc != 7) /* 7 if %n included in count. */
500 continue;
502 /* skip optional fields, terminated by " - " */
503 dash = strstr (line + target_e, " - ");
504 if (! dash)
505 continue;
507 rc = sscanf(dash, " - "
508 "%n%*s%n " /* FS type, start and end */
509 "%n%*s%n " /* source, start and end */
510 "%c", /* more data... */
511 &type_s, &type_e,
512 &source_s, &source_e,
513 &test);
514 if (rc != 1 && rc != 5) /* 5 if %n included in count. */
515 continue;
517 /* manipulate the sub-strings in place. */
518 line[mntroot_e] = '\0';
519 line[target_e] = '\0';
520 dash[type_e] = '\0';
521 dash[source_e] = '\0';
522 unescape_tab (dash + source_s);
523 unescape_tab (line + target_s);
524 unescape_tab (line + mntroot_s);
526 me = xmalloc (sizeof *me);
528 me->me_devname = xstrdup (dash + source_s);
529 me->me_mountdir = xstrdup (line + target_s);
530 me->me_mntroot = xstrdup (line + mntroot_s);
531 me->me_type = xstrdup (dash + type_s);
532 me->me_type_malloced = 1;
533 me->me_dev = makedev (devmaj, devmin);
534 /* we pass "false" for the "Bind" option as that's only
535 significant when the Fs_type is "none" which will not be
536 the case when parsing "/proc/self/mountinfo", and only
537 applies for static /etc/mtab files. */
538 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, false);
539 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
541 /* Add to the linked list. */
542 *mtail = me;
543 mtail = &me->me_next;
546 free (line);
548 if (ferror (fp))
550 int saved_errno = errno;
551 fclose (fp);
552 errno = saved_errno;
553 goto free_then_fail;
556 if (fclose (fp) == EOF)
557 goto free_then_fail;
559 else /* fallback to /proc/self/mounts (/etc/mtab). */
560 # endif /* __linux __ */
562 struct mntent *mnt;
563 char const *table = MOUNTED;
565 fp = setmntent (table, "r");
566 if (fp == NULL)
567 return NULL;
569 while ((mnt = getmntent (fp)))
571 bool bind = hasmntopt (mnt, "bind");
573 me = xmalloc (sizeof *me);
574 me->me_devname = xstrdup (mnt->mnt_fsname);
575 me->me_mountdir = xstrdup (mnt->mnt_dir);
576 me->me_mntroot = NULL;
577 me->me_type = xstrdup (mnt->mnt_type);
578 me->me_type_malloced = 1;
579 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, bind);
580 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
581 me->me_dev = dev_from_mount_options (mnt->mnt_opts);
583 /* Add to the linked list. */
584 *mtail = me;
585 mtail = &me->me_next;
588 if (endmntent (fp) == 0)
589 goto free_then_fail;
592 #endif /* MOUNTED_GETMNTENT1. */
594 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
596 struct statfs *fsp;
597 int entries;
599 entries = getmntinfo (&fsp, MNT_NOWAIT);
600 if (entries < 0)
601 return NULL;
602 for (; entries-- > 0; fsp++)
604 char *fs_type = fsp_to_string (fsp);
606 me = xmalloc (sizeof *me);
607 me->me_devname = xstrdup (fsp->f_mntfromname);
608 me->me_mountdir = xstrdup (fsp->f_mntonname);
609 me->me_mntroot = NULL;
610 me->me_type = fs_type;
611 me->me_type_malloced = 0;
612 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
613 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
614 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
616 /* Add to the linked list. */
617 *mtail = me;
618 mtail = &me->me_next;
621 #endif /* MOUNTED_GETMNTINFO */
623 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
625 struct statvfs *fsp;
626 int entries;
628 entries = getmntinfo (&fsp, MNT_NOWAIT);
629 if (entries < 0)
630 return NULL;
631 for (; entries-- > 0; fsp++)
633 me = xmalloc (sizeof *me);
634 me->me_devname = xstrdup (fsp->f_mntfromname);
635 me->me_mountdir = xstrdup (fsp->f_mntonname);
636 me->me_mntroot = NULL;
637 me->me_type = xstrdup (fsp->f_fstypename);
638 me->me_type_malloced = 1;
639 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
640 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
641 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
643 /* Add to the linked list. */
644 *mtail = me;
645 mtail = &me->me_next;
648 #endif /* MOUNTED_GETMNTINFO2 */
650 #ifdef MOUNTED_GETMNT /* (obsolete) Ultrix */
652 int offset = 0;
653 int val;
654 struct fs_data fsd;
656 while (errno = 0,
657 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
658 (char *) 0)))
660 me = xmalloc (sizeof *me);
661 me->me_devname = xstrdup (fsd.fd_req.devname);
662 me->me_mountdir = xstrdup (fsd.fd_req.path);
663 me->me_mntroot = NULL;
664 me->me_type = gt_names[fsd.fd_req.fstype];
665 me->me_type_malloced = 0;
666 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
667 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
668 me->me_dev = fsd.fd_req.dev;
670 /* Add to the linked list. */
671 *mtail = me;
672 mtail = &me->me_next;
674 if (val < 0)
675 goto free_then_fail;
677 #endif /* MOUNTED_GETMNT. */
679 #if defined MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
681 /* The next_dev() and fs_stat_dev() system calls give the list of
682 all file systems, including the information returned by statvfs()
683 (fs type, total blocks, free blocks etc.), but without the mount
684 point. But on BeOS all file systems except / are mounted in the
685 rootfs, directly under /.
686 The directory name of the mount point is often, but not always,
687 identical to the volume name of the device.
688 We therefore get the list of subdirectories of /, and the list
689 of all file systems, and match the two lists. */
691 DIR *dirp;
692 struct rootdir_entry
694 char *name;
695 dev_t dev;
696 ino_t ino;
697 struct rootdir_entry *next;
699 struct rootdir_entry *rootdir_list;
700 struct rootdir_entry **rootdir_tail;
701 int32 pos;
702 dev_t dev;
703 fs_info fi;
705 /* All volumes are mounted in the rootfs, directly under /. */
706 rootdir_list = NULL;
707 rootdir_tail = &rootdir_list;
708 dirp = opendir ("/");
709 if (dirp)
711 struct dirent *d;
713 while ((d = readdir (dirp)) != NULL)
715 char *name;
716 struct stat statbuf;
718 if (strcmp (d->d_name, "..") == 0)
719 continue;
721 if (strcmp (d->d_name, ".") == 0)
722 name = xstrdup ("/");
723 else
725 name = xmalloc (1 + strlen (d->d_name) + 1);
726 name[0] = '/';
727 strcpy (name + 1, d->d_name);
730 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
732 struct rootdir_entry *re = xmalloc (sizeof *re);
733 re->name = name;
734 re->dev = statbuf.st_dev;
735 re->ino = statbuf.st_ino;
737 /* Add to the linked list. */
738 *rootdir_tail = re;
739 rootdir_tail = &re->next;
741 else
742 free (name);
744 closedir (dirp);
746 *rootdir_tail = NULL;
748 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
749 if (fs_stat_dev (dev, &fi) >= 0)
751 /* Note: fi.dev == dev. */
752 struct rootdir_entry *re;
754 for (re = rootdir_list; re; re = re->next)
755 if (re->dev == fi.dev && re->ino == fi.root)
756 break;
758 me = xmalloc (sizeof *me);
759 me->me_devname = xstrdup (fi.device_name[0] != '\0'
760 ? fi.device_name : fi.fsh_name);
761 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
762 me->me_mntroot = NULL;
763 me->me_type = xstrdup (fi.fsh_name);
764 me->me_type_malloced = 1;
765 me->me_dev = fi.dev;
766 me->me_dummy = 0;
767 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
769 /* Add to the linked list. */
770 *mtail = me;
771 mtail = &me->me_next;
773 *mtail = NULL;
775 while (rootdir_list != NULL)
777 struct rootdir_entry *re = rootdir_list;
778 rootdir_list = re->next;
779 free (re->name);
780 free (re);
783 #endif /* MOUNTED_FS_STAT_DEV */
785 #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
787 int numsys, counter;
788 size_t bufsize;
789 struct statfs *stats;
791 numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
792 if (numsys < 0)
793 return NULL;
794 if (SIZE_MAX / sizeof *stats <= numsys)
795 xalloc_die ();
797 bufsize = (1 + numsys) * sizeof *stats;
798 stats = xmalloc (bufsize);
799 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
801 if (numsys < 0)
803 free (stats);
804 return NULL;
807 for (counter = 0; counter < numsys; counter++)
809 me = xmalloc (sizeof *me);
810 me->me_devname = xstrdup (stats[counter].f_mntfromname);
811 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
812 me->me_mntroot = NULL;
813 me->me_type = xstrdup (FS_TYPE (stats[counter]));
814 me->me_type_malloced = 1;
815 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
816 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
817 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
819 /* Add to the linked list. */
820 *mtail = me;
821 mtail = &me->me_next;
824 free (stats);
826 #endif /* MOUNTED_GETFSSTAT */
828 #if defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
830 struct mnttab mnt;
831 char *table = "/etc/mnttab";
832 FILE *fp;
834 fp = fopen (table, "r");
835 if (fp == NULL)
836 return NULL;
838 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
840 me = xmalloc (sizeof *me);
841 me->me_devname = xstrdup (mnt.mt_dev);
842 me->me_mountdir = xstrdup (mnt.mt_filsys);
843 me->me_mntroot = NULL;
844 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
845 me->me_type = "";
846 me->me_type_malloced = 0;
847 if (need_fs_type)
849 struct statfs fsd;
850 char typebuf[FSTYPSZ];
852 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
853 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
855 me->me_type = xstrdup (typebuf);
856 me->me_type_malloced = 1;
859 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
860 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
862 /* Add to the linked list. */
863 *mtail = me;
864 mtail = &me->me_next;
867 if (ferror (fp))
869 /* The last fread() call must have failed. */
870 int saved_errno = errno;
871 fclose (fp);
872 errno = saved_errno;
873 goto free_then_fail;
876 if (fclose (fp) == EOF)
877 goto free_then_fail;
879 #endif /* MOUNTED_FREAD_FSTYP. */
881 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
883 struct extmnttab mnt;
884 const char *table = MNTTAB;
885 FILE *fp;
886 int ret;
888 /* No locking is needed, because the contents of /etc/mnttab is generated
889 by the kernel. */
891 errno = 0;
892 fp = fopen (table, "r");
893 if (fp == NULL)
894 ret = errno;
895 else
897 while ((ret = getextmntent (fp, &mnt, 1)) == 0)
899 me = xmalloc (sizeof *me);
900 me->me_devname = xstrdup (mnt.mnt_special);
901 me->me_mountdir = xstrdup (mnt.mnt_mountp);
902 me->me_mntroot = NULL;
903 me->me_type = xstrdup (mnt.mnt_fstype);
904 me->me_type_malloced = 1;
905 me->me_dummy = MNT_IGNORE (&mnt) != 0;
906 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
907 me->me_dev = makedev (mnt.mnt_major, mnt.mnt_minor);
909 /* Add to the linked list. */
910 *mtail = me;
911 mtail = &me->me_next;
914 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
915 /* Here ret = -1 means success, ret >= 0 means failure. */
918 if (0 <= ret)
920 errno = ret;
921 goto free_then_fail;
924 #endif /* MOUNTED_GETEXTMNTENT */
926 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
928 struct mnttab mnt;
929 const char *table = MNTTAB;
930 FILE *fp;
931 int ret;
932 int lockfd = -1;
934 # if defined F_RDLCK && defined F_SETLKW
935 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
936 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
937 for this file name, we should use their macro name instead.
938 (Why not just lock MNTTAB directly? We don't know.) */
939 # ifndef MNTTAB_LOCK
940 # define MNTTAB_LOCK "/etc/.mnttab.lock"
941 # endif
942 lockfd = open (MNTTAB_LOCK, O_RDONLY);
943 if (0 <= lockfd)
945 struct flock flock;
946 flock.l_type = F_RDLCK;
947 flock.l_whence = SEEK_SET;
948 flock.l_start = 0;
949 flock.l_len = 0;
950 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
951 if (errno != EINTR)
953 int saved_errno = errno;
954 close (lockfd);
955 errno = saved_errno;
956 return NULL;
959 else if (errno != ENOENT)
960 return NULL;
961 # endif
963 errno = 0;
964 fp = fopen (table, "r");
965 if (fp == NULL)
966 ret = errno;
967 else
969 while ((ret = getmntent (fp, &mnt)) == 0)
971 me = xmalloc (sizeof *me);
972 me->me_devname = xstrdup (mnt.mnt_special);
973 me->me_mountdir = xstrdup (mnt.mnt_mountp);
974 me->me_mntroot = NULL;
975 me->me_type = xstrdup (mnt.mnt_fstype);
976 me->me_type_malloced = 1;
977 me->me_dummy = MNT_IGNORE (&mnt) != 0;
978 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
979 me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
981 /* Add to the linked list. */
982 *mtail = me;
983 mtail = &me->me_next;
986 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
987 /* Here ret = -1 means success, ret >= 0 means failure. */
990 if (0 <= lockfd && close (lockfd) != 0)
991 ret = errno;
993 if (0 <= ret)
995 errno = ret;
996 goto free_then_fail;
999 #endif /* MOUNTED_GETMNTENT2. */
1001 #ifdef MOUNTED_VMOUNT /* AIX */
1003 int bufsize;
1004 void *entries;
1005 char *thisent;
1006 struct vmount *vmp;
1007 int n_entries;
1008 int i;
1010 /* Ask how many bytes to allocate for the mounted file system info. */
1011 entries = &bufsize;
1012 if (mntctl (MCTL_QUERY, sizeof bufsize, entries) != 0)
1013 return NULL;
1014 entries = xmalloc (bufsize);
1016 /* Get the list of mounted file systems. */
1017 n_entries = mntctl (MCTL_QUERY, bufsize, entries);
1018 if (n_entries < 0)
1020 int saved_errno = errno;
1021 free (entries);
1022 errno = saved_errno;
1023 return NULL;
1026 for (i = 0, thisent = entries;
1027 i < n_entries;
1028 i++, thisent += vmp->vmt_length)
1030 char *options, *ignore;
1032 vmp = (struct vmount *) thisent;
1033 me = xmalloc (sizeof *me);
1034 if (vmp->vmt_flags & MNT_REMOTE)
1036 char *host, *dir;
1038 me->me_remote = 1;
1039 /* Prepend the remote dirname. */
1040 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
1041 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
1042 me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
1043 strcpy (me->me_devname, host);
1044 strcat (me->me_devname, ":");
1045 strcat (me->me_devname, dir);
1047 else
1049 me->me_remote = 0;
1050 me->me_devname = xstrdup (thisent +
1051 vmp->vmt_data[VMT_OBJECT].vmt_off);
1053 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
1054 me->me_mntroot = NULL;
1055 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
1056 me->me_type_malloced = 1;
1057 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
1058 ignore = strstr (options, "ignore");
1059 me->me_dummy = (ignore
1060 && (ignore == options || ignore[-1] == ',')
1061 && (ignore[sizeof "ignore" - 1] == ','
1062 || ignore[sizeof "ignore" - 1] == '\0'));
1063 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
1065 /* Add to the linked list. */
1066 *mtail = me;
1067 mtail = &me->me_next;
1069 free (entries);
1071 #endif /* MOUNTED_VMOUNT. */
1073 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
1075 DIR *dirp = opendir ("/dev/fs");
1076 char node[9 + NAME_MAX];
1078 if (!dirp)
1079 goto free_then_fail;
1081 while (1)
1083 struct statvfs dev;
1084 struct dirent entry;
1085 struct dirent *result;
1087 /* FIXME: readdir_r is planned to be withdrawn from POSIX and
1088 marked obsolescent in glibc. Use readdir instead. */
1089 if (readdir_r (dirp, &entry, &result) || result == NULL)
1090 break;
1092 strcpy (node, "/dev/fs/");
1093 strcat (node, entry.d_name);
1095 if (statvfs (node, &dev) == 0)
1097 me = xmalloc (sizeof *me);
1098 me->me_devname = xstrdup (dev.f_mntfromname);
1099 me->me_mountdir = xstrdup (dev.f_mntonname);
1100 me->me_mntroot = NULL;
1101 me->me_type = xstrdup (dev.f_fstypename);
1102 me->me_type_malloced = 1;
1103 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1104 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1105 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
1107 /* Add to the linked list. */
1108 *mtail = me;
1109 mtail = &me->me_next;
1112 closedir (dirp);
1114 #endif /* MOUNTED_INTERIX_STATVFS */
1116 *mtail = NULL;
1117 return mount_list;
1120 free_then_fail: _GL_UNUSED_LABEL
1122 int saved_errno = errno;
1123 *mtail = NULL;
1125 while (mount_list)
1127 me = mount_list->me_next;
1128 free_mount_entry (mount_list);
1129 mount_list = me;
1132 errno = saved_errno;
1133 return NULL;
1137 /* Free a mount entry as returned from read_file_system_list (). */
1139 void free_mount_entry (struct mount_entry *me)
1141 free (me->me_devname);
1142 free (me->me_mountdir);
1143 free (me->me_mntroot);
1144 if (me->me_type_malloced)
1145 free (me->me_type);
1146 free (me);