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