diff options
author | dm <dm@cvs.openbsd.org> | 1996-02-03 12:13:04 +0000 |
---|---|---|
committer | dm <dm@cvs.openbsd.org> | 1996-02-03 12:13:04 +0000 |
commit | f34705a30c83ef27acf58b47c75c736e6858247a (patch) | |
tree | 2121eb2901c910af7604845f5538c2fc26d01ac3 /usr.bin/rdistd/filesys.c | |
parent | fdb8a9c5e300099e2c65b848550471fb1d9f0cd4 (diff) |
rdist 6.1.1
Diffstat (limited to 'usr.bin/rdistd/filesys.c')
-rw-r--r-- | usr.bin/rdistd/filesys.c | 482 |
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); +} |