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