|
|
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.