BSD 4_4 release
[unix-history] / usr / src / usr.sbin / amd / config / mtab_file.c
index 9bec434..8101f71 100644 (file)
@@ -1,29 +1,44 @@
 /*
 /*
- * $Id: mtab_file.c,v 5.2 90/06/23 22:20:54 jsp Rel $
- *
  * Copyright (c) 1990 Jan-Simon Pendry
  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
  * 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.
+ * Copyright (c) 1990, 1993
+ *     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.
  *
  *
  * 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 are permitted provided
- * that: (1) source distributions retain this entire copyright notice and
- * comment, and (2) distributions including binaries display the following
- * acknowledgement:  ``This product includes software developed by the
- * University of California, Berkeley and its contributors'' in the
- * documentation or other materials provided with the distribution and in
- * all advertising materials mentioning features or use of this software.
- * 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     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
+ *    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.
+ *
+ *     @(#)mtab_file.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: mtab_file.c,v 5.2.2.1 1992/02/09 15:10:42 jsp beta $
  *
  *
- *     @(#)mtab_file.c 5.1 (Berkeley) 6/29/90
  */
 
 #include "am.h"
  */
 
 #include "am.h"
@@ -93,9 +108,144 @@ again:
 #endif /* LOCK_FCNTL */
 #endif /* MTAB_LOCKING */
 
 #endif /* LOCK_FCNTL */
 #endif /* MTAB_LOCKING */
 
+static FILE *open_locked_mtab(mtab_file, mode, fs)
+char *mtab_file;
+char *mode;
+char *fs;
+{
+       FILE *mfp = 0;
+
+#ifdef UPDATE_MTAB
+       /*
+        * 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;
+#ifdef MTAB_LOCKING
+       int rc;
+       int retries = 0;
+       struct stat st_before, st_after;
+#endif /* MTAB_LOCKING */
+
+       if (mnt_file) {
+#ifdef DEBUG
+               dlog("Forced close on %s in read_mtab", mtab_file);
+#endif /* DEBUG */
+               endmntent(mnt_file);
+               mnt_file = 0;
+       }
+
+#ifdef MTAB_LOCKING
+again:
+       if (mfp) {
+               endmntent(mfp);
+               mfp = 0;
+       }
+
+       clock_valid = 0;
+       if (stat(mtab_file, &st_before) < 0) {
+               plog(XLOG_ERROR, "%s: stat: %m", mtab_file);
+               if (errno == ESTALE) {
+                       /* happens occasionally */
+                       sleep(1);
+                       goto again;
+               }
+               return 0;
+       }
+#endif /* MTAB_LOCKING */
+#endif /* UPDATE_MTAB */
+
+eacces:
+       mfp = setmntent(mtab_file, 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", mtab_file, mode);
+               return 0;
+       }
+
+#ifdef MTAB_LOCKING
+#ifdef UPDATE_MTAB
+       /*
+        * 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", mtab_file);
+               endmntent(mfp);
+               return 0;
+       }
+       /*
+        * Now check whether the mtab file has changed under our feet
+        */
+       if (stat(mtab_file, &st_after) < 0) {
+               plog(XLOG_ERROR, "%s: stat", mtab_file);
+               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 = (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;
+       }
+#endif /* UPDATE_MTAB */
+#endif /* MTAB_LOCKING */
+
+       return mfp;
+}
+
 /*
  * Unlock the mount table
  */
 /*
  * Unlock the mount table
  */
+void unlock_mntlist P((void));
 void unlock_mntlist()
 {
        /*
 void unlock_mntlist()
 {
        /*
@@ -114,6 +264,7 @@ void rewrite_mtab(mp)
 mntlist *mp;
 {
        FILE *mfp;
 mntlist *mp;
 {
        FILE *mfp;
+       int error = 0;
 
        /*
         * Concoct a temporary name in the same
 
        /*
         * Concoct a temporary name in the same
@@ -157,23 +308,46 @@ enfile2:
                        goto enfile2;
                }
                plog(XLOG_ERROR, "setmntent(\"%s\", \"w\"): %m", tmpname);
                        goto enfile2;
                }
                plog(XLOG_ERROR, "setmntent(\"%s\", \"w\"): %m", tmpname);
-               return;
+               error = 1;
+               goto out;
        }
 
        while (mp) {
        }
 
        while (mp) {
-               if (mp->mnt)
-                       if (addmntent(mfp, mp->mnt))
+               if (mp->mnt) {
+                       if (addmntent(mfp, mp->mnt)) {
                                plog(XLOG_ERROR, "Can't write entry to %s", tmpname);
                                plog(XLOG_ERROR, "Can't write entry to %s", tmpname);
+                               error = 1;
+                               goto out;
+                       }
+               }
                mp = mp->mnext;
        }
 
                mp = mp->mnext;
        }
 
-       endmntent(mfp);
+       /*
+        * 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
         */
 
        /*
         * Rename temporary mtab to real mtab
         */
-       if (rename(tmpname, mtab) < 0)
+       if (rename(tmpname, mtab) < 0) {
                plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mtab);
                plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mtab);
+               error = 1;
+               goto out;
+       }
+
+out:
+       if (error)
+               (void) unlink(tmpname);
 }
 
 #ifdef MTAB_STRIPNL
 }
 
 #ifdef MTAB_STRIPNL
