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