Code

Using coreutils 4.5.11 version to fix Darwin problem
[nagiosplug.git] / lib / mountlist.c
1 /* mountlist.c -- return a list of mounted filesystems
2    Copyright (C) 1991, 1992, 1997-2000 Free Software Foundation, Inc.
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.
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.
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.  */
18 #include "../plugins/config.h"
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include "mountlist.h"
24 #ifdef STDC_HEADERS
25 # include <stdlib.h>
26 #else
27 void free ();
28 #endif
29 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
30 # include <string.h>
31 #else
32 # include <strings.h>
33 #endif
35 #ifndef strstr
36 char *strstr ();
37 #endif
38 /* char *xmalloc (); */
39 /* char *realloc (); */
40 /* char *xstrdup (); */
42 #include <errno.h>
43 #ifndef errno
44 extern int errno;
45 #endif
47 #ifdef HAVE_FCNTL_H
48 # include <fcntl.h>
49 #endif
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 #endif
55 #if HAVE_SYS_PARAM_H
56 # include <sys/param.h>
57 #endif
59 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
60 # include <sys/mount.h>
61 # include <sys/fs_types.h>
62 #endif /* MOUNTED_GETFSSTAT */
64 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
65 # include <mntent.h>
66 # if !defined(MOUNTED)
67 #  if defined(MNT_MNTTAB)       /* HP-UX.  */
68 #   define MOUNTED MNT_MNTTAB
69 #  endif
70 #  if defined(MNTTABNAME)       /* Dynix.  */
71 #   define MOUNTED MNTTABNAME
72 #  endif
73 # endif
74 #endif
76 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
77 # include <sys/mount.h>
78 #endif
80 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
81 # include <sys/mount.h>
82 # include <sys/fs_types.h>
83 #endif
85 #ifdef MOUNTED_FS_STAT_DEV      /* BeOS.  */
86 # include <fs_info.h>
87 # include <dirent.h>
88 #endif
90 #ifdef MOUNTED_FREAD            /* SVR2.  */
91 # include <mnttab.h>
92 #endif
94 #ifdef MOUNTED_FREAD_FSTYP      /* SVR3.  */
95 # include <mnttab.h>
96 # include <sys/fstyp.h>
97 # include <sys/statfs.h>
98 #endif
100 #ifdef MOUNTED_LISTMNTENT
101 # include <mntent.h>
102 #endif
104 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
105 # include <sys/mnttab.h>
106 #endif
108 #ifdef MOUNTED_VMOUNT           /* AIX.  */
109 # include <fshelp.h>
110 # include <sys/vfs.h>
111 #endif
113 #ifdef DOLPHIN
114 /* So special that it's not worth putting this in autoconf.  */
115 # undef MOUNTED_FREAD_FSTYP
116 # define MOUNTED_GETMNTTBL
117 #endif
119 #if HAVE_SYS_MNTENT_H
120 /* This is to get MNTOPT_IGNORE on e.g. SVR4.  */
121 # include <sys/mntent.h>
122 #endif
124 #if defined (MNTOPT_IGNORE) && defined (HAVE_HASMNTOPT)
125 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
126 #else
127 # define MNT_IGNORE(M) 0
128 #endif
130 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
131 /* Return the value of the hexadecimal number represented by CP.
132    No prefix (like '0x') or suffix (like 'h') is expected to be
133    part of CP. */
134 /* FIXME: this can overflow */
136 static int
137 xatoi (char *cp)
139   int val;
141   val = 0;
142   while (*cp)
143     {
144       if (*cp >= 'a' && *cp <= 'f')
145         val = val * 16 + *cp - 'a' + 10;
146       else if (*cp >= 'A' && *cp <= 'F')
147         val = val * 16 + *cp - 'A' + 10;
148       else if (*cp >= '0' && *cp <= '9')
149         val = val * 16 + *cp - '0';
150       else
151         break;
152       cp++;
153     }
154   return val;
156 #endif /* MOUNTED_GETMNTENT1.  */
158 #if MOUNTED_GETMNTINFO
160 # if ! HAVE_F_FSTYPENAME_IN_STATFS
161 static char *
162 fstype_to_string (short t)
164   switch (t)
165     {
166 #  ifdef MOUNT_PC
167     case MOUNT_PC:
168       return "pc";
169 #  endif
170 #  ifdef MOUNT_MFS
171     case MOUNT_MFS:
172       return "mfs";
173 #  endif
174 #  ifdef MOUNT_LO
175     case MOUNT_LO:
176       return "lo";
177 #  endif
178 #  ifdef MOUNT_TFS
179     case MOUNT_TFS:
180       return "tfs";
181 #  endif
182 #  ifdef MOUNT_TMP
183     case MOUNT_TMP:
184       return "tmp";
185 #  endif
186 #  ifdef MOUNT_UFS
187    case MOUNT_UFS:
188      return "ufs" ;
189 #  endif
190 #  ifdef MOUNT_NFS
191    case MOUNT_NFS:
192      return "nfs" ;
193 #  endif
194 #  ifdef MOUNT_MSDOS
195    case MOUNT_MSDOS:
196      return "msdos" ;
197 #  endif
198 #  ifdef MOUNT_LFS
199    case MOUNT_LFS:
200      return "lfs" ;
201 #  endif
202 #  ifdef MOUNT_LOFS
203    case MOUNT_LOFS:
204      return "lofs" ;
205 #  endif
206 #  ifdef MOUNT_FDESC
207    case MOUNT_FDESC:
208      return "fdesc" ;
209 #  endif
210 #  ifdef MOUNT_PORTAL
211    case MOUNT_PORTAL:
212      return "portal" ;
213 #  endif
214 #  ifdef MOUNT_NULL
215    case MOUNT_NULL:
216      return "null" ;
217 #  endif
218 #  ifdef MOUNT_UMAP
219    case MOUNT_UMAP:
220      return "umap" ;
221 #  endif
222 #  ifdef MOUNT_KERNFS
223    case MOUNT_KERNFS:
224      return "kernfs" ;
225 #  endif
226 #  ifdef MOUNT_PROCFS
227    case MOUNT_PROCFS:
228      return "procfs" ;
229 #  endif
230 #  ifdef MOUNT_AFS
231    case MOUNT_AFS:
232      return "afs" ;
233 #  endif
234 #  ifdef MOUNT_CD9660
235    case MOUNT_CD9660:
236      return "cd9660" ;
237 #  endif
238 #  ifdef MOUNT_UNION
239    case MOUNT_UNION:
240      return "union" ;
241 #  endif
242 #  ifdef MOUNT_DEVFS
243    case MOUNT_DEVFS:
244      return "devfs" ;
245 #  endif
246 #  ifdef MOUNT_EXT2FS
247    case MOUNT_EXT2FS:
248      return "ext2fs" ;
249 #  endif
250     default:
251       return "?";
252     }
254 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
256 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
257 static char *
258 fsp_to_string (const struct statfs *fsp)
260 # if defined HAVE_F_FSTYPENAME_IN_STATFS
261   return (char *) (fsp->f_fstypename);
262 # else
263   return fstype_to_string (fsp->f_type);
264 # endif
267 #endif /* MOUNTED_GETMNTINFO */
269 #ifdef MOUNTED_VMOUNT           /* AIX.  */
270 static char *
271 fstype_to_string (int t)
273   struct vfs_ent *e;
275   e = getvfsbytype (t);
276   if (!e || !e->vfsent_name)
277     return "none";
278   else
279     return e->vfsent_name;
281 #endif /* MOUNTED_VMOUNT */
283 /* Return a list of the currently mounted filesystems, or NULL on error.
284    Add each entry to the tail of the list so that they stay in order.
285    If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
286    the returned list are valid.  Otherwise, they might not be.  */
288 struct mount_entry *
289 read_filesystem_list (int need_fs_type)
291   struct mount_entry *mount_list;
292   struct mount_entry *me;
293   struct mount_entry **mtail = &mount_list;
295 #ifdef MOUNTED_LISTMNTENT
296   {
297     struct tabmntent *mntlist, *p;
298     struct mntent *mnt;
299     struct mount_entry *me;
301     /* the third and fourth arguments could be used to filter mounts,
302        but Crays doesn't seem to have any mounts that we want to
303        remove. Specifically, automount create normal NFS mounts.
304        */
306     if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0)
307       return NULL;
308     for (p = mntlist; p; p = p->next) {
309       mnt = p->ment;
310       me = (struct mount_entry*) malloc(sizeof (struct mount_entry));
311       me->me_devname = strdup(mnt->mnt_fsname);
312       me->me_mountdir = strdup(mnt->mnt_dir);
313       me->me_type = strdup(mnt->mnt_type);
314       me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
315       me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
316       me->me_dev = -1;
317       *mtail = me;
318       mtail = &me->me_next;
319     }
320     freemntlist(mntlist);
321   }
322 #endif
324 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
325   {
326     struct mntent *mnt;
327     char *table = MOUNTED;
328     FILE *fp;
329     char *devopt;
331     fp = setmntent (table, "r");
332     if (fp == NULL)
333       return NULL;
335     while ((mnt = getmntent (fp)))
336       {
337         me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
338         me->me_devname = strdup (mnt->mnt_fsname);
339         me->me_mountdir = strdup (mnt->mnt_dir);
340         me->me_type = strdup (mnt->mnt_type);
341         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
342         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
343         devopt = strstr (mnt->mnt_opts, "dev=");
344         if (devopt)
345           {
346             if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
347               me->me_dev = xatoi (devopt + 6);
348             else
349               me->me_dev = xatoi (devopt + 4);
350           }
351         else
352           me->me_dev = (dev_t) -1;      /* Magic; means not known yet. */
354         /* Add to the linked list. */
355         *mtail = me;
356         mtail = &me->me_next;
357       }
359     if (endmntent (fp) == 0)
360       goto free_then_fail;
361   }
362 #endif /* MOUNTED_GETMNTENT1. */
364 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
365   {
366     struct statfs *fsp;
367     int entries;
369     entries = getmntinfo (&fsp, MNT_NOWAIT);
370     if (entries < 0)
371       return NULL;
372     for (; entries-- > 0; fsp++)
373       {
374         char *fs_type = fsp_to_string (fsp);
376         me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
377         me->me_devname = strdup (fsp->f_mntfromname);
378         me->me_mountdir = strdup (fsp->f_mntonname);
379         me->me_type = fs_type;
380         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
381         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
382         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
384         /* Add to the linked list. */
385         *mtail = me;
386         mtail = &me->me_next;
387       }
388   }
389 #endif /* MOUNTED_GETMNTINFO */
391 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
392   {
393     int offset = 0;
394     int val;
395     struct fs_data fsd;
397     while (errno = 0,
398            0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
399                               (char *) 0)))
400       {
401         me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
402         me->me_devname = strdup (fsd.fd_req.devname);
403         me->me_mountdir = strdup (fsd.fd_req.path);
404         me->me_type = gt_names[fsd.fd_req.fstype];
405         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
406         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
407         me->me_dev = fsd.fd_req.dev;
409         /* Add to the linked list. */
410         *mtail = me;
411         mtail = &me->me_next;
412       }
413     if (val < 0)
414       goto free_then_fail;
415   }
416 #endif /* MOUNTED_GETMNT. */
418 #if defined (MOUNTED_FS_STAT_DEV) /* BeOS */
419   {
420     /* The next_dev() and fs_stat_dev() system calls give the list of
421        all filesystems, including the information returned by statvfs()
422        (fs type, total blocks, free blocks etc.), but without the mount
423        point. But on BeOS all filesystems except / are mounted in the
424        rootfs, directly under /.
425        The directory name of the mount point is often, but not always,
426        identical to the volume name of the device.
427        We therefore get the list of subdirectories of /, and the list
428        of all filesystems, and match the two lists.  */
430     DIR *dirp;
431     struct rootdir_entry
432       {
433         char *name;
434         dev_t dev;
435         ino_t ino;
436         struct rootdir_entry *next;
437       };
438     struct rootdir_entry *rootdir_list;
439     struct rootdir_entry **rootdir_tail;
440     int32 pos;
441     dev_t dev;
442     fs_info fi;
444     /* All volumes are mounted in the rootfs, directly under /. */
445     rootdir_list = NULL;
446     rootdir_tail = &rootdir_list;
447     dirp = opendir ("/");
448     if (dirp)
449       {
450         struct dirent *d;
452         while ((d = readdir (dirp)) != NULL)
453           {
454             char *name;
455             struct stat statbuf;
457             if (strcmp (d->d_name, "..") == 0)
458               continue;
460             if (strcmp (d->d_name, ".") == 0)
461               name = strdup ("/");
462             else
463               {
464                 name = malloc (1 + strlen (d->d_name) + 1);
465                 name[0] = '/';
466                 strcpy (name + 1, d->d_name);
467               }
469             if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
470               {
471                 struct rootdir_entry *re;
473                 re = (struct rootdir_entry *) malloc (sizeof (struct rootdir_entry));
474                 re->name = name;
475                 re->dev = statbuf.st_dev;
476                 re->ino = statbuf.st_ino;
478                 /* Add to the linked list.  */
479                 *rootdir_tail = re;
480                 rootdir_tail = &re->next;
481               }
482             else
483               free (name);
484           }
485         closedir (dirp);
486       }
487     *rootdir_tail = NULL;
489     for (pos = 0; (dev = next_dev (&pos)) >= 0; )
490       if (fs_stat_dev (dev, &fi) >= 0)
491         {
492           /* Note: fi.dev == dev. */
493           struct rootdir_entry *re;
495           for (re = rootdir_list; re; re = re->next)
496             if (re->dev == fi.dev && re->ino == fi.root)
497               break;
499           me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
500           me->me_devname = strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
501           me->me_mountdir = strdup (re != NULL ? re->name : fi.fsh_name);
502           me->me_type = strdup (fi.fsh_name);
503           me->me_dev = fi.dev;
504           me->me_dummy = 0;
505           me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
507           /* Add to the linked list. */
508           *mtail = me;
509           mtail = &me->me_next;
510         }
511     *mtail = NULL;
513     while (rootdir_list != NULL)
514       {
515         struct rootdir_entry *re = rootdir_list;
516         rootdir_list = re->next;
517         free (re->name);
518         free (re);
519       }
520   }
521 #endif /* MOUNTED_FS_STAT_DEV */
523 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
524   {
525     int numsys, counter, bufsize;
526     struct statfs *stats;
528     numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
529     if (numsys < 0)
530       return (NULL);
532     bufsize = (1 + numsys) * sizeof (struct statfs);
533     stats = (struct statfs *)malloc (bufsize);
534     numsys = getfsstat (stats, bufsize, MNT_WAIT);
536     if (numsys < 0)
537       {
538         free (stats);
539         return (NULL);
540       }
542     for (counter = 0; counter < numsys; counter++)
543       {
544         me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
545         me->me_devname = strdup (stats[counter].f_mntfromname);
546         me->me_mountdir = strdup (stats[counter].f_mntonname);
547         me->me_type = mnt_names[stats[counter].f_type];
548         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
549         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
550         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
552         /* Add to the linked list. */
553         *mtail = me;
554         mtail = &me->me_next;
555       }
557     free (stats);
558   }
559 #endif /* MOUNTED_GETFSSTAT */
561 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23].  */
562   {
563     struct mnttab mnt;
564     char *table = "/etc/mnttab";
565     FILE *fp;
567     fp = fopen (table, "r");
568     if (fp == NULL)
569       return NULL;
571     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
572       {
573         me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
574 # ifdef GETFSTYP                        /* SVR3.  */
575         me->me_devname = strdup (mnt.mt_dev);
576 # else
577         me->me_devname = malloc (strlen (mnt.mt_dev) + 6);
578         strcpy (me->me_devname, "/dev/");
579         strcpy (me->me_devname + 5, mnt.mt_dev);
580 # endif
581         me->me_mountdir = strdup (mnt.mt_filsys);
582         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
583         me->me_type = "";
584 # ifdef GETFSTYP                        /* SVR3.  */
585         if (need_fs_type)
586           {
587             struct statfs fsd;
588             char typebuf[FSTYPSZ];
590             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
591                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
592               me->me_type = strdup (typebuf);
593           }
594 # endif
595         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
596         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
598         /* Add to the linked list. */
599         *mtail = me;
600         mtail = &me->me_next;
601       }
603     if (ferror (fp))
604       {
605         int saved_errno = errno;
606         fclose (fp);
607         errno = saved_errno;
608         goto free_then_fail;
609       }
611     if (fclose (fp) == EOF)
612       goto free_then_fail;
613   }
614 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
616 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes it's own way */
617   {
618     struct mntent **mnttbl=getmnttbl(),**ent;
619     for (ent=mnttbl;*ent;ent++)
620       {
621         me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
622         me->me_devname = strdup ( (*ent)->mt_resource);
623         me->me_mountdir = strdup( (*ent)->mt_directory);
624         me->me_type =  strdup ((*ent)->mt_fstype);
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. */
629         /* Add to the linked list. */
630         *mtail = me;
631         mtail = &me->me_next;
632       }
633     endmnttbl();
634   }
635 #endif
637 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
638   {
639     struct mnttab mnt;
640     char *table = MNTTAB;
641     FILE *fp;
642     int ret;
643     int lockfd = -1;
645 # if defined F_RDLCK && defined F_SETLKW
646     /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
647        e.g. Solaris 2.6.  If the SVR4 folks ever define a macro
648        for this file name, we should use their macro name instead.
649        (Why not just lock MNTTAB directly?  We don't know.)  */
650 #  ifndef MNTTAB_LOCK
651 #   define MNTTAB_LOCK "/etc/.mnttab.lock"
652 #  endif
653     lockfd = open (MNTTAB_LOCK, O_RDONLY);
654     if (0 <= lockfd)
655       {
656         struct flock flock;
657         flock.l_type = F_RDLCK;
658         flock.l_whence = SEEK_SET;
659         flock.l_start = 0;
660         flock.l_len = 0;
661         while (fcntl (lockfd, F_SETLKW, &flock) == -1)
662           if (errno != EINTR)
663             {
664               int saved_errno = errno;
665               close (lockfd);
666               errno = saved_errno;
667               return NULL;
668             }
669       }
670     else if (errno != ENOENT)
671       return NULL;
672 # endif
674     errno = 0;
675     fp = fopen (table, "r");
676     if (fp == NULL)
677       ret = errno;
678     else
679       {
680         while ((ret = getmntent (fp, &mnt)) == 0)
681           {
682             me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
683             me->me_devname = strdup (mnt.mnt_special);
684             me->me_mountdir = strdup (mnt.mnt_mountp);
685             me->me_type = strdup (mnt.mnt_fstype);
686             me->me_dummy = MNT_IGNORE (&mnt) != 0;
687             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
688             me->me_dev = (dev_t) -1;    /* Magic; means not known yet. */
690             /* Add to the linked list. */
691             *mtail = me;
692             mtail = &me->me_next;
693           }
695         ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
696       }
698     if (0 <= lockfd && close (lockfd) != 0)
699       ret = errno;
701     if (0 <= ret)
702       {
703         errno = ret;
704         goto free_then_fail;
705       }
706   }
707 #endif /* MOUNTED_GETMNTENT2.  */
709 #ifdef MOUNTED_VMOUNT           /* AIX.  */
710   {
711     int bufsize;
712     char *entries, *thisent;
713     struct vmount *vmp;
715     /* Ask how many bytes to allocate for the mounted filesystem info.  */
716     mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
717     entries = malloc (bufsize);
719     /* Get the list of mounted filesystems.  */
720     mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
722     for (thisent = entries; thisent < entries + bufsize;
723          thisent += vmp->vmt_length)
724       {
725         char *options, *ignore;
727         vmp = (struct vmount *) thisent;
728         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
729         if (vmp->vmt_flags & MNT_REMOTE)
730           {
731             char *host, *path;
733             me->me_remote = 1;
734             /* Prepend the remote pathname.  */
735             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
736             path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
737             me->me_devname = malloc (strlen (host) + strlen (path) + 2);
738             strcpy (me->me_devname, host);
739             strcat (me->me_devname, ":");
740             strcat (me->me_devname, path);
741           }
742         else
743           {
744             me->me_remote = 0;
745             me->me_devname = strdup (thisent +
746                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
747           }
748         me->me_mountdir = strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
749         me->me_type = strdup (fstype_to_string (vmp->vmt_gfstype));
750         options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
751         ignore = strstr (options, "ignore");
752         me->me_dummy = (ignore
753                         && (ignore == options || ignore[-1] == ',')
754                         && (ignore[sizeof "ignore" - 1] == ','
755                             || ignore[sizeof "ignore" - 1] == '\0'));
756         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
758         /* Add to the linked list. */
759         *mtail = me;
760         mtail = &me->me_next;
761       }
762     free (entries);
763   }
764 #endif /* MOUNTED_VMOUNT. */
766   *mtail = NULL;
767   return mount_list;
770  free_then_fail:
771   {
772     int saved_errno = errno;
773     *mtail = NULL;
775     while (mount_list)
776       {
777         me = mount_list->me_next;
778         free (mount_list->me_devname);
779         free (mount_list->me_mountdir);
780         /* FIXME: me_type is not always malloced.  */
781         free (mount_list);
782         mount_list = me;
783       }
785     errno = saved_errno;
786     return NULL;
787   }