@@ -198,14 +372,16 @@ struct mntent *mp;
        int retries = 0;
        FILE *mfp;
 enfile:
        int retries = 0;
        FILE *mfp;
 enfile:
-       mfp = setmntent(mtab, "a");
+       mfp = open_locked_mtab(mtab, "a", mp->mnt_dir);
        if (mfp) {
 #ifdef MTAB_STRIPNL
                mtab_stripnl(mp->mnt_opts);
 #endif /* MTAB_STRIPNL */
                if (addmntent(mfp, mp))
                        plog(XLOG_ERROR, "Couldn't write %s: %m", mtab);
        if (mfp) {
 #ifdef MTAB_STRIPNL
                mtab_stripnl(mp->mnt_opts);
 #endif /* MTAB_STRIPNL */
                if (addmntent(mfp, mp))
                        plog(XLOG_ERROR, "Couldn't write %s: %m", mtab);
-               endmntent(mfp);
+               if (fflush(mfp))
+                       plog(XLOG_ERROR, "Couldn't flush %s: %m", mtab);
+               (void) endmntent(mfp);
        } else {
                if (errno == ENFILE && retries < NFILE_RETRIES) {
                        sleep(1);
        } else {
                if (errno == ENFILE && retries < NFILE_RETRIES) {
                        sleep(1);
@@ -230,6 +406,13 @@ struct mntent *mp;
        new_mp->mnt_freq = mp->mnt_freq;
        new_mp->mnt_passno = mp->mnt_passno;
 
        new_mp->mnt_freq = mp->mnt_freq;
        new_mp->mnt_passno = mp->mnt_passno;
 
+#ifdef FIXUP_MNTENT_DUP
+       /*
+        * Additional fields get dup'ed here
+        */
+       FIXUP_MNTENT_DUP(new_mp, mp);
+#endif
+
        return new_mp;
 }
 
        return new_mp;
 }
 
@@ -242,121 +425,10 @@ char *fs;
        mntlist **mpp, *mhp;
 
        struct mntent *mep;
        mntlist **mpp, *mhp;
 
        struct mntent *mep;
-       FILE *mfp = 0;
+       FILE *mfp = open_locked_mtab(mtab, "r+", fs);
 
 
-#ifdef UPDATE_MTAB
-       /*
-        * 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 = 0;
-#ifdef MTAB_LOCKING
-       int rc;
-       int retries = 0;
-       struct stat st_before, st_after;
-#endif /* MTAB_LOCKING */
-
-       if (mnt_file) {
-#ifdef DEBUG
-               dlog("Forced close on %s in read_mtab", mtab);
-#endif /* DEBUG */
-               endmntent(mnt_file);
-               mnt_file = 0;
-       }
-
-#ifdef MTAB_LOCKING
-again:
-       if (mfp) {
-               endmntent(mfp);
-               mfp = 0;
-       }
-
-       clock_valid = 0;
-       if (stat(mtab, &st_before) < 0) {
-               plog(XLOG_ERROR, "%s: stat: %m", mtab);
-               if (errno == ESTALE) {
-                       /* happens occasionally */
-                       sleep(1);
-                       goto again;
-               }
+       if (!mfp)
                return 0;
                return 0;
-       }
-#endif /* MTAB_LOCKING */
-#endif /* UPDATE_MTAB */
-
-eacces:
-       mfp = setmntent(mtab, "r+");
-       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\", \"r+\"): %m", mtab);
-               return 0;
-       }
-
-#ifdef MTAB_LOCKING
-#ifdef UPDATE_MTAB
-       /*
-        * 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", mtab);
-               endmntent(mfp);
-               return 0;
-       }
-       /*
-        * Now check whether the mtab file has changed under our feet
-        */
-       if (stat(mtab, &st_after) < 0) {
-               plog(XLOG_ERROR, "%s: stat", mtab);
-               goto again;
-       }
-
-       if (st_before.st_dev != st_after.st_dev ||
-               st_before.st_ino != st_after.st_ino) {
-                       if (racing == 0) {
-                               /* Sometimes print a warning */
-                               plog(XLOG_WARNING,
-                                       "Possible mount table race - retrying %s", fs);
-                       }
-                       racing = (racing+1) & 3;
-                       goto again;
-       }
-#endif /* UPDATE_MTAB */
-#endif /* MTAB_LOCKING */
 
        mpp = &mhp;
 
 
        mpp = &mhp;