getprogname: Work around program name truncation when possible.
[gnulib.git] / lib / mountlist.c
blobb691f3808093d426dace769a317357ba744d5879
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 and Darwin1.3.x */
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 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
66 # include <mntent.h>
67 # include <sys/types.h>
68 # if !defined MOUNTED
69 # if defined _PATH_MOUNTED /* GNU libc */
70 # define MOUNTED _PATH_MOUNTED
71 # endif
72 # if defined MNT_MNTTAB /* HP-UX. */
73 # define MOUNTED MNT_MNTTAB
74 # endif
75 # if defined MNTTABNAME /* Dynix. */
76 # define MOUNTED MNTTABNAME
77 # endif
78 # endif
79 #endif
81 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
82 # include <sys/mount.h>
83 #endif
85 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
86 # include <sys/statvfs.h>
87 #endif
89 #ifdef MOUNTED_GETMNT /* Ultrix. */
90 # include <sys/mount.h>
91 # include <sys/fs_types.h>
92 #endif
94 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
95 # include <fs_info.h>
96 # include <dirent.h>
97 #endif
99 #ifdef MOUNTED_FREAD /* SVR2. */
100 # include <mnttab.h>
101 #endif
103 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
104 # include <mnttab.h>
105 # include <sys/fstyp.h>
106 # include <sys/statfs.h>
107 #endif
109 #ifdef MOUNTED_LISTMNTENT
110 # include <mntent.h>
111 #endif
113 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
114 # include <sys/mnttab.h>
115 #endif
117 #ifdef MOUNTED_VMOUNT /* AIX. */
118 # include <fshelp.h>
119 # include <sys/vfs.h>
120 #endif
122 #ifdef MOUNTED_INTERIX_STATVFS /* Interix. */
123 # include <sys/statvfs.h>
124 # include <dirent.h>
125 #endif
127 #ifdef DOLPHIN
128 /* So special that it's not worth putting this in autoconf. */
129 # undef MOUNTED_FREAD_FSTYP
130 # define MOUNTED_GETMNTTBL
131 #endif
133 #if HAVE_SYS_MNTENT_H
134 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
135 # include <sys/mntent.h>
136 #endif
138 #ifndef HAVE_HASMNTOPT
139 # define hasmntopt(mnt, opt) ((char *) 0)
140 #endif
142 #undef MNT_IGNORE
143 #ifdef MNTOPT_IGNORE
144 # if defined __sun && defined __SVR4
145 /* Solaris defines hasmntopt(struct mnttab *, char *)
146 while it is otherwise hasmntopt(struct mnttab *, const char *). */
147 # define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
148 # else
149 # define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
150 # endif
151 #else
152 # define MNT_IGNORE(M) 0
153 #endif
155 #if USE_UNLOCKED_IO
156 # include "unlocked-io.h"
157 #endif
159 /* The results of opendir() in this file are not used with dirfd and fchdir,
160 therefore save some unnecessary work in fchdir.c. */
161 #ifdef GNULIB_defined_opendir
162 # undef opendir
163 #endif
164 #ifdef GNULIB_defined_closedir
165 # undef closedir
166 #endif
168 #define ME_DUMMY_0(Fs_name, Fs_type) \
169 (strcmp (Fs_type, "autofs") == 0 \
170 || strcmp (Fs_type, "proc") == 0 \
171 || strcmp (Fs_type, "subfs") == 0 \
172 /* for Linux 2.6/3.x */ \
173 || strcmp (Fs_type, "debugfs") == 0 \
174 || strcmp (Fs_type, "devpts") == 0 \
175 || strcmp (Fs_type, "fusectl") == 0 \
176 || strcmp (Fs_type, "mqueue") == 0 \
177 || strcmp (Fs_type, "rpc_pipefs") == 0 \
178 || strcmp (Fs_type, "sysfs") == 0 \
179 /* FreeBSD, Linux 2.4 */ \
180 || strcmp (Fs_type, "devfs") == 0 \
181 /* for NetBSD 3.0 */ \
182 || strcmp (Fs_type, "kernfs") == 0 \
183 /* for Irix 6.5 */ \
184 || strcmp (Fs_type, "ignore") == 0)
186 /* Historically, we have marked as "dummy" any file system of type "none",
187 but now that programs like du need to know about bind-mounted directories,
188 we grant an exception to any with "bind" in its list of mount options.
189 I.e., those are *not* dummy entries. */
190 #ifdef MOUNTED_GETMNTENT1
191 # define ME_DUMMY(Fs_name, Fs_type, Bind) \
192 (ME_DUMMY_0 (Fs_name, Fs_type) \
193 || (strcmp (Fs_type, "none") == 0 && !Bind))
194 #else
195 # define ME_DUMMY(Fs_name, Fs_type) \
196 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
197 #endif
199 #ifdef __CYGWIN__
200 # include <windows.h>
201 # define ME_REMOTE me_remote
202 /* All cygwin mount points include ':' or start with '//'; so it
203 requires a native Windows call to determine remote disks. */
204 static bool
205 me_remote (char const *fs_name, char const *fs_type _GL_UNUSED)
207 if (fs_name[0] && fs_name[1] == ':')
209 char drive[4];
210 sprintf (drive, "%c:\\", fs_name[0]);
211 switch (GetDriveType (drive))
213 case DRIVE_REMOVABLE:
214 case DRIVE_FIXED:
215 case DRIVE_CDROM:
216 case DRIVE_RAMDISK:
217 return false;
220 return true;
222 #endif
224 #ifndef ME_REMOTE
225 /* A file system is "remote" if its Fs_name contains a ':'
226 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//')
227 or Fs_name is equal to "-hosts" (used by autofs to mount remote fs). */
228 # define ME_REMOTE(Fs_name, Fs_type) \
229 (strchr (Fs_name, ':') != NULL \
230 || ((Fs_name)[0] == '/' \
231 && (Fs_name)[1] == '/' \
232 && (strcmp (Fs_type, "smbfs") == 0 \
233 || strcmp (Fs_type, "cifs") == 0)) \
234 || (strcmp("-hosts", Fs_name) == 0))
235 #endif
237 #if MOUNTED_GETMNTINFO
239 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
240 static char *
241 fstype_to_string (short int t)
243 switch (t)
245 # ifdef MOUNT_PC
246 case MOUNT_PC:
247 return "pc";
248 # endif
249 # ifdef MOUNT_MFS
250 case MOUNT_MFS:
251 return "mfs";
252 # endif
253 # ifdef MOUNT_LO
254 case MOUNT_LO:
255 return "lo";
256 # endif
257 # ifdef MOUNT_TFS
258 case MOUNT_TFS:
259 return "tfs";
260 # endif
261 # ifdef MOUNT_TMP
262 case MOUNT_TMP:
263 return "tmp";
264 # endif
265 # ifdef MOUNT_UFS
266 case MOUNT_UFS:
267 return "ufs" ;
268 # endif
269 # ifdef MOUNT_NFS
270 case MOUNT_NFS:
271 return "nfs" ;
272 # endif
273 # ifdef MOUNT_MSDOS
274 case MOUNT_MSDOS:
275 return "msdos" ;
276 # endif
277 # ifdef MOUNT_LFS
278 case MOUNT_LFS:
279 return "lfs" ;
280 # endif
281 # ifdef MOUNT_LOFS
282 case MOUNT_LOFS:
283 return "lofs" ;
284 # endif
285 # ifdef MOUNT_FDESC
286 case MOUNT_FDESC:
287 return "fdesc" ;
288 # endif
289 # ifdef MOUNT_PORTAL
290 case MOUNT_PORTAL:
291 return "portal" ;
292 # endif
293 # ifdef MOUNT_NULL
294 case MOUNT_NULL:
295 return "null" ;
296 # endif
297 # ifdef MOUNT_UMAP
298 case MOUNT_UMAP:
299 return "umap" ;
300 # endif
301 # ifdef MOUNT_KERNFS
302 case MOUNT_KERNFS:
303 return "kernfs" ;
304 # endif
305 # ifdef MOUNT_PROCFS
306 case MOUNT_PROCFS:
307 return "procfs" ;
308 # endif
309 # ifdef MOUNT_AFS
310 case MOUNT_AFS:
311 return "afs" ;
312 # endif
313 # ifdef MOUNT_CD9660
314 case MOUNT_CD9660:
315 return "cd9660" ;
316 # endif
317 # ifdef MOUNT_UNION
318 case MOUNT_UNION:
319 return "union" ;
320 # endif
321 # ifdef MOUNT_DEVFS
322 case MOUNT_DEVFS:
323 return "devfs" ;
324 # endif
325 # ifdef MOUNT_EXT2FS
326 case MOUNT_EXT2FS:
327 return "ext2fs" ;
328 # endif
329 default:
330 return "?";
333 # endif
335 static char *
336 fsp_to_string (const struct statfs *fsp)
338 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
339 return (char *) (fsp->f_fstypename);
340 # else
341 return fstype_to_string (fsp->f_type);
342 # endif
345 #endif /* MOUNTED_GETMNTINFO */
347 #ifdef MOUNTED_VMOUNT /* AIX. */
348 static char *
349 fstype_to_string (int t)
351 struct vfs_ent *e;
353 e = getvfsbytype (t);
354 if (!e || !e->vfsent_name)
355 return "none";
356 else
357 return e->vfsent_name;
359 #endif /* MOUNTED_VMOUNT */
362 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
364 /* Return the device number from MOUNT_OPTIONS, if possible.
365 Otherwise return (dev_t) -1. */
366 static dev_t
367 dev_from_mount_options (char const *mount_options)
369 /* GNU/Linux allows file system implementations to define their own
370 meaning for "dev=" mount options, so don't trust the meaning
371 here. */
372 # ifndef __linux__
374 static char const dev_pattern[] = ",dev=";
375 char const *devopt = strstr (mount_options, dev_pattern);
377 if (devopt)
379 char const *optval = devopt + sizeof dev_pattern - 1;
380 char *optvalend;
381 unsigned long int dev;
382 errno = 0;
383 dev = strtoul (optval, &optvalend, 16);
384 if (optval != optvalend
385 && (*optvalend == '\0' || *optvalend == ',')
386 && ! (dev == ULONG_MAX && errno == ERANGE)
387 && dev == (dev_t) dev)
388 return dev;
391 # endif
392 (void) mount_options;
393 return -1;
396 #endif
398 #if defined MOUNTED_GETMNTENT1 && defined __linux__
400 /* Unescape the paths in mount tables.
401 STR is updated in place. */
403 static void
404 unescape_tab (char *str)
406 size_t i, j = 0;
407 size_t len = strlen (str) + 1;
408 for (i = 0; i < len; i++)
410 if (str[i] == '\\' && (i + 4 < len)
411 && str[i + 1] >= '0' && str[i + 1] <= '3'
412 && str[i + 2] >= '0' && str[i + 2] <= '7'
413 && str[i + 3] >= '0' && str[i + 3] <= '7')
415 str[j++] = (str[i + 1] - '0') * 64 +
416 (str[i + 2] - '0') * 8 +
417 (str[i + 3] - '0');
418 i += 3;
420 else
421 str[j++] = str[i];
424 #endif
426 /* Return a list of the currently mounted file systems, or NULL on error.
427 Add each entry to the tail of the list so that they stay in order.
428 If NEED_FS_TYPE is true, ensure that the file system type fields in
429 the returned list are valid. Otherwise, they might not be. */
431 struct mount_entry *
432 read_file_system_list (bool need_fs_type)
434 struct mount_entry *mount_list;
435 struct mount_entry *me;
436 struct mount_entry **mtail = &mount_list;
437 (void) need_fs_type;
439 #ifdef MOUNTED_LISTMNTENT
441 struct tabmntent *mntlist, *p;
442 struct mntent *mnt;
444 /* the third and fourth arguments could be used to filter mounts,
445 but Crays doesn't seem to have any mounts that we want to
446 remove. Specifically, automount create normal NFS mounts.
449 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
450 return NULL;
451 for (p = mntlist; p; p = p->next)
453 mnt = p->ment;
454 me = xmalloc (sizeof *me);
455 me->me_devname = xstrdup (mnt->mnt_fsname);
456 me->me_mountdir = xstrdup (mnt->mnt_dir);
457 me->me_mntroot = NULL;
458 me->me_type = xstrdup (mnt->mnt_type);
459 me->me_type_malloced = 1;
460 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
461 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
462 me->me_dev = -1;
463 *mtail = me;
464 mtail = &me->me_next;
466 freemntlist (mntlist);
468 #endif
470 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
472 FILE *fp;
474 #ifdef __linux__
475 /* Try parsing mountinfo first, as that make device IDs available.
476 Note we could use libmount routines to simplify this parsing a little
477 (and that code is in previous versions of this function), however
478 libmount depends on libselinux which pulls in many dependencies. */
479 char const *mountinfo = "/proc/self/mountinfo";
480 fp = fopen (mountinfo, "r");
481 if (fp != NULL)
483 char *line = NULL;
484 size_t buf_size = 0;
486 while (getline (&line, &buf_size, fp) != -1)
488 unsigned int devmaj, devmin;
489 int target_s, target_e, type_s, type_e;
490 int source_s, source_e, mntroot_s, mntroot_e;
491 char test;
492 char *dash;
493 int rc;
495 rc = sscanf(line, "%*u " /* id - discarded */
496 "%*u " /* parent - discarded */
497 "%u:%u " /* dev major:minor */
498 "%n%*s%n " /* mountroot */
499 "%n%*s%n" /* target, start and end */
500 "%c", /* more data... */
501 &devmaj, &devmin,
502 &mntroot_s, &mntroot_e,
503 &target_s, &target_e,
504 &test);
506 if (rc != 3 && rc != 7) /* 7 if %n included in count. */
507 continue;
509 /* skip optional fields, terminated by " - " */
510 dash = strstr (line + target_e, " - ");
511 if (! dash)
512 continue;
514 rc = sscanf(dash, " - "
515 "%n%*s%n " /* FS type, start and end */
516 "%n%*s%n " /* source, start and end */
517 "%c", /* more data... */
518 &type_s, &type_e,
519 &source_s, &source_e,
520 &test);
521 if (rc != 1 && rc != 5) /* 5 if %n included in count. */
522 continue;
524 /* manipulate the sub-strings in place. */
525 line[mntroot_e] = '\0';
526 line[target_e] = '\0';
527 dash[type_e] = '\0';
528 dash[source_e] = '\0';
529 unescape_tab (dash + source_s);
530 unescape_tab (line + target_s);
531 unescape_tab (line + mntroot_s);
533 me = xmalloc (sizeof *me);
535 me->me_devname = xstrdup (dash + source_s);
536 me->me_mountdir = xstrdup (line + target_s);
537 me->me_mntroot = xstrdup (line + mntroot_s);
538 me->me_type = xstrdup (dash + type_s);
539 me->me_type_malloced = 1;
540 me->me_dev = makedev (devmaj, devmin);
541 /* we pass "false" for the "Bind" option as that's only
542 significant when the Fs_type is "none" which will not be
543 the case when parsing "/proc/self/mountinfo", and only
544 applies for static /etc/mtab files. */
545 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, false);
546 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
548 /* Add to the linked list. */
549 *mtail = me;
550 mtail = &me->me_next;
553 free (line);
555 if (ferror (fp))
557 int saved_errno = errno;
558 fclose (fp);
559 errno = saved_errno;
560 goto free_then_fail;
563 if (fclose (fp) == EOF)
564 goto free_then_fail;
566 else /* fallback to /proc/self/mounts (/etc/mtab). */
567 #endif /* __linux __ */
569 struct mntent *mnt;
570 char const *table = MOUNTED;
572 fp = setmntent (table, "r");
573 if (fp == NULL)
574 return NULL;
576 while ((mnt = getmntent (fp)))
578 bool bind = hasmntopt (mnt, "bind");
580 me = xmalloc (sizeof *me);
581 me->me_devname = xstrdup (mnt->mnt_fsname);
582 me->me_mountdir = xstrdup (mnt->mnt_dir);
583 me->me_mntroot = NULL;
584 me->me_type = xstrdup (mnt->mnt_type);
585 me->me_type_malloced = 1;
586 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, bind);
587 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
588 me->me_dev = dev_from_mount_options (mnt->mnt_opts);
590 /* Add to the linked list. */
591 *mtail = me;
592 mtail = &me->me_next;
595 if (endmntent (fp) == 0)
596 goto free_then_fail;
599 #endif /* MOUNTED_GETMNTENT1. */
601 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
603 struct statfs *fsp;
604 int entries;
606 entries = getmntinfo (&fsp, MNT_NOWAIT);
607 if (entries < 0)
608 return NULL;
609 for (; entries-- > 0; fsp++)
611 char *fs_type = fsp_to_string (fsp);
613 me = xmalloc (sizeof *me);
614 me->me_devname = xstrdup (fsp->f_mntfromname);
615 me->me_mountdir = xstrdup (fsp->f_mntonname);
616 me->me_mntroot = NULL;
617 me->me_type = fs_type;
618 me->me_type_malloced = 0;
619 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
620 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
621 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
623 /* Add to the linked list. */
624 *mtail = me;
625 mtail = &me->me_next;
628 #endif /* MOUNTED_GETMNTINFO */
630 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
632 struct statvfs *fsp;
633 int entries;
635 entries = getmntinfo (&fsp, MNT_NOWAIT);
636 if (entries < 0)
637 return NULL;
638 for (; entries-- > 0; fsp++)
640 me = xmalloc (sizeof *me);
641 me->me_devname = xstrdup (fsp->f_mntfromname);
642 me->me_mountdir = xstrdup (fsp->f_mntonname);
643 me->me_mntroot = NULL;
644 me->me_type = xstrdup (fsp->f_fstypename);
645 me->me_type_malloced = 1;
646 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
647 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
648 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
650 /* Add to the linked list. */
651 *mtail = me;
652 mtail = &me->me_next;
655 #endif /* MOUNTED_GETMNTINFO2 */
657 #ifdef MOUNTED_GETMNT /* Ultrix. */
659 int offset = 0;
660 int val;
661 struct fs_data fsd;
663 while (errno = 0,
664 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
665 (char *) 0)))
667 me = xmalloc (sizeof *me);
668 me->me_devname = xstrdup (fsd.fd_req.devname);
669 me->me_mountdir = xstrdup (fsd.fd_req.path);
670 me->me_mntroot = NULL;
671 me->me_type = gt_names[fsd.fd_req.fstype];
672 me->me_type_malloced = 0;
673 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
674 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
675 me->me_dev = fsd.fd_req.dev;
677 /* Add to the linked list. */
678 *mtail = me;
679 mtail = &me->me_next;
681 if (val < 0)
682 goto free_then_fail;
684 #endif /* MOUNTED_GETMNT. */
686 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
688 /* The next_dev() and fs_stat_dev() system calls give the list of
689 all file systems, including the information returned by statvfs()
690 (fs type, total blocks, free blocks etc.), but without the mount
691 point. But on BeOS all file systems except / are mounted in the
692 rootfs, directly under /.
693 The directory name of the mount point is often, but not always,
694 identical to the volume name of the device.
695 We therefore get the list of subdirectories of /, and the list
696 of all file systems, and match the two lists. */
698 DIR *dirp;
699 struct rootdir_entry
701 char *name;
702 dev_t dev;
703 ino_t ino;
704 struct rootdir_entry *next;
706 struct rootdir_entry *rootdir_list;
707 struct rootdir_entry **rootdir_tail;
708 int32 pos;
709 dev_t dev;
710 fs_info fi;
712 /* All volumes are mounted in the rootfs, directly under /. */
713 rootdir_list = NULL;
714 rootdir_tail = &rootdir_list;
715 dirp = opendir ("/");
716 if (dirp)
718 struct dirent *d;
720 while ((d = readdir (dirp)) != NULL)
722 char *name;
723 struct stat statbuf;
725 if (strcmp (d->d_name, "..") == 0)
726 continue;
728 if (strcmp (d->d_name, ".") == 0)
729 name = xstrdup ("/");
730 else
732 name = xmalloc (1 + strlen (d->d_name) + 1);
733 name[0] = '/';
734 strcpy (name + 1, d->d_name);
737 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
739 struct rootdir_entry *re = xmalloc (sizeof *re);
740 re->name = name;
741 re->dev = statbuf.st_dev;
742 re->ino = statbuf.st_ino;
744 /* Add to the linked list. */
745 *rootdir_tail = re;
746 rootdir_tail = &re->next;
748 else
749 free (name);
751 closedir (dirp);
753 *rootdir_tail = NULL;
755 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
756 if (fs_stat_dev (dev, &fi) >= 0)
758 /* Note: fi.dev == dev. */
759 struct rootdir_entry *re;
761 for (re = rootdir_list; re; re = re->next)
762 if (re->dev == fi.dev && re->ino == fi.root)
763 break;
765 me = xmalloc (sizeof *me);
766 me->me_devname = xstrdup (fi.device_name[0] != '\0'
767 ? fi.device_name : fi.fsh_name);
768 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
769 me->me_mntroot = NULL;
770 me->me_type = xstrdup (fi.fsh_name);
771 me->me_type_malloced = 1;
772 me->me_dev = fi.dev;
773 me->me_dummy = 0;
774 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
776 /* Add to the linked list. */
777 *mtail = me;
778 mtail = &me->me_next;
780 *mtail = NULL;
782 while (rootdir_list != NULL)
784 struct rootdir_entry *re = rootdir_list;
785 rootdir_list = re->next;
786 free (re->name);
787 free (re);
790 #endif /* MOUNTED_FS_STAT_DEV */
792 #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
794 int numsys, counter;
795 size_t bufsize;
796 struct statfs *stats;
798 numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
799 if (numsys < 0)
800 return NULL;
801 if (SIZE_MAX / sizeof *stats <= numsys)
802 xalloc_die ();
804 bufsize = (1 + numsys) * sizeof *stats;
805 stats = xmalloc (bufsize);
806 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
808 if (numsys < 0)
810 free (stats);
811 return NULL;
814 for (counter = 0; counter < numsys; counter++)
816 me = xmalloc (sizeof *me);
817 me->me_devname = xstrdup (stats[counter].f_mntfromname);
818 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
819 me->me_mntroot = NULL;
820 me->me_type = xstrdup (FS_TYPE (stats[counter]));
821 me->me_type_malloced = 1;
822 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
823 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
824 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
826 /* Add to the linked list. */
827 *mtail = me;
828 mtail = &me->me_next;
831 free (stats);
833 #endif /* MOUNTED_GETFSSTAT */
835 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
837 struct mnttab mnt;
838 char *table = "/etc/mnttab";
839 FILE *fp;
841 fp = fopen (table, "r");
842 if (fp == NULL)
843 return NULL;
845 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
847 me = xmalloc (sizeof *me);
848 # ifdef GETFSTYP /* SVR3. */
849 me->me_devname = xstrdup (mnt.mt_dev);
850 # else
851 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
852 strcpy (me->me_devname, "/dev/");
853 strcpy (me->me_devname + 5, mnt.mt_dev);
854 # endif
855 me->me_mountdir = xstrdup (mnt.mt_filsys);
856 me->me_mntroot = NULL;
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 = xstrdup (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 = xmalloc (sizeof *me);
902 me->me_devname = xstrdup ((*ent)->mt_resource);
903 me->me_mountdir = xstrdup ((*ent)->mt_directory);
904 me->me_mntroot = NULL;
905 me->me_type = xstrdup ((*ent)->mt_fstype);
906 me->me_type_malloced = 1;
907 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
908 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
909 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
911 /* Add to the linked list. */
912 *mtail = me;
913 mtail = &me->me_next;
915 endmnttbl ();
917 #endif
919 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
921 struct mnttab mnt;
922 char *table = MNTTAB;
923 FILE *fp;
924 int ret;
925 int lockfd = -1;
927 # if defined F_RDLCK && defined F_SETLKW
928 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
929 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
930 for this file name, we should use their macro name instead.
931 (Why not just lock MNTTAB directly? We don't know.) */
932 # ifndef MNTTAB_LOCK
933 # define MNTTAB_LOCK "/etc/.mnttab.lock"
934 # endif
935 lockfd = open (MNTTAB_LOCK, O_RDONLY);
936 if (0 <= lockfd)
938 struct flock flock;
939 flock.l_type = F_RDLCK;
940 flock.l_whence = SEEK_SET;
941 flock.l_start = 0;
942 flock.l_len = 0;
943 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
944 if (errno != EINTR)
946 int saved_errno = errno;
947 close (lockfd);
948 errno = saved_errno;
949 return NULL;
952 else if (errno != ENOENT)
953 return NULL;
954 # endif
956 errno = 0;
957 fp = fopen (table, "r");
958 if (fp == NULL)
959 ret = errno;
960 else
962 while ((ret = getmntent (fp, &mnt)) == 0)
964 me = xmalloc (sizeof *me);
965 me->me_devname = xstrdup (mnt.mnt_special);
966 me->me_mountdir = xstrdup (mnt.mnt_mountp);
967 me->me_mntroot = NULL;
968 me->me_type = xstrdup (mnt.mnt_fstype);
969 me->me_type_malloced = 1;
970 me->me_dummy = MNT_IGNORE (&mnt) != 0;
971 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
972 me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
974 /* Add to the linked list. */
975 *mtail = me;
976 mtail = &me->me_next;
979 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
982 if (0 <= lockfd && close (lockfd) != 0)
983 ret = errno;
985 if (0 <= ret)
987 errno = ret;
988 goto free_then_fail;
991 #endif /* MOUNTED_GETMNTENT2. */
993 #ifdef MOUNTED_VMOUNT /* AIX. */
995 int bufsize;
996 void *entries;
997 char *thisent;
998 struct vmount *vmp;
999 int n_entries;
1000 int i;
1002 /* Ask how many bytes to allocate for the mounted file system info. */
1003 entries = &bufsize;
1004 if (mntctl (MCTL_QUERY, sizeof bufsize, entries) != 0)
1005 return NULL;
1006 entries = xmalloc (bufsize);
1008 /* Get the list of mounted file systems. */
1009 n_entries = mntctl (MCTL_QUERY, bufsize, entries);
1010 if (n_entries < 0)
1012 int saved_errno = errno;
1013 free (entries);
1014 errno = saved_errno;
1015 return NULL;
1018 for (i = 0, thisent = entries;
1019 i < n_entries;
1020 i++, thisent += vmp->vmt_length)
1022 char *options, *ignore;
1024 vmp = (struct vmount *) thisent;
1025 me = xmalloc (sizeof *me);
1026 if (vmp->vmt_flags & MNT_REMOTE)
1028 char *host, *dir;
1030 me->me_remote = 1;
1031 /* Prepend the remote dirname. */
1032 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
1033 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
1034 me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
1035 strcpy (me->me_devname, host);
1036 strcat (me->me_devname, ":");
1037 strcat (me->me_devname, dir);
1039 else
1041 me->me_remote = 0;
1042 me->me_devname = xstrdup (thisent +
1043 vmp->vmt_data[VMT_OBJECT].vmt_off);
1045 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
1046 me->me_mntroot = NULL;
1047 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
1048 me->me_type_malloced = 1;
1049 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
1050 ignore = strstr (options, "ignore");
1051 me->me_dummy = (ignore
1052 && (ignore == options || ignore[-1] == ',')
1053 && (ignore[sizeof "ignore" - 1] == ','
1054 || ignore[sizeof "ignore" - 1] == '\0'));
1055 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
1057 /* Add to the linked list. */
1058 *mtail = me;
1059 mtail = &me->me_next;
1061 free (entries);
1063 #endif /* MOUNTED_VMOUNT. */
1065 #ifdef MOUNTED_INTERIX_STATVFS
1067 DIR *dirp = opendir ("/dev/fs");
1068 char node[9 + NAME_MAX];
1070 if (!dirp)
1071 goto free_then_fail;
1073 while (1)
1075 struct statvfs dev;
1076 struct dirent entry;
1077 struct dirent *result;
1079 /* FIXME: readdir_r is planned to be withdrawn from POSIX and
1080 marked obsolescent in glibc. Use readdir instead. */
1081 if (readdir_r (dirp, &entry, &result) || result == NULL)
1082 break;
1084 strcpy (node, "/dev/fs/");
1085 strcat (node, entry.d_name);
1087 if (statvfs (node, &dev) == 0)
1089 me = xmalloc (sizeof *me);
1090 me->me_devname = xstrdup (dev.f_mntfromname);
1091 me->me_mountdir = xstrdup (dev.f_mntonname);
1092 me->me_mntroot = NULL;
1093 me->me_type = xstrdup (dev.f_fstypename);
1094 me->me_type_malloced = 1;
1095 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1096 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1097 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
1099 /* Add to the linked list. */
1100 *mtail = me;
1101 mtail = &me->me_next;
1104 closedir (dirp);
1106 #endif /* MOUNTED_INTERIX_STATVFS */
1108 *mtail = NULL;
1109 return mount_list;
1112 free_then_fail: _GL_UNUSED_LABEL
1114 int saved_errno = errno;
1115 *mtail = NULL;
1117 while (mount_list)
1119 me = mount_list->me_next;
1120 free_mount_entry (mount_list);
1121 mount_list = me;
1124 errno = saved_errno;
1125 return NULL;
1129 /* Free a mount entry as returned from read_file_system_list (). */
1131 void free_mount_entry (struct mount_entry *me)
1133 free (me->me_devname);
1134 free (me->me_mountdir);
1135 free (me->me_mntroot);
1136 if (me->me_type_malloced)
1137 free (me->me_type);
1138 free (me);