travis-ci: Use RSA keys for SSH tests
[monitoring-plugins.git] / gl / mountlist.c
blob30f4286130c92487538777627175b113f9526bd8
1 /* mountlist.c -- return a list of mounted file systems
3 Copyright (C) 1991-1992, 1997-2013 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 MOUNTED_INTERIX_STATVFS /* Interix. */
116 # include <sys/statvfs.h>
117 # include <dirent.h>
118 #endif
120 #ifdef DOLPHIN
121 /* So special that it's not worth putting this in autoconf. */
122 # undef MOUNTED_FREAD_FSTYP
123 # define MOUNTED_GETMNTTBL
124 #endif
126 #if HAVE_SYS_MNTENT_H
127 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
128 # include <sys/mntent.h>
129 #endif
131 #ifndef HAVE_HASMNTOPT
132 # define hasmntopt(mnt, opt) ((char *) 0)
133 #endif
135 #undef MNT_IGNORE
136 #ifdef MNTOPT_IGNORE
137 # define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
138 #else
139 # define MNT_IGNORE(M) 0
140 #endif
142 #if USE_UNLOCKED_IO
143 # include "unlocked-io.h"
144 #endif
146 /* The results of open() in this file are not used with fchdir,
147 therefore save some unnecessary work in fchdir.c. */
148 #undef open
149 #undef close
151 /* The results of opendir() in this file are not used with dirfd and fchdir,
152 therefore save some unnecessary work in fchdir.c. */
153 #undef opendir
154 #undef closedir
156 #define ME_DUMMY_0(Fs_name, Fs_type) \
157 (strcmp (Fs_type, "autofs") == 0 \
158 || strcmp (Fs_type, "proc") == 0 \
159 || strcmp (Fs_type, "subfs") == 0 \
160 /* for Linux 2.6/3.x */ \
161 || strcmp (Fs_type, "debugfs") == 0 \
162 || strcmp (Fs_type, "devpts") == 0 \
163 || strcmp (Fs_type, "fusectl") == 0 \
164 || strcmp (Fs_type, "mqueue") == 0 \
165 || strcmp (Fs_type, "rpc_pipefs") == 0 \
166 || strcmp (Fs_type, "sysfs") == 0 \
167 /* FreeBSD, Linux 2.4 */ \
168 || strcmp (Fs_type, "devfs") == 0 \
169 /* for NetBSD 3.0 */ \
170 || strcmp (Fs_type, "kernfs") == 0 \
171 /* for Irix 6.5 */ \
172 || strcmp (Fs_type, "ignore") == 0)
174 /* Historically, we have marked as "dummy" any file system of type "none",
175 but now that programs like du need to know about bind-mounted directories,
176 we grant an exception to any with "bind" in its list of mount options.
177 I.e., those are *not* dummy entries. */
178 #ifdef MOUNTED_GETMNTENT1
179 # define ME_DUMMY(Fs_name, Fs_type, Fs_ent) \
180 (ME_DUMMY_0 (Fs_name, Fs_type) \
181 || (strcmp (Fs_type, "none") == 0 \
182 && !hasmntopt (Fs_ent, "bind")))
183 #else
184 # define ME_DUMMY(Fs_name, Fs_type) \
185 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
186 #endif
188 #ifdef __CYGWIN__
189 # include <windows.h>
190 # define ME_REMOTE me_remote
191 /* All cygwin mount points include ':' or start with '//'; so it
192 requires a native Windows call to determine remote disks. */
193 static bool
194 me_remote (char const *fs_name, char const *fs_type _GL_UNUSED)
196 if (fs_name[0] && fs_name[1] == ':')
198 char drive[4];
199 sprintf (drive, "%c:\\", fs_name[0]);
200 switch (GetDriveType (drive))
202 case DRIVE_REMOVABLE:
203 case DRIVE_FIXED:
204 case DRIVE_CDROM:
205 case DRIVE_RAMDISK:
206 return false;
209 return true;
211 #endif
213 #ifndef ME_REMOTE
214 /* A file system is "remote" if its Fs_name contains a ':'
215 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//'). */
216 # define ME_REMOTE(Fs_name, Fs_type) \
217 (strchr (Fs_name, ':') != NULL \
218 || ((Fs_name)[0] == '/' \
219 && (Fs_name)[1] == '/' \
220 && (strcmp (Fs_type, "smbfs") == 0 \
221 || strcmp (Fs_type, "cifs") == 0)))
222 #endif
224 #if MOUNTED_GETMNTINFO
226 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
227 static char *
228 fstype_to_string (short int t)
230 switch (t)
232 # ifdef MOUNT_PC
233 case MOUNT_PC:
234 return "pc";
235 # endif
236 # ifdef MOUNT_MFS
237 case MOUNT_MFS:
238 return "mfs";
239 # endif
240 # ifdef MOUNT_LO
241 case MOUNT_LO:
242 return "lo";
243 # endif
244 # ifdef MOUNT_TFS
245 case MOUNT_TFS:
246 return "tfs";
247 # endif
248 # ifdef MOUNT_TMP
249 case MOUNT_TMP:
250 return "tmp";
251 # endif
252 # ifdef MOUNT_UFS
253 case MOUNT_UFS:
254 return "ufs" ;
255 # endif
256 # ifdef MOUNT_NFS
257 case MOUNT_NFS:
258 return "nfs" ;
259 # endif
260 # ifdef MOUNT_MSDOS
261 case MOUNT_MSDOS:
262 return "msdos" ;
263 # endif
264 # ifdef MOUNT_LFS
265 case MOUNT_LFS:
266 return "lfs" ;
267 # endif
268 # ifdef MOUNT_LOFS
269 case MOUNT_LOFS:
270 return "lofs" ;
271 # endif
272 # ifdef MOUNT_FDESC
273 case MOUNT_FDESC:
274 return "fdesc" ;
275 # endif
276 # ifdef MOUNT_PORTAL
277 case MOUNT_PORTAL:
278 return "portal" ;
279 # endif
280 # ifdef MOUNT_NULL
281 case MOUNT_NULL:
282 return "null" ;
283 # endif
284 # ifdef MOUNT_UMAP
285 case MOUNT_UMAP:
286 return "umap" ;
287 # endif
288 # ifdef MOUNT_KERNFS
289 case MOUNT_KERNFS:
290 return "kernfs" ;
291 # endif
292 # ifdef MOUNT_PROCFS
293 case MOUNT_PROCFS:
294 return "procfs" ;
295 # endif
296 # ifdef MOUNT_AFS
297 case MOUNT_AFS:
298 return "afs" ;
299 # endif
300 # ifdef MOUNT_CD9660
301 case MOUNT_CD9660:
302 return "cd9660" ;
303 # endif
304 # ifdef MOUNT_UNION
305 case MOUNT_UNION:
306 return "union" ;
307 # endif
308 # ifdef MOUNT_DEVFS
309 case MOUNT_DEVFS:
310 return "devfs" ;
311 # endif
312 # ifdef MOUNT_EXT2FS
313 case MOUNT_EXT2FS:
314 return "ext2fs" ;
315 # endif
316 default:
317 return "?";
320 # endif
322 static char *
323 fsp_to_string (const struct statfs *fsp)
325 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
326 return (char *) (fsp->f_fstypename);
327 # else
328 return fstype_to_string (fsp->f_type);
329 # endif
332 #endif /* MOUNTED_GETMNTINFO */
334 #ifdef MOUNTED_VMOUNT /* AIX. */
335 static char *
336 fstype_to_string (int t)
338 struct vfs_ent *e;
340 e = getvfsbytype (t);
341 if (!e || !e->vfsent_name)
342 return "none";
343 else
344 return e->vfsent_name;
346 #endif /* MOUNTED_VMOUNT */
349 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
351 /* Return the device number from MOUNT_OPTIONS, if possible.
352 Otherwise return (dev_t) -1. */
353 static dev_t
354 dev_from_mount_options (char const *mount_options)
356 /* GNU/Linux allows file system implementations to define their own
357 meaning for "dev=" mount options, so don't trust the meaning
358 here. */
359 # ifndef __linux__
361 static char const dev_pattern[] = ",dev=";
362 char const *devopt = strstr (mount_options, dev_pattern);
364 if (devopt)
366 char const *optval = devopt + sizeof dev_pattern - 1;
367 char *optvalend;
368 unsigned long int dev;
369 errno = 0;
370 dev = strtoul (optval, &optvalend, 16);
371 if (optval != optvalend
372 && (*optvalend == '\0' || *optvalend == ',')
373 && ! (dev == ULONG_MAX && errno == ERANGE)
374 && dev == (dev_t) dev)
375 return dev;
378 # endif
379 (void) mount_options;
380 return -1;
383 #endif
385 /* Return a list of the currently mounted file systems, or NULL on error.
386 Add each entry to the tail of the list so that they stay in order.
387 If NEED_FS_TYPE is true, ensure that the file system type fields in
388 the returned list are valid. Otherwise, they might not be. */
390 struct mount_entry *
391 read_file_system_list (bool need_fs_type)
393 struct mount_entry *mount_list;
394 struct mount_entry *me;
395 struct mount_entry **mtail = &mount_list;
396 (void) need_fs_type;
398 #ifdef MOUNTED_LISTMNTENT
400 struct tabmntent *mntlist, *p;
401 struct mntent *mnt;
402 struct mount_entry *me;
404 /* the third and fourth arguments could be used to filter mounts,
405 but Crays doesn't seem to have any mounts that we want to
406 remove. Specifically, automount create normal NFS mounts.
409 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
410 return NULL;
411 for (p = mntlist; p; p = p->next)
413 mnt = p->ment;
414 me = xmalloc (sizeof *me);
415 me->me_devname = xstrdup (mnt->mnt_fsname);
416 me->me_mountdir = xstrdup (mnt->mnt_dir);
417 me->me_type = xstrdup (mnt->mnt_type);
418 me->me_type_malloced = 1;
419 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
420 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
421 me->me_dev = -1;
422 *mtail = me;
423 mtail = &me->me_next;
425 freemntlist (mntlist);
427 #endif
429 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
431 struct mntent *mnt;
432 char const *table = MOUNTED;
433 FILE *fp;
435 fp = setmntent (table, "r");
436 if (fp == NULL)
437 return NULL;
439 while ((mnt = getmntent (fp)))
441 me = xmalloc (sizeof *me);
442 me->me_devname = xstrdup (mnt->mnt_fsname);
443 me->me_mountdir = xstrdup (mnt->mnt_dir);
444 me->me_type = xstrdup (mnt->mnt_type);
445 me->me_type_malloced = 1;
446 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, mnt);
447 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
448 me->me_dev = dev_from_mount_options (mnt->mnt_opts);
450 /* Add to the linked list. */
451 *mtail = me;
452 mtail = &me->me_next;
455 if (endmntent (fp) == 0)
456 goto free_then_fail;
458 #endif /* MOUNTED_GETMNTENT1. */
460 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
462 struct statfs *fsp;
463 int entries;
465 entries = getmntinfo (&fsp, MNT_NOWAIT);
466 if (entries < 0)
467 return NULL;
468 for (; entries-- > 0; fsp++)
470 char *fs_type = fsp_to_string (fsp);
472 me = xmalloc (sizeof *me);
473 me->me_devname = xstrdup (fsp->f_mntfromname);
474 me->me_mountdir = xstrdup (fsp->f_mntonname);
475 me->me_type = fs_type;
476 me->me_type_malloced = 0;
477 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
478 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
479 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
481 /* Add to the linked list. */
482 *mtail = me;
483 mtail = &me->me_next;
486 #endif /* MOUNTED_GETMNTINFO */
488 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
490 struct statvfs *fsp;
491 int entries;
493 entries = getmntinfo (&fsp, MNT_NOWAIT);
494 if (entries < 0)
495 return NULL;
496 for (; entries-- > 0; fsp++)
498 me = xmalloc (sizeof *me);
499 me->me_devname = xstrdup (fsp->f_mntfromname);
500 me->me_mountdir = xstrdup (fsp->f_mntonname);
501 me->me_type = xstrdup (fsp->f_fstypename);
502 me->me_type_malloced = 1;
503 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
504 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
505 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
507 /* Add to the linked list. */
508 *mtail = me;
509 mtail = &me->me_next;
512 #endif /* MOUNTED_GETMNTINFO2 */
514 #ifdef MOUNTED_GETMNT /* Ultrix. */
516 int offset = 0;
517 int val;
518 struct fs_data fsd;
520 while (errno = 0,
521 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
522 (char *) 0)))
524 me = xmalloc (sizeof *me);
525 me->me_devname = xstrdup (fsd.fd_req.devname);
526 me->me_mountdir = xstrdup (fsd.fd_req.path);
527 me->me_type = gt_names[fsd.fd_req.fstype];
528 me->me_type_malloced = 0;
529 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
530 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
531 me->me_dev = fsd.fd_req.dev;
533 /* Add to the linked list. */
534 *mtail = me;
535 mtail = &me->me_next;
537 if (val < 0)
538 goto free_then_fail;
540 #endif /* MOUNTED_GETMNT. */
542 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
544 /* The next_dev() and fs_stat_dev() system calls give the list of
545 all file systems, including the information returned by statvfs()
546 (fs type, total blocks, free blocks etc.), but without the mount
547 point. But on BeOS all file systems except / are mounted in the
548 rootfs, directly under /.
549 The directory name of the mount point is often, but not always,
550 identical to the volume name of the device.
551 We therefore get the list of subdirectories of /, and the list
552 of all file systems, and match the two lists. */
554 DIR *dirp;
555 struct rootdir_entry
557 char *name;
558 dev_t dev;
559 ino_t ino;
560 struct rootdir_entry *next;
562 struct rootdir_entry *rootdir_list;
563 struct rootdir_entry **rootdir_tail;
564 int32 pos;
565 dev_t dev;
566 fs_info fi;
568 /* All volumes are mounted in the rootfs, directly under /. */
569 rootdir_list = NULL;
570 rootdir_tail = &rootdir_list;
571 dirp = opendir ("/");
572 if (dirp)
574 struct dirent *d;
576 while ((d = readdir (dirp)) != NULL)
578 char *name;
579 struct stat statbuf;
581 if (strcmp (d->d_name, "..") == 0)
582 continue;
584 if (strcmp (d->d_name, ".") == 0)
585 name = xstrdup ("/");
586 else
588 name = xmalloc (1 + strlen (d->d_name) + 1);
589 name[0] = '/';
590 strcpy (name + 1, d->d_name);
593 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
595 struct rootdir_entry *re = xmalloc (sizeof *re);
596 re->name = name;
597 re->dev = statbuf.st_dev;
598 re->ino = statbuf.st_ino;
600 /* Add to the linked list. */
601 *rootdir_tail = re;
602 rootdir_tail = &re->next;
604 else
605 free (name);
607 closedir (dirp);
609 *rootdir_tail = NULL;
611 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
612 if (fs_stat_dev (dev, &fi) >= 0)
614 /* Note: fi.dev == dev. */
615 struct rootdir_entry *re;
617 for (re = rootdir_list; re; re = re->next)
618 if (re->dev == fi.dev && re->ino == fi.root)
619 break;
621 me = xmalloc (sizeof *me);
622 me->me_devname = xstrdup (fi.device_name[0] != '\0'
623 ? fi.device_name : fi.fsh_name);
624 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
625 me->me_type = xstrdup (fi.fsh_name);
626 me->me_type_malloced = 1;
627 me->me_dev = fi.dev;
628 me->me_dummy = 0;
629 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
631 /* Add to the linked list. */
632 *mtail = me;
633 mtail = &me->me_next;
635 *mtail = NULL;
637 while (rootdir_list != NULL)
639 struct rootdir_entry *re = rootdir_list;
640 rootdir_list = re->next;
641 free (re->name);
642 free (re);
645 #endif /* MOUNTED_FS_STAT_DEV */
647 #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
649 int numsys, counter;
650 size_t bufsize;
651 struct statfs *stats;
653 numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
654 if (numsys < 0)
655 return NULL;
656 if (SIZE_MAX / sizeof *stats <= numsys)
657 xalloc_die ();
659 bufsize = (1 + numsys) * sizeof *stats;
660 stats = xmalloc (bufsize);
661 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
663 if (numsys < 0)
665 free (stats);
666 return NULL;
669 for (counter = 0; counter < numsys; counter++)
671 me = xmalloc (sizeof *me);
672 me->me_devname = xstrdup (stats[counter].f_mntfromname);
673 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
674 me->me_type = xstrdup (FS_TYPE (stats[counter]));
675 me->me_type_malloced = 1;
676 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
677 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
678 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
680 /* Add to the linked list. */
681 *mtail = me;
682 mtail = &me->me_next;
685 free (stats);
687 #endif /* MOUNTED_GETFSSTAT */
689 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
691 struct mnttab mnt;
692 char *table = "/etc/mnttab";
693 FILE *fp;
695 fp = fopen (table, "r");
696 if (fp == NULL)
697 return NULL;
699 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
701 me = xmalloc (sizeof *me);
702 # ifdef GETFSTYP /* SVR3. */
703 me->me_devname = xstrdup (mnt.mt_dev);
704 # else
705 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
706 strcpy (me->me_devname, "/dev/");
707 strcpy (me->me_devname + 5, mnt.mt_dev);
708 # endif
709 me->me_mountdir = xstrdup (mnt.mt_filsys);
710 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
711 me->me_type = "";
712 me->me_type_malloced = 0;
713 # ifdef GETFSTYP /* SVR3. */
714 if (need_fs_type)
716 struct statfs fsd;
717 char typebuf[FSTYPSZ];
719 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
720 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
722 me->me_type = xstrdup (typebuf);
723 me->me_type_malloced = 1;
726 # endif
727 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
728 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
730 /* Add to the linked list. */
731 *mtail = me;
732 mtail = &me->me_next;
735 if (ferror (fp))
737 /* The last fread() call must have failed. */
738 int saved_errno = errno;
739 fclose (fp);
740 errno = saved_errno;
741 goto free_then_fail;
744 if (fclose (fp) == EOF)
745 goto free_then_fail;
747 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
749 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
751 struct mntent **mnttbl = getmnttbl (), **ent;
752 for (ent = mnttbl; *ent; ent++)
754 me = xmalloc (sizeof *me);
755 me->me_devname = xstrdup ((*ent)->mt_resource);
756 me->me_mountdir = xstrdup ((*ent)->mt_directory);
757 me->me_type = xstrdup ((*ent)->mt_fstype);
758 me->me_type_malloced = 1;
759 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
760 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
761 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
763 /* Add to the linked list. */
764 *mtail = me;
765 mtail = &me->me_next;
767 endmnttbl ();
769 #endif
771 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
773 struct mnttab mnt;
774 char *table = MNTTAB;
775 FILE *fp;
776 int ret;
777 int lockfd = -1;
779 # if defined F_RDLCK && defined F_SETLKW
780 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
781 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
782 for this file name, we should use their macro name instead.
783 (Why not just lock MNTTAB directly? We don't know.) */
784 # ifndef MNTTAB_LOCK
785 # define MNTTAB_LOCK "/etc/.mnttab.lock"
786 # endif
787 lockfd = open (MNTTAB_LOCK, O_RDONLY);
788 if (0 <= lockfd)
790 struct flock flock;
791 flock.l_type = F_RDLCK;
792 flock.l_whence = SEEK_SET;
793 flock.l_start = 0;
794 flock.l_len = 0;
795 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
796 if (errno != EINTR)
798 int saved_errno = errno;
799 close (lockfd);
800 errno = saved_errno;
801 return NULL;
804 else if (errno != ENOENT)
805 return NULL;
806 # endif
808 errno = 0;
809 fp = fopen (table, "r");
810 if (fp == NULL)
811 ret = errno;
812 else
814 while ((ret = getmntent (fp, &mnt)) == 0)
816 me = xmalloc (sizeof *me);
817 me->me_devname = xstrdup (mnt.mnt_special);
818 me->me_mountdir = xstrdup (mnt.mnt_mountp);
819 me->me_type = xstrdup (mnt.mnt_fstype);
820 me->me_type_malloced = 1;
821 me->me_dummy = MNT_IGNORE (&mnt) != 0;
822 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
823 me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
825 /* Add to the linked list. */
826 *mtail = me;
827 mtail = &me->me_next;
830 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
833 if (0 <= lockfd && close (lockfd) != 0)
834 ret = errno;
836 if (0 <= ret)
838 errno = ret;
839 goto free_then_fail;
842 #endif /* MOUNTED_GETMNTENT2. */
844 #ifdef MOUNTED_VMOUNT /* AIX. */
846 int bufsize;
847 char *entries, *thisent;
848 struct vmount *vmp;
849 int n_entries;
850 int i;
852 /* Ask how many bytes to allocate for the mounted file system info. */
853 if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
854 return NULL;
855 entries = xmalloc (bufsize);
857 /* Get the list of mounted file systems. */
858 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
859 if (n_entries < 0)
861 int saved_errno = errno;
862 free (entries);
863 errno = saved_errno;
864 return NULL;
867 for (i = 0, thisent = entries;
868 i < n_entries;
869 i++, thisent += vmp->vmt_length)
871 char *options, *ignore;
873 vmp = (struct vmount *) thisent;
874 me = xmalloc (sizeof *me);
875 if (vmp->vmt_flags & MNT_REMOTE)
877 char *host, *dir;
879 me->me_remote = 1;
880 /* Prepend the remote dirname. */
881 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
882 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
883 me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
884 strcpy (me->me_devname, host);
885 strcat (me->me_devname, ":");
886 strcat (me->me_devname, dir);
888 else
890 me->me_remote = 0;
891 me->me_devname = xstrdup (thisent +
892 vmp->vmt_data[VMT_OBJECT].vmt_off);
894 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
895 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
896 me->me_type_malloced = 1;
897 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
898 ignore = strstr (options, "ignore");
899 me->me_dummy = (ignore
900 && (ignore == options || ignore[-1] == ',')
901 && (ignore[sizeof "ignore" - 1] == ','
902 || ignore[sizeof "ignore" - 1] == '\0'));
903 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
905 /* Add to the linked list. */
906 *mtail = me;
907 mtail = &me->me_next;
909 free (entries);
911 #endif /* MOUNTED_VMOUNT. */
913 #ifdef MOUNTED_INTERIX_STATVFS
915 DIR *dirp = opendir ("/dev/fs");
916 char node[9 + NAME_MAX];
918 if (!dirp)
919 goto free_then_fail;
921 while (1)
923 struct statvfs dev;
924 struct dirent entry;
925 struct dirent *result;
927 if (readdir_r (dirp, &entry, &result) || result == NULL)
928 break;
930 strcpy (node, "/dev/fs/");
931 strcat (node, entry.d_name);
933 if (statvfs (node, &dev) == 0)
935 me = xmalloc (sizeof *me);
936 me->me_devname = xstrdup (dev.f_mntfromname);
937 me->me_mountdir = xstrdup (dev.f_mntonname);
938 me->me_type = xstrdup (dev.f_fstypename);
939 me->me_type_malloced = 1;
940 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
941 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
942 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
944 /* Add to the linked list. */
945 *mtail = me;
946 mtail = &me->me_next;
950 #endif /* MOUNTED_INTERIX_STATVFS */
952 *mtail = NULL;
953 return mount_list;
956 free_then_fail:
958 int saved_errno = errno;
959 *mtail = NULL;
961 while (mount_list)
963 me = mount_list->me_next;
964 free_mount_entry (mount_list);
965 mount_list = me;
968 errno = saved_errno;
969 return NULL;
973 /* Free a mount entry as returned from read_file_system_list (). */
975 void free_mount_entry (struct mount_entry *me)
977 free (me->me_devname);
978 free (me->me_mountdir);
979 if (me->me_type_malloced)
980 free (me->me_type);
981 free (me);