home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / amd / config / mtab_file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-12  |  10.1 KB  |  447 lines

  1. /*
  2.  * Copyright (c) 1990 Jan-Simon Pendry
  3.  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
  4.  * Copyright (c) 1990 The Regents of the University of California.
  5.  * All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * Jan-Simon Pendry at Imperial College, London.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  * 1. Redistributions of source code must retain the above copyright
  14.  *    notice, this list of conditions and the following disclaimer.
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in the
  17.  *    documentation and/or other materials provided with the distribution.
  18.  * 3. All advertising materials mentioning features or use of this software
  19.  *    must display the following acknowledgement:
  20.  *    This product includes software developed by the University of
  21.  *    California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  *
  38.  *    @(#)mtab_file.c    5.3 (Berkeley) 5/12/91
  39.  *
  40.  * $Id: mtab_file.c,v 5.2.1.3 91/05/07 22:19:58 jsp Alpha $
  41.  *
  42.  */
  43.  
  44. #include "am.h"
  45.  
  46. #ifdef READ_MTAB_FROM_FILE
  47.  
  48. #ifdef USE_FCNTL
  49. #include <fcntl.h>
  50. #else
  51. #include <sys/file.h>
  52. #endif /* USE_FCNTL */
  53.  
  54. #ifdef UPDATE_MTAB
  55.  
  56. /*
  57.  * Do strict /etc/mtab locking
  58.  */
  59. #define    MTAB_LOCKING
  60.  
  61. /*
  62.  * Firewall mtab entries
  63.  */
  64. #define    MTAB_STRIPNL
  65.  
  66. #include <sys/stat.h>
  67. static FILE *mnt_file;
  68.  
  69. /*
  70.  * If the system is being trashed by something, then
  71.  * opening mtab may fail with ENFILE.  So, go to sleep
  72.  * for a second and try again. (Yes - this has happened to me.)
  73.  *
  74.  * Note that this *may* block the automounter, oh well. 
  75.  * If we get to this state then things are badly wrong anyway...
  76.  *
  77.  * Give the system 10 seconds to recover but then give up.
  78.  * Hopefully something else will exit and free up some file
  79.  * table slots in that time.
  80.  */
  81. #define    NFILE_RETRIES    10 /* seconds */
  82.  
  83. #ifdef MTAB_LOCKING
  84. #ifdef LOCK_FCNTL
  85. static int lock(fd)
  86. {
  87.     int rc;
  88.     struct flock lk;
  89.  
  90.     lk.l_type = F_WRLCK;
  91.     lk.l_whence = 0;
  92.     lk.l_start = 0;
  93.     lk.l_len = 0;
  94.  
  95. again:
  96.     rc = fcntl(fd, F_SETLKW, (caddr_t) &lk);
  97.     if (rc < 0 && (errno == EACCES || errno == EAGAIN)) {
  98. #ifdef DEBUG
  99.         dlog("Blocked, trying to obtain exclusive mtab lock");
  100. #endif /* DEBUG */
  101.         sleep(1);
  102.         goto again;
  103.     }
  104.     return rc;
  105. }
  106. #else
  107. #define lock(fd) (flock((fd), LOCK_EX))
  108. #endif /* LOCK_FCNTL */
  109. #endif /* MTAB_LOCKING */
  110.  
  111. static FILE *open_locked_mtab(mtab_file, mode, fs)
  112. char *mtab_file;
  113. char *mode;
  114. char *fs;
  115. {
  116.     FILE *mfp = 0;
  117.  
  118. #ifdef UPDATE_MTAB
  119.     /*
  120.      * There is a possible race condition if two processes enter
  121.      * this routine at the same time.  One will be blocked by the
  122.      * exclusive lock below (or by the shared lock in setmntent)
  123.      * and by the time the second process has the exclusive lock
  124.      * it will be on the wrong underlying object.  To check for this
  125.      * the mtab file is stat'ed before and after all the locking
  126.      * sequence, and if it is a different file then we assume that
  127.      * it may be the wrong file (only "may", since there is another
  128.      * race between the initial stat and the setmntent).
  129.      *
  130.      * Simpler solutions to this problem are invited...
  131.      */
  132.     int racing = 2;
  133. #ifdef MTAB_LOCKING
  134.     int rc;
  135.     int retries = 0;
  136.     struct stat st_before, st_after;
  137. #endif /* MTAB_LOCKING */
  138.  
  139.     if (mnt_file) {
  140. #ifdef DEBUG
  141.         dlog("Forced close on %s in read_mtab", mtab_file);
  142. #endif /* DEBUG */
  143.         endmntent(mnt_file);
  144.         mnt_file = 0;
  145.     }
  146.  
  147. #ifdef MTAB_LOCKING
  148. again:
  149.     if (mfp) {
  150.         endmntent(mfp);
  151.         mfp = 0;
  152.     }
  153.  
  154.     clock_valid = 0;
  155.     if (stat(mtab_file, &st_before) < 0) {
  156.         plog(XLOG_ERROR, "%s: stat: %m", mtab_file);
  157.         if (errno == ESTALE) {
  158.             /* happens occasionally */
  159.             sleep(1);
  160.             goto again;
  161.         }
  162.         return 0;
  163.     }
  164. #endif /* MTAB_LOCKING */
  165. #endif /* UPDATE_MTAB */
  166.  
  167. eacces:
  168.     mfp = setmntent(mtab_file, mode);
  169.     if (!mfp) {
  170.         /*
  171.          * Since setmntent locks the descriptor, it
  172.          * is possible it can fail... so retry if
  173.          * needed.
  174.          */
  175.         if (errno == EACCES || errno == EAGAIN) {
  176. #ifdef DEBUG
  177.             dlog("Blocked, trying to obtain exclusive mtab lock");
  178. #endif /* DEBUG */
  179.             goto eacces;
  180.         } else if (errno == ENFILE && retries++ < NFILE_RETRIES) {
  181.             sleep(1);
  182.             goto eacces;
  183.         }
  184.  
  185.         plog(XLOG_ERROR, "setmntent(\"%s\", \"%s\"): %m", mtab_file, mode);
  186.         return 0;
  187.     }
  188.  
  189. #ifdef MTAB_LOCKING
  190. #ifdef UPDATE_MTAB
  191.     /*
  192.      * At this point we have an exclusive lock on the mount list,
  193.      * but it may be the wrong one so...
  194.      */
  195.  
  196.     /*
  197.      * Need to get an exclusive lock on the current
  198.      * mount table until we have a new copy written
  199.      * out, when the lock is released in free_mntlist.
  200.      * flock is good enough since the mount table is
  201.      * not shared between machines.
  202.      */
  203.     do
  204.         rc = lock(fileno(mfp));
  205.     while (rc < 0 && errno == EINTR);
  206.     if (rc < 0) {
  207.         plog(XLOG_ERROR, "Couldn't lock %s: %m", mtab_file);
  208.         endmntent(mfp);
  209.         return 0;
  210.     }
  211.     /*
  212.      * Now check whether the mtab file has changed under our feet
  213.      */
  214.     if (stat(mtab_file, &st_after) < 0) {
  215.         plog(XLOG_ERROR, "%s: stat", mtab_file);
  216.         goto again;
  217.     }
  218.  
  219.     if (st_before.st_dev != st_after.st_dev ||
  220.         st_before.st_ino != st_after.st_ino) {
  221.             struct timeval tv;
  222.             if (racing == 0) {
  223.                 /* Sometimes print a warning */
  224.                 plog(XLOG_WARNING,
  225.                     "Possible mount table race - retrying %s", fs);
  226.             }
  227.             racing = (racing+1) & 3;
  228.             /*
  229.              * Take a nap.  From: Doug Kingston <dpk@morgan.com>
  230.              */
  231.             tv.tv_sec = 0;
  232.             tv.tv_usec = (mypid & 0x07) << 17;
  233.             if (tv.tv_usec)
  234.                 if (select(0, (voidp) 0, (voidp) 0, (voidp) 0, &tv) < 0)
  235.                     plog(XLOG_WARNING, "mtab nap failed: %m");
  236.  
  237.             goto again;
  238.     }
  239. #endif /* UPDATE_MTAB */
  240. #endif /* MTAB_LOCKING */
  241.  
  242.     return mfp;
  243. }
  244.  
  245. /*
  246.  * Unlock the mount table
  247.  */
  248. void unlock_mntlist P((void));
  249. void unlock_mntlist()
  250. {
  251.     /*
  252.      * Release file lock, by closing the file
  253.      */
  254.     if (mnt_file) {
  255.         endmntent(mnt_file);
  256.         mnt_file = 0;
  257.     }
  258. }
  259.  
  260. /*
  261.  * Write out a mount list
  262.  */
  263. void rewrite_mtab(mp)
  264. mntlist *mp;
  265. {
  266.     FILE *mfp;
  267.  
  268.     /*
  269.      * Concoct a temporary name in the same
  270.      * directory as the target mount table
  271.      * so that rename() will work.
  272.      */
  273.     char tmpname[64];
  274.     int retries;
  275.     int tmpfd;
  276.     char *cp;
  277.     char *mcp = mtab;
  278.     cp = strrchr(mcp, '/');
  279.     if (cp) {
  280.         bcopy(mcp, tmpname, cp - mcp);
  281.         tmpname[cp-mcp] = '\0';
  282.     } else {
  283.         plog(XLOG_WARNING, "No '/' in mtab (%s), using \".\" as tmp directory", mtab);
  284.         tmpname[0] = '.'; tmpname[1] = '\0';
  285.     }
  286.     strcat(tmpname, "/mtabXXXXXX");
  287.     mktemp(tmpname);
  288.     retries = 0;
  289. enfile1:
  290.     if ((tmpfd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
  291.         if (errno == ENFILE && retries++ < NFILE_RETRIES) {
  292.             sleep(1);
  293.             goto enfile1;
  294.         }
  295.         plog(XLOG_ERROR, "%s: open: %m", tmpname);
  296.         return;
  297.     }
  298.     if (close(tmpfd) < 0)
  299.         plog(XLOG_ERROR, "Couldn't close tmp file descriptor: %m");
  300.  
  301.     retries = 0;
  302. enfile2:
  303.     mfp = setmntent(tmpname, "w");
  304.     if (!mfp) {
  305.         if (errno == ENFILE && retries++ < NFILE_RETRIES) {
  306.             sleep(1);
  307.             goto enfile2;
  308.         }
  309.         plog(XLOG_ERROR, "setmntent(\"%s\", \"w\"): %m", tmpname);
  310.         return;
  311.     }
  312.  
  313.     while (mp) {
  314.         if (mp->mnt)
  315.             if (addmntent(mfp, mp->mnt))
  316.                 plog(XLOG_ERROR, "Can't write entry to %s", tmpname);
  317.         mp = mp->mnext;
  318.     }
  319.  
  320.     endmntent(mfp);
  321.  
  322.     /*
  323.      * Rename temporary mtab to real mtab
  324.      */
  325.     if (rename(tmpname, mtab) < 0)
  326.         plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mtab);
  327. }
  328.  
  329. #ifdef MTAB_STRIPNL
  330. static void mtab_stripnl(s)
  331. char *s;
  332. {
  333.     do {
  334.         s = strchr(s, '\n');
  335.         if (s)
  336.             *s++ = ' ';
  337.     } while (s);
  338. }
  339. #endif /* MTAB_STRIPNL */
  340.  
  341. /*
  342.  * Append a mntent structure to the
  343.  * current mount table.
  344.  */
  345. void write_mntent(mp)
  346. struct mntent *mp;
  347. {
  348.     int retries = 0;
  349.     FILE *mfp;
  350. enfile:
  351.     mfp = open_locked_mtab(mtab, "a", mp->mnt_dir);
  352.     if (mfp) {
  353. #ifdef MTAB_STRIPNL
  354.         mtab_stripnl(mp->mnt_opts);
  355. #endif /* MTAB_STRIPNL */
  356.         if (addmntent(mfp, mp))
  357.             plog(XLOG_ERROR, "Couldn't write %s: %m", mtab);
  358.         endmntent(mfp);
  359.     } else {
  360.         if (errno == ENFILE && retries < NFILE_RETRIES) {
  361.             sleep(1);
  362.             goto enfile;
  363.         }
  364.         plog(XLOG_ERROR, "setmntent(\"%s\", \"a\"): %m", mtab);
  365.     }
  366. }
  367.  
  368. #endif /* UPDATE_MTAB */
  369.  
  370. static struct mntent *mnt_dup(mp)
  371. struct mntent *mp;
  372. {
  373.     struct mntent *new_mp = ALLOC(mntent);
  374.  
  375.     new_mp->mnt_fsname = strdup(mp->mnt_fsname);
  376.     new_mp->mnt_dir = strdup(mp->mnt_dir);
  377.     new_mp->mnt_type = strdup(mp->mnt_type);
  378.     new_mp->mnt_opts = strdup(mp->mnt_opts);
  379.  
  380.     new_mp->mnt_freq = mp->mnt_freq;
  381.     new_mp->mnt_passno = mp->mnt_passno;
  382.  
  383. #ifdef FIXUP_MNTENT_DUP
  384.     /*
  385.      * Additional fields get dup'ed here
  386.      */
  387.     FIXUP_MNTENT_DUP(new_mp, mp);
  388. #endif
  389.  
  390.     return new_mp;
  391. }
  392.  
  393. /*
  394.  * Read a mount table into memory
  395.  */
  396. mntlist *read_mtab(fs)
  397. char *fs;
  398. {
  399.     mntlist **mpp, *mhp;
  400.  
  401.     struct mntent *mep;
  402.     FILE *mfp = open_locked_mtab(mtab, "r+", fs);
  403.  
  404.     if (!mfp)
  405.         return 0;
  406.  
  407.     mpp = &mhp;
  408.  
  409. /*
  410.  * XXX - In SunOS 4 there is (yet another) memory leak
  411.  * which loses 1K the first time getmntent is called.
  412.  * (jsp)
  413.  */
  414.     while (mep = getmntent(mfp)) {
  415.         /*
  416.          * Allocate a new slot
  417.          */
  418.         *mpp = ALLOC(mntlist);
  419.  
  420.         /*
  421.          * Copy the data returned by getmntent
  422.          */
  423.         (*mpp)->mnt = mnt_dup(mep);
  424.  
  425.         /*
  426.          * Move to next pointer
  427.          */
  428.         mpp = &(*mpp)->mnext;
  429.     }
  430.     *mpp = 0;
  431.  
  432. #ifdef UPDATE_MTAB
  433.     /*
  434.      * If we are not updating the mount table then we
  435.      * can free the resources held here, otherwise they
  436.      * must be held until the mount table update is complete
  437.      */
  438.     mnt_file = mfp;
  439. #else
  440.     endmntent(mfp);
  441. #endif /* UPDATE_MTAB */
  442.  
  443.     return mhp;
  444. }
  445.  
  446. #endif /* READ_MTAB_FROM_FILE */
  447.