[MOUNTED_GETFSSTAT]:
[pspp] / lib / mountlist.c
1 /* mountlist.c -- return a list of mounted filesystems
2    Copyright (C) 1991, 1992, 1997-2001 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include "mountlist.h"
25
26 #ifdef STDC_HEADERS
27 # include <stdlib.h>
28 #else
29 void free ();
30 #endif
31 #if defined STDC_HEADERS || defined HAVE_STRING_H
32 # include <string.h>
33 #else
34 # include <strings.h>
35 #endif
36
37 #ifndef strstr
38 char *strstr ();
39 #endif
40 char *xmalloc ();
41 char *xrealloc ();
42 char *xstrdup ();
43
44 #include <errno.h>
45 #ifndef errno
46 extern int errno;
47 #endif
48
49 #ifdef HAVE_FCNTL_H
50 # include <fcntl.h>
51 #endif
52
53 #ifdef HAVE_UNISTD_H
54 # include <unistd.h>
55 #endif
56
57 #if HAVE_SYS_PARAM_H
58 # include <sys/param.h>
59 #endif
60
61 #if defined MOUNTED_GETFSSTAT   /* OSF_1 and Darwin1.3.x */
62 # if HAVE_SYS_UCRED_H
63 #  include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
64 # endif
65 # if HAVE_SYS_MOUNT_H
66 #  include <sys/mount.h>
67 # endif
68 # if HAVE_SYS_FS_TYPES_H
69 #  include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
70 # endif
71 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
72 #  define FS_TYPE(Ent) ((Ent).f_fstypename)
73 # else
74 #  define FS_TYPE(Ent) mnt_names[(Ent).f_type]
75 # endif
76 #endif /* MOUNTED_GETFSSTAT */
77
78 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
79 # include <mntent.h>
80 # if !defined MOUNTED
81 #  if defined _PATH_MOUNTED     /* GNU libc  */
82 #   define MOUNTED _PATH_MOUNTED
83 #  endif
84 #  if defined MNT_MNTTAB        /* HP-UX.  */
85 #   define MOUNTED MNT_MNTTAB
86 #  endif
87 #  if defined MNTTABNAME        /* Dynix.  */
88 #   define MOUNTED MNTTABNAME
89 #  endif
90 # endif
91 #endif
92
93 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
94 # include <sys/mount.h>
95 #endif
96
97 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
98 # include <sys/mount.h>
99 # include <sys/fs_types.h>
100 #endif
101
102 #ifdef MOUNTED_FS_STAT_DEV      /* BeOS.  */
103 # include <fs_info.h>
104 # include <dirent.h>
105 #endif
106
107 #ifdef MOUNTED_FREAD            /* SVR2.  */
108 # include <mnttab.h>
109 #endif
110
111 #ifdef MOUNTED_FREAD_FSTYP      /* SVR3.  */
112 # include <mnttab.h>
113 # include <sys/fstyp.h>
114 # include <sys/statfs.h>
115 #endif
116
117 #ifdef MOUNTED_LISTMNTENT
118 # include <mntent.h>
119 #endif
120
121 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
122 # include <sys/mnttab.h>
123 #endif
124
125 #ifdef MOUNTED_VMOUNT           /* AIX.  */
126 # include <fshelp.h>
127 # include <sys/vfs.h>
128 #endif
129
130 #ifdef DOLPHIN
131 /* So special that it's not worth putting this in autoconf.  */
132 # undef MOUNTED_FREAD_FSTYP
133 # define MOUNTED_GETMNTTBL
134 #endif
135
136 #if HAVE_SYS_MNTENT_H
137 /* This is to get MNTOPT_IGNORE on e.g. SVR4.  */
138 # include <sys/mntent.h>
139 #endif
140
141 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
142 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
143 #else
144 # define MNT_IGNORE(M) 0
145 #endif
146
147 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
148 /* Return the value of the hexadecimal number represented by CP.
149    No prefix (like '0x') or suffix (like 'h') is expected to be
150    part of CP. */
151 /* FIXME: this can overflow */
152
153 static int
154 xatoi (char *cp)
155 {
156   int val;
157
158   val = 0;
159   while (*cp)
160     {
161       if (*cp >= 'a' && *cp <= 'f')
162         val = val * 16 + *cp - 'a' + 10;
163       else if (*cp >= 'A' && *cp <= 'F')
164         val = val * 16 + *cp - 'A' + 10;
165       else if (*cp >= '0' && *cp <= '9')
166         val = val * 16 + *cp - '0';
167       else
168         break;
169       cp++;
170     }
171   return val;
172 }
173 #endif /* MOUNTED_GETMNTENT1.  */
174
175 #if MOUNTED_GETMNTINFO
176
177 # if ! HAVE_F_FSTYPENAME_IN_STATFS
178 static char *
179 fstype_to_string (short 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 /* ! HAVE_F_FSTYPENAME_IN_STATFS */
272
273 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
274 static char *
275 fsp_to_string (const struct statfs *fsp)
276 {
277 # if defined HAVE_F_FSTYPENAME_IN_STATFS
278   return (char *) (fsp->f_fstypename);
279 # else
280   return fstype_to_string (fsp->f_type);
281 # endif
282 }
283
284 #endif /* MOUNTED_GETMNTINFO */
285
286 #ifdef MOUNTED_VMOUNT           /* AIX.  */
287 static char *
288 fstype_to_string (int t)
289 {
290   struct vfs_ent *e;
291
292   e = getvfsbytype (t);
293   if (!e || !e->vfsent_name)
294     return "none";
295   else
296     return e->vfsent_name;
297 }
298 #endif /* MOUNTED_VMOUNT */
299
300 /* Return a list of the currently mounted filesystems, or NULL on error.
301    Add each entry to the tail of the list so that they stay in order.
302    If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
303    the returned list are valid.  Otherwise, they might not be.  */
304
305 struct mount_entry *
306 read_filesystem_list (int need_fs_type)
307 {
308   struct mount_entry *mount_list;
309   struct mount_entry *me;
310   struct mount_entry **mtail = &mount_list;
311
312 #ifdef MOUNTED_LISTMNTENT
313   {
314     struct tabmntent *mntlist, *p;
315     struct mntent *mnt;
316     struct mount_entry *me;
317
318     /* the third and fourth arguments could be used to filter mounts,
319        but Crays doesn't seem to have any mounts that we want to
320        remove. Specifically, automount create normal NFS mounts.
321        */
322
323     if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0)
324       return NULL;
325     for (p = mntlist; p; p = p->next) {
326       mnt = p->ment;
327       me = (struct mount_entry*) xmalloc(sizeof (struct mount_entry));
328       me->me_devname = xstrdup(mnt->mnt_fsname);
329       me->me_mountdir = xstrdup(mnt->mnt_dir);
330       me->me_type = xstrdup(mnt->mnt_type);
331       me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
332       me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
333       me->me_dev = -1;
334       *mtail = me;
335       mtail = &me->me_next;
336     }
337     freemntlist(mntlist);
338   }
339 #endif
340
341 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
342   {
343     struct mntent *mnt;
344     char *table = MOUNTED;
345     FILE *fp;
346     char *devopt;
347
348     fp = setmntent (table, "r");
349     if (fp == NULL)
350       return NULL;
351
352     while ((mnt = getmntent (fp)))
353       {
354         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
355         me->me_devname = xstrdup (mnt->mnt_fsname);
356         me->me_mountdir = xstrdup (mnt->mnt_dir);
357         me->me_type = xstrdup (mnt->mnt_type);
358         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
359         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
360         devopt = strstr (mnt->mnt_opts, "dev=");
361         if (devopt)
362           {
363             if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
364               me->me_dev = xatoi (devopt + 6);
365             else
366               me->me_dev = xatoi (devopt + 4);
367           }
368         else
369           me->me_dev = (dev_t) -1;      /* Magic; means not known yet. */
370
371         /* Add to the linked list. */
372         *mtail = me;
373         mtail = &me->me_next;
374       }
375
376     if (endmntent (fp) == 0)
377       goto free_then_fail;
378   }
379 #endif /* MOUNTED_GETMNTENT1. */
380
381 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
382   {
383     struct statfs *fsp;
384     int entries;
385
386     entries = getmntinfo (&fsp, MNT_NOWAIT);
387     if (entries < 0)
388       return NULL;
389     for (; entries-- > 0; fsp++)
390       {
391         char *fs_type = fsp_to_string (fsp);
392
393         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
394         me->me_devname = xstrdup (fsp->f_mntfromname);
395         me->me_mountdir = xstrdup (fsp->f_mntonname);
396         me->me_type = fs_type;
397         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
398         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
399         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
400
401         /* Add to the linked list. */
402         *mtail = me;
403         mtail = &me->me_next;
404       }
405   }
406 #endif /* MOUNTED_GETMNTINFO */
407
408 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
409   {
410     int offset = 0;
411     int val;
412     struct fs_data fsd;
413
414     while (errno = 0,
415            0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
416                               (char *) 0)))
417       {
418         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
419         me->me_devname = xstrdup (fsd.fd_req.devname);
420         me->me_mountdir = xstrdup (fsd.fd_req.path);
421         me->me_type = gt_names[fsd.fd_req.fstype];
422         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
423         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
424         me->me_dev = fsd.fd_req.dev;
425
426         /* Add to the linked list. */
427         *mtail = me;
428         mtail = &me->me_next;
429       }
430     if (val < 0)
431       goto free_then_fail;
432   }
433 #endif /* MOUNTED_GETMNT. */
434
435 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
436   {
437     /* The next_dev() and fs_stat_dev() system calls give the list of
438        all filesystems, including the information returned by statvfs()
439        (fs type, total blocks, free blocks etc.), but without the mount
440        point. But on BeOS all filesystems except / are mounted in the
441        rootfs, directly under /.
442        The directory name of the mount point is often, but not always,
443        identical to the volume name of the device.
444        We therefore get the list of subdirectories of /, and the list
445        of all filesystems, and match the two lists.  */
446
447     DIR *dirp;
448     struct rootdir_entry
449       {
450         char *name;
451         dev_t dev;
452         ino_t ino;
453         struct rootdir_entry *next;
454       };
455     struct rootdir_entry *rootdir_list;
456     struct rootdir_entry **rootdir_tail;
457     int32 pos;
458     dev_t dev;
459     fs_info fi;
460
461     /* All volumes are mounted in the rootfs, directly under /. */
462     rootdir_list = NULL;
463     rootdir_tail = &rootdir_list;
464     dirp = opendir ("/");
465     if (dirp)
466       {
467         struct dirent *d;
468
469         while ((d = readdir (dirp)) != NULL)
470           {
471             char *name;
472             struct stat statbuf;
473
474             if (strcmp (d->d_name, "..") == 0)
475               continue;
476
477             if (strcmp (d->d_name, ".") == 0)
478               name = xstrdup ("/");
479             else
480               {
481                 name = xmalloc (1 + strlen (d->d_name) + 1);
482                 name[0] = '/';
483                 strcpy (name + 1, d->d_name);
484               }
485
486             if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
487               {
488                 struct rootdir_entry *re;
489
490                 re = (struct rootdir_entry *) xmalloc (sizeof (struct rootdir_entry));
491                 re->name = name;
492                 re->dev = statbuf.st_dev;
493                 re->ino = statbuf.st_ino;
494
495                 /* Add to the linked list.  */
496                 *rootdir_tail = re;
497                 rootdir_tail = &re->next;
498               }
499             else
500               free (name);
501           }
502         closedir (dirp);
503       }
504     *rootdir_tail = NULL;
505
506     for (pos = 0; (dev = next_dev (&pos)) >= 0; )
507       if (fs_stat_dev (dev, &fi) >= 0)
508         {
509           /* Note: fi.dev == dev. */
510           struct rootdir_entry *re;
511
512           for (re = rootdir_list; re; re = re->next)
513             if (re->dev == fi.dev && re->ino == fi.root)
514               break;
515
516           me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
517           me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
518           me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
519           me->me_type = xstrdup (fi.fsh_name);
520           me->me_dev = fi.dev;
521           me->me_dummy = 0;
522           me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
523
524           /* Add to the linked list. */
525           *mtail = me;
526           mtail = &me->me_next;
527         }
528     *mtail = NULL;
529
530     while (rootdir_list != NULL)
531       {
532         struct rootdir_entry *re = rootdir_list;
533         rootdir_list = re->next;
534         free (re->name);
535         free (re);
536       }
537   }
538 #endif /* MOUNTED_FS_STAT_DEV */
539
540 #if defined MOUNTED_GETFSSTAT   /* __alpha running OSF_1 */
541   {
542     int numsys, counter, bufsize;
543     struct statfs *stats;
544
545     numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
546     if (numsys < 0)
547       return (NULL);
548
549     bufsize = (1 + numsys) * sizeof (struct statfs);
550     stats = (struct statfs *)xmalloc (bufsize);
551     numsys = getfsstat (stats, bufsize, MNT_WAIT);
552
553     if (numsys < 0)
554       {
555         free (stats);
556         return (NULL);
557       }
558
559     for (counter = 0; counter < numsys; counter++)
560       {
561         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
562         me->me_devname = xstrdup (stats[counter].f_mntfromname);
563         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
564         me->me_type = xstrdup (FS_TYPE (stats[counter]));
565         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
566         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
567         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
568
569         /* Add to the linked list. */
570         *mtail = me;
571         mtail = &me->me_next;
572       }
573
574     free (stats);
575   }
576 #endif /* MOUNTED_GETFSSTAT */
577
578 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23].  */
579   {
580     struct mnttab mnt;
581     char *table = "/etc/mnttab";
582     FILE *fp;
583
584     fp = fopen (table, "r");
585     if (fp == NULL)
586       return NULL;
587
588     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
589       {
590         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
591 # ifdef GETFSTYP                        /* SVR3.  */
592         me->me_devname = xstrdup (mnt.mt_dev);
593 # else
594         me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
595         strcpy (me->me_devname, "/dev/");
596         strcpy (me->me_devname + 5, mnt.mt_dev);
597 # endif
598         me->me_mountdir = xstrdup (mnt.mt_filsys);
599         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
600         me->me_type = "";
601 # ifdef GETFSTYP                        /* SVR3.  */
602         if (need_fs_type)
603           {
604             struct statfs fsd;
605             char typebuf[FSTYPSZ];
606
607             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
608                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
609               me->me_type = xstrdup (typebuf);
610           }
611 # endif
612         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
613         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
614
615         /* Add to the linked list. */
616         *mtail = me;
617         mtail = &me->me_next;
618       }
619
620     if (ferror (fp))
621       {
622         int saved_errno = errno;
623         fclose (fp);
624         errno = saved_errno;
625         goto free_then_fail;
626       }
627
628     if (fclose (fp) == EOF)
629       goto free_then_fail;
630   }
631 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
632
633 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes it's own way */
634   {
635     struct mntent **mnttbl=getmnttbl(),**ent;
636     for (ent=mnttbl;*ent;ent++)
637       {
638         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
639         me->me_devname = xstrdup ( (*ent)->mt_resource);
640         me->me_mountdir = xstrdup( (*ent)->mt_directory);
641         me->me_type =  xstrdup ((*ent)->mt_fstype);
642         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
643         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
644         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
645
646         /* Add to the linked list. */
647         *mtail = me;
648         mtail = &me->me_next;
649       }
650     endmnttbl();
651   }
652 #endif
653
654 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
655   {
656     struct mnttab mnt;
657     char *table = MNTTAB;
658     FILE *fp;
659     int ret;
660     int lockfd = -1;
661
662 # if defined F_RDLCK && defined F_SETLKW
663     /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
664        e.g. Solaris 2.6.  If the SVR4 folks ever define a macro
665        for this file name, we should use their macro name instead.
666        (Why not just lock MNTTAB directly?  We don't know.)  */
667 #  ifndef MNTTAB_LOCK
668 #   define MNTTAB_LOCK "/etc/.mnttab.lock"
669 #  endif
670     lockfd = open (MNTTAB_LOCK, O_RDONLY);
671     if (0 <= lockfd)
672       {
673         struct flock flock;
674         flock.l_type = F_RDLCK;
675         flock.l_whence = SEEK_SET;
676         flock.l_start = 0;
677         flock.l_len = 0;
678         while (fcntl (lockfd, F_SETLKW, &flock) == -1)
679           if (errno != EINTR)
680             {
681               int saved_errno = errno;
682               close (lockfd);
683               errno = saved_errno;
684               return NULL;
685             }
686       }
687     else if (errno != ENOENT)
688       return NULL;
689 # endif
690
691     errno = 0;
692     fp = fopen (table, "r");
693     if (fp == NULL)
694       ret = errno;
695     else
696       {
697         while ((ret = getmntent (fp, &mnt)) == 0)
698           {
699             me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
700             me->me_devname = xstrdup (mnt.mnt_special);
701             me->me_mountdir = xstrdup (mnt.mnt_mountp);
702             me->me_type = xstrdup (mnt.mnt_fstype);
703             me->me_dummy = MNT_IGNORE (&mnt) != 0;
704             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
705             me->me_dev = (dev_t) -1;    /* Magic; means not known yet. */
706
707             /* Add to the linked list. */
708             *mtail = me;
709             mtail = &me->me_next;
710           }
711
712         ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
713       }
714
715     if (0 <= lockfd && close (lockfd) != 0)
716       ret = errno;
717
718     if (0 <= ret)
719       {
720         errno = ret;
721         goto free_then_fail;
722       }
723   }
724 #endif /* MOUNTED_GETMNTENT2.  */
725
726 #ifdef MOUNTED_VMOUNT           /* AIX.  */
727   {
728     int bufsize;
729     char *entries, *thisent;
730     struct vmount *vmp;
731
732     /* Ask how many bytes to allocate for the mounted filesystem info.  */
733     mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
734     entries = xmalloc (bufsize);
735
736     /* Get the list of mounted filesystems.  */
737     mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
738
739     for (thisent = entries; thisent < entries + bufsize;
740          thisent += vmp->vmt_length)
741       {
742         char *options, *ignore;
743
744         vmp = (struct vmount *) thisent;
745         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
746         if (vmp->vmt_flags & MNT_REMOTE)
747           {
748             char *host, *path;
749
750             me->me_remote = 1;
751             /* Prepend the remote pathname.  */
752             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
753             path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
754             me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
755             strcpy (me->me_devname, host);
756             strcat (me->me_devname, ":");
757             strcat (me->me_devname, path);
758           }
759         else
760           {
761             me->me_remote = 0;
762             me->me_devname = xstrdup (thisent +
763                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
764           }
765         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
766         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
767         options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
768         ignore = strstr (options, "ignore");
769         me->me_dummy = (ignore
770                         && (ignore == options || ignore[-1] == ',')
771                         && (ignore[sizeof "ignore" - 1] == ','
772                             || ignore[sizeof "ignore" - 1] == '\0'));
773         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
774
775         /* Add to the linked list. */
776         *mtail = me;
777         mtail = &me->me_next;
778       }
779     free (entries);
780   }
781 #endif /* MOUNTED_VMOUNT. */
782
783   *mtail = NULL;
784   return mount_list;
785
786
787  free_then_fail:
788   {
789     int saved_errno = errno;
790     *mtail = NULL;
791
792     while (mount_list)
793       {
794         me = mount_list->me_next;
795         free (mount_list->me_devname);
796         free (mount_list->me_mountdir);
797         /* FIXME: me_type is not always malloced.  */
798         free (mount_list);
799         mount_list = me;
800       }
801
802     errno = saved_errno;
803     return NULL;
804   }
805 }