/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1996,1998 by Sun Microsystems, Inc. * All rights reserved. */ #include "dump.h" /* * File system mount table input routines. We handle a * a combination of BSD and SVR4 formats by coding functions * to explicitly read the SVR4 vfstab file and using * #define's to build a routine to read both BSD files * (fstab and mtab) and SVR4's mnttab file. Internally * we keep everything in the common (mtab/mnttab) format. */ static struct pmntent { struct mntent *pm_mnt; struct pmntent *pm_next; } *mnttable; /* Note that nothing is ever free()'d, so this is safe */ #define mntstrdup(s) ((s) ? strdup((s)) : "") #ifdef __STDC__ static struct mntent *mygetmntent(FILE *, char *); static struct pmntent *addmtab(char *, struct pmntent *); static struct mntent *allocmntent(struct mntent *); #else /* !__STDC__ */ static struct pmntent *addmtab(); static struct mntent *mygetmntent(); static struct mntent *allocmntent(); static int idatesort(); #endif static struct mntent * mygetmntent(f, name) FILE *f; char *name; { static struct mntent mt; int status; if ((status = getmntent(f, &mt)) == 0) return (&mt); switch (status) { case EOF: break; /* normal exit condition */ case MNT_TOOLONG: msg(gettext("%s has a line that is too long\n"), name); break; case MNT_TOOMANY: msg(gettext("%s has a line with too many entries\n"), name); break; case MNT_TOOFEW: msg(gettext("%s has a line with too few entries\n"), name); break; default: msg(gettext( "Unknown return code, %d, from getmntent() on %s\n"), status, name); break; } return (NULL); } /* * Read in SVR4 vfstab-format table. */ static struct pmntent * addvfstab(tablename, pm) char *tablename; struct pmntent *pm; { struct mnttab *mnt; struct vfstab vfs; FILE *tp; int status; assert(((mnttable == NULL) && (pm == NULL)) || (pm != NULL)); /* * No need to secure this, as tablename is hard-coded to VFSTAB, * and that file is in /etc. If random people have write-permission * there, then there are more problems than any degree of paranoia * on our part can fix. */ tp = fopen(tablename, "r"); if (tp == (FILE *)0) { msg(gettext("Cannot open %s for dump table information.\n"), tablename); return ((struct pmntent *)0); } while ((status = getvfsent(tp, &vfs)) == 0) { if (vfs.vfs_fstype == (char *)0 || strcmp(vfs.vfs_fstype, MNTTYPE_42) != 0) continue; mnt = (struct mnttab *)xmalloc(sizeof (*mnt)); mnt->mnt_fsname = mntstrdup(vfs.vfs_special); mnt->mnt_dir = mntstrdup(vfs.vfs_mountp); mnt->mnt_type = mntstrdup(vfs.vfs_fstype); mnt->mnt_opts = mntstrdup(vfs.vfs_mntopts); if (mnttable == (struct pmntent *)0) /* * Guaranteed by caller that pm will also be NULL, * so no memory leak to worry about. */ mnttable = pm = (struct pmntent *)xmalloc(sizeof (*pm)); else { /* Guaranteed pm not NULL by caller and local logic */ pm->pm_next = (struct pmntent *)xmalloc(sizeof (*pm)); pm = pm->pm_next; } pm->pm_mnt = mnt; pm->pm_next = (struct pmntent *)0; } switch (status) { case EOF: break; /* normal exit condition */ case VFS_TOOLONG: msg(gettext("%s has a line that is too long\n"), tablename); break; case VFS_TOOMANY: msg(gettext("%s has a line with too many entries\n"), tablename); break; case VFS_TOOFEW: msg(gettext("%s has a line with too few entries\n"), tablename); break; default: msg(gettext( "Unknown return code, %d, from getvfsent() on %s\n"), status, tablename); break; } (void) fclose(tp); return (pm); } static struct mntent * allocmntent(mnt) struct mntent *mnt; { struct mntent *new; new = (struct mntent *)xmalloc(sizeof (*mnt)); new->mnt_fsname = mntstrdup(mnt->mnt_fsname); /* mnt_special */ new->mnt_dir = mntstrdup(mnt->mnt_dir); /* mnt_mountp */ new->mnt_type = mntstrdup(mnt->mnt_type); /* mnt_fstype */ new->mnt_opts = mntstrdup(mnt->mnt_opts); /* mnt_mntopts */ return (new); } void mnttabread() { struct pmntent *pm = (struct pmntent *)0; if (mnttable != (struct pmntent *)0) return; /* * Read in the file system mount tables. Order * is important as the first matched entry is used * if the target device/filesystem is not mounted. * We try fstab or vfstab first, then mtab or mnttab. */ pm = addvfstab(VFSTAB, pm); (void) addmtab(MOUNTED, pm); } static struct pmntent * addmtab(tablename, pm) char *tablename; struct pmntent *pm; { struct mntent *mnt; FILE *tp; tp = setmntent(tablename, "r"); if (tp == (FILE *)0) { msg(gettext("Cannot open %s for dump table information.\n"), tablename); return ((struct pmntent *)0); } while (mnt = mygetmntent(tp, tablename)) { if (mnt->mnt_type == (char *)0 || strcmp(mnt->mnt_type, MNTTYPE_42) != 0) continue; mnt = allocmntent(mnt); if (mnttable == (struct pmntent *)0) /* * Guaranteed by caller that pm will also be NULL, * so no memory leak to worry about. */ mnttable = pm = (struct pmntent *)xmalloc(sizeof (*pm)); else { /* Guaranteed pm not NULL by caller and local logic */ pm->pm_next = (struct pmntent *)xmalloc(sizeof (*pm)); pm = pm->pm_next; } pm->pm_mnt = mnt; pm->pm_next = (struct pmntent *)0; } (void) endmntent(tp); return (pm); } /* * Search in fstab and potentially mtab for a file name. * If "mounted" is non-zero, the target file system must * be mounted in order for the search to succeed. * This file name can be either the special or the path file name. * * The entries in either fstab or mtab are the BLOCK special names, * not the character special names. * The caller of mnttabsearch assures that the character device * is dumped (that is much faster) * * The file name can omit the leading '/'. */ struct mntent * mnttabsearch(key, mounted) char *key; int mounted; { struct pmntent *pm; struct mntent *mnt; struct mntent *first = (struct mntent *)0; char *s; char *gotreal; char path[MAXPATHLEN]; for (pm = mnttable; pm; pm = pm->pm_next) { s = NULL; mnt = pm->pm_mnt; if (strcmp(mnt->mnt_dir, key) == 0) goto found; if (strcmp(mnt->mnt_fsname, key) == 0) goto found; if ((s = rawname(mnt->mnt_fsname)) != NULL && strcmp(s, key) == 0) goto found; gotreal = realpath(mnt->mnt_dir, path); if (gotreal && strcmp(path, key) == 0) goto found; if (key[0] != '/') { if (*mnt->mnt_fsname == '/' && strcmp(mnt->mnt_fsname + 1, key) == 0) goto found; if (*mnt->mnt_dir == '/' && strcmp(mnt->mnt_dir + 1, key) == 0) goto found; if (gotreal && *path == '/' && strcmp(path + 1, key) == 0) goto found; } if (s != NULL && s != mnt->mnt_fsname) free(s); continue; found: /* Pointer comparison, not string comparison */ if (s != NULL && s != mnt->mnt_fsname) free(s); /* * Found a match; return immediately if * it is mounted (valid), otherwise just * record if it's the first matched entry. */ if (lf_ismounted(mnt->mnt_fsname, mnt->mnt_dir) > 0) return (mnt); else if (first == (struct mntent *)0) first = mnt; } /* * If we get here, there were either * no matches, or no matched entries * were mounted. Return failure if * we were supposed to find a mounted * entry, otherwise return the first * matched entry (or null). */ if (mounted) return ((struct mntent *)0); return (first); } static struct pmntent *current; static int set; void #ifdef __STDC__ setmnttab(void) #else setmnttab() #endif { current = mnttable; set = 1; } struct mntent * #ifdef __STDC__ getmnttab(void) #else getmnttab() #endif { struct pmntent *pm; if (!set) setmnttab(); pm = current; if (current) { current = current->pm_next; return (pm->pm_mnt); } return ((struct mntent *)0); }