1 /* vim:expandtab:ts=2 sw=2:
2 */
3 /* mountlist.c -- return a list of mounted file systems
4 
5    Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
6    2004, 2005, 2006, 2007 Free Software Foundation, Inc.
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2, or (at your option)
11    any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 // This file is not used on some platforms, so don't do anything for them
23 #if(!(defined(__WIN32__)||defined(WIN32)))&&(!defined(__amigaos4__))&&(!defined(__AROS__))&&(!defined(__MORPHOS__))&&(!defined(__amigaos__))
24 
25 // We don't use autoconf and all that in grafx2, so let's do the config here ...
26 #if defined(__macosx__) || defined(__FreeBSD__) || defined(__OpenBSD__)                       // MacOS X is POSIX compliant
27     #define MOUNTED_GETMNTINFO
28 #if defined(__macosx__) || defined(__FreeBSD__)
29     #include <sys/types.h>
30 #endif
31 #if defined(__OpenBSD__)
32     #define HAVE_STRUCT_STATFS_F_FSTYPENAME 1
33     #include <sys/param.h> /* types.h needs this */
34     #include <sys/types.h>
35 #endif
36 #elif defined(__NetBSD__)
37     #define MOUNTED_GETMNTINFO2
38 #elif defined(__BEOS__) || defined(__HAIKU__)
39     #define MOUNTED_FS_STAT_DEV
40 #elif defined(__TRU64__)
41     #define MOUNTED_GETFSSTAT 1
42     #define HAVE_SYS_MOUNT_H 1
43     #include <sys/types.h>
44 #elif defined(__SKYOS__)||defined(__ANDROID__)
45     #warning "Your platform is missing some specific code here ! please check and fix :)"
46 #elif defined(__SWITCH__)
47     // Nothing much to do
48 #else
49     #define MOUNTED_GETMNTENT1
50 #endif
51 
52 // --- END GRAFX2 CUSTOM CONFIG ---
53 
54 #include "mountlist.h"
55 
56 #include <limits.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 
61 #include <errno.h>
62 
63 #include <fcntl.h>
64 
65 #ifndef _MSC_VER
66 #include <unistd.h>
67 #endif
68 
69 #if HAVE_SYS_PARAM_H
70 # include <sys/param.h>
71 #endif
72 
73 #if defined MOUNTED_GETFSSTAT        /* OSF_1 and Darwin1.3.x */
74 # if HAVE_SYS_UCRED_H
75 #  include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
76                       NGROUPS is used as an array dimension in ucred.h */
77 #  include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
78 # endif
79 # if HAVE_SYS_MOUNT_H
80 #  include <sys/mount.h>
81 # endif
82 # if HAVE_SYS_FS_TYPES_H
83 #  include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
84 # endif
85 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
86 #  define FS_TYPE(Ent) ((Ent).f_fstypename)
87 # else
88 #  define FS_TYPE(Ent) mnt_names[(Ent).f_type]
89 # endif
90 #endif /* MOUNTED_GETFSSTAT */
91 
92 #ifdef MOUNTED_GETMNTENT1        /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
93 # include <mntent.h>
94 # if !defined MOUNTED
95 #  if defined _PATH_MOUNTED        /* GNU libc  */
96 #   define MOUNTED _PATH_MOUNTED
97 #  endif
98 #  if defined MNT_MNTTAB        /* HP-UX.  */
99 #   define MOUNTED MNT_MNTTAB
100 #  endif
101 #  if defined MNTTABNAME        /* Dynix.  */
102 #   define MOUNTED MNTTABNAME
103 #  endif
104 # endif
105 #endif
106 
107 #ifdef MOUNTED_GETMNTINFO        /* 4.4BSD.  */
108 # include <sys/mount.h>
109 #endif
110 
111 #ifdef MOUNTED_GETMNTINFO2        /* NetBSD 3.0.  */
112 # include <sys/statvfs.h>
113 #endif
114 
115 #ifdef MOUNTED_GETMNT                /* Ultrix.  */
116 # include <sys/mount.h>
117 # include <sys/fs_types.h>
118 #endif
119 
120 #ifdef MOUNTED_FS_STAT_DEV        /* BeOS.  */
121 # include <fs_info.h>
122 # include <dirent.h>
123 #endif
124 
125 #ifdef MOUNTED_FREAD                /* SVR2.  */
126 # include <mnttab.h>
127 #endif
128 
129 #ifdef MOUNTED_FREAD_FSTYP        /* SVR3.  */
130 # include <mnttab.h>
131 # include <sys/fstyp.h>
132 # include <sys/statfs.h>
133 #endif
134 
135 #ifdef MOUNTED_LISTMNTENT
136 # include <mntent.h>
137 #endif
138 
139 #ifdef MOUNTED_GETMNTENT2        /* SVR4.  */
140 # include <sys/mnttab.h>
141 #endif
142 
143 #ifdef MOUNTED_VMOUNT                /* AIX.  */
144 # include <fshelp.h>
145 # include <sys/vfs.h>
146 #endif
147 
148 #ifdef DOLPHIN
149 /* So special that it's not worth putting this in autoconf.  */
150 # undef MOUNTED_FREAD_FSTYP
151 # define MOUNTED_GETMNTTBL
152 #endif
153 
154 #if HAVE_SYS_MNTENT_H
155 /* This is to get MNTOPT_IGNORE on e.g. SVR4.  */
156 # include <sys/mntent.h>
157 #endif
158 
159 #undef MNT_IGNORE
160 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
161 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
162 #else
163 # define MNT_IGNORE(M) 0
164 #endif
165 
166 #if USE_UNLOCKED_IO
167 # include "unlocked-io.h"
168 #endif
169 
170 #ifndef SIZE_MAX
171 # define SIZE_MAX ((size_t) -1)
172 #endif
173 
174 /* The results of open() in this file are not used with fchdir,
175    therefore save some unnecessary work in fchdir.c.  */
176 #undef open
177 #undef close
178 
179 /* The results of opendir() in this file are not used with dirfd and fchdir,
180    therefore save some unnecessary work in fchdir.c.  */
181 #undef opendir
182 #undef closedir
183 
184 // gcc2 under haiku and beos don't like these macros for some reason.
185 // As they are not used there anyways, we remove them and everyone is happy.
186 #if !defined(__HAIKU__) && !defined(__BEOS__)
187 #ifndef ME_DUMMY
188 # define ME_DUMMY(Fs_name, Fs_type)                \
189     (strcmp (Fs_type, "autofs") == 0            \
190      || strcmp (Fs_type, "none") == 0           \
191      || strcmp (Fs_type, "proc") == 0           \
192      || strcmp (Fs_type, "subfs") == 0          \
193      || strcmp (Fs_type, "sysfs") == 0          \
194      || strcmp (Fs_type, "usbfs") == 0          \
195      || strcmp (Fs_type, "devpts") == 0         \
196      || strcmp (Fs_type, "tmpfs") == 0          \
197      /* for NetBSD 3.0 */                       \
198      || strcmp (Fs_type, "kernfs") == 0         \
199      /* for Irix 6.5 */                         \
200      || strcmp (Fs_type, "ignore") == 0         \
201      /* for MacOSX */                           \
202      || strcmp (Fs_type, "devfs") == 0          \
203      || strcmp (Fs_type, "fdesc") == 0          \
204      || strcmp (Fs_type, "nfs") == 0            \
205      || strcmp (Fs_type, "volfs") == 0)
206 #endif
207 
208 #ifndef ME_REMOTE
209 /* A file system is `remote' if its Fs_name contains a `:'
210    or if (it is of type (smbfs or cifs) and its Fs_name starts with `//').  */
211 # define ME_REMOTE(Fs_name, Fs_type)                \
212     (strchr (Fs_name, ':') != NULL                \
213      || ((Fs_name)[0] == '/'                        \
214          && (Fs_name)[1] == '/'                        \
215          && (strcmp (Fs_type, "smbfs") == 0        \
216              || strcmp (Fs_type, "cifs") == 0)))
217 #endif
218 #endif // HAIKU / BEOS
219 
220 #ifdef MOUNTED_VMOUNT                /* AIX.  */
221 static char *
fstype_to_string(int t)222 fstype_to_string (int t)
223 {
224   struct vfs_ent *e;
225 
226   e = getvfsbytype (t);
227   if (!e || !e->vfsent_name)
228     return "none";
229   else
230     return e->vfsent_name;
231 }
232 #endif /* MOUNTED_VMOUNT */
233 
234 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
235 
236 /* Return the device number from MOUNT_OPTIONS, if possible.
237    Otherwise return (dev_t) -1.  */
238 
239 static dev_t
dev_from_mount_options(char const * mount_options)240 dev_from_mount_options (char const *mount_options)
241 {
242   /* GNU/Linux allows file system implementations to define their own
243      meaning for "dev=" mount options, so don't trust the meaning
244      here.  */
245 # ifndef __linux__
246   static char const dev_pattern[] = ",dev=";
247   char const *devopt = strstr (mount_options, dev_pattern);
248 
249   if (devopt)
250     {
251       char const *optval = devopt + sizeof dev_pattern - 1;
252       char *optvalend;
253       unsigned long int dev;
254       errno = 0;
255       dev = strtoul (optval, &optvalend, 16);
256       if (optval != optvalend
257           && (*optvalend == '\0' || *optvalend == ',')
258           && ! (dev == ULONG_MAX && errno == ERANGE)
259           && dev == (dev_t) dev)
260         return dev;
261     }
262 #else
263   (void)mount_options; // unused
264 # endif
265 
266   return -1;
267 }
268 
269 #endif
270 
271 /* Return a list of the currently mounted file systems, or NULL on error.
272    Add each entry to the tail of the list so that they stay in order.
273    If NEED_FS_TYPE is true, ensure that the file system type fields in
274    the returned list are valid.  Otherwise, they might not be.  */
275 
276 struct mount_entry *
read_file_system_list(bool need_fs_type)277 read_file_system_list (bool need_fs_type)
278 {
279   struct mount_entry *mount_list;
280   struct mount_entry *me;
281   struct mount_entry **mtail = &mount_list;
282   (void)need_fs_type; // may be unused
283 
284 #if defined(__SWITCH__)
285   (void)me; // unused on switch
286 #endif
287 
288 #ifdef MOUNTED_LISTMNTENT
289   {
290     struct tabmntent *mntlist, *p;
291     struct mntent *mnt;
292     struct mount_entry *me;
293 
294     /* the third and fourth arguments could be used to filter mounts,
295        but Crays doesn't seem to have any mounts that we want to
296        remove. Specifically, automount create normal NFS mounts.
297        */
298 
299     if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
300       return NULL;
301     for (p = mntlist; p; p = p->next) {
302       mnt = p->ment;
303       me = xmalloc (sizeof *me);
304       me->me_devname = xstrdup (mnt->mnt_fsname);
305       me->me_mountdir = xstrdup (mnt->mnt_dir);
306       me->me_type = xstrdup (mnt->mnt_type);
307       me->me_type_malloced = 1;
308       me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
309       me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
310       me->me_dev = -1;
311       *mtail = me;
312       mtail = &me->me_next;
313     }
314     freemntlist (mntlist);
315   }
316 #endif
317 
318 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
319   {
320     struct mntent *mnt;
321     char *table = MOUNTED;
322     FILE *fp;
323 
324     fp = setmntent (table, "r");
325     if (fp == NULL)
326       return NULL;
327 
328     while ((mnt = getmntent (fp)))
329       {
330         me = malloc (sizeof *me);
331         me->me_devname = strdup (mnt->mnt_fsname);
332         me->me_mountdir = strdup (mnt->mnt_dir);
333         me->me_type = strdup (mnt->mnt_type);
334         me->me_type_malloced = 1;
335         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
336         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
337         me->me_dev = dev_from_mount_options (mnt->mnt_opts);
338 
339         /* Add to the linked list. */
340         *mtail = me;
341         mtail = &me->me_next;
342       }
343 
344     if (endmntent (fp) == 0)
345       goto free_then_fail;
346   }
347 #endif /* MOUNTED_GETMNTENT1. */
348 
349 #ifdef MOUNTED_GETMNTINFO        /* 4.4BSD.  */
350   {
351     struct statfs *fsp;
352     int entries;
353 
354     entries = getmntinfo (&fsp, MNT_NOWAIT);
355     if (entries < 0)
356       return NULL;
357     for (; entries-- > 0; fsp++)
358       {
359         me = malloc (sizeof *me);
360         me->me_devname = strdup (fsp->f_mntfromname);
361         me->me_mountdir = strdup (fsp->f_mntonname);
362 #if defined(__macosx__) || defined(__OpenBSD__) || defined(__FreeBSD__)
363         me->me_type = fsp->f_fstypename;
364 #else
365         me->me_type = fsp->fs_typename;
366 #endif
367         me->me_type_malloced = 0;
368         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
369         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
370         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
371 
372         /* Add to the linked list. */
373         *mtail = me;
374         mtail = &me->me_next;
375       }
376   }
377 #endif /* MOUNTED_GETMNTINFO */
378 
379 #ifdef MOUNTED_GETMNTINFO2        /* NetBSD 3.0.  */
380   {
381     struct statvfs *fsp;
382     int entries;
383 
384     entries = getmntinfo (&fsp, MNT_NOWAIT);
385     if (entries < 0)
386       return NULL;
387     for (; entries-- > 0; fsp++)
388       {
389         me = malloc (sizeof *me);
390         me->me_devname = strdup (fsp->f_mntfromname);
391         me->me_mountdir = strdup (fsp->f_mntonname);
392         me->me_type = strdup (fsp->f_fstypename);
393         me->me_type_malloced = 1;
394         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
395         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
396         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
397 
398         /* Add to the linked list. */
399         *mtail = me;
400         mtail = &me->me_next;
401       }
402   }
403 #endif /* MOUNTED_GETMNTINFO2 */
404 
405 #ifdef MOUNTED_GETMNT                /* Ultrix.  */
406   {
407     int offset = 0;
408     int val;
409     struct fs_data fsd;
410 
411     while (errno = 0,
412            0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
413                               (char *) 0)))
414       {
415         me = xmalloc (sizeof *me);
416         me->me_devname = xstrdup (fsd.fd_req.devname);
417         me->me_mountdir = xstrdup (fsd.fd_req.path);
418         me->me_type = gt_names[fsd.fd_req.fstype];
419         me->me_type_malloced = 0;
420         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
421         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
422         me->me_dev = fsd.fd_req.dev;
423 
424         /* Add to the linked list. */
425         *mtail = me;
426         mtail = &me->me_next;
427       }
428     if (val < 0)
429       goto free_then_fail;
430   }
431 #endif /* MOUNTED_GETMNT. */
432 
433 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
434   {
435     /* The next_dev() and fs_stat_dev() system calls give the list of
436        all file systems, including the information returned by statvfs()
437        (fs type, total blocks, free blocks etc.), but without the mount
438        point. But on BeOS all file systems except / are mounted in the
439        rootfs, directly under /.
440        The directory name of the mount point is often, but not always,
441        identical to the volume name of the device.
442        We therefore get the list of subdirectories of /, and the list
443        of all file systems, and match the two lists.  */
444 
445     DIR *dirp;
446     struct rootdir_entry
447       {
448         char *name;
449         dev_t dev;
450         ino_t ino;
451         struct rootdir_entry *next;
452       };
453     struct rootdir_entry *rootdir_list;
454     struct rootdir_entry **rootdir_tail;
455     int32 pos;
456     dev_t dev;
457     fs_info fi;
458 
459     /* All volumes are mounted in the rootfs, directly under /. */
460     rootdir_list = NULL;
461     rootdir_tail = &rootdir_list;
462     dirp = opendir ("/");
463     if (dirp)
464       {
465         struct dirent *d;
466 
467         while ((d = readdir (dirp)) != NULL)
468           {
469             char *name;
470             struct stat statbuf;
471 
472             if (strcmp (d->d_name, "..") == 0)
473               continue;
474 
475             if (strcmp (d->d_name, ".") == 0)
476               name = strdup ("/");
477             else
478               {
479                 name = malloc (1 + strlen (d->d_name) + 1);
480                 name[0] = '/';
481                 strcpy (name + 1, d->d_name);
482               }
483 
484             if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
485               {
486                 struct rootdir_entry *re = malloc (sizeof *re);
487                 re->name = name;
488                 re->dev = statbuf.st_dev;
489                 re->ino = statbuf.st_ino;
490 
491                 /* Add to the linked list.  */
492                 *rootdir_tail = re;
493                 rootdir_tail = &re->next;
494               }
495             else
496               free (name);
497           }
498         closedir (dirp);
499       }
500     *rootdir_tail = NULL;
501 
502     for (pos = 0; (dev = next_dev (&pos)) >= 0; )
503       if (fs_stat_dev (dev, &fi) >= 0)
504         {
505           /* Note: fi.dev == dev. */
506           struct rootdir_entry *re;
507 
508           for (re = rootdir_list; re; re = re->next)
509             if (re->dev == fi.dev && re->ino == fi.root)
510               break;
511 
512           me = malloc (sizeof *me);
513           me->me_devname = strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
514           me->me_mountdir = strdup (re != NULL ? re->name : fi.fsh_name);
515           me->me_type = strdup (fi.fsh_name);
516           me->me_type_malloced = 1;
517           me->me_dev = fi.dev;
518           me->me_dummy = 0;
519           me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
520 
521           /* Add to the linked list. */
522           *mtail = me;
523           mtail = &me->me_next;
524         }
525     *mtail = NULL;
526 
527     while (rootdir_list != NULL)
528       {
529         struct rootdir_entry *re = rootdir_list;
530         rootdir_list = re->next;
531         free (re->name);
532         free (re);
533       }
534   }
535 #endif /* MOUNTED_FS_STAT_DEV */
536 
537 #if defined MOUNTED_GETFSSTAT        /* __alpha running OSF_1 */
538   {
539     int numsys, counter;
540     size_t bufsize;
541     struct statfs *stats;
542 
543     numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
544     if (numsys < 0)
545       return (NULL);
546       /*
547     if (SIZE_MAX / sizeof *stats <= numsys)
548       xalloc_die ();*/
549 
550     bufsize = (1 + numsys) * sizeof *stats;
551     stats = malloc (bufsize);
552     numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
553 
554     if (numsys < 0)
555       {
556         free (stats);
557         return (NULL);
558       }
559 
560     for (counter = 0; counter < numsys; counter++)
561       {
562         me = malloc (sizeof *me);
563         me->me_devname = strdup (stats[counter].f_mntfromname);
564         me->me_mountdir = strdup (stats[counter].f_mntonname);
565         //me->me_type = strdup (FS_TYPE (stats[counter]));
566         me->me_type_malloced = 1;
567         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
568         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
569         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
570 
571         /* Add to the linked list. */
572         *mtail = me;
573         mtail = &me->me_next;
574       }
575 
576     free (stats);
577   }
578 #endif /* MOUNTED_GETFSSTAT */
579 
580 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23].  */
581   {
582     struct mnttab mnt;
583     char *table = "/etc/mnttab";
584     FILE *fp;
585 
586     fp = fopen (table, "r");
587     if (fp == NULL)
588       return NULL;
589 
590     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
591       {
592         me = xmalloc (sizeof *me);
593 # ifdef GETFSTYP                        /* SVR3.  */
594         me->me_devname = xstrdup (mnt.mt_dev);
595 # else
596         me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
597         strcpy (me->me_devname, "/dev/");
598         strcpy (me->me_devname + 5, mnt.mt_dev);
599 # endif
600         me->me_mountdir = xstrdup (mnt.mt_filsys);
601         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
602         me->me_type = "";
603         me->me_type_malloced = 0;
604 # ifdef GETFSTYP                        /* SVR3.  */
605         if (need_fs_type)
606           {
607             struct statfs fsd;
608             char typebuf[FSTYPSZ];
609 
610             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
611                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
612               {
613                 me->me_type = xstrdup (typebuf);
614                 me->me_type_malloced = 1;
615               }
616           }
617 # endif
618         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
619         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
620 
621         /* Add to the linked list. */
622         *mtail = me;
623         mtail = &me->me_next;
624       }
625 
626     if (ferror (fp))
627       {
628         /* The last fread() call must have failed.  */
629         int saved_errno = errno;
630         fclose (fp);
631         errno = saved_errno;
632         goto free_then_fail;
633       }
634 
635     if (fclose (fp) == EOF)
636       goto free_then_fail;
637   }
638 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
639 
640 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes its own way.  */
641   {
642     struct mntent **mnttbl = getmnttbl (), **ent;
643     for (ent=mnttbl;*ent;ent++)
644       {
645         me = xmalloc (sizeof *me);
646         me->me_devname = xstrdup ( (*ent)->mt_resource);
647         me->me_mountdir = xstrdup ( (*ent)->mt_directory);
648         me->me_type = xstrdup ((*ent)->mt_fstype);
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. */
653 
654         /* Add to the linked list. */
655         *mtail = me;
656         mtail = &me->me_next;
657       }
658     endmnttbl ();
659   }
660 #endif
661 
662 #ifdef MOUNTED_GETMNTENT2        /* SVR4.  */
663   {
664     struct mnttab mnt;
665     char *table = MNTTAB;
666     FILE *fp;
667     int ret;
668     int lockfd = -1;
669 
670 # if defined F_RDLCK && defined F_SETLKW
671     /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
672        e.g. Solaris 2.6.  If the SVR4 folks ever define a macro
673        for this file name, we should use their macro name instead.
674        (Why not just lock MNTTAB directly?  We don't know.)  */
675 #  ifndef MNTTAB_LOCK
676 #   define MNTTAB_LOCK "/etc/.mnttab.lock"
677 #  endif
678     lockfd = open (MNTTAB_LOCK, O_RDONLY);
679     if (0 <= lockfd)
680       {
681         struct flock flock;
682         flock.l_type = F_RDLCK;
683         flock.l_whence = SEEK_SET;
684         flock.l_start = 0;
685         flock.l_len = 0;
686         while (fcntl (lockfd, F_SETLKW, &flock) == -1)
687           if (errno != EINTR)
688             {
689               int saved_errno = errno;
690               close (lockfd);
691               errno = saved_errno;
692               return NULL;
693             }
694       }
695     else if (errno != ENOENT)
696       return NULL;
697 # endif
698 
699     errno = 0;
700     fp = fopen (table, "r");
701     if (fp == NULL)
702       ret = errno;
703     else
704       {
705         while ((ret = getmntent (fp, &mnt)) == 0)
706           {
707             me = xmalloc (sizeof *me);
708             me->me_devname = xstrdup (mnt.mnt_special);
709             me->me_mountdir = xstrdup (mnt.mnt_mountp);
710             me->me_type = xstrdup (mnt.mnt_fstype);
711             me->me_type_malloced = 1;
712             me->me_dummy = MNT_IGNORE (&mnt) != 0;
713             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
714             me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
715 
716             /* Add to the linked list. */
717             *mtail = me;
718             mtail = &me->me_next;
719           }
720 
721         ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
722       }
723 
724     if (0 <= lockfd && close (lockfd) != 0)
725       ret = errno;
726 
727     if (0 <= ret)
728       {
729         errno = ret;
730         goto free_then_fail;
731       }
732   }
733 #endif /* MOUNTED_GETMNTENT2.  */
734 
735 #ifdef MOUNTED_VMOUNT                /* AIX.  */
736   {
737     int bufsize;
738     char *entries, *thisent;
739     struct vmount *vmp;
740     int n_entries;
741     int i;
742 
743     /* Ask how many bytes to allocate for the mounted file system info.  */
744     if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
745       return NULL;
746     entries = xmalloc (bufsize);
747 
748     /* Get the list of mounted file systems.  */
749     n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
750     if (n_entries < 0)
751       {
752         int saved_errno = errno;
753         free (entries);
754         errno = saved_errno;
755         return NULL;
756       }
757 
758     for (i = 0, thisent = entries;
759          i < n_entries;
760          i++, thisent += vmp->vmt_length)
761       {
762         char *options, *ignore;
763 
764         vmp = (struct vmount *) thisent;
765         me = xmalloc (sizeof *me);
766         if (vmp->vmt_flags & MNT_REMOTE)
767           {
768             char *host, *dir;
769 
770             me->me_remote = 1;
771             /* Prepend the remote dirname.  */
772             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
773             dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
774             me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
775             strcpy (me->me_devname, host);
776             strcat (me->me_devname, ":");
777             strcat (me->me_devname, dir);
778           }
779         else
780           {
781             me->me_remote = 0;
782             me->me_devname = xstrdup (thisent +
783                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
784           }
785         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
786         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
787         me->me_type_malloced = 1;
788         options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
789         ignore = strstr (options, "ignore");
790         me->me_dummy = (ignore
791                         && (ignore == options || ignore[-1] == ',')
792                         && (ignore[sizeof "ignore" - 1] == ','
793                             || ignore[sizeof "ignore" - 1] == '\0'));
794         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
795 
796         /* Add to the linked list. */
797         *mtail = me;
798         mtail = &me->me_next;
799       }
800     free (entries);
801   }
802 #endif /* MOUNTED_VMOUNT. */
803 
804   *mtail = NULL;
805   return mount_list;
806 
807 #if defined(MOUNTED_GETMNTENT1) || defined(MOUNTED_GETMNTENT2) || defined(MOUNTED_GETMNT) || defined(MOUNTED_FREAD) || defined(MOUNTED_FREAD_FSTYP)
808  free_then_fail:
809   {
810     int saved_errno = errno;
811     *mtail = NULL;
812 
813     while (mount_list)
814       {
815         me = mount_list->me_next;
816         free (mount_list->me_devname);
817         free (mount_list->me_mountdir);
818         if (mount_list->me_type_malloced)
819           free (mount_list->me_type);
820         free (mount_list);
821         mount_list = me;
822       }
823 
824     errno = saved_errno;
825     return NULL;
826   }
827 #endif
828 }
829 
830 #endif
831 
832