*** empty log message ***
[coreutils.git] / lib / mountlist.c
blob6f7d07cbc1b9eb970801d2669e2ffcd29c499b15
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 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include "mountlist.h"
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
37 #ifndef strstr
38 char *strstr ();
39 #endif
40 char *xmalloc ();
41 char *xrealloc ();
42 char *xstrdup ();
44 #include <errno.h>
45 #ifndef errno
46 extern int errno;
47 #endif
49 #ifdef HAVE_FCNTL_H
50 # include <fcntl.h>
51 #endif
53 #ifdef HAVE_UNISTD_H
54 # include <unistd.h>
55 #endif
57 #if HAVE_SYS_PARAM_H
58 # include <sys/param.h>
59 #endif
61 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
62 # include <sys/mount.h>
63 # include <sys/fs_types.h>
64 #endif /* MOUNTED_GETFSSTAT */
66 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
67 # include <mntent.h>
68 # if !defined(MOUNTED)
69 # if defined(MNT_MNTTAB) /* HP-UX. */
70 # define MOUNTED MNT_MNTTAB
71 # endif
72 # if defined(MNTTABNAME) /* Dynix. */
73 # define MOUNTED MNTTABNAME
74 # endif
75 # endif
76 #endif
78 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
79 # include <sys/mount.h>
80 #endif
82 #ifdef MOUNTED_GETMNT /* Ultrix. */
83 # include <sys/mount.h>
84 # include <sys/fs_types.h>
85 #endif
87 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
88 # include <fs_info.h>
89 # include <dirent.h>
90 #endif
92 #ifdef MOUNTED_FREAD /* SVR2. */
93 # include <mnttab.h>
94 #endif
96 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
97 # include <mnttab.h>
98 # include <sys/fstyp.h>
99 # include <sys/statfs.h>
100 #endif
102 #ifdef MOUNTED_LISTMNTENT
103 # include <mntent.h>
104 #endif
106 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
107 # include <sys/mnttab.h>
108 #endif
110 #ifdef MOUNTED_VMOUNT /* AIX. */
111 # include <fshelp.h>
112 # include <sys/vfs.h>
113 #endif
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
121 #if HAVE_SYS_MNTENT_H
122 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
123 # include <sys/mntent.h>
124 #endif
126 #if defined (MNTOPT_IGNORE) && defined (HAVE_HASMNTOPT)
127 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
128 #else
129 # define MNT_IGNORE(M) 0
130 #endif
132 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
133 /* Return the value of the hexadecimal number represented by CP.
134 No prefix (like '0x') or suffix (like 'h') is expected to be
135 part of CP. */
136 /* FIXME: this can overflow */
138 static int
139 xatoi (char *cp)
141 int val;
143 val = 0;
144 while (*cp)
146 if (*cp >= 'a' && *cp <= 'f')
147 val = val * 16 + *cp - 'a' + 10;
148 else if (*cp >= 'A' && *cp <= 'F')
149 val = val * 16 + *cp - 'A' + 10;
150 else if (*cp >= '0' && *cp <= '9')
151 val = val * 16 + *cp - '0';
152 else
153 break;
154 cp++;
156 return val;
158 #endif /* MOUNTED_GETMNTENT1. */
160 #if MOUNTED_GETMNTINFO
162 # if ! HAVE_F_FSTYPENAME_IN_STATFS
163 static char *
164 fstype_to_string (short t)
166 switch (t)
168 # ifdef MOUNT_PC
169 case MOUNT_PC:
170 return "pc";
171 # endif
172 # ifdef MOUNT_MFS
173 case MOUNT_MFS:
174 return "mfs";
175 # endif
176 # ifdef MOUNT_LO
177 case MOUNT_LO:
178 return "lo";
179 # endif
180 # ifdef MOUNT_TFS
181 case MOUNT_TFS:
182 return "tfs";
183 # endif
184 # ifdef MOUNT_TMP
185 case MOUNT_TMP:
186 return "tmp";
187 # endif
188 # ifdef MOUNT_UFS
189 case MOUNT_UFS:
190 return "ufs" ;
191 # endif
192 # ifdef MOUNT_NFS
193 case MOUNT_NFS:
194 return "nfs" ;
195 # endif
196 # ifdef MOUNT_MSDOS
197 case MOUNT_MSDOS:
198 return "msdos" ;
199 # endif
200 # ifdef MOUNT_LFS
201 case MOUNT_LFS:
202 return "lfs" ;
203 # endif
204 # ifdef MOUNT_LOFS
205 case MOUNT_LOFS:
206 return "lofs" ;
207 # endif
208 # ifdef MOUNT_FDESC
209 case MOUNT_FDESC:
210 return "fdesc" ;
211 # endif
212 # ifdef MOUNT_PORTAL
213 case MOUNT_PORTAL:
214 return "portal" ;
215 # endif
216 # ifdef MOUNT_NULL
217 case MOUNT_NULL:
218 return "null" ;
219 # endif
220 # ifdef MOUNT_UMAP
221 case MOUNT_UMAP:
222 return "umap" ;
223 # endif
224 # ifdef MOUNT_KERNFS
225 case MOUNT_KERNFS:
226 return "kernfs" ;
227 # endif
228 # ifdef MOUNT_PROCFS
229 case MOUNT_PROCFS:
230 return "procfs" ;
231 # endif
232 # ifdef MOUNT_AFS
233 case MOUNT_AFS:
234 return "afs" ;
235 # endif
236 # ifdef MOUNT_CD9660
237 case MOUNT_CD9660:
238 return "cd9660" ;
239 # endif
240 # ifdef MOUNT_UNION
241 case MOUNT_UNION:
242 return "union" ;
243 # endif
244 # ifdef MOUNT_DEVFS
245 case MOUNT_DEVFS:
246 return "devfs" ;
247 # endif
248 # ifdef MOUNT_EXT2FS
249 case MOUNT_EXT2FS:
250 return "ext2fs" ;
251 # endif
252 default:
253 return "?";
256 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
258 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
259 static char *
260 fsp_to_string (const struct statfs *fsp)
262 # if defined HAVE_F_FSTYPENAME_IN_STATFS
263 return (char *) (fsp->f_fstypename);
264 # else
265 return fstype_to_string (fsp->f_type);
266 # endif
269 #endif /* MOUNTED_GETMNTINFO */
271 #ifdef MOUNTED_VMOUNT /* AIX. */
272 static char *
273 fstype_to_string (int t)
275 struct vfs_ent *e;
277 e = getvfsbytype (t);
278 if (!e || !e->vfsent_name)
279 return "none";
280 else
281 return e->vfsent_name;
283 #endif /* MOUNTED_VMOUNT */
285 /* Return a list of the currently mounted filesystems, or NULL on error.
286 Add each entry to the tail of the list so that they stay in order.
287 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
288 the returned list are valid. Otherwise, they might not be. */
290 struct mount_entry *
291 read_filesystem_list (int need_fs_type)
293 struct mount_entry *mount_list;
294 struct mount_entry *me;
295 struct mount_entry **mtail = &mount_list;
297 #ifdef MOUNTED_LISTMNTENT
299 struct tabmntent *mntlist, *p;
300 struct mntent *mnt;
301 struct mount_entry *me;
303 /* the third and fourth arguments could be used to filter mounts,
304 but Crays doesn't seem to have any mounts that we want to
305 remove. Specifically, automount create normal NFS mounts.
308 if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0)
309 return NULL;
310 for (p = mntlist; p; p = p->next) {
311 mnt = p->ment;
312 me = (struct mount_entry*) xmalloc(sizeof (struct mount_entry));
313 me->me_devname = xstrdup(mnt->mnt_fsname);
314 me->me_mountdir = xstrdup(mnt->mnt_dir);
315 me->me_type = xstrdup(mnt->mnt_type);
316 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
317 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
318 me->me_dev = -1;
319 *mtail = me;
320 mtail = &me->me_next;
322 freemntlist(mntlist);
324 #endif
326 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
328 struct mntent *mnt;
329 char *table = MOUNTED;
330 FILE *fp;
331 char *devopt;
333 fp = setmntent (table, "r");
334 if (fp == NULL)
335 return NULL;
337 while ((mnt = getmntent (fp)))
339 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
340 me->me_devname = xstrdup (mnt->mnt_fsname);
341 me->me_mountdir = xstrdup (mnt->mnt_dir);
342 me->me_type = xstrdup (mnt->mnt_type);
343 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
344 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
345 devopt = strstr (mnt->mnt_opts, "dev=");
346 if (devopt)
348 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
349 me->me_dev = xatoi (devopt + 6);
350 else
351 me->me_dev = xatoi (devopt + 4);
353 else
354 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
356 /* Add to the linked list. */
357 *mtail = me;
358 mtail = &me->me_next;
361 if (endmntent (fp) == 0)
362 goto free_then_fail;
364 #endif /* MOUNTED_GETMNTENT1. */
366 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
368 struct statfs *fsp;
369 int entries;
371 entries = getmntinfo (&fsp, MNT_NOWAIT);
372 if (entries < 0)
373 return NULL;
374 for (; entries-- > 0; fsp++)
376 char *fs_type = fsp_to_string (fsp);
378 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
379 me->me_devname = xstrdup (fsp->f_mntfromname);
380 me->me_mountdir = xstrdup (fsp->f_mntonname);
381 me->me_type = fs_type;
382 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
383 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
384 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
386 /* Add to the linked list. */
387 *mtail = me;
388 mtail = &me->me_next;
391 #endif /* MOUNTED_GETMNTINFO */
393 #ifdef MOUNTED_GETMNT /* Ultrix. */
395 int offset = 0;
396 int val;
397 struct fs_data fsd;
399 while (errno = 0,
400 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
401 (char *) 0)))
403 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
404 me->me_devname = xstrdup (fsd.fd_req.devname);
405 me->me_mountdir = xstrdup (fsd.fd_req.path);
406 me->me_type = gt_names[fsd.fd_req.fstype];
407 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
408 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
409 me->me_dev = fsd.fd_req.dev;
411 /* Add to the linked list. */
412 *mtail = me;
413 mtail = &me->me_next;
415 if (val < 0)
416 goto free_then_fail;
418 #endif /* MOUNTED_GETMNT. */
420 #if defined (MOUNTED_FS_STAT_DEV) /* BeOS */
422 /* The next_dev() and fs_stat_dev() system calls give the list of
423 all filesystems, including the information returned by statvfs()
424 (fs type, total blocks, free blocks etc.), but without the mount
425 point. But on BeOS all filesystems except / are mounted in the
426 rootfs, directly under /.
427 The directory name of the mount point is often, but not always,
428 identical to the volume name of the device.
429 We therefore get the list of subdirectories of /, and the list
430 of all filesystems, and match the two lists. */
432 DIR *dirp;
433 struct rootdir_entry
435 char *name;
436 dev_t dev;
437 ino_t ino;
438 struct rootdir_entry *next;
440 struct rootdir_entry *rootdir_list;
441 struct rootdir_entry **rootdir_tail;
442 int32 pos;
443 dev_t dev;
444 fs_info fi;
446 /* All volumes are mounted in the rootfs, directly under /. */
447 rootdir_list = NULL;
448 rootdir_tail = &rootdir_list;
449 dirp = opendir ("/");
450 if (dirp)
452 struct dirent *d;
454 while ((d = readdir (dirp)) != NULL)
456 char *name;
457 struct stat statbuf;
459 if (strcmp (d->d_name, "..") == 0)
460 continue;
462 if (strcmp (d->d_name, ".") == 0)
463 name = xstrdup ("/");
464 else
466 name = xmalloc (1 + strlen (d->d_name) + 1);
467 name[0] = '/';
468 strcpy (name + 1, d->d_name);
471 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
473 struct rootdir_entry *re;
475 re = (struct rootdir_entry *) xmalloc (sizeof (struct rootdir_entry));
476 re->name = name;
477 re->dev = statbuf.st_dev;
478 re->ino = statbuf.st_ino;
480 /* Add to the linked list. */
481 *rootdir_tail = re;
482 rootdir_tail = &re->next;
484 else
485 free (name);
487 closedir (dirp);
489 *rootdir_tail = NULL;
491 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
492 if (fs_stat_dev (dev, &fi) >= 0)
494 /* Note: fi.dev == dev. */
495 struct rootdir_entry *re;
497 for (re = rootdir_list; re; re = re->next)
498 if (re->dev == fi.dev && re->ino == fi.root)
499 break;
501 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
502 me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
503 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
504 me->me_type = xstrdup (fi.fsh_name);
505 me->me_dev = fi.dev;
506 me->me_dummy = 0;
507 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
509 /* Add to the linked list. */
510 *mtail = me;
511 mtail = &me->me_next;
513 *mtail = NULL;
515 while (rootdir_list != NULL)
517 struct rootdir_entry *re = rootdir_list;
518 rootdir_list = re->next;
519 free (re->name);
520 free (re);
523 #endif /* MOUNTED_FS_STAT_DEV */
525 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
527 int numsys, counter, bufsize;
528 struct statfs *stats;
530 numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
531 if (numsys < 0)
532 return (NULL);
534 bufsize = (1 + numsys) * sizeof (struct statfs);
535 stats = (struct statfs *)xmalloc (bufsize);
536 numsys = getfsstat (stats, bufsize, MNT_WAIT);
538 if (numsys < 0)
540 free (stats);
541 return (NULL);
544 for (counter = 0; counter < numsys; counter++)
546 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
547 me->me_devname = xstrdup (stats[counter].f_mntfromname);
548 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
549 me->me_type = mnt_names[stats[counter].f_type];
550 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
551 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
552 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
554 /* Add to the linked list. */
555 *mtail = me;
556 mtail = &me->me_next;
559 free (stats);
561 #endif /* MOUNTED_GETFSSTAT */
563 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23]. */
565 struct mnttab mnt;
566 char *table = "/etc/mnttab";
567 FILE *fp;
569 fp = fopen (table, "r");
570 if (fp == NULL)
571 return NULL;
573 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
575 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
576 # ifdef GETFSTYP /* SVR3. */
577 me->me_devname = xstrdup (mnt.mt_dev);
578 # else
579 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
580 strcpy (me->me_devname, "/dev/");
581 strcpy (me->me_devname + 5, mnt.mt_dev);
582 # endif
583 me->me_mountdir = xstrdup (mnt.mt_filsys);
584 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
585 me->me_type = "";
586 # ifdef GETFSTYP /* SVR3. */
587 if (need_fs_type)
589 struct statfs fsd;
590 char typebuf[FSTYPSZ];
592 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
593 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
594 me->me_type = xstrdup (typebuf);
596 # endif
597 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
598 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
600 /* Add to the linked list. */
601 *mtail = me;
602 mtail = &me->me_next;
605 if (ferror (fp))
607 int saved_errno = errno;
608 fclose (fp);
609 errno = saved_errno;
610 goto free_then_fail;
613 if (fclose (fp) == EOF)
614 goto free_then_fail;
616 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
618 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
620 struct mntent **mnttbl=getmnttbl(),**ent;
621 for (ent=mnttbl;*ent;ent++)
623 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
624 me->me_devname = xstrdup ( (*ent)->mt_resource);
625 me->me_mountdir = xstrdup( (*ent)->mt_directory);
626 me->me_type = xstrdup ((*ent)->mt_fstype);
627 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
628 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
629 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
631 /* Add to the linked list. */
632 *mtail = me;
633 mtail = &me->me_next;
635 endmnttbl();
637 #endif
639 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
641 struct mnttab mnt;
642 char *table = MNTTAB;
643 FILE *fp;
644 int ret;
645 int lockfd = -1;
647 # if defined F_RDLCK && defined F_SETLKW
648 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
649 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
650 for this file name, we should use their macro name instead.
651 (Why not just lock MNTTAB directly? We don't know.) */
652 # ifndef MNTTAB_LOCK
653 # define MNTTAB_LOCK "/etc/.mnttab.lock"
654 # endif
655 lockfd = open (MNTTAB_LOCK, O_RDONLY);
656 if (0 <= lockfd)
658 struct flock flock;
659 flock.l_type = F_RDLCK;
660 flock.l_whence = SEEK_SET;
661 flock.l_start = 0;
662 flock.l_len = 0;
663 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
664 if (errno != EINTR)
666 int saved_errno = errno;
667 close (lockfd);
668 errno = saved_errno;
669 return NULL;
672 else if (errno != ENOENT)
673 return NULL;
674 # endif
676 errno = 0;
677 fp = fopen (table, "r");
678 if (fp == NULL)
679 ret = errno;
680 else
682 while ((ret = getmntent (fp, &mnt)) == 0)
684 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
685 me->me_devname = xstrdup (mnt.mnt_special);
686 me->me_mountdir = xstrdup (mnt.mnt_mountp);
687 me->me_type = xstrdup (mnt.mnt_fstype);
688 me->me_dummy = MNT_IGNORE (&mnt) != 0;
689 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
690 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
692 /* Add to the linked list. */
693 *mtail = me;
694 mtail = &me->me_next;
697 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
700 if (0 <= lockfd && close (lockfd) != 0)
701 ret = errno;
703 if (0 <= ret)
705 errno = ret;
706 goto free_then_fail;
709 #endif /* MOUNTED_GETMNTENT2. */
711 #ifdef MOUNTED_VMOUNT /* AIX. */
713 int bufsize;
714 char *entries, *thisent;
715 struct vmount *vmp;
717 /* Ask how many bytes to allocate for the mounted filesystem info. */
718 mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
719 entries = xmalloc (bufsize);
721 /* Get the list of mounted filesystems. */
722 mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
724 for (thisent = entries; thisent < entries + bufsize;
725 thisent += vmp->vmt_length)
727 char *options, *ignore;
729 vmp = (struct vmount *) thisent;
730 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
731 if (vmp->vmt_flags & MNT_REMOTE)
733 char *host, *path;
735 me->me_remote = 1;
736 /* Prepend the remote pathname. */
737 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
738 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
739 me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
740 strcpy (me->me_devname, host);
741 strcat (me->me_devname, ":");
742 strcat (me->me_devname, path);
744 else
746 me->me_remote = 0;
747 me->me_devname = xstrdup (thisent +
748 vmp->vmt_data[VMT_OBJECT].vmt_off);
750 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
751 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
752 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
753 ignore = strstr (options, "ignore");
754 me->me_dummy = (ignore
755 && (ignore == options || ignore[-1] == ',')
756 && (ignore[sizeof "ignore" - 1] == ','
757 || ignore[sizeof "ignore" - 1] == '\0'));
758 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
760 /* Add to the linked list. */
761 *mtail = me;
762 mtail = &me->me_next;
764 free (entries);
766 #endif /* MOUNTED_VMOUNT. */
768 *mtail = NULL;
769 return mount_list;
772 free_then_fail:
774 int saved_errno = errno;
775 *mtail = NULL;
777 while (mount_list)
779 me = mount_list->me_next;
780 free (mount_list->me_devname);
781 free (mount_list->me_mountdir);
782 /* FIXME: me_type is not always malloced. */
783 free (mount_list);
784 mount_list = me;
787 errno = saved_errno;
788 return NULL;