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