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