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