diff options
author | Cy Schubert <cy@FreeBSD.org> | 2016-08-31 00:08:49 +0000 |
---|---|---|
committer | Cy Schubert <cy@FreeBSD.org> | 2016-08-31 00:08:49 +0000 |
commit | ca57057f598bfc7119f79f71bf38ec88244ab396 (patch) | |
tree | 051f78ef258707b493cc7cb21569b6949915f6c7 /conf/mtab | |
parent | e66b16bf080ead1c51f321eaf56710c771778706 (diff) | |
download | src-ca57057f598bfc7119f79f71bf38ec88244ab396.tar.gz src-ca57057f598bfc7119f79f71bf38ec88244ab396.zip |
Import am-utils 6.2,vendor/amd/6.2vendor/amd
Suggested by: pfg@
Obtained from: ftp://ftp.am-utils.org/pub/am-utils/
Notes
Notes:
svn path=/vendor/amd/dist/; revision=305100
svn path=/vendor/amd/6.2/; revision=305101; tag=vendor/amd/6.2
Diffstat (limited to 'conf/mtab')
-rw-r--r-- | conf/mtab/mtab_aix.c | 178 | ||||
-rw-r--r-- | conf/mtab/mtab_bsd.c | 21 | ||||
-rw-r--r-- | conf/mtab/mtab_file.c | 454 | ||||
-rw-r--r-- | conf/mtab/mtab_isc3.c | 269 | ||||
-rw-r--r-- | conf/mtab/mtab_linux.c | 565 | ||||
-rw-r--r-- | conf/mtab/mtab_mach3.c | 501 | ||||
-rw-r--r-- | conf/mtab/mtab_osf.c | 146 | ||||
-rw-r--r-- | conf/mtab/mtab_svr4.c | 302 | ||||
-rw-r--r-- | conf/mtab/mtab_ultrix.c | 119 |
9 files changed, 2544 insertions, 11 deletions
diff --git a/conf/mtab/mtab_aix.c b/conf/mtab/mtab_aix.c new file mode 100644 index 000000000000..072adc74151d --- /dev/null +++ b/conf/mtab/mtab_aix.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 1997-2014 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * File: am-utils/conf/mtab/mtab_aix.c + * + */ + +/* + * AIX systems don't write their mount tables on a file. Instead, they + * use a (better) system where the kernel keeps this state, and you access + * the mount tables via a known interface. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amu.h> + +/* + * These were missing external definitions from old AIX's headers. They + * appear to be available in <sys/vmount.h> on AIX 5.3, and possibly + * earlier. Hence I commented this out. + */ +#ifndef HAVE_EXTERN_MNTCTL +extern int mntctl(int cmd, int size, voidp buf); +#endif /* not HAVE_EXTERN_MNTCTL */ + + +static mntent_t * +mnt_dup(struct vmount *mp) +{ + mntent_t *new_mp = ALLOC(mntent_t); + char *ty; + char *fsname = xstrdup(vmt2dataptr(mp, VMT_OBJECT)); + + new_mp->mnt_dir = strdup(vmt2dataptr(mp, VMT_STUB)); + new_mp->mnt_opts = strdup(vmt2dataptr(mp, VMT_ARGS)); + + switch (mp->vmt_gfstype) { + + case MOUNT_TYPE_UFS: + ty = MNTTAB_TYPE_UFS; + new_mp->mnt_fsname = xstrdup(fsname); + break; + + case MOUNT_TYPE_NFS: + ty = MNTTAB_TYPE_NFS; + new_mp->mnt_fsname = str3cat((char *) NULL, + vmt2dataptr(mp, VMT_HOSTNAME), ":", + fsname); + break; + +#ifdef HAVE_FS_NFS3 + case MOUNT_TYPE_NFS3: + ty = MNTTAB_TYPE_NFS3; + new_mp->mnt_fsname = str3cat((char *) NULL, + vmt2dataptr(mp, VMT_HOSTNAME), ":", + fsname); + break; +#endif /* HAVE_FS_NFS3 */ + + default: + ty = "unknown"; + new_mp->mnt_fsname = xstrdup(fsname); + break; + + } + + new_mp->mnt_type = xstrdup(ty); + /* store the VFS ID for uvmount() */ + new_mp->mnt_passno = mp->vmt_vfsnumber; + new_mp->mnt_freq = 0; + + XFREE(fsname); + + return new_mp; +} + + +/* + * Read a mount table into memory + */ +mntlist * +read_mtab(char *fs, const char *mnttabname) +{ + mntlist **mpp, *mhp; + int i; + char *mntinfo = NULL, *cp; + struct vmount *vp; + int ret; + int maxtry = 10; /* maximum number of times to try mntctl */ + + /* + * Figure out size of mount table and allocate space for a copy. Then get + * mount table for real. We repeat this loop at most 10 times to minimze + * the chance of a race condition (something gets un/mounted in between + * calls to mntctl() + */ + i = sizeof(int); + do { + if (mntinfo) + XFREE(mntinfo); + mntinfo = xmalloc(i); + ret = mntctl(MCTL_QUERY, i, mntinfo); + if (ret == 0) + i = *(int*) mntinfo; + if (--maxtry <= 0) { + plog(XLOG_ERROR, "mntctl: could not get a stable result"); + ret = -1; + errno = EINVAL; + break; + } + } while (ret == 0); + if (ret < 0) { + plog(XLOG_ERROR, "mntctl: %m"); + goto out; + } + + mpp = &mhp; + for (i = 0, cp = mntinfo; i < ret; i++, cp += vp->vmt_length) { + vp = (struct vmount *) cp; + + /* + * Allocate a new slot + */ + *mpp = ALLOC(struct mntlist); + + /* + * Copy the data returned by mntctl + */ + (*mpp)->mnt = mnt_dup(vp); + + /* + * Move to next pointer + */ + mpp = &(*mpp)->mnext; + } + + *mpp = NULL; + +out: + if (mntinfo) + XFREE(mntinfo); + return mhp; +} diff --git a/conf/mtab/mtab_bsd.c b/conf/mtab/mtab_bsd.c index fe3991aa575d..203a265e13af 100644 --- a/conf/mtab/mtab_bsd.c +++ b/conf/mtab/mtab_bsd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2006 Erez Zadok + * Copyright (c) 1997-2014 Erez Zadok * Copyright (c) 1990 Jan-Simon Pendry * Copyright (c) 1990 Imperial College of Science, Technology & Medicine * Copyright (c) 1990 The Regents of the University of California. @@ -16,11 +16,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgment: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -53,6 +49,9 @@ #include <am_defs.h> #include <amu.h> +#if __NetBSD_Version__ > 200030000 +#define statfs statvfs +#endif static mntent_t * mnt_dup(struct statfs *mp) @@ -60,8 +59,8 @@ mnt_dup(struct statfs *mp) mntent_t *new_mp = ALLOC(mntent_t); char *ty; - new_mp->mnt_fsname = strdup(mp->f_mntfromname); - new_mp->mnt_dir = strdup(mp->f_mntonname); + new_mp->mnt_fsname = xstrdup(mp->f_mntfromname); + new_mp->mnt_dir = xstrdup(mp->f_mntonname); #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME ty = mp->f_fstypename; @@ -93,8 +92,8 @@ mnt_dup(struct statfs *mp) } #endif /* not HAVE_STRUCT_STATFS_F_FSTYPENAME */ - new_mp->mnt_type = strdup(ty); - new_mp->mnt_opts = strdup("unset"); + new_mp->mnt_type = xstrdup(ty); + new_mp->mnt_opts = xstrdup("unset"); new_mp->mnt_freq = 0; new_mp->mnt_passno = 0; @@ -138,7 +137,7 @@ read_mtab(char *fs, const char *mnttabname) /* * Terminate the list */ - *mpp = 0; + *mpp = NULL; return mhp; } diff --git a/conf/mtab/mtab_file.c b/conf/mtab/mtab_file.c new file mode 100644 index 000000000000..5004ef5f0e68 --- /dev/null +++ b/conf/mtab/mtab_file.c @@ -0,0 +1,454 @@ +/* + * Copyright (c) 1997-2014 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * File: am-utils/conf/mtab/mtab_file.c + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amu.h> + +#define NFILE_RETRIES 10 /* number of retries (seconds) */ + +#ifdef MOUNT_TABLE_ON_FILE + +static FILE *mnt_file; + + +/* + * If the system is being trashed by something, then + * opening mtab may fail with ENFILE. So, go to sleep + * for a second and try again. (Yes - this has happened to me.) + * + * Note that this *may* block the automounter, oh well. + * If we get to this state then things are badly wrong anyway... + * + * Give the system 10 seconds to recover but then give up. + * Hopefully something else will exit and free up some file + * table slots in that time. + */ +# ifdef HAVE_FLOCK +# define lock(fd) (flock((fd), LOCK_EX)) +# else /* not HAVE_FLOCK */ +static int +lock(int fd) +{ + int rc; + struct flock lk; + + lk.l_type = F_WRLCK; + lk.l_whence = 0; + lk.l_start = 0; + lk.l_len = 0; + +again: + rc = fcntl(fd, F_SETLKW, (caddr_t) & lk); + if (rc < 0 && (errno == EACCES || errno == EAGAIN)) { +# ifdef DEBUG + dlog("Blocked, trying to obtain exclusive mtab lock"); +# endif /* DEBUG */ + sleep(1); + goto again; + } + return rc; +} +# endif /* not HAVE_FLOCK */ + + +static FILE * +open_locked_mtab(const char *mnttabname, char *mode, char *fs) +{ + FILE *mfp = NULL; + + /* + * There is a possible race condition if two processes enter + * this routine at the same time. One will be blocked by the + * exclusive lock below (or by the shared lock in setmntent) + * and by the time the second process has the exclusive lock + * it will be on the wrong underlying object. To check for this + * the mtab file is stat'ed before and after all the locking + * sequence, and if it is a different file then we assume that + * it may be the wrong file (only "may", since there is another + * race between the initial stat and the setmntent). + * + * Simpler solutions to this problem are invited... + */ + int racing = 2; + int rc; + int retries = 0; + struct stat st_before, st_after; + + if (mnt_file) { +# ifdef DEBUG + dlog("Forced close on %s in read_mtab", mnttabname); +# endif /* DEBUG */ + endmntent(mnt_file); + mnt_file = NULL; + } +again: + if (mfp) { + endmntent(mfp); + mfp = NULL; + } + if (stat(mnttabname, &st_before) < 0) { + plog(XLOG_ERROR, "%s: stat: %m", mnttabname); + if (errno == ESTALE) { + /* happens occasionally */ + sleep(1); + goto again; + } + /* + * If 'mnttabname' file does not exist give setmntent() a + * chance to create it (depending on the mode). + * Otherwise, bail out. + */ + else if (errno != ENOENT) { + return 0; + } + } + +eacces: + mfp = setmntent((char *)mnttabname, mode); + if (!mfp) { + /* + * Since setmntent locks the descriptor, it + * is possible it can fail... so retry if + * needed. + */ + if (errno == EACCES || errno == EAGAIN) { +# ifdef DEBUG + dlog("Blocked, trying to obtain exclusive mtab lock"); +# endif /* DEBUG */ + goto eacces; + } else if (errno == ENFILE && retries++ < NFILE_RETRIES) { + sleep(1); + goto eacces; + } + plog(XLOG_ERROR, "setmntent(\"%s\", \"%s\"): %m", mnttabname, mode); + return 0; + } + /* + * At this point we have an exclusive lock on the mount list, + * but it may be the wrong one so... + */ + + /* + * Need to get an exclusive lock on the current + * mount table until we have a new copy written + * out, when the lock is released in free_mntlist. + * flock is good enough since the mount table is + * not shared between machines. + */ + do + rc = lock(fileno(mfp)); + while (rc < 0 && errno == EINTR); + if (rc < 0) { + plog(XLOG_ERROR, "Couldn't lock %s: %m", mnttabname); + endmntent(mfp); + return 0; + } + /* + * Now check whether the mtab file has changed under our feet + */ + if (stat(mnttabname, &st_after) < 0) { + plog(XLOG_ERROR, "%s: stat: %m", mnttabname); + goto again; + } + if (st_before.st_dev != st_after.st_dev || + st_before.st_ino != st_after.st_ino) { + struct timeval tv; + if (racing == 0) { + /* Sometimes print a warning */ + plog(XLOG_WARNING, + "Possible mount table race - retrying %s", fs); + } + racing = (racing + 1) & 3; + /* + * Take a nap. From: Doug Kingston <dpk@morgan.com> + */ + tv.tv_sec = 0; + tv.tv_usec = (am_mypid & 0x07) << 17; + if (tv.tv_usec) + if (select(0, (voidp) 0, (voidp) 0, (voidp) 0, &tv) < 0) + plog(XLOG_WARNING, "mtab nap failed: %m"); + + goto again; + } + + return mfp; +} + + +/* + * Unlock the mount table + */ +void +unlock_mntlist(void) +{ + /* + * Release file lock, by closing the file + */ + if (mnt_file) { + dlog("unlock_mntlist: releasing"); + endmntent(mnt_file); + mnt_file = NULL; + } +} + + +/* + * Write out a mount list + */ +void +rewrite_mtab(mntlist *mp, const char *mnttabname) +{ + FILE *mfp; + int error = 0; + + /* + * Concoct a temporary name in the same directory as the target mount + * table so that rename() will work. + */ + char tmpname[64]; + int retries; + int tmpfd; + char *cp; + char mcp[128]; + + xstrlcpy(mcp, mnttabname, sizeof(mcp)); + cp = strrchr(mcp, '/'); + if (cp) { + memmove(tmpname, mcp, cp - mcp); + tmpname[cp - mcp] = '\0'; + } else { + plog(XLOG_WARNING, "No '/' in mtab (%s), using \".\" as tmp directory", mnttabname); + tmpname[0] = '.'; + tmpname[1] = '\0'; + } + xstrlcat(tmpname, "/mtabXXXXXX", sizeof(tmpname)); + retries = 0; +enfile1: +#ifdef HAVE_MKSTEMP + tmpfd = mkstemp(tmpname); + fchmod(tmpfd, 0644); +#else /* not HAVE_MKSTEMP */ + mktemp(tmpname); + tmpfd = open(tmpname, O_RDWR | O_CREAT | O_TRUNC, 0644); +#endif /* not HAVE_MKSTEMP */ + if (tmpfd < 0) { + if (errno == ENFILE && retries++ < NFILE_RETRIES) { + sleep(1); + goto enfile1; + } + plog(XLOG_ERROR, "%s: open: %m", tmpname); + return; + } + if (close(tmpfd) < 0) + plog(XLOG_ERROR, "Couldn't close tmp file descriptor: %m"); + + retries = 0; +enfile2: + mfp = setmntent(tmpname, "w"); + if (!mfp) { + if (errno == ENFILE && retries++ < NFILE_RETRIES) { + sleep(1); + goto enfile2; + } + plog(XLOG_ERROR, "setmntent(\"%s\", \"w\"): %m", tmpname); + error = 1; + goto out; + } + while (mp) { + if (mp->mnt) { + if (addmntent(mfp, mp->mnt)) { + plog(XLOG_ERROR, "Can't write entry to %s", tmpname); + error = 1; + goto out; + } + } + mp = mp->mnext; + } + + /* + * SunOS 4.1 manuals say that the return code from entmntent() + * is always 1 and to treat as a void. That means we need to + * call fflush() to make sure the new mtab file got written. + */ + if (fflush(mfp)) { + plog(XLOG_ERROR, "flush new mtab file: %m"); + error = 1; + goto out; + } + (void) endmntent(mfp); + + /* + * Rename temporary mtab to real mtab + */ + if (rename(tmpname, mnttabname) < 0) { + plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mnttabname); + error = 1; + goto out; + } +out: + if (error) + (void) unlink(tmpname); +} + + +static void +mtab_stripnl(char *s) +{ + do { + s = strchr(s, '\n'); + if (s) + *s++ = ' '; + } while (s); +} + + +/* + * Append a mntent structure to the + * current mount table. + */ +void +write_mntent(mntent_t *mp, const char *mnttabname) +{ + int retries = 0; + FILE *mfp; +enfile: + mfp = open_locked_mtab(mnttabname, "a", mp->mnt_dir); + if (mfp) { + mtab_stripnl(mp->mnt_opts); + if (addmntent(mfp, mp)) + plog(XLOG_ERROR, "Couldn't write %s: %m", mnttabname); + if (fflush(mfp)) + plog(XLOG_ERROR, "Couldn't flush %s: %m", mnttabname); + (void) endmntent(mfp); + } else { + if (errno == ENFILE && retries < NFILE_RETRIES) { + sleep(1); + goto enfile; + } + plog(XLOG_ERROR, "setmntent(\"%s\", \"a\"): %m", mnttabname); + } +} + +#endif /* MOUNT_TABLE_ON_FILE */ + + +static mntent_t * +mnt_dup(mntent_t *mp) +{ + mntent_t *new_mp = ALLOC(mntent_t); + + new_mp->mnt_fsname = xstrdup(mp->mnt_fsname); + new_mp->mnt_dir = xstrdup(mp->mnt_dir); + new_mp->mnt_type = xstrdup(mp->mnt_type); + new_mp->mnt_opts = xstrdup(mp->mnt_opts); + + new_mp->mnt_freq = mp->mnt_freq; + new_mp->mnt_passno = mp->mnt_passno; + +#ifdef HAVE_MNTENT_T_MNT_TIME +# ifdef HAVE_MNTENT_T_MNT_TIME_STRING + new_mp->mnt_time = xstrdup(mp->mnt_time); +# else /* not HAVE_MNTENT_T_MNT_TIME_STRING */ + new_mp->mnt_time = mp->mnt_time; +# endif /* not HAVE_MNTENT_T_MNT_TIME_STRING */ +#endif /* HAVE_MNTENT_T_MNT_TIME */ + +#ifdef HAVE_MNTENT_T_MNT_CNODE + new_mp->mnt_cnode = mp->mnt_cnode; +#endif /* HAVE_MNTENT_T_MNT_CNODE */ + + return new_mp; +} + + +/* + * Read a mount table into memory + */ +mntlist * +read_mtab(char *fs, const char *mnttabname) +{ + mntlist **mpp, *mhp; + + mntent_t *mep; + FILE *mfp = open_locked_mtab(mnttabname, "r+", fs); + + if (!mfp) + return 0; + + mpp = &mhp; + +/* + * XXX - In SunOS 4 there is (yet another) memory leak + * which loses 1K the first time getmntent is called. + * (jsp) + */ + while ((mep = getmntent(mfp))) { + /* + * Allocate a new slot + */ + *mpp = ALLOC(struct mntlist); + + /* + * Copy the data returned by getmntent + */ + (*mpp)->mnt = mnt_dup(mep); + + /* + * Move to next pointer + */ + mpp = &(*mpp)->mnext; + } + *mpp = NULL; + +#ifdef MOUNT_TABLE_ON_FILE + /* + * If we are not updating the mount table then we + * can free the resources held here, otherwise they + * must be held until the mount table update is complete + */ + mnt_file = mfp; +#else /* not MOUNT_TABLE_ON_FILE */ + endmntent(mfp); +#endif /* not MOUNT_TABLE_ON_FILE */ + + return mhp; +} diff --git a/conf/mtab/mtab_isc3.c b/conf/mtab/mtab_isc3.c new file mode 100644 index 000000000000..9c8df1bae7d8 --- /dev/null +++ b/conf/mtab/mtab_isc3.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 1997-2014 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * File: am-utils/conf/mtab/mtab_isc3.c + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amu.h> + +/* fd for /etc/.mnt.lock (also act as flag for: is_locked) */ +static int mtlckf = 0; +static char mtlckname[] = "/etc/.mnt.lock"; +static char mnttabname[] = "/etc/mnttab"; + + +static void +unlockmnttab(void) +{ + if (mtlckf) { + close(mtlckf); + mtlckf = 0; + } +} + + +static +lockfile(int fd, int type) +{ + struct flock lk; + + lk.l_type = type; + lk.l_whence = 0; + lk.l_start = 0; + lk.l_len = 0; + + return fcntl(fd, F_SETLKW, &lk); +} + + +static +lockmnttab(void) +{ + if (mtlckf == 0) { /* need lock on /etc/.mnt.lock */ + mtlckf = open(mtlckname, O_RDWR); + if (mtlckf >= 0) { + if (lockfile(mtlckf, F_WRLCK) < 0) { + close(mtlckf); + mtlckf = 0; +#ifdef DEBUG + dlog("lock failed %m"); +#endif /* DEBUG */ + } else { + return 0; + } + } + } + plog(XLOG_ERROR, "Unable to lock %s: %m", mtlckname); + return -1; +} + + +void +unlock_mntlist(void) +{ + dlog("unlock_mntlist: releasing"); + unlockmnttab(); +} + + +/* convert from ix386 mnttab to amd mntent */ +static mntent_t * +mnt_dup(mntent_t *mp) +{ + /* note: may not be null terminated */ + mntent_t *new_mp = ALLOC(mntent_t); + char nullcpy[128]; + + xstrlcpy(nullcpy, mp->mt_dev, 32); + new_mp->mnt_fsname = xstrdup(nullcpy); + + xstrlcpy(nullcpy, mp->mt_filsys, 32); + new_mp->mnt_dir = xstrdup(nullcpy); + + xstrlcpy(nullcpy, mp->mt_fstyp, 16); + new_mp->mnt_type = xstrdup(nullcpy); + + xstrlcpy(nullcpy, mp->mt_mntopts, 64); + new_mp->mnt_opts = xstrdup(nullcpy); + + new_mp->mnt_freq = 0; + new_mp->mnt_passno = 0; + + new_mp->mnt_time = mp->mt_time; + new_mp->mnt_ro = mp->mt_ro_flg; + + return new_mp; +} + + +/* convert back (static alloc) */ +static mntent_t * +mtab_of(mntent_t *mnt) +{ + static mntent_t mt; + + xstrlcpy(mt.mt_dev, mnt->mnt_fsname, 32); + xstrlcpy(mt.mt_filsys, mnt->mnt_dir, 32); + + mt.mt_ro_flg = mnt->mnt_ro; + mt.mt_time = mnt->mnt_time; + + xstrlcpy(mt.mt_fstyp, mnt->mnt_type, 16); + xstrlcpy(mt.mt_mntopts, mnt->mnt_opts, 64); + + return &mt; +} + + +/* + * Read a mount table into memory + */ +mntlist * +read_mtab(char *fs, const char *mnttabname) +{ + mntlist **mpp, *mhp; + /* From: Piete Brooks <pb@cl.cam.ac.uk> */ + int fd; + mntent_t mountbuffer[NMOUNT], *fs_data; + int ret; + int nmts; + + if (lockmnttab() != 0) + return (mntlist *) NULL; + + fd = open(mnttabname, O_RDONLY); + if (fd < 0) { + plog(XLOG_ERROR, "Can't open %s: %m", mnttabname); + return (mntlist *) NULL; + } + mpp = &mhp; + while ((ret = read(fd, (char *) mountbuffer, NMOUNT * sizeof(mntent_t))) > 0) { + nmts = ret / sizeof(mntent_t); + for (fs_data = mountbuffer; fs_data < &mountbuffer[nmts]; fs_data++) { + /* + * Allocate a new slot + */ + *mpp = ALLOC(struct mntlist); + + /* + * Copy the data returned by getmntent + */ + (*mpp)->mnt = mnt_dup(fs_data); + + /* + * Move to next pointer + */ + mpp = &(*mpp)->mnext; + } + } + if (ret < 0) { + plog(XLOG_ERROR, "read error on %s: %m", mnttabname); + unlockmnttab(); + mhp = (mntlist *) NULL; + } + *mpp = NULL; + + close(fd); + return mhp; +} + + +static +write_mntent_to_mtab(int fd, mntent_t *mnt) +{ + int wr; + +eagain: + wr = write(fd, (char *) mtab_of(mnt), sizeof(mntent_t)); + if (wr < 0) { + switch (wr) { + case EAGAIN: + goto eagain; + default: + return -1; + } + } + if (wr != sizeof(mntent_t)) + plog(XLOG_ERROR, "Can't write entry to %s: %m", mnttabname); + return 0; +} + + +void +rewrite_mtab(mntlist *mp, const char *mnttabname) +{ + int fd; + + assert(mtlckf != 0); + + fd = open(mnttabname, O_RDWR | O_TRUNC); + if (fd < 0) { + plog(XLOG_ERROR, "Can't open %s: %m", mnttabname); + unlockmnttab(); + } + while (mp) { + if (mp->mnt) + write_mntent_to_mtab(fd, mp->mnt); + mp = mp->mnext; + } + + close(fd); + unlockmnttab(); +} + + +void +write_mntent(mntent_t *mp, const char *mnttabname) +{ + int fd; + + if (lockmnttab() == -1) + return; + + fd = open(mnttabname, O_RDWR | O_APPEND); + if (fd < 0) { + plog(XLOG_ERROR, "Unable to append %s: %m", mnttabname); + return; + } + write_mntent_to_mtab(fd, mp); + + close(fd); + unlockmnttab(); +} diff --git a/conf/mtab/mtab_linux.c b/conf/mtab/mtab_linux.c new file mode 100644 index 000000000000..829c97a57a35 --- /dev/null +++ b/conf/mtab/mtab_linux.c @@ -0,0 +1,565 @@ +/* + * Copyright (c) 1997-2014 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * File: am-utils/conf/mtab/mtab_linux.c + * + */ + +/* This file was adapted by Red Hat for Linux from mtab_file.c */ + +/* + * The locking code must be kept in sync with that used + * by the mount command in util-linux, otherwise you'll + * end with with race conditions leading to a corrupt + * /etc/mtab, particularly when AutoFS is used on same + * machine as AMD. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amu.h> + +#define NFILE_RETRIES 10 /* number of retries (seconds) */ +#define LOCK_TIMEOUT 10 + +#ifdef MOUNT_TABLE_ON_FILE + +# define PROC_MOUNTS "/proc/mounts" + +static FILE *mnt_file = NULL; +/* Information about mtab. ------------------------------------*/ +static int have_mtab_info = 0; +static int var_mtab_does_not_exist = 0; +static int var_mtab_is_a_symlink = 0; +/* Flag for already existing lock file. */ +static int we_created_lockfile = 0; +static int lockfile_fd = -1; + + +static void +get_mtab_info(void) +{ + struct stat mtab_stat; + + if (!have_mtab_info) { + if (lstat(MOUNTED, &mtab_stat)) + var_mtab_does_not_exist = 1; + else if (S_ISLNK(mtab_stat.st_mode)) + var_mtab_is_a_symlink = 1; + have_mtab_info = 1; + } +} + + +static int +mtab_is_a_symlink(void) +{ + get_mtab_info(); + return var_mtab_is_a_symlink; +} + + +static int +mtab_is_writable() +{ + static int ret = -1; + + /* + * Should we write to /etc/mtab upon an update? Probably not if it is a + * symlink to /proc/mounts, since that would create a file /proc/mounts in + * case the proc filesystem is not mounted. + */ + if (mtab_is_a_symlink()) + return 0; + + if (ret == -1) { + int fd = open(MOUNTED, O_RDWR | O_CREAT, 0644); + if (fd >= 0) { + close(fd); + ret = 1; + } else + ret = 0; + } + return ret; +} + + +static void +setlkw_timeout(int sig) +{ + /* nothing, fcntl will fail anyway */ +} + + +/* + * Create the lock file. + * The lock file will be removed if we catch a signal or when we exit. + * + * The old code here used flock on a lock file /etc/mtab~ and deleted + * this lock file afterwards. However, as rgooch remarks, that has a + * race: a second mount may be waiting on the lock and proceed as + * soon as the lock file is deleted by the first mount, and immediately + * afterwards a third mount comes, creates a new /etc/mtab~, applies + * flock to that, and also proceeds, so that the second and third mount + * now both are scribbling in /etc/mtab. + * The new code uses a link() instead of a creat(), where we proceed + * only if it was us that created the lock, and hence we always have + * to delete the lock afterwards. Now the use of flock() is in principle + * superfluous, but avoids an arbitrary sleep(). + */ + +/* + * Where does the link point to? Obvious choices are mtab and mtab~~. + * HJLu points out that the latter leads to races. Right now we use + * mtab~.<pid> instead. + */ +#define MOUNTED_LOCK "/etc/mtab~" +#define MOUNTLOCK_LINKTARGET MOUNTED_LOCK "%d" + +int +lock_mtab(void) +{ + int tries = 100000, i; + char *linktargetfile; + size_t l; + int rc = 1; + + /* + * Redhat's original code set a signal handler called "handler()" for all + * non-ALRM signals. The handler called unlock_mntlist(), plog'ed the + * signal name, and then exit(1)! Never, ever, exit() from inside a + * utility function. This messed up Amd's careful signal-handling code, + * and caused Amd to abort uncleanly only any other "innocent" signal + * (even simple SIGUSR1), leaving behind a hung Amd mnt point. That code + * should have at least restored the signal handlers' states upon a + * successful mtab unlocking. Anyway, that handler was unnecessary, + * because will call unlock_mntlist() properly anyway on exit. + */ + setup_sighandler(SIGALRM, setlkw_timeout); + + /* somewhat clumsy, but some ancient systems do not have snprintf() */ + /* use 20 as upper bound for the length of %d output */ + l = strlen(MOUNTLOCK_LINKTARGET) + 20; + linktargetfile = xmalloc(l); + xsnprintf(linktargetfile, l, MOUNTLOCK_LINKTARGET, getpid()); + + i = open(linktargetfile, O_WRONLY|O_CREAT, 0); + if (i < 0) { + int errsv = errno; + /* + * linktargetfile does not exist (as a file) and we cannot create + * it. Read-only filesystem? Too many files open in the system? + * Filesystem full? + */ + plog(XLOG_ERROR, "%s: can't create lock file %s: %s " + "(use -n flag to override)", __func__, + linktargetfile, strerror(errsv)); + goto error; + } + close(i); + + + /* Repeat until it was us who made the link */ + while (!we_created_lockfile) { + struct flock flock; + int errsv, j; + + j = link(linktargetfile, MOUNTED_LOCK); + errsv = errno; + + if (j < 0 && errsv != EEXIST) { + (void) unlink(linktargetfile); + plog(XLOG_ERROR, "can't link lock file %s: %s ", + MOUNTED_LOCK, strerror(errsv)); + rc = 0; + goto error; + } + + lockfile_fd = open(MOUNTED_LOCK, O_WRONLY); + if (lockfile_fd < 0) { + int errsv = errno; + /* Strange... Maybe the file was just deleted? */ + if (errno == ENOENT && tries-- > 0) { + if (tries % 200 == 0) + usleep(30); + continue; + } + (void) unlink(linktargetfile); + plog(XLOG_ERROR,"%s: can't open lock file %s: %s ", __func__, + MOUNTED_LOCK, strerror(errsv)); + rc = 0; + goto error; + } + + flock.l_type = F_WRLCK; + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 0; + + if (j == 0) { + /* We made the link. Now claim the lock. */ + if (fcntl(lockfile_fd, F_SETLK, &flock) == -1) { + int errsv = errno; + plog(XLOG_ERROR, "%s: Can't lock lock file %s: %s", __func__, + MOUNTED_LOCK, strerror(errsv)); + /* proceed, since it was us who created the lockfile anyway */ + } + we_created_lockfile = 1; + (void) unlink(linktargetfile); + } else { + static int tries = 0; + + /* Someone else made the link. Wait. */ + alarm(LOCK_TIMEOUT); + + if (fcntl(lockfile_fd, F_SETLKW, &flock) == -1) { + int errsv = errno; + (void) unlink(linktargetfile); + plog(XLOG_ERROR, "%s: can't lock lock file %s: %s", __func__, + MOUNTED_LOCK, (errno == EINTR) ? + "timed out" : strerror(errsv)); + rc = 0; + goto error; + } + alarm(0); + /* + * Limit the number of iterations - maybe there + * still is some old /etc/mtab~ + */ + ++tries; + if (tries % 200 == 0) + usleep(30); + if (tries > 100000) { + (void) unlink(linktargetfile); + close(lockfile_fd); + plog(XLOG_ERROR, + "%s: Cannot create link %s; Perhaps there is a stale lock file?", + __func__, MOUNTED_LOCK); + rc = 0; + goto error; + } + close(lockfile_fd); + } + } + +error: + XFREE(linktargetfile); + + return rc; +} + + +static FILE * +open_locked_mtab(const char *mnttabname, char *mode, char *fs) +{ + FILE *mfp = NULL; + + if (mnt_file) { + dlog("Forced close on %s in read_mtab", mnttabname); + endmntent(mnt_file); + mnt_file = NULL; + } + + if (!mtab_is_a_symlink() && + !lock_mtab()) { + plog(XLOG_ERROR, "%s: Couldn't lock mtab", __func__); + return 0; + } + + mfp = setmntent((char *)mnttabname, mode); + if (!mfp) { + plog(XLOG_ERROR, "%s: setmntent(\"%s\", \"%s\"): %m", __func__, mnttabname, + mode); + return 0; + } + return mfp; +} + + +/* + * Unlock the mount table + */ +void +unlock_mntlist(void) +{ + if (mnt_file || we_created_lockfile) + dlog("unlock_mntlist: releasing"); + if (mnt_file) { + endmntent(mnt_file); + mnt_file = NULL; + } + if (we_created_lockfile) { + close(lockfile_fd); + lockfile_fd = -1; + unlink(MOUNTED_LOCK); + we_created_lockfile = 0; + } +} + + +/* + * Write out a mount list + */ +void +rewrite_mtab(mntlist *mp, const char *mnttabname) +{ + FILE *mfp; + int error = 0; + char tmpname[64]; + int retries; + int tmpfd; + char *cp; + char mcp[128]; + + if (!mtab_is_writable()) { + return; + } + + /* + * Concoct a temporary name in the same directory as the target mount + * table so that rename() will work. + */ + xstrlcpy(mcp, mnttabname, sizeof(mcp)); + cp = strrchr(mcp, '/'); + if (cp) { + memmove(tmpname, mcp, cp - mcp); + tmpname[cp - mcp] = '\0'; + } else { + plog(XLOG_WARNING, "No '/' in mtab (%s), using \".\" as tmp directory", mnttabname); + tmpname[0] = '.'; + tmpname[1] = '\0'; + } + xstrlcat(tmpname, "/mtabXXXXXX", sizeof(tmpname)); + retries = 0; + enfile1: +#ifdef HAVE_MKSTEMP + tmpfd = mkstemp(tmpname); + fchmod(tmpfd, 0644); +#else /* not HAVE_MKSTEMP */ + mktemp(tmpname); + tmpfd = open(tmpname, O_RDWR | O_CREAT | O_TRUNC, 0644); +#endif /* not HAVE_MKSTEMP */ + if (tmpfd < 0) { + if (errno == ENFILE && retries++ < NFILE_RETRIES) { + sleep(1); + goto enfile1; + } + plog(XLOG_ERROR, "%s: open: %m", tmpname); + return; + } + if (close(tmpfd) < 0) + plog(XLOG_ERROR, "%s: Couldn't close tmp file descriptor: %m", __func__); + + retries = 0; + enfile2: + mfp = setmntent(tmpname, "w"); + if (!mfp) { + if (errno == ENFILE && retries++ < NFILE_RETRIES) { + sleep(1); + goto enfile2; + } + plog(XLOG_ERROR, "%s: setmntent(\"%s\", \"w\"): %m", __func__, tmpname); + error = 1; + goto out; + } + while (mp) { + if (mp->mnt) { + if (addmntent(mfp, mp->mnt)) { + plog(XLOG_ERROR, "%s: Can't write entry to %s", __func__, tmpname); + error = 1; + goto out; + } + } + mp = mp->mnext; + } + + /* + * SunOS 4.1 manuals say that the return code from entmntent() + * is always 1 and to treat as a void. That means we need to + * call fflush() to make sure the new mtab file got written. + */ + if (fflush(mfp)) { + plog(XLOG_ERROR, "flush new mtab file: %m"); + error = 1; + goto out; + } + (void) endmntent(mfp); + + /* + * Rename temporary mtab to real mtab + */ + if (rename(tmpname, mnttabname) < 0) { + plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mnttabname); + error = 1; + goto out; + } + out: + if (error) + (void) unlink(tmpname); +} + + +static void +mtab_stripnl(char *s) +{ + do { + s = strchr(s, '\n'); + if (s) + *s++ = ' '; + } while (s); +} + + +/* + * Append a mntent structure to the + * current mount table. + */ +void +write_mntent(mntent_t *mp, const char *mnttabname) +{ + int retries = 0; + FILE *mfp; + + if (!mtab_is_writable()) { + return; + } + + enfile: + mfp = open_locked_mtab(mnttabname, "a", mp->mnt_dir); + if (mfp) { + mtab_stripnl(mp->mnt_opts); + if (addmntent(mfp, mp)) + plog(XLOG_ERROR, "%s: Couldn't write %s: %m", __func__, mnttabname); + if (fflush(mfp)) + plog(XLOG_ERROR, "%s: Couldn't flush %s: %m", __func__, mnttabname); + (void) endmntent(mfp); + } else { + if (errno == ENFILE && retries < NFILE_RETRIES) { + sleep(1); + goto enfile; + } + plog(XLOG_ERROR, "%s: setmntent(\"%s\", \"a\"): %m", __func__, mnttabname); + } + + unlock_mntlist(); +} + +#endif /* MOUNT_TABLE_ON_FILE */ + + +static mntent_t * +mnt_dup(mntent_t *mp) +{ + mntent_t *new_mp = ALLOC(mntent_t); + + new_mp->mnt_fsname = xstrdup(mp->mnt_fsname); + new_mp->mnt_dir = xstrdup(mp->mnt_dir); + new_mp->mnt_type = xstrdup(mp->mnt_type); + new_mp->mnt_opts = xstrdup(mp->mnt_opts); + + new_mp->mnt_freq = mp->mnt_freq; + new_mp->mnt_passno = mp->mnt_passno; + +#ifdef HAVE_MNTENT_T_MNT_TIME +# ifdef HAVE_MNTENT_T_MNT_TIME_STRING + new_mp->mnt_time = xstrdup(mp->mnt_time); +# else /* not HAVE_MNTENT_T_MNT_TIME_STRING */ + new_mp->mnt_time = mp->mnt_time; +# endif /* not HAVE_MNTENT_T_MNT_TIME_STRING */ +#endif /* HAVE_MNTENT_T_MNT_TIME */ + +#ifdef HAVE_MNTENT_T_MNT_CNODE + new_mp->mnt_cnode = mp->mnt_cnode; +#endif /* HAVE_MNTENT_T_MNT_CNODE */ + + return new_mp; +} + + +/* + * Read a mount table into memory + */ +mntlist * +read_mtab(char *fs, const char *mnttabname) +{ + mntlist **mpp, *mhp; + + mntent_t *mep; + + FILE *mfp = open_locked_mtab(mnttabname, "r+", fs); + + if (!mfp) + return 0; + + mpp = &mhp; + + /* + * XXX - In SunOS 4 there is (yet another) memory leak + * which loses 1K the first time getmntent is called. + * (jsp) + */ + while ((mep = getmntent(mfp))) { + /* + * Allocate a new slot + */ + *mpp = ALLOC(struct mntlist); + + /* + * Copy the data returned by getmntent + */ + (*mpp)->mnt = mnt_dup(mep); + + /* + * Move to next pointer + */ + mpp = &(*mpp)->mnext; + } + *mpp = NULL; + +#ifdef MOUNT_TABLE_ON_FILE + /* + * If we are not updating the mount table then we + * can free the resources held here, otherwise they + * must be held until the mount table update is complete + */ + mnt_file = mfp; +#else /* not MOUNT_TABLE_ON_FILE */ + endmntent(mfp); +#endif /* not MOUNT_TABLE_ON_FILE */ + + return mhp; +} diff --git a/conf/mtab/mtab_mach3.c b/conf/mtab/mtab_mach3.c new file mode 100644 index 000000000000..af1313d3d8da --- /dev/null +++ b/conf/mtab/mtab_mach3.c @@ -0,0 +1,501 @@ +/* + * Copyright (c) 1997-2014 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * File: am-utils/conf/mtab/mtab_mach3.c + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amu.h> + +#define NFILE_RETRIES 10 /* number of retries (seconds) */ + +static FILE *mnt_file; + + +/* + * If the system is being trashed by something, then + * opening mtab may fail with ENFILE. So, go to sleep + * for a second and try again. (Yes - this has happened to me.) + * + * Note that this *may* block the automounter, oh well. + * If we get to this state then things are badly wrong anyway... + * + * Give the system 10 seconds to recover but then give up. + * Hopefully something else will exit and free up some file + * table slots in that time. + */ +#ifdef HAVE_FCNTL_H +static int +lock(int fd) +{ + int rc; + struct flock lk; + + lk.l_type = F_WRLCK; + lk.l_whence = 0; + lk.l_start = 0; + lk.l_len = 0; + +again: + rc = fcntl(fd, F_SETLKW, (caddr_t) & lk); + if (rc < 0 && (errno == EACCES || errno == EAGAIN)) { +# ifdef DEBUG + dlog("Blocked, trying to obtain exclusive mtab lock"); +# endif /* DEBUG */ + sleep(1); + goto again; + } + return rc; +} +#else /* not HAVE_FCNTL_H */ +# define lock(fd) (flock((fd), LOCK_EX)) +#endif /* not HAVE_FCNTL_H */ + + +static FILE * +open_locked_mtab(char *mnttabname, char *mode, char *fs) +{ + FILE *mfp = NULL; + + /* + * There is a possible race condition if two processes enter + * this routine at the same time. One will be blocked by the + * exclusive lock below (or by the shared lock in setmntent) + * and by the time the second process has the exclusive lock + * it will be on the wrong underlying object. To check for this + * the mtab file is stat'ed before and after all the locking + * sequence, and if it is a different file then we assume that + * it may be the wrong file (only "may", since there is another + * race between the initial stat and the setmntent). + * + * Simpler solutions to this problem are invited... + */ + int racing = 2; + int rc; + int retries = 0; + struct stat st_before, st_after; + + if (mnt_file) { +#ifdef DEBUG + dlog("Forced close on %s in read_mtab", mnttabname); +#endif /* DEBUG */ + endmntent(mnt_file); + mnt_file = NULL; + } +again: + if (mfp) { + endmntent(mfp); + mfp = NULL; + } + if (stat(mnttabname, &st_before) < 0) { + plog(XLOG_ERROR, "%s: stat: %m", mnttabname); + if (errno == ESTALE) { + /* happens occasionally */ + sleep(1); + goto again; + } + /* + * If 'mnttabname' file does not exist give setmntent() a + * chance to create it (depending on the mode). + * Otherwise, bail out. + */ + else if (errno != ENOENT) { + return 0; + } + } +eacces: + mfp = setmntent(mnttabname, mode); + if (!mfp) { + /* + * Since setmntent locks the descriptor, it + * is possible it can fail... so retry if + * needed. + */ + if (errno == EACCES || errno == EAGAIN) { +#ifdef DEBUG + dlog("Blocked, trying to obtain exclusive mtab lock"); +#endif /* DEBUG */ + goto eacces; + } else if (errno == ENFILE && retries++ < NFILE_RETRIES) { + sleep(1); + goto eacces; + } + plog(XLOG_ERROR, "setmntent(\"%s\", \"%s\"): %m", mnttabname, mode); + return 0; + } + /* + * At this point we have an exclusive lock on the mount list, + * but it may be the wrong one so... + */ + + /* + * Need to get an exclusive lock on the current + * mount table until we have a new copy written + * out, when the lock is released in free_mntlist. + * flock is good enough since the mount table is + * not shared between machines. + */ + do + rc = lock(fileno(mfp)); + while (rc < 0 && errno == EINTR); + if (rc < 0) { + plog(XLOG_ERROR, "Couldn't lock %s: %m", mnttabname); + endmntent(mfp); + return 0; + } + /* + * Now check whether the mtab file has changed under our feet + */ + if (stat(mnttabname, &st_after) < 0) { + plog(XLOG_ERROR, "%s: stat", mnttabname); + goto again; + } + if (st_before.st_dev != st_after.st_dev || + st_before.st_ino != st_after.st_ino) { + struct timeval tv; + if (racing == 0) { + /* Sometimes print a warning */ + plog(XLOG_WARNING, + "Possible mount table race - retrying %s", fs); + } + racing = (racing + 1) & 3; + /* + * Take a nap. From: Doug Kingston <dpk@morgan.com> + */ + tv.tv_sec = 0; + tv.tv_usec = (am_mypid & 0x07) << 17; + if (tv.tv_usec) + if (select(0, (voidp) 0, (voidp) 0, (voidp) 0, &tv) < 0) + plog(XLOG_WARNING, "mtab nap failed: %m"); + + goto again; + } + return mfp; +} + + +/* + * Unlock the mount table + */ +void +unlock_mntlist(void) +{ + /* + * Release file lock, by closing the file + */ + if (mnt_file) { + dlog("unlock_mntlist: releasing"); + endmntent(mnt_file); + mnt_file = NULL; + } +} + + +/* + * routine to convert notation "/@honeydew" to the notation + * honeydew:/ and vice versa (honeydew:/ to /@honeydew) + * This lets you put /@honeydew in /etc/fstab without changing + * fstab.c and it lets you use EITHER notation on the command line! + */ +static char * +convert(register char *s, char bad, char good) +{ + char *index(); + register char *t, *p; + register int len1, len2, i; + char *ptr; + + if ((p = index(s, bad)) == NULL) { + return (s); + } + ptr = t = (char *) xzalloc(MAXPATHLEN * sizeof(char)); + len1 = p - s; + len2 = strlen(s) - len1 - 1; + p++; + for (i = 0; i < len2; i++) + *t++ = p[i]; + *t++ = good; + for (i = 0; i < len1; i++) + *t++ = s[i]; + return (ptr); +} + + +static +mntprtent3(FILE *mnttabp, register mntent_t *mnt) +{ + char *cvtd = convert(mnt->mnt_fsname, ':', '@'); + + dlog("%x:%s:%s:%s:%d:%d:%s:%s:\n", + mnttabp, + (cvtd ? cvtd : ""), + (mnt->mnt_dir ? mnt->mnt_dir : ""), + (mnt->mnt_opts ? mnt->mnt_opts : ""), + mnt->mnt_freq, + mnt->mnt_passno, + (mnt->mnt_type ? mnt->mnt_type : ""), + (mnt->mnt_opts2 ? mnt->mnt_opts2 : "") + ); + fprintf(mnttabp, "%s:%s:%s:%d:%d:%s:%s:\n", + (cvtd ? cvtd : ""), + (mnt->mnt_dir ? mnt->mnt_dir : ""), + (mnt->mnt_opts ? mnt->mnt_opts : ""), + mnt->mnt_freq, + mnt->mnt_passno, + (mnt->mnt_type ? mnt->mnt_type : ""), + (mnt->mnt_opts2 ? mnt->mnt_opts2 : "") + ); + XFREE(cvtd); + cvtd = NULL; + return (0); +} + + +addmntent3(FILE *mnttabp, register mntent_t *mnt) +{ + if (fseek(mnttabp, 0, 2) < 0) { + return (1); + } + mntprtent3(mnttabp, mnt); + return (0); +} + + +/* + * Write out a mount list + */ +void +rewrite_mtab(mntlist *mp, const char *mnttabname) +{ + FILE *mfp; + int error = 0; + /* + * Concoct a temporary name in the same directory as the target mount + * table so that rename() will work. + */ + char tmpname[64]; + int retries; + int tmpfd; + char *cp; + char *mcp = mnttabname; + + cp = strrchr(mcp, '/'); + if (cp) { + memmove(tmpname, mcp, cp - mcp); + tmpname[cp - mcp] = '\0'; + } else { + plog(XLOG_WARNING, "No '/' in mtab (%s), using \".\" as tmp directory", mnttabname); + tmpname[0] = '.'; + tmpname[1] = '\0'; + } + xstrlcat(tmpname, "/mtabXXXXXX", sizeof(tmpname)); + retries = 0; +enfile1: +#ifdef HAVE_MKSTEMP + tmpfd = mkstemp(tmpname); + fchmod(tmpfd, 0644); +#else /* not HAVE_MKSTEMP */ + mktemp(tmpname); + tmpfd = open(tmpname, O_RDWR | O_CREAT | O_TRUNC, 0644); +#endif /* not HAVE_MKSTEMP */ + if (tmpfd < 0) { + if (errno == ENFILE && retries++ < NFILE_RETRIES) { + sleep(1); + goto enfile1; + } + plog(XLOG_ERROR, "%s: open: %m", tmpname); + return; + } + if (close(tmpfd) < 0) + plog(XLOG_ERROR, "Couldn't close tmp file descriptor: %m"); + + retries = 0; +enfile2: + mfp = setmntent(tmpname, "w"); + if (!mfp) { + if (errno == ENFILE && retries++ < NFILE_RETRIES) { + sleep(1); + goto enfile2; + } + plog(XLOG_ERROR, "setmntent(\"%s\", \"w\"): %m", tmpname); + error = 1; + goto out; + } + while (mp) { + if (mp->mnt) { + if (addmntent3(mfp, mp->mnt)) { + plog(XLOG_ERROR, "Can't write entry to %s", tmpname); + error = 1; + goto out; + } + } + mp = mp->mnext; + } + + /* + * SunOS 4.1 manuals say that the return code from endmntent() + * is always 1 and to treat as a void. That means we need to + * call fflush() to make sure the new mtab file got written. + */ + if (fflush(mfp)) { + plog(XLOG_ERROR, "flush new mtab file: %m"); + error = 1; + goto out; + } + (void) endmntent(mfp); + + /* + * Rename temporary mtab to real mtab + */ + if (rename(tmpname, mnttabname) < 0) { + plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mnttabname); + error = 1; + goto out; + } +out: + if (error) + (void) unlink(tmpname); +} + + +static void +mtab_stripnl(char *s) +{ + do { + s = strchr(s, '\n'); + if (s) + *s++ = ' '; + } while (s); +} + + +/* + * Append a mntent structure to the + * current mount table. + */ +void +write_mntent(mntent_t *mp, const char *mnttabname) +{ + int retries = 0; + FILE *mfp; +enfile: + mfp = open_locked_mtab(mnttabname, "a", mp->mnt_dir); + if (mfp) { + mtab_stripnl(mp->mnt_opts); + if (addmntent3(mfp, mp)) + plog(XLOG_ERROR, "Couldn't write %s: %m", mnttabname); + if (fflush(mfp)) + plog(XLOG_ERROR, "Couldn't flush %s: %m", mnttabname); + (void) endmntent(mfp); + } else { + if (errno == ENFILE && retries < NFILE_RETRIES) { + sleep(1); + goto enfile; + } + plog(XLOG_ERROR, "setmntent(\"%s\", \"a\"): %m", mnttabname); + } +} + + +static mntent_t * +mnt_dup(mntent_t *mp) +{ + mntent_t *new_mp = ALLOC(mntent_t); + + new_mp->mnt_fsname = convert(mp->mnt_fsname, '@', ':'); + + new_mp->mnt_dir = xstrdup(mp->mnt_dir); + new_mp->mnt_type = xstrdup(mp->mnt_type); + new_mp->mnt_opts = xstrdup(mp->mnt_opts); + + new_mp->mnt_freq = mp->mnt_freq; + new_mp->mnt_passno = mp->mnt_passno; + + return new_mp; +} + + +/* + * Read a mount table into memory + */ +mntlist * +read_mtab(char *fs, const char *mnttabname) +{ + mntlist **mpp, *mhp; + + mntent_t *mep; + FILE *mfp = open_locked_mtab(mnttabname, "r+", fs); + + if (!mfp) + return 0; + + mpp = &mhp; + +/* + * XXX - In SunOS 4 there is (yet another) memory leak + * which loses 1K the first time getmntent is called. + * (jsp) + */ + while (mep = getmntent(mfp)) { + /* + * Allocate a new slot + */ + *mpp = ALLOC(struct mntlist); + + /* + * Copy the data returned by getmntent + */ + (*mpp)->mnt = mnt_dup(mep); + + /* + * Move to next pointer + */ + mpp = &(*mpp)->mnext; + } + *mpp = NULL; + + /* + * If we are not updating the mount table then we + * can free the resources held here, otherwise they + * must be held until the mount table update is complete + */ + mnt_file = mfp; + + return mhp; +} diff --git a/conf/mtab/mtab_osf.c b/conf/mtab/mtab_osf.c new file mode 100644 index 000000000000..b9a1de533234 --- /dev/null +++ b/conf/mtab/mtab_osf.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 1997-2014 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * File: am-utils/conf/mtab/mtab_osf.c + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amu.h> + + +static mntent_t * +mnt_dup(struct statfs *mp) +{ + mntent_t *new_mp = ALLOC(mntent_t); + char *ty; + char *at; + char mntfrombuf[MNAMELEN]; + char *mntfromptr; + + /* + * Under DEC OSF/1 T1.2-2 the f_mntfromname fields of + * the statfs structure can be in the format <fs>@<host> + * instead of <host>:<fs>. Here we check for this and + * reformat it if necessary. + */ + mntfromptr = mp->f_mntfromname; + + switch (mp->f_type) { + case MOUNT_TYPE_NFS: +#ifdef HAVE_FS_NFS3 + case MOUNT_TYPE_NFS3: +#endif /* HAVE_FS_NFS3 */ + at = strchr(mp->f_mntfromname, '@'); + if (at != '\0') { + xstrlcpy(mntfrombuf, (at + 1), sizeof(mntfrombuf)); + xstrlcat(mntfrombuf, ":", sizeof(mntfrombuf)); + strncat(mntfrombuf, mp->f_mntfromname, (at - mp->f_mntfromname)); + mntfromptr = mntfrombuf; + } + } + new_mp->mnt_fsname = xstrdup(mntfromptr); + + new_mp->mnt_dir = xstrdup(mp->f_mntonname); + switch (mp->f_type) { + case MOUNT_TYPE_UFS: + ty = MNTTAB_TYPE_UFS; + break; +#ifdef HAVE_FS_NFS3 + case MOUNT_TYPE_NFS3: + ty = MNTTAB_TYPE_NFS3; + break; +#endif /* HAVE_FS_NFS3 */ + case MOUNT_TYPE_NFS: + ty = MNTTAB_TYPE_NFS; + break; + case MOUNT_TYPE_MFS: + ty = MNTTAB_TYPE_MFS; + break; + default: + ty = "unknown"; + break; + } + + new_mp->mnt_type = xstrdup(ty); + new_mp->mnt_opts = xstrdup("unset"); + new_mp->mnt_freq = 0; + new_mp->mnt_passno = 0; + + return new_mp; +} + + +/* + * Read a mount table into memory + */ +mntlist * +read_mtab(char *fs, const char *mnttabname) +{ + mntlist **mpp, *mhp; + struct statfs *mntbufp, *mntp; + + int nloc = getmntinfo(&mntbufp, MNT_NOWAIT); + + if (nloc == 0) { + plog(XLOG_ERROR, "Can't read mount table"); + return 0; + } + mpp = &mhp; + for (mntp = mntbufp; mntp < mntbufp + nloc; mntp++) { + /* + * Allocate a new slot + */ + *mpp = ALLOC(struct mntlist); + + /* + * Copy the data returned by getmntent + */ + (*mpp)->mnt = mnt_dup(mntp); + + /* + * Move to next pointer + */ + mpp = &(*mpp)->mnext; + } + + /* terminate the linked list */ + *mpp = NULL; + + return mhp; +} diff --git a/conf/mtab/mtab_svr4.c b/conf/mtab/mtab_svr4.c new file mode 100644 index 000000000000..b9a310a1903c --- /dev/null +++ b/conf/mtab/mtab_svr4.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 1997-2014 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * File: am-utils/conf/mtab/mtab_svr4.c + * + * How to manage the mount table file. Based on other SVR3 ports. + * -Erez Zadok <ezk@cs.columbia.edu> + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amu.h> + +/* + * file descriptor for lock file + * values: -1 no file-descriptor was set yet (or mnttab unlocked, or error + * in locking). + * >=0 legal file-descriptor value (file lock succeeded) + */ +static int mntent_lock_fd = -1; + + +#ifdef MOUNT_TABLE_ON_FILE +static char mtlckname[] = "/etc/.mnttab.lock"; +#endif /* MOUNT_TABLE_ON_FILE */ + + +/****************************************************************************/ +/*** Private functions */ +/****************************************************************************/ + +static void +unlockmnttab(void) +{ +#ifdef MOUNT_TABLE_ON_FILE + if (mntent_lock_fd >= 0) { + close(mntent_lock_fd); + mntent_lock_fd = -1; + } +#endif /* MOUNT_TABLE_ON_FILE */ +} + + +#ifdef MOUNT_TABLE_ON_FILE +static int +lockfile(int fd, int type) +{ + struct flock lk; + int ret; + + lk.l_type = type; + lk.l_whence = 0; + lk.l_start = 0; + lk.l_len = 0; + + /* + * F_SETLKW means to block until the read or write block is free to be + * locked. + */ + ret = fcntl(fd, F_SETLKW, &lk); + return ret; +} +#endif /* MOUNT_TABLE_ON_FILE */ + + +/* return 0 if locking succeeded, -1 if failed */ +static int +lockmnttab(void) +{ +#ifdef MOUNT_TABLE_ON_FILE + /* if mnttab file is locked, all is well */ + if (mntent_lock_fd >= 0) + return 0; + + /* need to lock mnttab file. first, open the file */ + mntent_lock_fd = open(mtlckname, O_RDWR | O_CREAT, 0600); + if (mntent_lock_fd < 0) { + plog(XLOG_ERROR, "Unable to open/creat %s: %m", mtlckname); + return -1; + } + + /* if succeeded in opening the file, try to lock it */ + if (lockfile(mntent_lock_fd, F_WRLCK) < 0) { + close(mntent_lock_fd); + mntent_lock_fd = -1; +#ifdef DEBUG + dlog("lock %s failed: %m", mtlckname); +#endif /* DEBUG */ + return -1; + } +#else /* not MOUNT_TABLE_ON_FILE */ + /* fake lock for in-kernel mount table */ +#endif /* not MOUNT_TABLE_ON_FILE */ + + /* finally, succeeded in also locking the file */ + return 0; +} + + +/* + * Convert from solaris mnttab to Amd mntent. Since am-utils uses + * native "struct mnttab" if available, this really copies fields of + * the same structure. + */ +static mntent_t * +mnt_dup(const mntent_t *mtp) +{ + mntent_t *mep = ALLOC(mntent_t); + + mep->mnt_fsname = xstrdup(mtp->mnt_fsname); + mep->mnt_dir = xstrdup(mtp->mnt_dir); + mep->mnt_type = xstrdup(mtp->mnt_type); + mep->mnt_opts = xstrdup(mtp->mnt_opts); + mep->mnt_time = xstrdup(mtp->mnt_time); + + return mep; +} + + +/* + * Adjust arguments in mntent_t. + */ +#ifdef MOUNT_TABLE_ON_FILE +static mntent_t * +update_mnttab_fields(const mntent_t *mnt) +{ + static mntent_t mt; + static char timestr[16]; + struct timeval tv; + + /* most fields don't change, only update mnt_time below */ + mt.mnt_fsname = mnt->mnt_fsname; + mt.mnt_dir = mnt->mnt_dir; + mt.mnt_type = mnt->mnt_type; + mt.mnt_opts = mnt->mnt_opts; + + /* + * Solaris 2.5 and newer take a second argument to gettimeofday(). If you + * find a useful svr4-like OS that uses the old style, and this code here + * fails, then create a new autoconf test that will determine the number + * of arguments gettimeofday() takes. -Erez. + */ + if (gettimeofday(&tv, NULL) < 0) + timestr[0] = '\0'; + else + xsnprintf(timestr, sizeof(timestr), "%ld", tv.tv_sec); + + mt.mnt_time = timestr; + + return &mt; +} +#endif /* MOUNT_TABLE_ON_FILE */ + + +static void +write_mntent_to_mtab(FILE *fp, const mntent_t *mnt) +{ +#ifdef MOUNT_TABLE_ON_FILE + putmntent(fp, update_mnttab_fields(mnt)); +#endif /* MOUNT_TABLE_ON_FILE */ +} + + +/****************************************************************************/ +/*** Public functions */ +/****************************************************************************/ + + +void +unlock_mntlist(void) +{ + unlockmnttab(); +} + + +/* + * Read a mount table into memory + */ +mntlist * +read_mtab(char *fs, const char *mnttabname) +{ + mntlist **mpp, *mhp; + FILE *fp; + mntent_t mountbuf; + int ret; + + if (lockmnttab() < 0) /* failed locking */ + return NULL; + + fp = fopen(mnttabname, "r"); + if (fp == NULL) { + plog(XLOG_ERROR, "Can't open %s: %m", mnttabname); + return NULL; + } + mpp = &mhp; + + while ((ret = getmntent(fp, &mountbuf)) == 0) { + /* + * Allocate a new slot + */ + *mpp = ALLOC(struct mntlist); + + /* + * Copy the data returned by getmntent + */ + (*mpp)->mnt = mnt_dup(&mountbuf); + + /* + * Move to next pointer + */ + mpp = &(*mpp)->mnext; + } + + if (ret > 0) { + plog(XLOG_ERROR, "read error on %s: %m", mnttabname); + unlockmnttab(); + mhp = NULL; + } + *mpp = NULL; + + fclose(fp); + return mhp; +} + + +void +rewrite_mtab(mntlist *mp, const char *mnttabname) +{ + FILE *fp; + + assert(mntent_lock_fd >= 0); /* ensure lock fd is valid */ + + fp = fopen(mnttabname, "r+"); + if (fp == NULL) { + plog(XLOG_ERROR, "Can't open %s: %m", mnttabname); + unlockmnttab(); + return; + } + while (mp) { + if (mp->mnt) + write_mntent_to_mtab(fp, mp->mnt); + mp = mp->mnext; + } + + ftruncate(fileno(fp), ftell(fp)); + fclose(fp); + unlockmnttab(); +} + + +void +write_mntent(mntent_t *mtp, const char *mnttabname) +{ + FILE *fp; + + if (lockmnttab() < 0) + return; + + fp = fopen(mnttabname, "a"); + if (fp == NULL) { + plog(XLOG_ERROR, "Unable to append %s: %m", mnttabname); + return; + } + write_mntent_to_mtab(fp, mtp); + + fclose(fp); + unlockmnttab(); +} diff --git a/conf/mtab/mtab_ultrix.c b/conf/mtab/mtab_ultrix.c new file mode 100644 index 000000000000..ea0eed6e8cf5 --- /dev/null +++ b/conf/mtab/mtab_ultrix.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1997-2014 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * File: am-utils/conf/mtab/mtab_ultrix.c + * + */ + +/* + * Include before config.h to force single definition of gt_names[] here. + * This can be done unconditionally since this file is Ultrix specific + * anyway and <sys/fs_types.h> is properly protected from multiple inclusion. + * - Rainer Orth <ro@TechFak.Uni-Bielefeld.DE> + * Hack hack hack. Sigh. -Erez. + */ +#include <sys/fs_types.h> + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amu.h> + +#ifndef NMOUNT +# define NMOUNT 20 +#endif /* NMOUNT */ + + +static mntent_t * +mnt_dup(struct fs_data *mp) +{ + mntent_t *new_mp = ALLOC(mntent_t); + + new_mp->mnt_fsname = xstrdup(mp->fd_devname); + new_mp->mnt_dir = xstrdup(mp->fd_path); + if (mp->fd_fstype >= GT_NUMTYPES) + mp->fd_fstype = GT_UNKWN; + else if (gt_names[mp->fd_fstype] == 0) + mp->fd_fstype = GT_UNKWN; + new_mp->mnt_type = xstrdup(gt_names[mp->fd_fstype]); + new_mp->mnt_opts = xstrdup("unset"); + + new_mp->mnt_freq = 0; + new_mp->mnt_passno = mp->fd_dev; + + return new_mp; +} + + +/* + * Read a mount table into memory + */ +mntlist * +read_mtab(char *fs, const char *mnttabname) +{ + mntlist **mpp, *mhp; + /* From: Piete Brooks <pb@cl.cam.ac.uk> */ + int loc = 0; + struct fs_data mountbuffer[NMOUNT], *fs_data; + int ret; + + mpp = &mhp; + while ((ret = getmountent(&loc, mountbuffer, NMOUNT)) > 0) { + for (fs_data = mountbuffer; fs_data < &mountbuffer[ret]; fs_data++) { + /* + * Allocate a new slot + */ + *mpp = ALLOC(struct mntlist); + + /* + * Copy the data returned by getmntent + */ + (*mpp)->mnt = mnt_dup(fs_data); + + /* + * Move to next pointer + */ + mpp = &(*mpp)->mnext; + } + } + if (ret < 0) { + plog(XLOG_ERROR, "getmountent: %m"); + return 0; + } + *mpp = NULL; + + return mhp; +} |