summaryrefslogtreecommitdiff
path: root/usr.bin/rdistd/filesys.c
diff options
context:
space:
mode:
authordm <dm@cvs.openbsd.org>1996-02-03 12:13:04 +0000
committerdm <dm@cvs.openbsd.org>1996-02-03 12:13:04 +0000
commitf34705a30c83ef27acf58b47c75c736e6858247a (patch)
tree2121eb2901c910af7604845f5538c2fc26d01ac3 /usr.bin/rdistd/filesys.c
parentfdb8a9c5e300099e2c65b848550471fb1d9f0cd4 (diff)
rdist 6.1.1
Diffstat (limited to 'usr.bin/rdistd/filesys.c')
-rw-r--r--usr.bin/rdistd/filesys.c482
1 files changed, 482 insertions, 0 deletions
diff --git a/usr.bin/rdistd/filesys.c b/usr.bin/rdistd/filesys.c
new file mode 100644
index 00000000000..5f7586fd3f3
--- /dev/null
+++ b/usr.bin/rdistd/filesys.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char RCSid[] =
+"$Id: filesys.c,v 1.1 1996/02/03 12:12:57 dm Exp $";
+
+static char sccsid[] = "@(#)filesys.c";
+
+static char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * This file contains functions dealing with getting info
+ * about mounted filesystems.
+ */
+
+#include "defs.h"
+#include "filesys.h"
+
+jmp_buf env;
+
+/*
+ * Given a pathname, find the fullest component that exists.
+ * If statbuf is not NULL, set it to point at our stat buffer.
+ */
+char *find_file(pathname, statbuf, isvalid)
+ char *pathname;
+ struct stat *statbuf;
+ int *isvalid;
+{
+ static char last_pathname[MAXPATHLEN];
+ static char file[MAXPATHLEN + 3];
+ static struct stat filestat;
+ register char *p;
+
+ /*
+ * Mark the statbuf as invalid to start with.
+ */
+ *isvalid = 0;
+
+ /*
+ * If this is the same pathname as the last time, and
+ * the file buffer is valid and we're doing the same stat()
+ * or lstat(), then set statbuf to the last filestat and
+ * return the last file we found.
+ */
+ if (strcmp(pathname, last_pathname) == 0 && file[0]) {
+ if (statbuf)
+ statbuf = &filestat;
+ if (strcmp(pathname, file) == 0)
+ *isvalid = 1;
+ return(file);
+ }
+
+ if ((int)strlen(pathname) > sizeof(file)+3) {
+ error("%s: Name to large for buffer.", pathname);
+ return((char *) NULL);
+ }
+
+ /*
+ * Save for next time
+ */
+ (void) strcpy(last_pathname, pathname);
+
+ if (*pathname == '/')
+ (void) strcpy(file, pathname);
+ else {
+ /*
+ * Ensure we have a directory (".") in our path
+ * so we have something to stat in case the file
+ * does not exist.
+ */
+ (void) strcpy(file, "./");
+ (void) strcat(file, pathname);
+ }
+
+ while (lstat(file, &filestat) != 0) {
+ /*
+ * Trim the last part of the pathname to try next level up
+ */
+ if (errno == ENOENT) {
+ /*
+ * Trim file name to get directory name.
+ * Normally we want to change /dir1/dir2/file
+ * into "/dir1/dir2/."
+ */
+ if (p = (char *) strrchr(file, '/')) {
+ *++p = '.';
+ *++p = CNULL;
+ } else {
+ /*
+ * Couldn't find anything, so give up.
+ */
+ debugmsg(DM_MISC, "Cannot find dir of `%s'",
+ pathname);
+ return((char *) NULL);
+ }
+ continue;
+ } else {
+ error("%s: lstat failed: %s", pathname, SYSERR);
+ return((char *) NULL);
+ }
+ }
+
+ if (statbuf)
+ bcopy((char *) &filestat, (char *) statbuf, sizeof(filestat));
+
+ /*
+ * Trim the "/." that we added.
+ */
+ p = &file[strlen(file) - 1];
+ if (*p == '.')
+ *p-- = CNULL;
+ for ( ; p && *p && *p == '/' && p != file; --p)
+ *p = CNULL;
+
+ /*
+ * If this file is a symlink we really want the parent directory
+ * name in case the symlink points to another filesystem.
+ */
+ if (S_ISLNK(filestat.st_mode))
+ if ((p = (char *) strrchr(file, '/')) && *p+1) {
+ /* Is this / (root)? */
+ if (p == file)
+ file[1] = CNULL;
+ else
+ *p = CNULL;
+ }
+
+ if (strcmp(pathname, file) == 0)
+ *isvalid = 1;
+
+ return((file && *file) ? file : (char *)NULL);
+}
+
+#if defined(NFS_CHECK) || defined(RO_CHECK)
+
+/*
+ * Find the device that "filest" is on in the "mntinfo" linked list.
+ */
+mntent_t *findmnt(filest, mntinfo)
+ struct stat *filest;
+ struct mntinfo *mntinfo;
+{
+ register struct mntinfo *mi;
+
+ for (mi = mntinfo; mi; mi = mi->mi_nxt) {
+ if (mi->mi_mnt->me_flags & MEFLAG_IGNORE)
+ continue;
+ if (filest->st_dev == mi->mi_statb->st_dev)
+ return(mi->mi_mnt);
+ }
+
+ return((mntent_t *) NULL);
+}
+
+/*
+ * Is "mnt" a duplicate of any of the mntinfo->mi_mnt elements?
+ */
+int isdupmnt(mnt, mntinfo)
+ mntent_t *mnt;
+ struct mntinfo *mntinfo;
+{
+ register struct mntinfo *m;
+
+ for (m = mntinfo; m; m = m->mi_nxt)
+ if (strcmp(m->mi_mnt->me_path, mnt->me_path) == 0)
+ return(1);
+
+ return(0);
+}
+
+/*
+ * Alarm clock
+ */
+void wakeup()
+{
+ debugmsg(DM_CALL, "wakeup() in filesys.c called");
+ longjmp(env, 1);
+}
+
+/*
+ * Make a linked list of mntinfo structures.
+ * Use "mi" as the base of the list if it's non NULL.
+ */
+struct mntinfo *makemntinfo(mi)
+ struct mntinfo *mi;
+{
+ FILE *mfp;
+ static struct mntinfo *mntinfo, *newmi, *m;
+ struct stat mntstat;
+ mntent_t *mnt;
+ int timeo = 310;
+
+ if (!(mfp = setmountent(MOUNTED_FILE, "r"))) {
+ message(MT_NERROR, "%s: setmntent failed: %s",
+ MOUNTED_FILE, SYSERR);
+ return((struct mntinfo *) NULL);
+ }
+
+ (void) signal(SIGALRM, wakeup);
+ (void) alarm(timeo);
+ if (setjmp(env)) {
+ message(MT_NERROR, "Timeout getting mount info");
+ return((struct mntinfo *) NULL);
+ }
+
+ mntinfo = mi;
+ while (mnt = getmountent(mfp)) {
+ debugmsg(DM_MISC, "mountent = '%s' (%s)",
+ mnt->me_path, mnt->me_type);
+
+ /*
+ * Make sure we don't already have it for some reason
+ */
+ if (isdupmnt(mnt, mntinfo))
+ continue;
+
+ /*
+ * Get stat info
+ */
+ if (stat(mnt->me_path, &mntstat) != 0) {
+ message(MT_WARNING, "%s: Cannot stat filesystem: %s",
+ mnt->me_path, SYSERR);
+ continue;
+ }
+
+ /*
+ * Create new entry
+ */
+ newmi = (struct mntinfo *) xcalloc(1, sizeof(struct mntinfo));
+ newmi->mi_mnt = newmountent(mnt);
+ newmi->mi_statb =
+ (struct stat *) xcalloc(1, sizeof(struct stat));
+ bcopy((char *) &mntstat, (char *) newmi->mi_statb,
+ sizeof(struct stat));
+
+ /*
+ * Add entry to list
+ */
+ if (mntinfo) {
+ for (m = mntinfo; m && m->mi_nxt; m = m->mi_nxt);
+ m->mi_nxt = newmi;
+ } else
+ mntinfo = newmi;
+ }
+
+ (void) alarm(0);
+ (void) endmountent(mfp);
+
+ return(mntinfo);
+}
+
+/*
+ * Given a name like /usr/src/etc/foo.c returns the mntent
+ * structure for the file system it lives in.
+ *
+ * If "statbuf" is not NULL it is used as the stat buffer too avoid
+ * stat()'ing the file again back in server.c.
+ */
+mntent_t *getmntpt(pathname, statbuf, isvalid)
+ char *pathname;
+ struct stat *statbuf;
+ int *isvalid;
+{
+ static struct mntinfo *mntinfo = NULL;
+ static struct stat filestat;
+ struct stat *pstat;
+ struct mntinfo *tmpmi;
+ register mntent_t *mnt;
+
+ /*
+ * Use the supplied stat buffer if not NULL or our own.
+ */
+ if (statbuf)
+ pstat = statbuf;
+ else
+ pstat = &filestat;
+
+ if (!find_file(pathname, pstat, isvalid))
+ return((mntent_t *) NULL);
+
+ /*
+ * Make mntinfo if it doesn't exist.
+ */
+ if (!mntinfo)
+ mntinfo = makemntinfo((struct mntinfo *) NULL);
+
+ /*
+ * Find the mnt that pathname is on.
+ */
+ if (mnt = findmnt(pstat, mntinfo))
+ return(mnt);
+
+ /*
+ * We failed to find correct mnt, so maybe it's a newly
+ * mounted filesystem. We rebuild mntinfo and try again.
+ */
+ if (tmpmi = makemntinfo(mntinfo)) {
+ mntinfo = tmpmi;
+ if (mnt = findmnt(pstat, mntinfo))
+ return(mnt);
+ }
+
+ error("%s: Could not find mount point", pathname);
+ return((mntent_t *) NULL);
+}
+
+#endif /* NFS_CHECK || RO_CHECK */
+
+#if defined(NFS_CHECK)
+/*
+ * Is "path" NFS mounted? Return 1 if it is, 0 if not, or -1 on error.
+ */
+int is_nfs_mounted(path, statbuf, isvalid)
+ char *path;
+ struct stat *statbuf;
+ int *isvalid;
+{
+ mntent_t *mnt;
+
+ if ((mnt = (mntent_t *) getmntpt(path, statbuf, isvalid)) == NULL)
+ return(-1);
+
+ if (strcmp(mnt->me_type, METYPE_NFS) == 0)
+ return(1);
+
+ return(0);
+}
+#endif /* NFS_CHECK */
+
+#if defined(RO_CHECK)
+/*
+ * Is "path" on a read-only mounted filesystem?
+ * Return 1 if it is, 0 if not, or -1 on error.
+ */
+int is_ro_mounted(path, statbuf, isvalid)
+ char *path;
+ struct stat *statbuf;
+ int *isvalid;
+{
+ mntent_t *mnt;
+
+ if ((mnt = (mntent_t *) getmntpt(path, statbuf, isvalid)) == NULL)
+ return(-1);
+
+ if (mnt->me_flags & MEFLAG_READONLY)
+ return(1);
+
+ return(0);
+}
+#endif /* RO_CHECK */
+
+/*
+ * Is "path" a symlink?
+ * Return 1 if it is, 0 if not, or -1 on error.
+ */
+int is_symlinked(path, statbuf, isvalid)
+ /*ARGSUSED*/
+ char *path;
+ struct stat *statbuf;
+ int *isvalid;
+{
+ static struct stat stb;
+
+ if (!(*isvalid)) {
+ if (lstat(path, &stb) != 0)
+ return(-1);
+ statbuf = &stb;
+ }
+
+ if (S_ISLNK(statbuf->st_mode))
+ return(1);
+
+ return(0);
+}
+
+/*
+ * Get filesystem information for "file". Set freespace
+ * to the amount of free (available) space and number of free
+ * files (inodes) on the filesystem "file" resides on.
+ * Returns 0 on success or -1 on failure.
+ * Filesystem values < 0 indicate unsupported or unavailable
+ * information.
+ */
+int getfilesysinfo(file, freespace, freefiles)
+ char *file;
+ long *freespace;
+ long *freefiles;
+{
+#if defined(STATFS_TYPE)
+ static statfs_t statfsbuf;
+ char *mntpt;
+ int t, r;
+
+ /*
+ * Get the mount point of the file.
+ */
+ mntpt = find_file(file, NULL, &t);
+ if (!mntpt) {
+ debugmsg(DM_MISC, "unknown mount point for `%s'", file);
+ return(-1);
+ }
+
+ /*
+ * Stat the filesystem (system specific)
+ */
+#if STATFS_TYPE == STATFS_SYSV
+ r = statfs(mntpt, &statfsbuf, sizeof(statfs_t), 0);
+#endif
+#if STATFS_TYPE == STATFS_BSD
+ r = statfs(mntpt, &statfsbuf);
+#endif
+#if STATFS_TYPE == STATFS_OSF1
+ r = statfs(mntpt, &statfsbuf, sizeof(statfs_t));
+#endif
+
+ if (r < 0) {
+ error("%s: Cannot statfs filesystem: %s.", mntpt, SYSERR);
+ return(-1);
+ }
+
+ /*
+ * If values are < 0, then assume the value is unsupported
+ * or unavailable for that filesystem type.
+ */
+ if (statfsbuf.f_bavail >= 0)
+ *freespace = (statfsbuf.f_bavail * (statfsbuf.f_bsize / 512))
+ / 2;
+
+ /*
+ * BROKEN_STATFS means that statfs() does not set fields
+ * to < 0 if the field is unsupported for the filesystem type.
+ */
+#if defined(BROKEN_STATFS)
+ if (statfsbuf.f_ffree > 0)
+#else
+ if (statfsbuf.f_ffree >= 0)
+#endif /* BROKEN_STATFS */
+ *freefiles = statfsbuf.f_ffree;
+
+#else /* !STATFS_TYPE */
+
+ *freespace = *freefiles = -1;
+
+#endif /* STATFS_TYPE */
+
+ return(0);
+}