(jm_CHECK_DECLS): Reflect interface change.
[coreutils.git] / lib / mountlist.c
blobac25ee1892834ff5387cf5b0cd6e0c76ac79931d
1 /* mountlist.c -- return a list of mounted filesystems
2 Copyright (C) 1991, 1992, 1997, 1998 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 ();
43 void error ();
45 #include <errno.h>
46 #ifndef errno
47 extern int errno;
48 #endif
50 #ifdef HAVE_FCNTL_H
51 # include <fcntl.h>
52 #endif
54 #ifdef HAVE_UNISTD_H
55 # include <unistd.h>
56 #endif
58 #if HAVE_SYS_PARAM_H
59 # include <sys/param.h>
60 #endif
62 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
63 # include <sys/mount.h>
64 # include <sys/fs_types.h>
65 #endif /* MOUNTED_GETFSSTAT */
67 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
68 # include <mntent.h>
69 # if !defined(MOUNTED)
70 # if defined(MNT_MNTTAB) /* HP-UX. */
71 # define MOUNTED MNT_MNTTAB
72 # endif
73 # if defined(MNTTABNAME) /* Dynix. */
74 # define MOUNTED MNTTABNAME
75 # endif
76 # endif
77 #endif
79 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
80 # include <sys/mount.h>
81 #endif
83 #ifdef MOUNTED_GETMNT /* Ultrix. */
84 # include <sys/mount.h>
85 # include <sys/fs_types.h>
86 #endif
88 #ifdef MOUNTED_FREAD /* SVR2. */
89 # include <mnttab.h>
90 #endif
92 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
93 # include <mnttab.h>
94 # include <sys/fstyp.h>
95 # include <sys/statfs.h>
96 #endif
98 #ifdef MOUNTED_LISTMNTENT
99 # include <mntent.h>
100 #endif
102 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
103 # include <sys/mnttab.h>
104 #endif
106 #ifdef MOUNTED_VMOUNT /* AIX. */
107 # include <fshelp.h>
108 # include <sys/vfs.h>
109 #endif
111 #ifdef DOLPHIN
112 /* So special that it's not worth putting this in autoconf. */
113 # undef MOUNTED_FREAD_FSTYP
114 # define MOUNTED_GETMNTTBL
115 #endif
117 #if HAVE_SYS_MNTENT_H
118 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
119 # include <sys/mntent.h>
120 #endif
122 #if defined (MNTOPT_IGNORE) && defined (HAVE_HASMNTOPT)
123 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
124 #else
125 # define MNT_IGNORE(M) 0
126 #endif
128 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
129 /* Return the value of the hexadecimal number represented by CP.
130 No prefix (like '0x') or suffix (like 'h') is expected to be
131 part of CP. */
132 /* FIXME: this can overflow */
134 static int
135 xatoi (char *cp)
137 int val;
139 val = 0;
140 while (*cp)
142 if (*cp >= 'a' && *cp <= 'f')
143 val = val * 16 + *cp - 'a' + 10;
144 else if (*cp >= 'A' && *cp <= 'F')
145 val = val * 16 + *cp - 'A' + 10;
146 else if (*cp >= '0' && *cp <= '9')
147 val = val * 16 + *cp - '0';
148 else
149 break;
150 cp++;
152 return val;
154 #endif /* MOUNTED_GETMNTENT1. */
156 #if MOUNTED_GETMNTINFO
158 # if ! HAVE_F_FSTYPENAME_IN_STATFS
159 static char *
160 fstype_to_string (short t)
162 switch (t)
164 # ifdef MOUNT_PC
165 case MOUNT_PC:
166 return "pc";
167 # endif
168 # ifdef MOUNT_MFS
169 case MOUNT_MFS:
170 return "mfs";
171 # endif
172 # ifdef MOUNT_LO
173 case MOUNT_LO:
174 return "lo";
175 # endif
176 # ifdef MOUNT_TFS
177 case MOUNT_TFS:
178 return "tfs";
179 # endif
180 # ifdef MOUNT_TMP
181 case MOUNT_TMP:
182 return "tmp";
183 # endif
184 # ifdef MOUNT_UFS
185 case MOUNT_UFS:
186 return "ufs" ;
187 # endif
188 # ifdef MOUNT_NFS
189 case MOUNT_NFS:
190 return "nfs" ;
191 # endif
192 # ifdef MOUNT_MSDOS
193 case MOUNT_MSDOS:
194 return "msdos" ;
195 # endif
196 # ifdef MOUNT_LFS
197 case MOUNT_LFS:
198 return "lfs" ;
199 # endif
200 # ifdef MOUNT_LOFS
201 case MOUNT_LOFS:
202 return "lofs" ;
203 # endif
204 # ifdef MOUNT_FDESC
205 case MOUNT_FDESC:
206 return "fdesc" ;
207 # endif
208 # ifdef MOUNT_PORTAL
209 case MOUNT_PORTAL:
210 return "portal" ;
211 # endif
212 # ifdef MOUNT_NULL
213 case MOUNT_NULL:
214 return "null" ;
215 # endif
216 # ifdef MOUNT_UMAP
217 case MOUNT_UMAP:
218 return "umap" ;
219 # endif
220 # ifdef MOUNT_KERNFS
221 case MOUNT_KERNFS:
222 return "kernfs" ;
223 # endif
224 # ifdef MOUNT_PROCFS
225 case MOUNT_PROCFS:
226 return "procfs" ;
227 # endif
228 # ifdef MOUNT_AFS
229 case MOUNT_AFS:
230 return "afs" ;
231 # endif
232 # ifdef MOUNT_CD9660
233 case MOUNT_CD9660:
234 return "cd9660" ;
235 # endif
236 # ifdef MOUNT_UNION
237 case MOUNT_UNION:
238 return "union" ;
239 # endif
240 # ifdef MOUNT_DEVFS
241 case MOUNT_DEVFS:
242 return "devfs" ;
243 # endif
244 # ifdef MOUNT_EXT2FS
245 case MOUNT_EXT2FS:
246 return "ext2fs" ;
247 # endif
248 default:
249 return "?";
252 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
254 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
255 static char *
256 fsp_to_string (const struct statfs *fsp)
258 # if defined HAVE_F_FSTYPENAME_IN_STATFS
259 return fsp->f_fstypename;
260 # else
261 return fstype_to_string (fsp->f_type);
262 # endif
265 #endif /* MOUNTED_GETMNTINFO */
267 #ifdef MOUNTED_VMOUNT /* AIX. */
268 static char *
269 fstype_to_string (int t)
271 struct vfs_ent *e;
273 e = getvfsbytype (t);
274 if (!e || !e->vfsent_name)
275 return "none";
276 else
277 return e->vfsent_name;
279 #endif /* MOUNTED_VMOUNT */
281 /* Return a list of the currently mounted filesystems, or NULL on error.
282 Add each entry to the tail of the list so that they stay in order.
283 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
284 the returned list are valid. Otherwise, they might not be. */
286 struct mount_entry *
287 read_filesystem_list (int need_fs_type)
289 struct mount_entry *mount_list;
290 struct mount_entry *me;
291 struct mount_entry **mtail = &mount_list;
293 #ifdef MOUNTED_LISTMNTENT
295 struct tabmntent *mntlist, *p;
296 struct mntent *mnt;
297 struct mount_entry *me;
299 /* the third and fourth arguments could be used to filter mounts,
300 but Crays doesn't seem to have any mounts that we want to
301 remove. Specifically, automount create normal NFS mounts.
304 if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0)
305 return NULL;
306 for (p = mntlist; p; p = p->next) {
307 mnt = p->ment;
308 me = (struct mount_entry*) xmalloc(sizeof (struct mount_entry));
309 me->me_devname = xstrdup(mnt->mnt_fsname);
310 me->me_mountdir = xstrdup(mnt->mnt_dir);
311 me->me_type = xstrdup(mnt->mnt_type);
312 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
313 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
314 me->me_dev = -1;
315 *mtail = me;
316 mtail = &me->me_next;
318 freemntlist(mntlist);
320 #endif
322 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
324 struct mntent *mnt;
325 char *table = MOUNTED;
326 FILE *fp;
327 char *devopt;
329 fp = setmntent (table, "r");
330 if (fp == NULL)
331 return NULL;
333 while ((mnt = getmntent (fp)))
335 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
336 me->me_devname = xstrdup (mnt->mnt_fsname);
337 me->me_mountdir = xstrdup (mnt->mnt_dir);
338 me->me_type = xstrdup (mnt->mnt_type);
339 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
340 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
341 devopt = strstr (mnt->mnt_opts, "dev=");
342 if (devopt)
344 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
345 me->me_dev = xatoi (devopt + 6);
346 else
347 me->me_dev = xatoi (devopt + 4);
349 else
350 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
352 /* Add to the linked list. */
353 *mtail = me;
354 mtail = &me->me_next;
357 if (endmntent (fp) == 0)
358 goto free_then_fail;
360 #endif /* MOUNTED_GETMNTENT1. */
362 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
364 struct statfs *fsp;
365 int entries;
367 entries = getmntinfo (&fsp, MNT_NOWAIT);
368 if (entries < 0)
369 return NULL;
370 for (; entries-- > 0; fsp++)
372 char *fs_type = fsp_to_string (fsp);
374 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
375 me->me_devname = xstrdup (fsp->f_mntfromname);
376 me->me_mountdir = xstrdup (fsp->f_mntonname);
377 me->me_type = fs_type;
378 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
379 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
380 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
382 /* Add to the linked list. */
383 *mtail = me;
384 mtail = &me->me_next;
387 #endif /* MOUNTED_GETMNTINFO */
389 #ifdef MOUNTED_GETMNT /* Ultrix. */
391 int offset = 0;
392 int val;
393 struct fs_data fsd;
395 while (errno = 0,
396 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
397 (char *) 0)))
399 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
400 me->me_devname = xstrdup (fsd.fd_req.devname);
401 me->me_mountdir = xstrdup (fsd.fd_req.path);
402 me->me_type = gt_names[fsd.fd_req.fstype];
403 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
404 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
405 me->me_dev = fsd.fd_req.dev;
407 /* Add to the linked list. */
408 *mtail = me;
409 mtail = &me->me_next;
411 if (val < 0)
412 goto free_then_fail;
414 #endif /* MOUNTED_GETMNT. */
416 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
418 int numsys, counter, bufsize;
419 struct statfs *stats;
421 numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
422 if (numsys < 0)
423 return (NULL);
425 bufsize = (1 + numsys) * sizeof (struct statfs);
426 stats = (struct statfs *)xmalloc (bufsize);
427 numsys = getfsstat (stats, bufsize, MNT_WAIT);
429 if (numsys < 0)
431 free (stats);
432 return (NULL);
435 for (counter = 0; counter < numsys; counter++)
437 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
438 me->me_devname = xstrdup (stats[counter].f_mntfromname);
439 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
440 me->me_type = mnt_names[stats[counter].f_type];
441 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
442 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
443 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
445 /* Add to the linked list. */
446 *mtail = me;
447 mtail = &me->me_next;
450 free (stats);
452 #endif /* MOUNTED_GETFSSTAT */
454 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23]. */
456 struct mnttab mnt;
457 char *table = "/etc/mnttab";
458 FILE *fp;
460 fp = fopen (table, "r");
461 if (fp == NULL)
462 return NULL;
464 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
466 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
467 # ifdef GETFSTYP /* SVR3. */
468 me->me_devname = xstrdup (mnt.mt_dev);
469 # else
470 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
471 strcpy (me->me_devname, "/dev/");
472 strcpy (me->me_devname + 5, mnt.mt_dev);
473 # endif
474 me->me_mountdir = xstrdup (mnt.mt_filsys);
475 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
476 me->me_type = "";
477 # ifdef GETFSTYP /* SVR3. */
478 if (need_fs_type)
480 struct statfs fsd;
481 char typebuf[FSTYPSZ];
483 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
484 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
485 me->me_type = xstrdup (typebuf);
487 # endif
488 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
489 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
491 /* Add to the linked list. */
492 *mtail = me;
493 mtail = &me->me_next;
496 if (ferror (fp))
498 int saved_errno = errno;
499 fclose (fp);
500 errno = saved_errno;
501 goto free_then_fail;
504 if (fclose (fp) == EOF)
505 goto free_then_fail;
507 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
509 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
511 struct mntent **mnttbl=getmnttbl(),**ent;
512 for (ent=mnttbl;*ent;ent++)
514 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
515 me->me_devname = xstrdup ( (*ent)->mt_resource);
516 me->me_mountdir = xstrdup( (*ent)->mt_directory);
517 me->me_type = xstrdup ((*ent)->mt_fstype);
518 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
519 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
520 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
522 /* Add to the linked list. */
523 *mtail = me;
524 mtail = &me->me_next;
526 endmnttbl();
528 #endif
530 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
532 struct mnttab mnt;
533 char *table = MNTTAB;
534 FILE *fp;
535 int ret;
536 int lockfd = -1;
538 # if defined F_RDLCK && defined F_SETLKW
539 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
540 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
541 for this file name, we should use their macro name instead.
542 (Why not just lock MNTTAB directly? We don't know.) */
543 # ifndef MNTTAB_LOCK
544 # define MNTTAB_LOCK "/etc/.mnttab.lock"
545 # endif
546 lockfd = open (MNTTAB_LOCK, O_RDONLY);
547 if (0 <= lockfd)
549 struct flock flock;
550 flock.l_type = F_RDLCK;
551 flock.l_whence = SEEK_SET;
552 flock.l_start = 0;
553 flock.l_len = 0;
554 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
555 if (errno != EINTR)
557 int saved_errno = errno;
558 close (lockfd);
559 errno = saved_errno;
560 return NULL;
563 else if (errno != ENOENT)
564 return NULL;
565 # endif
567 errno = 0;
568 fp = fopen (table, "r");
569 if (fp == NULL)
570 ret = errno;
571 else
573 while ((ret = getmntent (fp, &mnt)) == 0)
575 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
576 me->me_devname = xstrdup (mnt.mnt_special);
577 me->me_mountdir = xstrdup (mnt.mnt_mountp);
578 me->me_type = xstrdup (mnt.mnt_fstype);
579 me->me_dummy = MNT_IGNORE (&mnt) != 0;
580 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
581 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
583 /* Add to the linked list. */
584 *mtail = me;
585 mtail = &me->me_next;
588 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
591 if (0 <= lockfd && close (lockfd) != 0)
592 ret = errno;
594 if (0 <= ret)
596 errno = ret;
597 goto free_then_fail;
600 #endif /* MOUNTED_GETMNTENT2. */
602 #ifdef MOUNTED_VMOUNT /* AIX. */
604 int bufsize;
605 char *entries, *thisent;
606 struct vmount *vmp;
608 /* Ask how many bytes to allocate for the mounted filesystem info. */
609 mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
610 entries = xmalloc (bufsize);
612 /* Get the list of mounted filesystems. */
613 mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
615 for (thisent = entries; thisent < entries + bufsize;
616 thisent += vmp->vmt_length)
618 vmp = (struct vmount *) thisent;
619 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
620 if (vmp->vmt_flags & MNT_REMOTE)
622 char *host, *path;
624 me->me_remote = 1;
625 /* Prepend the remote pathname. */
626 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
627 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
628 me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
629 strcpy (me->me_devname, host);
630 strcat (me->me_devname, ":");
631 strcat (me->me_devname, path);
633 else
635 me->me_remote = 0;
636 me->me_devname = xstrdup (thisent +
637 vmp->vmt_data[VMT_OBJECT].vmt_off);
639 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
640 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
641 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
642 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
644 /* Add to the linked list. */
645 *mtail = me;
646 mtail = &me->me_next;
648 free (entries);
650 #endif /* MOUNTED_VMOUNT. */
652 *mtail = NULL;
653 return mount_list;
656 free_then_fail:
658 int saved_errno = errno;
659 *mtail = NULL;
661 while (mount_list)
663 me = mount_list->me_next;
664 free (mount_list->me_devname);
665 free (mount_list->me_mountdir);
666 /* FIXME: me_type is not always malloced. */
667 free (mount_list);
668 mount_list = me;
671 errno = saved_errno;
672 return NULL;