BSD 4_3_Net_2 release
[unix-history] / usr / src / usr.sbin / amd / config / mtab_file.c
CommitLineData
e1a31032 1/*
e1a31032
KM
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 *
af359dea
C
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 $
e1a31032 41 *
e1a31032
KM
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>
67static 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
85static 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
95again:
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
2f619045
JSP
111static FILE *open_locked_mtab(mtab_file, mode, fs)
112char *mtab_file;
113char *mode;
114char *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
148again:
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
167eacces:
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
e1a31032
KM
245/*
246 * Unlock the mount table
247 */
2f619045 248void unlock_mntlist P((void));
e1a31032
KM
249void 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 */
263void rewrite_mtab(mp)
264mntlist *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;
289enfile1:
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;
302enfile2:
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
330static void mtab_stripnl(s)
331char *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 */
345void write_mntent(mp)
346struct mntent *mp;
347{
348 int retries = 0;
349 FILE *mfp;
350enfile:
2f619045 351 mfp = open_locked_mtab(mtab, "a", mp->mnt_dir);
e1a31032
KM
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
370static struct mntent *mnt_dup(mp)
371struct 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
2f619045
JSP
383#ifdef FIXUP_MNTENT_DUP
384 /*
385 * Additional fields get dup'ed here
386 */
387 FIXUP_MNTENT_DUP(new_mp, mp);
388#endif
389
e1a31032
KM
390 return new_mp;
391}
392
393/*
394 * Read a mount table into memory
395 */
396mntlist *read_mtab(fs)
397char *fs;
398{
399 mntlist **mpp, *mhp;
400
401 struct mntent *mep;
2f619045 402 FILE *mfp = open_locked_mtab(mtab, "r+", fs);
e1a31032 403
2f619045 404 if (!mfp)
e1a31032 405 return 0;
e1a31032
KM
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 */