home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume21 / amd / part08 / mtab.c next >
Encoding:
C/C++ Source or Header  |  1990-04-10  |  11.7 KB  |  571 lines

  1. /*
  2.  * $Id: mtab.c,v 5.1.1.3 90/01/11 17:11:26 jsp Exp Locker: jsp $
  3.  *
  4.  * Copyright (c) 1989 Jan-Simon Pendry
  5.  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
  6.  * Copyright (c) 1989 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * This code is derived from software contributed to Berkeley by
  10.  * Jan-Simon Pendry at Imperial College, London.
  11.  *
  12.  * Redistribution and use in source and binary forms are permitted
  13.  * provided that the above copyright notice and this paragraph are
  14.  * duplicated in all such forms and that any documentation,
  15.  * advertising materials, and other materials related to such
  16.  * distribution and use acknowledge that the software was developed
  17.  * by Imperial College of Science, Technology and Medicine, London, UK.
  18.  * The names of the College and University may not be used to endorse
  19.  * or promote products derived from this software without specific
  20.  * prior written permission.
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  22.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  23.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  *
  25.  *    %W% (Berkeley) %G%
  26.  */
  27.  
  28. #include "am.h"
  29.  
  30. /*
  31.  * Firewall /etc/mtab entries
  32.  */
  33. #define    MTAB_STRIPNL
  34.  
  35. /*
  36.  * Do strict /etc/mtab locking
  37.  */
  38. #define MTAB_LOCKING
  39.  
  40. #ifdef READ_MTAB_FROM_FILE
  41. #ifdef USE_FCNTL
  42. #include <fcntl.h>
  43. #else
  44. #include <sys/file.h>
  45. #endif
  46. #endif
  47.  
  48. #ifdef READ_MTAB_ULTRIX_STYLE
  49. #include <sys/mount.h>
  50. #include <sys/fs_types.h>
  51. #endif
  52.  
  53. #ifdef READ_MTAB_BSD_STYLE
  54. #include <sys/mount.h>
  55. #endif
  56.  
  57. #ifdef UPDATE_MTAB
  58. #include <sys/stat.h>
  59. static FILE *mnt_file;
  60.  
  61. /*
  62.  * If the system is being trashed by something, then
  63.  * opening mtab may fail with ENFILE.  So, go to sleep
  64.  * for a second and try again. (Yes - this has happened to me.)
  65.  *
  66.  * Note that this *may* block the automounter, oh well. 
  67.  * If we get to this state then things are badly wrong anyway...
  68.  *
  69.  * Give the system 10 seconds to recover but then give up.
  70.  * Hopefully something else will exit and free up some file
  71.  * table slots in that time.
  72.  */
  73. #define    NFILE_RETRIES    10 /* seconds */
  74.  
  75. #endif /* UPDATE_MTAB */
  76.  
  77. #ifdef MTAB_LOCKING
  78. #ifdef LOCK_FCNTL
  79. static int lock(fd)
  80. {
  81.     int rc;
  82.     struct flock lk;
  83.  
  84.     lk.l_type = F_WRLCK;
  85.     lk.l_whence = 0;
  86.     lk.l_start = 0;
  87.     lk.l_len = 0;
  88.  
  89. again:
  90.     rc = fcntl(fd, F_SETLKW, (caddr_t) &lk);
  91.     if (rc < 0 && (errno == EACCES || errno == EAGAIN)) {
  92. #ifdef DEBUG
  93.         dlog("Blocked, trying to obtain exclusive mtab lock");
  94. #endif
  95.         sleep(1);
  96.         goto again;
  97.     }
  98.     return rc;
  99. }
  100. #else
  101. #define lock(fd) (flock((fd), LOCK_EX))
  102. #endif
  103. #endif /* MTAB_LOCKING */
  104.  
  105. #ifdef MTAB_STRIPNL
  106. static void mtab_stripnl(s)
  107. char *s;
  108. {
  109.     do {
  110.         s = strchr(s, '\n');
  111.         if (s)
  112.             *s++ = ' ';
  113.     } while (s);
  114. }
  115. #endif
  116.  
  117. static struct mntent *mnt_dup(mp)
  118. #ifdef READ_MTAB_BSD_STYLE
  119. struct statfs *mp;
  120. #endif
  121. #ifdef READ_MTAB_ULTRIX_STYLE
  122. struct fs_data *mp;
  123. #endif
  124. #ifdef READ_MTAB_FROM_FILE
  125. struct mntent *mp;
  126. #endif
  127. {
  128.     struct mntent *new_mp = ALLOC(mntent);
  129. #ifdef READ_MTAB_BSD_STYLE
  130.     char *ty;
  131.     new_mp->mnt_fsname = strdup(mp->f_mntfromname);
  132.     new_mp->mnt_dir = strdup(mp->f_mntonname);
  133.     switch (mp->f_type) {
  134.     case MOUNT_UFS:  ty = MTAB_TYPE_UFS; break;
  135.     case MOUNT_NFS:  ty = MTAB_TYPE_NFS; break;
  136.     case MOUNT_MFS:  ty = MTAB_TYPE_MFS; break;
  137.     default:  ty = "unknown"; break;
  138.     }
  139.     new_mp->mnt_type = strdup(ty);
  140.     new_mp->mnt_opts = strdup("unset");
  141.     new_mp->mnt_freq = 0;
  142.     new_mp->mnt_passno = 0;
  143. #endif
  144.  
  145. #ifdef READ_MTAB_ULTRIX_STYLE
  146.     new_mp->mnt_fsname = strdup(mp->fd_devname);
  147.     new_mp->mnt_dir = strdup(mp->fd_path);
  148.         if (mp->fd_fstype >= GT_NUMTYPES)
  149.                 mp->fd_fstype = GT_UNKWN;
  150.         else if (gt_names[mp->fd_fstype] == 0)
  151.                 mp->fd_fstype = GT_UNKWN;
  152.         new_mp->mnt_type = strdup(gt_names[mp->fd_fstype]);
  153.     new_mp->mnt_opts = strdup("unset");
  154.  
  155.     new_mp->mnt_freq = 0;
  156.     new_mp->mnt_passno = mp->fd_dev;
  157. #endif
  158.  
  159. #ifdef READ_MTAB_FROM_FILE
  160.     new_mp->mnt_fsname = strdup(mp->mnt_fsname);
  161.     new_mp->mnt_dir = strdup(mp->mnt_dir);
  162.     new_mp->mnt_type = strdup(mp->mnt_type);
  163.     new_mp->mnt_opts = strdup(mp->mnt_opts);
  164.  
  165.     new_mp->mnt_freq = mp->mnt_freq;
  166.     new_mp->mnt_passno = mp->mnt_passno;
  167. #endif
  168.     return new_mp;
  169. }
  170.  
  171. void mnt_free(mp)
  172. struct mntent *mp;
  173. {
  174.     free(mp->mnt_fsname);
  175.     free(mp->mnt_dir);
  176.     free(mp->mnt_type);
  177.     free(mp->mnt_opts);
  178.     free((voidp) mp);
  179. }
  180.  
  181. /*
  182.  * Read a mount table into memory
  183.  */
  184.  
  185. #ifdef READ_MTAB_BSD_STYLE
  186. mntlist *read_mtab(fs)
  187. char *fs;
  188. {
  189.     mntlist **mpp, *mhp;
  190.     struct statfs *mntbufp, *mntp;
  191.  
  192.     int nloc = getmntinfo(&mntbufp);
  193.  
  194.     if (nloc == 0) {
  195.         plog(XLOG_ERROR, "Can't read mount table");
  196.         return 0;
  197.     }
  198.  
  199.     mpp = &mhp;
  200.     for (mntp = mntbufp; mntp < mntbufp + nloc; mntp++) {
  201.         /*
  202.          * Allocate a new slot
  203.          */
  204.         *mpp = ALLOC(mntlist);
  205.  
  206.         /*
  207.          * Copy the data returned by getmntent
  208.          */
  209.         (*mpp)->mnt = mnt_dup(mntp);
  210.  
  211.         /*
  212.          * Move to next pointer
  213.          */
  214.         mpp = &(*mpp)->mnext;
  215.     }
  216.  
  217.     return mhp;
  218. }
  219. #endif /* READ_MTAB_BSD_STYLE */
  220.  
  221. #ifdef READ_MTAB_ULTRIX_STYLE
  222. mntlist *read_mtab(fs)
  223. char *fs;
  224. {
  225.     mntlist **mpp, *mhp;
  226.  
  227. /* From: Piete Brooks <pb@cl.cam.ac.uk> */
  228.  
  229.     int loc=0;
  230. #undef    NMOUNT
  231. #define    NMOUNT    20
  232.     struct fs_data mountbuffer[NMOUNT], *fs_data;
  233.     int ret;
  234.  
  235.     mpp = &mhp;
  236.     while ((ret = getmountent(&loc, mountbuffer, NMOUNT)) > 0) {
  237.             for (fs_data = mountbuffer; fs_data < &mountbuffer[ret]; fs_data++) {
  238.             /*
  239.              * Allocate a new slot
  240.              */
  241.             *mpp = ALLOC(mntlist);
  242.  
  243.             /*
  244.              * Copy the data returned by getmntent
  245.              */
  246.             (*mpp)->mnt = mnt_dup(fs_data);
  247.  
  248.             /*
  249.              * Move to next pointer
  250.              */
  251.             mpp = &(*mpp)->mnext;
  252.         }
  253.     }
  254.     if (ret < 0) {
  255.         plog(XLOG_ERROR, "getmountent: %m");
  256.         return 0;
  257.     }
  258.     *mpp = 0;
  259.  
  260.     return mhp;
  261. }
  262. #endif /* READ_MTAB_ULTRIX_STYLE */
  263.  
  264. #ifdef READ_MTAB_FROM_FILE
  265. mntlist *read_mtab(fs)
  266. char *fs;
  267. {
  268.     mntlist **mpp, *mhp;
  269.  
  270.     struct mntent *mep;
  271.     FILE *mfp = 0;
  272.  
  273. #ifdef UPDATE_MTAB
  274.     /*
  275.      * There is a possible race condition if two processes enter
  276.      * this routine at the same time.  One will be blocked by the
  277.      * exclusive lock below (or by the shared lock in setmntent)
  278.      * and by the time the second process has the exclusive lock
  279.      * it will be on the wrong underlying object.  To check for this
  280.      * the mtab file is stat'ed before and after all the locking
  281.      * sequence, and if it is a different file then we assume that
  282.      * it may be the wrong file (only "may", since there is another
  283.      * race between the initial stat and the setmntent).
  284.      *
  285.      * Simpler solutions to this problem are invited...
  286.      */
  287.     int racing = 0;
  288. #ifdef MTAB_LOCKING
  289.     int rc;
  290.     int retries = 0;
  291.     struct stat st_before, st_after;
  292. #endif /* MTAB_LOCKING */
  293.  
  294.     if (mnt_file) {
  295. #ifdef DEBUG
  296.         dlog("Forced close on %s in read_mtab", mtab);
  297. #endif /* DEBUG */
  298.         endmntent(mnt_file);
  299.         mnt_file = 0;
  300.     }
  301.  
  302. #ifdef MTAB_LOCKING
  303. again:
  304.     if (mfp) {
  305.         endmntent(mfp);
  306.         mfp = 0;
  307.     }
  308.  
  309.     clock_valid = 0;
  310.     if (stat(mtab, &st_before) < 0) {
  311.         plog(XLOG_ERROR, "%s: stat: %m", mtab);
  312.         if (errno == ESTALE) {
  313.             /* happens occasionally */
  314.             sleep(1);
  315.             goto again;
  316.         }
  317.         return 0;
  318.     }
  319. #endif /* MTAB_LOCKING */
  320. #endif /* UPDATE_MTAB */
  321.  
  322. eacces:
  323.     mfp = setmntent(mtab, "r+");
  324.     if (!mfp) {
  325.         /*
  326.          * Since setmntent locks the descriptor, it
  327.          * is possible it can fail... so retry if
  328.          * needed.
  329.          */
  330.         if (errno == EACCES || errno == EAGAIN) {
  331. #ifdef DEBUG
  332.             dlog("Blocked, trying to obtain exclusive mtab lock");
  333. #endif /* DEBUG */
  334.             goto eacces;
  335.         } else if (errno == ENFILE && retries++ < NFILE_RETRIES) {
  336.             sleep(1);
  337.             goto eacces;
  338.         }
  339.  
  340.         plog(XLOG_ERROR, "setmntent(\"%s\", \"r+\"): %m", mtab);
  341.         return 0;
  342.     }
  343.  
  344. #ifdef MTAB_LOCKING
  345. #ifdef UPDATE_MTAB
  346.     /*
  347.      * At this point we have an exclusive lock on the mount list,
  348.      * but it may be the wrong one so...
  349.      */
  350.  
  351.     /*
  352.      * Need to get an exclusive lock on the current
  353.      * mount table until we have a new copy written
  354.      * out, when the lock is released in free_mntlist.
  355.      * flock is good enough since the mount table is
  356.      * not shared between machines.
  357.      */
  358.     do
  359.         rc = lock(fileno(mfp));
  360.     while (rc < 0 && errno == EINTR);
  361.     if (rc < 0) {
  362.         plog(XLOG_ERROR, "Couldn't lock %s: %m", mtab);
  363.         endmntent(mfp);
  364.         return 0;
  365.     }
  366.     /*
  367.      * Now check whether the mtab file has changed under our feet
  368.      */
  369.     if (stat(mtab, &st_after) < 0) {
  370.         plog(XLOG_ERROR, "%s: stat", mtab);
  371.         goto again;
  372.     }
  373.  
  374.     if (st_before.st_dev != st_after.st_dev ||
  375.         st_before.st_ino != st_after.st_ino) {
  376.             if (racing == 0) {
  377.                 /* Sometimes print a warning */
  378.                 plog(XLOG_WARNING,
  379.                     "Possible mount table race - retrying %s", fs);
  380.             }
  381.             racing = (racing+1) & 3;
  382.             goto again;
  383.     }
  384. #endif /* UPDATE_MTAB */
  385. #endif /* MTAB_LOCKING */
  386.  
  387.     mpp = &mhp;
  388.  
  389. /*
  390.  * XXX - In SunOS 4 there is (yet another) memory leak
  391.  * which loses 1K the first time getmntent is called.
  392.  * (jsp)
  393.  */
  394.     while (mep = getmntent(mfp)) {
  395.         /*
  396.          * Allocate a new slot
  397.          */
  398.         *mpp = ALLOC(mntlist);
  399.  
  400.         /*
  401.          * Copy the data returned by getmntent
  402.          */
  403.         (*mpp)->mnt = mnt_dup(mep);
  404.  
  405.         /*
  406.          * Move to next pointer
  407.          */
  408.         mpp = &(*mpp)->mnext;
  409.     }
  410.     *mpp = 0;
  411.  
  412. #ifdef UPDATE_MTAB
  413.     /*
  414.      * If we are not updating the mount table then we
  415.      * can free the resources held here, otherwise they
  416.      * must be held until the mount table update is complete
  417.      */
  418.     mnt_file = mfp;
  419. #else
  420.     endmntent(mfp);
  421. #endif /* UPDATE_MTAB */
  422.  
  423.     return mhp;
  424. }
  425. #endif /* READ_MTAB_FROM_FILE */
  426.  
  427. /*
  428.  * Throw away a mount list
  429.  */
  430. void free_mntlist(mp)
  431. mntlist *mp;
  432. {
  433.     mntlist *mp2;
  434.  
  435.     while (mp2 = mp) {
  436.         mp = mp->mnext;
  437.         if (mp2->mnt)
  438.             mnt_free(mp2->mnt);
  439.         free(mp2);
  440.     }
  441.  
  442. #ifdef UPDATE_MTAB
  443.     /*
  444.      * Release file lock, by closing the file
  445.      */
  446.     if (mnt_file) {
  447.         endmntent(mnt_file);
  448.         mnt_file = 0;
  449.     }
  450. #endif /* UPDATE_MTAB */
  451. }
  452.  
  453. #ifdef UPDATE_MTAB
  454. /*
  455.  * Write out a mount list
  456.  */
  457. void rewrite_mtab(mp)
  458. mntlist *mp;
  459. {
  460.     FILE *mfp;
  461.  
  462.     /*
  463.      * Concoct a temporary name in the same
  464.      * directory as the target mount table
  465.      * so that rename() will work.
  466.      */
  467.     char tmpname[64];
  468.     int retries;
  469.     int tmpfd;
  470.     char *cp;
  471.     char *mcp = mtab;
  472.     cp = strrchr(mcp, '/');
  473.     if (cp) {
  474.         bcopy(mcp, tmpname, cp - mcp);
  475.         tmpname[cp-mcp] = '\0';
  476.     } else {
  477.         plog(XLOG_WARNING, "No '/' in mtab (%s), using \".\" as tmp directory", mtab);
  478.         tmpname[0] = '.'; tmpname[1] = '\0';
  479.     }
  480.     strcat(tmpname, "/mtabXXXXXX");
  481.     mktemp(tmpname);
  482.     retries = 0;
  483. enfile1:
  484.     if ((tmpfd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
  485.         if (errno == ENFILE && retries++ < NFILE_RETRIES) {
  486.             sleep(1);
  487.             goto enfile1;
  488.         }
  489.         plog(XLOG_ERROR, "%s: open: %m", tmpname);
  490.         return;
  491.     }
  492.     if (close(tmpfd) < 0)
  493.         plog(XLOG_ERROR, "Couldn't close tmp file descriptor: %m");
  494.  
  495.     retries = 0;
  496. enfile2:
  497.     mfp = setmntent(tmpname, "w");
  498.     if (!mfp) {
  499.         if (errno == ENFILE && retries++ < NFILE_RETRIES) {
  500.             sleep(1);
  501.             goto enfile2;
  502.         }
  503.         plog(XLOG_ERROR, "setmntent(\"%s\", \"w\"): %m", tmpname);
  504.         return;
  505.     }
  506.  
  507.     while (mp) {
  508.         if (mp->mnt)
  509.             if (addmntent(mfp, mp->mnt))
  510.                 plog(XLOG_ERROR, "Can't write entry to %s", tmpname);
  511.         mp = mp->mnext;
  512.     }
  513.  
  514.     endmntent(mfp);
  515.  
  516.     /*
  517.      * Rename temporary mtab to real mtab
  518.      */
  519.     if (rename(tmpname, mtab) < 0)
  520.         plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mtab);
  521. }
  522.  
  523. /*
  524.  * Append a mntent structure to the
  525.  * current mount table.
  526.  */
  527. void write_mntent(mp)
  528. struct mntent *mp;
  529. {
  530.     int retries = 0;
  531.     FILE *mfp;
  532. enfile:
  533.     mfp = setmntent(mtab, "a");
  534.     if (mfp) {
  535. #ifdef MTAB_STRIPNL
  536.         mtab_stripnl(mp->mnt_opts);
  537. #endif /* MTAB_STRIPNL */
  538.         if (addmntent(mfp, mp))
  539.             plog(XLOG_ERROR, "Couldn't write %s: %m", mtab);
  540.         endmntent(mfp);
  541.     } else {
  542.         if (errno == ENFILE && retries < NFILE_RETRIES) {
  543.             sleep(1);
  544.             goto enfile;
  545.         }
  546.         plog(XLOG_ERROR, "setmntent(\"%s\", \"a\"): %m", mtab);
  547.     }
  548. }
  549. #endif /* UPDATE_MTAB */
  550.  
  551. /*
  552.  * Utility routine which determines the value of a
  553.  * numeric option in the mount options (such as port=%d).
  554.  * Returns 0 if the option is not specified.
  555.  */
  556. int hasmntval(mnt, opt)
  557. struct mntent *mnt;
  558. char *opt;
  559. {
  560.     char *str = hasmntopt(mnt, opt);
  561.     if (str) {
  562.         char *eq = strchr(str, '=');
  563.         if (eq)
  564.             return atoi(eq+1);
  565.         else
  566.             plog(XLOG_USER, "bad numeric option \"%s\" in \"%s\"", opt, str);
  567.     }
  568.  
  569.     return 0;
  570. }
  571.