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