home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Id: mtab.c,v 5.1.1.3 90/01/11 17:11:26 jsp Exp Locker: jsp $
- *
- * Copyright (c) 1989 Jan-Simon Pendry
- * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
- * Copyright (c) 1989 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Jan-Simon Pendry at Imperial College, London.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Imperial College of Science, Technology and Medicine, London, UK.
- * The names of the College and University may not be used to endorse
- * or promote products derived from this software without specific
- * prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * %W% (Berkeley) %G%
- */
-
- #include "am.h"
-
- /*
- * Firewall /etc/mtab entries
- */
- #define MTAB_STRIPNL
-
- /*
- * Do strict /etc/mtab locking
- */
- #define MTAB_LOCKING
-
- #ifdef READ_MTAB_FROM_FILE
- #ifdef USE_FCNTL
- #include <fcntl.h>
- #else
- #include <sys/file.h>
- #endif
- #endif
-
- #ifdef READ_MTAB_ULTRIX_STYLE
- #include <sys/mount.h>
- #include <sys/fs_types.h>
- #endif
-
- #ifdef READ_MTAB_BSD_STYLE
- #include <sys/mount.h>
- #endif
-
- #ifdef UPDATE_MTAB
- #include <sys/stat.h>
- static FILE *mnt_file;
-
- /*
- * If the system is being trashed by something, then
- * opening mtab may fail with ENFILE. So, go to sleep
- * for a second and try again. (Yes - this has happened to me.)
- *
- * Note that this *may* block the automounter, oh well.
- * If we get to this state then things are badly wrong anyway...
- *
- * Give the system 10 seconds to recover but then give up.
- * Hopefully something else will exit and free up some file
- * table slots in that time.
- */
- #define NFILE_RETRIES 10 /* seconds */
-
- #endif /* UPDATE_MTAB */
-
- #ifdef MTAB_LOCKING
- #ifdef LOCK_FCNTL
- static int lock(fd)
- {
- int rc;
- struct flock lk;
-
- lk.l_type = F_WRLCK;
- lk.l_whence = 0;
- lk.l_start = 0;
- lk.l_len = 0;
-
- again:
- rc = fcntl(fd, F_SETLKW, (caddr_t) &lk);
- if (rc < 0 && (errno == EACCES || errno == EAGAIN)) {
- #ifdef DEBUG
- dlog("Blocked, trying to obtain exclusive mtab lock");
- #endif
- sleep(1);
- goto again;
- }
- return rc;
- }
- #else
- #define lock(fd) (flock((fd), LOCK_EX))
- #endif
- #endif /* MTAB_LOCKING */
-
- #ifdef MTAB_STRIPNL
- static void mtab_stripnl(s)
- char *s;
- {
- do {
- s = strchr(s, '\n');
- if (s)
- *s++ = ' ';
- } while (s);
- }
- #endif
-
- static struct mntent *mnt_dup(mp)
- #ifdef READ_MTAB_BSD_STYLE
- struct statfs *mp;
- #endif
- #ifdef READ_MTAB_ULTRIX_STYLE
- struct fs_data *mp;
- #endif
- #ifdef READ_MTAB_FROM_FILE
- struct mntent *mp;
- #endif
- {
- struct mntent *new_mp = ALLOC(mntent);
- #ifdef READ_MTAB_BSD_STYLE
- char *ty;
- new_mp->mnt_fsname = strdup(mp->f_mntfromname);
- new_mp->mnt_dir = strdup(mp->f_mntonname);
- switch (mp->f_type) {
- case MOUNT_UFS: ty = MTAB_TYPE_UFS; break;
- case MOUNT_NFS: ty = MTAB_TYPE_NFS; break;
- case MOUNT_MFS: ty = MTAB_TYPE_MFS; break;
- default: ty = "unknown"; break;
- }
- new_mp->mnt_type = strdup(ty);
- new_mp->mnt_opts = strdup("unset");
- new_mp->mnt_freq = 0;
- new_mp->mnt_passno = 0;
- #endif
-
- #ifdef READ_MTAB_ULTRIX_STYLE
- new_mp->mnt_fsname = strdup(mp->fd_devname);
- new_mp->mnt_dir = strdup(mp->fd_path);
- if (mp->fd_fstype >= GT_NUMTYPES)
- mp->fd_fstype = GT_UNKWN;
- else if (gt_names[mp->fd_fstype] == 0)
- mp->fd_fstype = GT_UNKWN;
- new_mp->mnt_type = strdup(gt_names[mp->fd_fstype]);
- new_mp->mnt_opts = strdup("unset");
-
- new_mp->mnt_freq = 0;
- new_mp->mnt_passno = mp->fd_dev;
- #endif
-
- #ifdef READ_MTAB_FROM_FILE
- new_mp->mnt_fsname = strdup(mp->mnt_fsname);
- new_mp->mnt_dir = strdup(mp->mnt_dir);
- new_mp->mnt_type = strdup(mp->mnt_type);
- new_mp->mnt_opts = strdup(mp->mnt_opts);
-
- new_mp->mnt_freq = mp->mnt_freq;
- new_mp->mnt_passno = mp->mnt_passno;
- #endif
- return new_mp;
- }
-
- void mnt_free(mp)
- struct mntent *mp;
- {
- free(mp->mnt_fsname);
- free(mp->mnt_dir);
- free(mp->mnt_type);
- free(mp->mnt_opts);
- free((voidp) mp);
- }
-
- /*
- * Read a mount table into memory
- */
-
- #ifdef READ_MTAB_BSD_STYLE
- mntlist *read_mtab(fs)
- char *fs;
- {
- mntlist **mpp, *mhp;
- struct statfs *mntbufp, *mntp;
-
- int nloc = getmntinfo(&mntbufp);
-
- if (nloc == 0) {
- plog(XLOG_ERROR, "Can't read mount table");
- return 0;
- }
-
- mpp = &mhp;
- for (mntp = mntbufp; mntp < mntbufp + nloc; mntp++) {
- /*
- * Allocate a new slot
- */
- *mpp = ALLOC(mntlist);
-
- /*
- * Copy the data returned by getmntent
- */
- (*mpp)->mnt = mnt_dup(mntp);
-
- /*
- * Move to next pointer
- */
- mpp = &(*mpp)->mnext;
- }
-
- return mhp;
- }
- #endif /* READ_MTAB_BSD_STYLE */
-
- #ifdef READ_MTAB_ULTRIX_STYLE
- mntlist *read_mtab(fs)
- char *fs;
- {
- mntlist **mpp, *mhp;
-
- /* From: Piete Brooks <pb@cl.cam.ac.uk> */
-
- int loc=0;
- #undef NMOUNT
- #define NMOUNT 20
- struct fs_data mountbuffer[NMOUNT], *fs_data;
- int ret;
-
- mpp = &mhp;
- while ((ret = getmountent(&loc, mountbuffer, NMOUNT)) > 0) {
- for (fs_data = mountbuffer; fs_data < &mountbuffer[ret]; fs_data++) {
- /*
- * Allocate a new slot
- */
- *mpp = ALLOC(mntlist);
-
- /*
- * Copy the data returned by getmntent
- */
- (*mpp)->mnt = mnt_dup(fs_data);
-
- /*
- * Move to next pointer
- */
- mpp = &(*mpp)->mnext;
- }
- }
- if (ret < 0) {
- plog(XLOG_ERROR, "getmountent: %m");
- return 0;
- }
- *mpp = 0;
-
- return mhp;
- }
- #endif /* READ_MTAB_ULTRIX_STYLE */
-
- #ifdef READ_MTAB_FROM_FILE
- mntlist *read_mtab(fs)
- char *fs;
- {
- mntlist **mpp, *mhp;
-
- struct mntent *mep;
- FILE *mfp = 0;
-
- #ifdef UPDATE_MTAB
- /*
- * There is a possible race condition if two processes enter
- * this routine at the same time. One will be blocked by the
- * exclusive lock below (or by the shared lock in setmntent)
- * and by the time the second process has the exclusive lock
- * it will be on the wrong underlying object. To check for this
- * the mtab file is stat'ed before and after all the locking
- * sequence, and if it is a different file then we assume that
- * it may be the wrong file (only "may", since there is another
- * race between the initial stat and the setmntent).
- *
- * Simpler solutions to this problem are invited...
- */
- int racing = 0;
- #ifdef MTAB_LOCKING
- int rc;
- int retries = 0;
- struct stat st_before, st_after;
- #endif /* MTAB_LOCKING */
-
- if (mnt_file) {
- #ifdef DEBUG
- dlog("Forced close on %s in read_mtab", mtab);
- #endif /* DEBUG */
- endmntent(mnt_file);
- mnt_file = 0;
- }
-
- #ifdef MTAB_LOCKING
- again:
- if (mfp) {
- endmntent(mfp);
- mfp = 0;
- }
-
- clock_valid = 0;
- if (stat(mtab, &st_before) < 0) {
- plog(XLOG_ERROR, "%s: stat: %m", mtab);
- if (errno == ESTALE) {
- /* happens occasionally */
- sleep(1);
- goto again;
- }
- return 0;
- }
- #endif /* MTAB_LOCKING */
- #endif /* UPDATE_MTAB */
-
- eacces:
- mfp = setmntent(mtab, "r+");
- if (!mfp) {
- /*
- * Since setmntent locks the descriptor, it
- * is possible it can fail... so retry if
- * needed.
- */
- if (errno == EACCES || errno == EAGAIN) {
- #ifdef DEBUG
- dlog("Blocked, trying to obtain exclusive mtab lock");
- #endif /* DEBUG */
- goto eacces;
- } else if (errno == ENFILE && retries++ < NFILE_RETRIES) {
- sleep(1);
- goto eacces;
- }
-
- plog(XLOG_ERROR, "setmntent(\"%s\", \"r+\"): %m", mtab);
- return 0;
- }
-
- #ifdef MTAB_LOCKING
- #ifdef UPDATE_MTAB
- /*
- * At this point we have an exclusive lock on the mount list,
- * but it may be the wrong one so...
- */
-
- /*
- * Need to get an exclusive lock on the current
- * mount table until we have a new copy written
- * out, when the lock is released in free_mntlist.
- * flock is good enough since the mount table is
- * not shared between machines.
- */
- do
- rc = lock(fileno(mfp));
- while (rc < 0 && errno == EINTR);
- if (rc < 0) {
- plog(XLOG_ERROR, "Couldn't lock %s: %m", mtab);
- endmntent(mfp);
- return 0;
- }
- /*
- * Now check whether the mtab file has changed under our feet
- */
- if (stat(mtab, &st_after) < 0) {
- plog(XLOG_ERROR, "%s: stat", mtab);
- goto again;
- }
-
- if (st_before.st_dev != st_after.st_dev ||
- st_before.st_ino != st_after.st_ino) {
- if (racing == 0) {
- /* Sometimes print a warning */
- plog(XLOG_WARNING,
- "Possible mount table race - retrying %s", fs);
- }
- racing = (racing+1) & 3;
- goto again;
- }
- #endif /* UPDATE_MTAB */
- #endif /* MTAB_LOCKING */
-
- mpp = &mhp;
-
- /*
- * XXX - In SunOS 4 there is (yet another) memory leak
- * which loses 1K the first time getmntent is called.
- * (jsp)
- */
- while (mep = getmntent(mfp)) {
- /*
- * Allocate a new slot
- */
- *mpp = ALLOC(mntlist);
-
- /*
- * Copy the data returned by getmntent
- */
- (*mpp)->mnt = mnt_dup(mep);
-
- /*
- * Move to next pointer
- */
- mpp = &(*mpp)->mnext;
- }
- *mpp = 0;
-
- #ifdef UPDATE_MTAB
- /*
- * If we are not updating the mount table then we
- * can free the resources held here, otherwise they
- * must be held until the mount table update is complete
- */
- mnt_file = mfp;
- #else
- endmntent(mfp);
- #endif /* UPDATE_MTAB */
-
- return mhp;
- }
- #endif /* READ_MTAB_FROM_FILE */
-
- /*
- * Throw away a mount list
- */
- void free_mntlist(mp)
- mntlist *mp;
- {
- mntlist *mp2;
-
- while (mp2 = mp) {
- mp = mp->mnext;
- if (mp2->mnt)
- mnt_free(mp2->mnt);
- free(mp2);
- }
-
- #ifdef UPDATE_MTAB
- /*
- * Release file lock, by closing the file
- */
- if (mnt_file) {
- endmntent(mnt_file);
- mnt_file = 0;
- }
- #endif /* UPDATE_MTAB */
- }
-
- #ifdef UPDATE_MTAB
- /*
- * Write out a mount list
- */
- void rewrite_mtab(mp)
- mntlist *mp;
- {
- FILE *mfp;
-
- /*
- * Concoct a temporary name in the same
- * directory as the target mount table
- * so that rename() will work.
- */
- char tmpname[64];
- int retries;
- int tmpfd;
- char *cp;
- char *mcp = mtab;
- cp = strrchr(mcp, '/');
- if (cp) {
- bcopy(mcp, tmpname, cp - mcp);
- tmpname[cp-mcp] = '\0';
- } else {
- plog(XLOG_WARNING, "No '/' in mtab (%s), using \".\" as tmp directory", mtab);
- tmpname[0] = '.'; tmpname[1] = '\0';
- }
- strcat(tmpname, "/mtabXXXXXX");
- mktemp(tmpname);
- retries = 0;
- enfile1:
- if ((tmpfd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
- if (errno == ENFILE && retries++ < NFILE_RETRIES) {
- sleep(1);
- goto enfile1;
- }
- plog(XLOG_ERROR, "%s: open: %m", tmpname);
- return;
- }
- if (close(tmpfd) < 0)
- plog(XLOG_ERROR, "Couldn't close tmp file descriptor: %m");
-
- retries = 0;
- enfile2:
- mfp = setmntent(tmpname, "w");
- if (!mfp) {
- if (errno == ENFILE && retries++ < NFILE_RETRIES) {
- sleep(1);
- goto enfile2;
- }
- plog(XLOG_ERROR, "setmntent(\"%s\", \"w\"): %m", tmpname);
- return;
- }
-
- while (mp) {
- if (mp->mnt)
- if (addmntent(mfp, mp->mnt))
- plog(XLOG_ERROR, "Can't write entry to %s", tmpname);
- mp = mp->mnext;
- }
-
- endmntent(mfp);
-
- /*
- * Rename temporary mtab to real mtab
- */
- if (rename(tmpname, mtab) < 0)
- plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mtab);
- }
-
- /*
- * Append a mntent structure to the
- * current mount table.
- */
- void write_mntent(mp)
- struct mntent *mp;
- {
- int retries = 0;
- FILE *mfp;
- enfile:
- mfp = setmntent(mtab, "a");
- if (mfp) {
- #ifdef MTAB_STRIPNL
- mtab_stripnl(mp->mnt_opts);
- #endif /* MTAB_STRIPNL */
- if (addmntent(mfp, mp))
- plog(XLOG_ERROR, "Couldn't write %s: %m", mtab);
- endmntent(mfp);
- } else {
- if (errno == ENFILE && retries < NFILE_RETRIES) {
- sleep(1);
- goto enfile;
- }
- plog(XLOG_ERROR, "setmntent(\"%s\", \"a\"): %m", mtab);
- }
- }
- #endif /* UPDATE_MTAB */
-
- /*
- * Utility routine which determines the value of a
- * numeric option in the mount options (such as port=%d).
- * Returns 0 if the option is not specified.
- */
- int hasmntval(mnt, opt)
- struct mntent *mnt;
- char *opt;
- {
- char *str = hasmntopt(mnt, opt);
- if (str) {
- char *eq = strchr(str, '=');
- if (eq)
- return atoi(eq+1);
- else
- plog(XLOG_USER, "bad numeric option \"%s\" in \"%s\"", opt, str);
- }
-
- return 0;
- }
-