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