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