1 /* mountlist.c -- return a list of mounted file systems
2 
3    Copyright (C) 1991-1992, 1997-2015 Free Software Foundation, Inc.
4 
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.
9 
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.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17 
18 #include <config.h>
19 
20 #include "mountlist.h"
21 
22 #include <limits.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdint.h>
27 
28 #include "xalloc.h"
29 
30 #include <errno.h>
31 
32 #include <fcntl.h>
33 
34 #include <unistd.h>
35 
36 #if HAVE_SYS_PARAM_H
37 # include <sys/param.h>
38 #endif
39 
40 #if defined MOUNTED_GETFSSTAT   /* OSF_1 and Darwin1.3.x */
41 # if HAVE_SYS_UCRED_H
42 #  include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
43                       NGROUPS is used as an array dimension in ucred.h */
44 #  include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
45 # endif
46 # if HAVE_SYS_MOUNT_H
47 #  include <sys/mount.h>
48 # endif
49 # if HAVE_SYS_FS_TYPES_H
50 #  include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
51 # endif
52 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
53 #  define FS_TYPE(Ent) ((Ent).f_fstypename)
54 # else
55 #  define FS_TYPE(Ent) mnt_names[(Ent).f_type]
56 # endif
57 #endif /* MOUNTED_GETFSSTAT */
58 
59 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
60 # include <mntent.h>
61 # if !defined MOUNTED
62 #  if defined _PATH_MOUNTED     /* GNU libc  */
63 #   define MOUNTED _PATH_MOUNTED
64 #  endif
65 #  if defined MNT_MNTTAB        /* HP-UX.  */
66 #   define MOUNTED MNT_MNTTAB
67 #  endif
68 #  if defined MNTTABNAME        /* Dynix.  */
69 #   define MOUNTED MNTTABNAME
70 #  endif
71 # endif
72 #endif
73 
74 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
75 # include <sys/mount.h>
76 #endif
77 
78 #ifdef MOUNTED_GETMNTINFO2      /* NetBSD 3.0.  */
79 # include <sys/statvfs.h>
80 #endif
81 
82 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
83 # include <sys/mount.h>
84 # include <sys/fs_types.h>
85 #endif
86 
87 #ifdef MOUNTED_FS_STAT_DEV      /* BeOS.  */
88 # include <fs_info.h>
89 # include <dirent.h>
90 #endif
91 
92 #ifdef MOUNTED_FREAD            /* SVR2.  */
93 # include <mnttab.h>
94 #endif
95 
96 #ifdef MOUNTED_FREAD_FSTYP      /* SVR3.  */
97 # include <mnttab.h>
98 # include <sys/fstyp.h>
99 # include <sys/statfs.h>
100 #endif
101 
102 #ifdef MOUNTED_LISTMNTENT
103 # include <mntent.h>
104 #endif
105 
106 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
107 # include <sys/mnttab.h>
108 #endif
109 
110 #ifdef MOUNTED_VMOUNT           /* AIX.  */
111 # include <fshelp.h>
112 # include <sys/vfs.h>
113 #endif
114 
115 #ifdef MOUNTED_INTERIX_STATVFS  /* Interix. */
116 # include <sys/statvfs.h>
117 # include <dirent.h>
118 #endif
119 
120 #ifdef DOLPHIN
121 /* So special that it's not worth putting this in autoconf.  */
122 # undef MOUNTED_FREAD_FSTYP
123 # define MOUNTED_GETMNTTBL
124 #endif
125 
126 #if HAVE_SYS_MNTENT_H
127 /* This is to get MNTOPT_IGNORE on e.g. SVR4.  */
128 # include <sys/mntent.h>
129 #endif
130 
131 #ifdef MOUNTED_PROC_MOUNTINFO
132 /* Use /proc/self/mountinfo instead of /proc/self/mounts (/etc/mtab)
133  * on Linux, if available */
134 # include <libmount/libmount.h>
135 #endif
136 
137 #ifndef HAVE_HASMNTOPT
138 # define hasmntopt(mnt, opt) ((char *) 0)
139 #endif
140 
141 #undef MNT_IGNORE
142 #ifdef MNTOPT_IGNORE
143 # if defined __sun && defined __SVR4
144 /* Solaris defines hasmntopt(struct mnttab *, char *)
145    while it is otherwise hasmntopt(struct mnttab *, const char *).  */
146 #  define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
147 # else
148 #  define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
149 # endif
150 #else
151 # define MNT_IGNORE(M) 0
152 #endif
153 
154 #if USE_UNLOCKED_IO
155 # include "unlocked-io.h"
156 #endif
157 
158 /* The results of opendir() in this file are not used with dirfd and fchdir,
159    therefore save some unnecessary work in fchdir.c.  */
160 #ifdef GNULIB_defined_opendir
161 # undef opendir
162 #endif
163 #ifdef GNULIB_defined_closedir
164 # undef closedir
165 #endif
166 
167 #define ME_DUMMY_0(Fs_name, Fs_type)            \
168   (strcmp (Fs_type, "autofs") == 0              \
169    || strcmp (Fs_type, "proc") == 0             \
170    || strcmp (Fs_type, "subfs") == 0            \
171    /* for Linux 2.6/3.x */                      \
172    || strcmp (Fs_type, "debugfs") == 0          \
173    || strcmp (Fs_type, "devpts") == 0           \
174    || strcmp (Fs_type, "fusectl") == 0          \
175    || strcmp (Fs_type, "mqueue") == 0           \
176    || strcmp (Fs_type, "rpc_pipefs") == 0       \
177    || strcmp (Fs_type, "sysfs") == 0            \
178    /* FreeBSD, Linux 2.4 */                     \
179    || strcmp (Fs_type, "devfs") == 0            \
180    /* for NetBSD 3.0 */                         \
181    || strcmp (Fs_type, "kernfs") == 0           \
182    /* for Irix 6.5 */                           \
183    || strcmp (Fs_type, "ignore") == 0)
184 
185 /* Historically, we have marked as "dummy" any file system of type "none",
186    but now that programs like du need to know about bind-mounted directories,
187    we grant an exception to any with "bind" in its list of mount options.
188    I.e., those are *not* dummy entries.  */
189 #ifdef MOUNTED_GETMNTENT1
190 # define ME_DUMMY(Fs_name, Fs_type, Bind)	\
191   (ME_DUMMY_0 (Fs_name, Fs_type)		\
192    || (strcmp (Fs_type, "none") == 0 && !Bind))
193 #else
194 # define ME_DUMMY(Fs_name, Fs_type)		\
195   (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
196 #endif
197 
198 #ifdef __CYGWIN__
199 # include <windows.h>
200 # define ME_REMOTE me_remote
201 /* All cygwin mount points include ':' or start with '//'; so it
202    requires a native Windows call to determine remote disks.  */
203 static bool
me_remote(char const * fs_name,char const * fs_type _GL_UNUSED)204 me_remote (char const *fs_name, char const *fs_type _GL_UNUSED)
205 {
206   if (fs_name[0] && fs_name[1] == ':')
207     {
208       char drive[4];
209       sprintf (drive, "%c:\\", fs_name[0]);
210       switch (GetDriveType (drive))
211         {
212         case DRIVE_REMOVABLE:
213         case DRIVE_FIXED:
214         case DRIVE_CDROM:
215         case DRIVE_RAMDISK:
216           return false;
217         }
218     }
219   return true;
220 }
221 #endif
222 
223 #ifndef ME_REMOTE
224 /* A file system is "remote" if its Fs_name contains a ':'
225    or if (it is of type (smbfs or cifs) and its Fs_name starts with '//').  */
226 # define ME_REMOTE(Fs_name, Fs_type)            \
227     (strchr (Fs_name, ':') != NULL              \
228      || ((Fs_name)[0] == '/'                    \
229          && (Fs_name)[1] == '/'                 \
230          && (strcmp (Fs_type, "smbfs") == 0     \
231              || strcmp (Fs_type, "cifs") == 0)))
232 #endif
233 
234 #if MOUNTED_GETMNTINFO
235 
236 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
237 static char *
fstype_to_string(short int t)238 fstype_to_string (short int t)
239 {
240   switch (t)
241     {
242 #  ifdef MOUNT_PC
243     case MOUNT_PC:
244       return "pc";
245 #  endif
246 #  ifdef MOUNT_MFS
247     case MOUNT_MFS:
248       return "mfs";
249 #  endif
250 #  ifdef MOUNT_LO
251     case MOUNT_LO:
252       return "lo";
253 #  endif
254 #  ifdef MOUNT_TFS
255     case MOUNT_TFS:
256       return "tfs";
257 #  endif
258 #  ifdef MOUNT_TMP
259     case MOUNT_TMP:
260       return "tmp";
261 #  endif
262 #  ifdef MOUNT_UFS
263    case MOUNT_UFS:
264      return "ufs" ;
265 #  endif
266 #  ifdef MOUNT_NFS
267    case MOUNT_NFS:
268      return "nfs" ;
269 #  endif
270 #  ifdef MOUNT_MSDOS
271    case MOUNT_MSDOS:
272      return "msdos" ;
273 #  endif
274 #  ifdef MOUNT_LFS
275    case MOUNT_LFS:
276      return "lfs" ;
277 #  endif
278 #  ifdef MOUNT_LOFS
279    case MOUNT_LOFS:
280      return "lofs" ;
281 #  endif
282 #  ifdef MOUNT_FDESC
283    case MOUNT_FDESC:
284      return "fdesc" ;
285 #  endif
286 #  ifdef MOUNT_PORTAL
287    case MOUNT_PORTAL:
288      return "portal" ;
289 #  endif
290 #  ifdef MOUNT_NULL
291    case MOUNT_NULL:
292      return "null" ;
293 #  endif
294 #  ifdef MOUNT_UMAP
295    case MOUNT_UMAP:
296      return "umap" ;
297 #  endif
298 #  ifdef MOUNT_KERNFS
299    case MOUNT_KERNFS:
300      return "kernfs" ;
301 #  endif
302 #  ifdef MOUNT_PROCFS
303    case MOUNT_PROCFS:
304      return "procfs" ;
305 #  endif
306 #  ifdef MOUNT_AFS
307    case MOUNT_AFS:
308      return "afs" ;
309 #  endif
310 #  ifdef MOUNT_CD9660
311    case MOUNT_CD9660:
312      return "cd9660" ;
313 #  endif
314 #  ifdef MOUNT_UNION
315    case MOUNT_UNION:
316      return "union" ;
317 #  endif
318 #  ifdef MOUNT_DEVFS
319    case MOUNT_DEVFS:
320      return "devfs" ;
321 #  endif
322 #  ifdef MOUNT_EXT2FS
323    case MOUNT_EXT2FS:
324      return "ext2fs" ;
325 #  endif
326     default:
327       return "?";
328     }
329 }
330 # endif
331 
332 static char *
fsp_to_string(const struct statfs * fsp)333 fsp_to_string (const struct statfs *fsp)
334 {
335 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
336   return (char *) (fsp->f_fstypename);
337 # else
338   return fstype_to_string (fsp->f_type);
339 # endif
340 }
341 
342 #endif /* MOUNTED_GETMNTINFO */
343 
344 #ifdef MOUNTED_VMOUNT           /* AIX.  */
345 static char *
fstype_to_string(int t)346 fstype_to_string (int t)
347 {
348   struct vfs_ent *e;
349 
350   e = getvfsbytype (t);
351   if (!e || !e->vfsent_name)
352     return "none";
353   else
354     return e->vfsent_name;
355 }
356 #endif /* MOUNTED_VMOUNT */
357 
358 
359 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
360 
361 /* Return the device number from MOUNT_OPTIONS, if possible.
362    Otherwise return (dev_t) -1.  */
363 static dev_t
dev_from_mount_options(char const * mount_options)364 dev_from_mount_options (char const *mount_options)
365 {
366   /* GNU/Linux allows file system implementations to define their own
367      meaning for "dev=" mount options, so don't trust the meaning
368      here.  */
369 # ifndef __linux__
370 
371   static char const dev_pattern[] = ",dev=";
372   char const *devopt = strstr (mount_options, dev_pattern);
373 
374   if (devopt)
375     {
376       char const *optval = devopt + sizeof dev_pattern - 1;
377       char *optvalend;
378       unsigned long int dev;
379       errno = 0;
380       dev = strtoul (optval, &optvalend, 16);
381       if (optval != optvalend
382           && (*optvalend == '\0' || *optvalend == ',')
383           && ! (dev == ULONG_MAX && errno == ERANGE)
384           && dev == (dev_t) dev)
385         return dev;
386     }
387 
388 # endif
389   (void) mount_options;
390   return -1;
391 }
392 
393 #endif
394 
395 /* Return a list of the currently mounted file systems, or NULL on error.
396    Add each entry to the tail of the list so that they stay in order.
397    If NEED_FS_TYPE is true, ensure that the file system type fields in
398    the returned list are valid.  Otherwise, they might not be.  */
399 
400 struct mount_entry *
read_file_system_list(bool need_fs_type)401 read_file_system_list (bool need_fs_type)
402 {
403   struct mount_entry *mount_list;
404   struct mount_entry *me;
405   struct mount_entry **mtail = &mount_list;
406   (void) need_fs_type;
407 
408 #ifdef MOUNTED_LISTMNTENT
409   {
410     struct tabmntent *mntlist, *p;
411     struct mntent *mnt;
412     struct mount_entry *me;
413 
414     /* the third and fourth arguments could be used to filter mounts,
415        but Crays doesn't seem to have any mounts that we want to
416        remove. Specifically, automount create normal NFS mounts.
417        */
418 
419     if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
420       return NULL;
421     for (p = mntlist; p; p = p->next)
422       {
423         mnt = p->ment;
424         me = xmalloc (sizeof *me);
425         me->me_devname = xstrdup (mnt->mnt_fsname);
426         me->me_mountdir = xstrdup (mnt->mnt_dir);
427         me->me_type = xstrdup (mnt->mnt_type);
428         me->me_type_malloced = 1;
429         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
430         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
431         me->me_dev = -1;
432         *mtail = me;
433         mtail = &me->me_next;
434       }
435     freemntlist (mntlist);
436   }
437 #endif
438 
439 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
440   {
441 #ifdef MOUNTED_PROC_MOUNTINFO
442     struct libmnt_table *fstable = NULL;
443 
444     fstable = mnt_new_table_from_file ("/proc/self/mountinfo");
445 
446     if (fstable != NULL)
447       {
448         struct libmnt_fs *fs;
449         struct libmnt_iter *iter;
450 
451         iter = mnt_new_iter (MNT_ITER_FORWARD);
452 
453         while (iter && mnt_table_next_fs (fstable, iter, &fs) == 0)
454           {
455             me = xmalloc (sizeof *me);
456 
457             me->me_devname = xstrdup (mnt_fs_get_source (fs));
458             me->me_mountdir = xstrdup (mnt_fs_get_target (fs));
459             me->me_type = xstrdup (mnt_fs_get_fstype (fs));
460             me->me_type_malloced = 1;
461             me->me_dev = mnt_fs_get_devno (fs);
462             /* Note we don't use mnt_fs_is_pseudofs() or mnt_fs_is_netfs() here
463                as libmount's classification is non-compatible currently.
464                Also we pass "false" for the "Bind" option as that's only
465                significant when the Fs_type is "none" which will not be
466                the case when parsing "/proc/self/mountinfo", and only
467                applies for static /etc/mtab files.  */
468             me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, false);
469             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
470 
471             /* Add to the linked list. */
472             *mtail = me;
473             mtail = &me->me_next;
474           }
475 
476         mnt_free_iter (iter);
477         mnt_free_table (fstable);
478       }
479     else /* fallback to /proc/self/mounts (/etc/mtab) if anything failed */
480 #endif /* MOUNTED_PROC_MOUNTINFO */
481       {
482         FILE * fp;
483         struct mntent *mnt;
484         char const *table = MOUNTED;
485 
486         fp = setmntent (table, "r");
487         if (fp == NULL)
488           return NULL;
489 
490         while ((mnt = getmntent (fp)))
491           {
492             bool bind = hasmntopt (mnt, "bind");
493 
494             me = xmalloc (sizeof *me);
495             me->me_devname = xstrdup (mnt->mnt_fsname);
496             me->me_mountdir = xstrdup (mnt->mnt_dir);
497             me->me_type = xstrdup (mnt->mnt_type);
498             me->me_type_malloced = 1;
499             me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, bind);
500             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
501             me->me_dev = dev_from_mount_options (mnt->mnt_opts);
502 
503             /* Add to the linked list. */
504             *mtail = me;
505             mtail = &me->me_next;
506           }
507 
508         if (endmntent (fp) == 0)
509           goto free_then_fail;
510       }
511   }
512 #endif /* MOUNTED_GETMNTENT1. */
513 
514 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
515   {
516     struct statfs *fsp;
517     int entries;
518 
519     entries = getmntinfo (&fsp, MNT_NOWAIT);
520     if (entries < 0)
521       return NULL;
522     for (; entries-- > 0; fsp++)
523       {
524         char *fs_type = fsp_to_string (fsp);
525 
526         me = xmalloc (sizeof *me);
527         me->me_devname = xstrdup (fsp->f_mntfromname);
528         me->me_mountdir = xstrdup (fsp->f_mntonname);
529         me->me_type = fs_type;
530         me->me_type_malloced = 0;
531         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
532         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
533         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
534 
535         /* Add to the linked list. */
536         *mtail = me;
537         mtail = &me->me_next;
538       }
539   }
540 #endif /* MOUNTED_GETMNTINFO */
541 
542 #ifdef MOUNTED_GETMNTINFO2      /* NetBSD 3.0.  */
543   {
544     struct statvfs *fsp;
545     int entries;
546 
547     entries = getmntinfo (&fsp, MNT_NOWAIT);
548     if (entries < 0)
549       return NULL;
550     for (; entries-- > 0; fsp++)
551       {
552         me = xmalloc (sizeof *me);
553         me->me_devname = xstrdup (fsp->f_mntfromname);
554         me->me_mountdir = xstrdup (fsp->f_mntonname);
555         me->me_type = xstrdup (fsp->f_fstypename);
556         me->me_type_malloced = 1;
557         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
558         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
559         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
560 
561         /* Add to the linked list. */
562         *mtail = me;
563         mtail = &me->me_next;
564       }
565   }
566 #endif /* MOUNTED_GETMNTINFO2 */
567 
568 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
569   {
570     int offset = 0;
571     int val;
572     struct fs_data fsd;
573 
574     while (errno = 0,
575            0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
576                               (char *) 0)))
577       {
578         me = xmalloc (sizeof *me);
579         me->me_devname = xstrdup (fsd.fd_req.devname);
580         me->me_mountdir = xstrdup (fsd.fd_req.path);
581         me->me_type = gt_names[fsd.fd_req.fstype];
582         me->me_type_malloced = 0;
583         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
584         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
585         me->me_dev = fsd.fd_req.dev;
586 
587         /* Add to the linked list. */
588         *mtail = me;
589         mtail = &me->me_next;
590       }
591     if (val < 0)
592       goto free_then_fail;
593   }
594 #endif /* MOUNTED_GETMNT. */
595 
596 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
597   {
598     /* The next_dev() and fs_stat_dev() system calls give the list of
599        all file systems, including the information returned by statvfs()
600        (fs type, total blocks, free blocks etc.), but without the mount
601        point. But on BeOS all file systems except / are mounted in the
602        rootfs, directly under /.
603        The directory name of the mount point is often, but not always,
604        identical to the volume name of the device.
605        We therefore get the list of subdirectories of /, and the list
606        of all file systems, and match the two lists.  */
607 
608     DIR *dirp;
609     struct rootdir_entry
610       {
611         char *name;
612         dev_t dev;
613         ino_t ino;
614         struct rootdir_entry *next;
615       };
616     struct rootdir_entry *rootdir_list;
617     struct rootdir_entry **rootdir_tail;
618     int32 pos;
619     dev_t dev;
620     fs_info fi;
621 
622     /* All volumes are mounted in the rootfs, directly under /. */
623     rootdir_list = NULL;
624     rootdir_tail = &rootdir_list;
625     dirp = opendir ("/");
626     if (dirp)
627       {
628         struct dirent *d;
629 
630         while ((d = readdir (dirp)) != NULL)
631           {
632             char *name;
633             struct stat statbuf;
634 
635             if (strcmp (d->d_name, "..") == 0)
636               continue;
637 
638             if (strcmp (d->d_name, ".") == 0)
639               name = xstrdup ("/");
640             else
641               {
642                 name = xmalloc (1 + strlen (d->d_name) + 1);
643                 name[0] = '/';
644                 strcpy (name + 1, d->d_name);
645               }
646 
647             if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
648               {
649                 struct rootdir_entry *re = xmalloc (sizeof *re);
650                 re->name = name;
651                 re->dev = statbuf.st_dev;
652                 re->ino = statbuf.st_ino;
653 
654                 /* Add to the linked list.  */
655                 *rootdir_tail = re;
656                 rootdir_tail = &re->next;
657               }
658             else
659               free (name);
660           }
661         closedir (dirp);
662       }
663     *rootdir_tail = NULL;
664 
665     for (pos = 0; (dev = next_dev (&pos)) >= 0; )
666       if (fs_stat_dev (dev, &fi) >= 0)
667         {
668           /* Note: fi.dev == dev. */
669           struct rootdir_entry *re;
670 
671           for (re = rootdir_list; re; re = re->next)
672             if (re->dev == fi.dev && re->ino == fi.root)
673               break;
674 
675           me = xmalloc (sizeof *me);
676           me->me_devname = xstrdup (fi.device_name[0] != '\0'
677                                     ? fi.device_name : fi.fsh_name);
678           me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
679           me->me_type = xstrdup (fi.fsh_name);
680           me->me_type_malloced = 1;
681           me->me_dev = fi.dev;
682           me->me_dummy = 0;
683           me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
684 
685           /* Add to the linked list. */
686           *mtail = me;
687           mtail = &me->me_next;
688         }
689     *mtail = NULL;
690 
691     while (rootdir_list != NULL)
692       {
693         struct rootdir_entry *re = rootdir_list;
694         rootdir_list = re->next;
695         free (re->name);
696         free (re);
697       }
698   }
699 #endif /* MOUNTED_FS_STAT_DEV */
700 
701 #if defined MOUNTED_GETFSSTAT   /* __alpha running OSF_1 */
702   {
703     int numsys, counter;
704     size_t bufsize;
705     struct statfs *stats;
706 
707     numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
708     if (numsys < 0)
709       return NULL;
710     if (SIZE_MAX / sizeof *stats <= numsys)
711       xalloc_die ();
712 
713     bufsize = (1 + numsys) * sizeof *stats;
714     stats = xmalloc (bufsize);
715     numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
716 
717     if (numsys < 0)
718       {
719         free (stats);
720         return NULL;
721       }
722 
723     for (counter = 0; counter < numsys; counter++)
724       {
725         me = xmalloc (sizeof *me);
726         me->me_devname = xstrdup (stats[counter].f_mntfromname);
727         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
728         me->me_type = xstrdup (FS_TYPE (stats[counter]));
729         me->me_type_malloced = 1;
730         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
731         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
732         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
733 
734         /* Add to the linked list. */
735         *mtail = me;
736         mtail = &me->me_next;
737       }
738 
739     free (stats);
740   }
741 #endif /* MOUNTED_GETFSSTAT */
742 
743 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23].  */
744   {
745     struct mnttab mnt;
746     char *table = "/etc/mnttab";
747     FILE *fp;
748 
749     fp = fopen (table, "r");
750     if (fp == NULL)
751       return NULL;
752 
753     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
754       {
755         me = xmalloc (sizeof *me);
756 # ifdef GETFSTYP                        /* SVR3.  */
757         me->me_devname = xstrdup (mnt.mt_dev);
758 # else
759         me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
760         strcpy (me->me_devname, "/dev/");
761         strcpy (me->me_devname + 5, mnt.mt_dev);
762 # endif
763         me->me_mountdir = xstrdup (mnt.mt_filsys);
764         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
765         me->me_type = "";
766         me->me_type_malloced = 0;
767 # ifdef GETFSTYP                        /* SVR3.  */
768         if (need_fs_type)
769           {
770             struct statfs fsd;
771             char typebuf[FSTYPSZ];
772 
773             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
774                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
775               {
776                 me->me_type = xstrdup (typebuf);
777                 me->me_type_malloced = 1;
778               }
779           }
780 # endif
781         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
782         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
783 
784         /* Add to the linked list. */
785         *mtail = me;
786         mtail = &me->me_next;
787       }
788 
789     if (ferror (fp))
790       {
791         /* The last fread() call must have failed.  */
792         int saved_errno = errno;
793         fclose (fp);
794         errno = saved_errno;
795         goto free_then_fail;
796       }
797 
798     if (fclose (fp) == EOF)
799       goto free_then_fail;
800   }
801 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
802 
803 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes its own way.  */
804   {
805     struct mntent **mnttbl = getmnttbl (), **ent;
806     for (ent = mnttbl; *ent; ent++)
807       {
808         me = xmalloc (sizeof *me);
809         me->me_devname = xstrdup ((*ent)->mt_resource);
810         me->me_mountdir = xstrdup ((*ent)->mt_directory);
811         me->me_type = xstrdup ((*ent)->mt_fstype);
812         me->me_type_malloced = 1;
813         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
814         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
815         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
816 
817         /* Add to the linked list. */
818         *mtail = me;
819         mtail = &me->me_next;
820       }
821     endmnttbl ();
822   }
823 #endif
824 
825 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
826   {
827     struct mnttab mnt;
828     char *table = MNTTAB;
829     FILE *fp;
830     int ret;
831     int lockfd = -1;
832 
833 # if defined F_RDLCK && defined F_SETLKW
834     /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
835        e.g. Solaris 2.6.  If the SVR4 folks ever define a macro
836        for this file name, we should use their macro name instead.
837        (Why not just lock MNTTAB directly?  We don't know.)  */
838 #  ifndef MNTTAB_LOCK
839 #   define MNTTAB_LOCK "/etc/.mnttab.lock"
840 #  endif
841     lockfd = open (MNTTAB_LOCK, O_RDONLY);
842     if (0 <= lockfd)
843       {
844         struct flock flock;
845         flock.l_type = F_RDLCK;
846         flock.l_whence = SEEK_SET;
847         flock.l_start = 0;
848         flock.l_len = 0;
849         while (fcntl (lockfd, F_SETLKW, &flock) == -1)
850           if (errno != EINTR)
851             {
852               int saved_errno = errno;
853               close (lockfd);
854               errno = saved_errno;
855               return NULL;
856             }
857       }
858     else if (errno != ENOENT)
859       return NULL;
860 # endif
861 
862     errno = 0;
863     fp = fopen (table, "r");
864     if (fp == NULL)
865       ret = errno;
866     else
867       {
868         while ((ret = getmntent (fp, &mnt)) == 0)
869           {
870             me = xmalloc (sizeof *me);
871             me->me_devname = xstrdup (mnt.mnt_special);
872             me->me_mountdir = xstrdup (mnt.mnt_mountp);
873             me->me_type = xstrdup (mnt.mnt_fstype);
874             me->me_type_malloced = 1;
875             me->me_dummy = MNT_IGNORE (&mnt) != 0;
876             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
877             me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
878 
879             /* Add to the linked list. */
880             *mtail = me;
881             mtail = &me->me_next;
882           }
883 
884         ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
885       }
886 
887     if (0 <= lockfd && close (lockfd) != 0)
888       ret = errno;
889 
890     if (0 <= ret)
891       {
892         errno = ret;
893         goto free_then_fail;
894       }
895   }
896 #endif /* MOUNTED_GETMNTENT2.  */
897 
898 #ifdef MOUNTED_VMOUNT           /* AIX.  */
899   {
900     int bufsize;
901     char *entries, *thisent;
902     struct vmount *vmp;
903     int n_entries;
904     int i;
905 
906     /* Ask how many bytes to allocate for the mounted file system info.  */
907     if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
908       return NULL;
909     entries = xmalloc (bufsize);
910 
911     /* Get the list of mounted file systems.  */
912     n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
913     if (n_entries < 0)
914       {
915         int saved_errno = errno;
916         free (entries);
917         errno = saved_errno;
918         return NULL;
919       }
920 
921     for (i = 0, thisent = entries;
922          i < n_entries;
923          i++, thisent += vmp->vmt_length)
924       {
925         char *options, *ignore;
926 
927         vmp = (struct vmount *) thisent;
928         me = xmalloc (sizeof *me);
929         if (vmp->vmt_flags & MNT_REMOTE)
930           {
931             char *host, *dir;
932 
933             me->me_remote = 1;
934             /* Prepend the remote dirname.  */
935             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
936             dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
937             me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
938             strcpy (me->me_devname, host);
939             strcat (me->me_devname, ":");
940             strcat (me->me_devname, dir);
941           }
942         else
943           {
944             me->me_remote = 0;
945             me->me_devname = xstrdup (thisent +
946                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
947           }
948         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
949         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
950         me->me_type_malloced = 1;
951         options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
952         ignore = strstr (options, "ignore");
953         me->me_dummy = (ignore
954                         && (ignore == options || ignore[-1] == ',')
955                         && (ignore[sizeof "ignore" - 1] == ','
956                             || ignore[sizeof "ignore" - 1] == '\0'));
957         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
958 
959         /* Add to the linked list. */
960         *mtail = me;
961         mtail = &me->me_next;
962       }
963     free (entries);
964   }
965 #endif /* MOUNTED_VMOUNT. */
966 
967 #ifdef MOUNTED_INTERIX_STATVFS
968   {
969     DIR *dirp = opendir ("/dev/fs");
970     char node[9 + NAME_MAX];
971 
972     if (!dirp)
973       goto free_then_fail;
974 
975     while (1)
976       {
977         struct statvfs dev;
978         struct dirent entry;
979         struct dirent *result;
980 
981         if (readdir_r (dirp, &entry, &result) || result == NULL)
982           break;
983 
984         strcpy (node, "/dev/fs/");
985         strcat (node, entry.d_name);
986 
987         if (statvfs (node, &dev) == 0)
988           {
989             me = xmalloc (sizeof *me);
990             me->me_devname = xstrdup (dev.f_mntfromname);
991             me->me_mountdir = xstrdup (dev.f_mntonname);
992             me->me_type = xstrdup (dev.f_fstypename);
993             me->me_type_malloced = 1;
994             me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
995             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
996             me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
997 
998             /* Add to the linked list. */
999             *mtail = me;
1000             mtail = &me->me_next;
1001           }
1002       }
1003     closedir (dirp);
1004   }
1005 #endif /* MOUNTED_INTERIX_STATVFS */
1006 
1007   *mtail = NULL;
1008   return mount_list;
1009 
1010 
1011  free_then_fail:
1012   {
1013     int saved_errno = errno;
1014     *mtail = NULL;
1015 
1016     while (mount_list)
1017       {
1018         me = mount_list->me_next;
1019         free_mount_entry (mount_list);
1020         mount_list = me;
1021       }
1022 
1023     errno = saved_errno;
1024     return NULL;
1025   }
1026 }
1027 
1028 /* Free a mount entry as returned from read_file_system_list ().  */
1029 
free_mount_entry(struct mount_entry * me)1030 void free_mount_entry (struct mount_entry *me)
1031 {
1032   free (me->me_devname);
1033   free (me->me_mountdir);
1034   if (me->me_type_malloced)
1035     free (me->me_type);
1036   free (me);
1037 }
1038