Annotation of src/usr.bin/rdistd/filesys.c, Revision 1.1
1.1 ! dm 1: /*
! 2: * Copyright (c) 1983 Regents of the University of California.
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: * 3. All advertising materials mentioning features or use of this software
! 14: * must display the following acknowledgement:
! 15: * This product includes software developed by the University of
! 16: * California, Berkeley and its contributors.
! 17: * 4. Neither the name of the University nor the names of its contributors
! 18: * may be used to endorse or promote products derived from this software
! 19: * without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 31: * SUCH DAMAGE.
! 32: */
! 33:
! 34: #ifndef lint
! 35: static char RCSid[] =
! 36: "$Id: filesys.c,v 6.23 1994/08/15 22:06:43 mcooper Exp $";
! 37:
! 38: static char sccsid[] = "@(#)filesys.c";
! 39:
! 40: static char copyright[] =
! 41: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
! 42: All rights reserved.\n";
! 43: #endif /* not lint */
! 44:
! 45: /*
! 46: * This file contains functions dealing with getting info
! 47: * about mounted filesystems.
! 48: */
! 49:
! 50: #include "defs.h"
! 51: #include "filesys.h"
! 52:
! 53: jmp_buf env;
! 54:
! 55: /*
! 56: * Given a pathname, find the fullest component that exists.
! 57: * If statbuf is not NULL, set it to point at our stat buffer.
! 58: */
! 59: char *find_file(pathname, statbuf, isvalid)
! 60: char *pathname;
! 61: struct stat *statbuf;
! 62: int *isvalid;
! 63: {
! 64: static char last_pathname[MAXPATHLEN];
! 65: static char file[MAXPATHLEN + 3];
! 66: static struct stat filestat;
! 67: register char *p;
! 68:
! 69: /*
! 70: * Mark the statbuf as invalid to start with.
! 71: */
! 72: *isvalid = 0;
! 73:
! 74: /*
! 75: * If this is the same pathname as the last time, and
! 76: * the file buffer is valid and we're doing the same stat()
! 77: * or lstat(), then set statbuf to the last filestat and
! 78: * return the last file we found.
! 79: */
! 80: if (strcmp(pathname, last_pathname) == 0 && file[0]) {
! 81: if (statbuf)
! 82: statbuf = &filestat;
! 83: if (strcmp(pathname, file) == 0)
! 84: *isvalid = 1;
! 85: return(file);
! 86: }
! 87:
! 88: if ((int)strlen(pathname) > sizeof(file)+3) {
! 89: error("%s: Name to large for buffer.", pathname);
! 90: return((char *) NULL);
! 91: }
! 92:
! 93: /*
! 94: * Save for next time
! 95: */
! 96: (void) strcpy(last_pathname, pathname);
! 97:
! 98: if (*pathname == '/')
! 99: (void) strcpy(file, pathname);
! 100: else {
! 101: /*
! 102: * Ensure we have a directory (".") in our path
! 103: * so we have something to stat in case the file
! 104: * does not exist.
! 105: */
! 106: (void) strcpy(file, "./");
! 107: (void) strcat(file, pathname);
! 108: }
! 109:
! 110: while (lstat(file, &filestat) != 0) {
! 111: /*
! 112: * Trim the last part of the pathname to try next level up
! 113: */
! 114: if (errno == ENOENT) {
! 115: /*
! 116: * Trim file name to get directory name.
! 117: * Normally we want to change /dir1/dir2/file
! 118: * into "/dir1/dir2/."
! 119: */
! 120: if (p = (char *) strrchr(file, '/')) {
! 121: *++p = '.';
! 122: *++p = CNULL;
! 123: } else {
! 124: /*
! 125: * Couldn't find anything, so give up.
! 126: */
! 127: debugmsg(DM_MISC, "Cannot find dir of `%s'",
! 128: pathname);
! 129: return((char *) NULL);
! 130: }
! 131: continue;
! 132: } else {
! 133: error("%s: lstat failed: %s", pathname, SYSERR);
! 134: return((char *) NULL);
! 135: }
! 136: }
! 137:
! 138: if (statbuf)
! 139: bcopy((char *) &filestat, (char *) statbuf, sizeof(filestat));
! 140:
! 141: /*
! 142: * Trim the "/." that we added.
! 143: */
! 144: p = &file[strlen(file) - 1];
! 145: if (*p == '.')
! 146: *p-- = CNULL;
! 147: for ( ; p && *p && *p == '/' && p != file; --p)
! 148: *p = CNULL;
! 149:
! 150: /*
! 151: * If this file is a symlink we really want the parent directory
! 152: * name in case the symlink points to another filesystem.
! 153: */
! 154: if (S_ISLNK(filestat.st_mode))
! 155: if ((p = (char *) strrchr(file, '/')) && *p+1) {
! 156: /* Is this / (root)? */
! 157: if (p == file)
! 158: file[1] = CNULL;
! 159: else
! 160: *p = CNULL;
! 161: }
! 162:
! 163: if (strcmp(pathname, file) == 0)
! 164: *isvalid = 1;
! 165:
! 166: return((file && *file) ? file : (char *)NULL);
! 167: }
! 168:
! 169: #if defined(NFS_CHECK) || defined(RO_CHECK)
! 170:
! 171: /*
! 172: * Find the device that "filest" is on in the "mntinfo" linked list.
! 173: */
! 174: mntent_t *findmnt(filest, mntinfo)
! 175: struct stat *filest;
! 176: struct mntinfo *mntinfo;
! 177: {
! 178: register struct mntinfo *mi;
! 179:
! 180: for (mi = mntinfo; mi; mi = mi->mi_nxt) {
! 181: if (mi->mi_mnt->me_flags & MEFLAG_IGNORE)
! 182: continue;
! 183: if (filest->st_dev == mi->mi_statb->st_dev)
! 184: return(mi->mi_mnt);
! 185: }
! 186:
! 187: return((mntent_t *) NULL);
! 188: }
! 189:
! 190: /*
! 191: * Is "mnt" a duplicate of any of the mntinfo->mi_mnt elements?
! 192: */
! 193: int isdupmnt(mnt, mntinfo)
! 194: mntent_t *mnt;
! 195: struct mntinfo *mntinfo;
! 196: {
! 197: register struct mntinfo *m;
! 198:
! 199: for (m = mntinfo; m; m = m->mi_nxt)
! 200: if (strcmp(m->mi_mnt->me_path, mnt->me_path) == 0)
! 201: return(1);
! 202:
! 203: return(0);
! 204: }
! 205:
! 206: /*
! 207: * Alarm clock
! 208: */
! 209: void wakeup()
! 210: {
! 211: debugmsg(DM_CALL, "wakeup() in filesys.c called");
! 212: longjmp(env, 1);
! 213: }
! 214:
! 215: /*
! 216: * Make a linked list of mntinfo structures.
! 217: * Use "mi" as the base of the list if it's non NULL.
! 218: */
! 219: struct mntinfo *makemntinfo(mi)
! 220: struct mntinfo *mi;
! 221: {
! 222: FILE *mfp;
! 223: static struct mntinfo *mntinfo, *newmi, *m;
! 224: struct stat mntstat;
! 225: mntent_t *mnt;
! 226: int timeo = 310;
! 227:
! 228: if (!(mfp = setmountent(MOUNTED_FILE, "r"))) {
! 229: message(MT_NERROR, "%s: setmntent failed: %s",
! 230: MOUNTED_FILE, SYSERR);
! 231: return((struct mntinfo *) NULL);
! 232: }
! 233:
! 234: (void) signal(SIGALRM, wakeup);
! 235: (void) alarm(timeo);
! 236: if (setjmp(env)) {
! 237: message(MT_NERROR, "Timeout getting mount info");
! 238: return((struct mntinfo *) NULL);
! 239: }
! 240:
! 241: mntinfo = mi;
! 242: while (mnt = getmountent(mfp)) {
! 243: debugmsg(DM_MISC, "mountent = '%s' (%s)",
! 244: mnt->me_path, mnt->me_type);
! 245:
! 246: /*
! 247: * Make sure we don't already have it for some reason
! 248: */
! 249: if (isdupmnt(mnt, mntinfo))
! 250: continue;
! 251:
! 252: /*
! 253: * Get stat info
! 254: */
! 255: if (stat(mnt->me_path, &mntstat) != 0) {
! 256: message(MT_WARNING, "%s: Cannot stat filesystem: %s",
! 257: mnt->me_path, SYSERR);
! 258: continue;
! 259: }
! 260:
! 261: /*
! 262: * Create new entry
! 263: */
! 264: newmi = (struct mntinfo *) xcalloc(1, sizeof(struct mntinfo));
! 265: newmi->mi_mnt = newmountent(mnt);
! 266: newmi->mi_statb =
! 267: (struct stat *) xcalloc(1, sizeof(struct stat));
! 268: bcopy((char *) &mntstat, (char *) newmi->mi_statb,
! 269: sizeof(struct stat));
! 270:
! 271: /*
! 272: * Add entry to list
! 273: */
! 274: if (mntinfo) {
! 275: for (m = mntinfo; m && m->mi_nxt; m = m->mi_nxt);
! 276: m->mi_nxt = newmi;
! 277: } else
! 278: mntinfo = newmi;
! 279: }
! 280:
! 281: (void) alarm(0);
! 282: (void) endmountent(mfp);
! 283:
! 284: return(mntinfo);
! 285: }
! 286:
! 287: /*
! 288: * Given a name like /usr/src/etc/foo.c returns the mntent
! 289: * structure for the file system it lives in.
! 290: *
! 291: * If "statbuf" is not NULL it is used as the stat buffer too avoid
! 292: * stat()'ing the file again back in server.c.
! 293: */
! 294: mntent_t *getmntpt(pathname, statbuf, isvalid)
! 295: char *pathname;
! 296: struct stat *statbuf;
! 297: int *isvalid;
! 298: {
! 299: static struct mntinfo *mntinfo = NULL;
! 300: static struct stat filestat;
! 301: struct stat *pstat;
! 302: struct mntinfo *tmpmi;
! 303: register mntent_t *mnt;
! 304:
! 305: /*
! 306: * Use the supplied stat buffer if not NULL or our own.
! 307: */
! 308: if (statbuf)
! 309: pstat = statbuf;
! 310: else
! 311: pstat = &filestat;
! 312:
! 313: if (!find_file(pathname, pstat, isvalid))
! 314: return((mntent_t *) NULL);
! 315:
! 316: /*
! 317: * Make mntinfo if it doesn't exist.
! 318: */
! 319: if (!mntinfo)
! 320: mntinfo = makemntinfo((struct mntinfo *) NULL);
! 321:
! 322: /*
! 323: * Find the mnt that pathname is on.
! 324: */
! 325: if (mnt = findmnt(pstat, mntinfo))
! 326: return(mnt);
! 327:
! 328: /*
! 329: * We failed to find correct mnt, so maybe it's a newly
! 330: * mounted filesystem. We rebuild mntinfo and try again.
! 331: */
! 332: if (tmpmi = makemntinfo(mntinfo)) {
! 333: mntinfo = tmpmi;
! 334: if (mnt = findmnt(pstat, mntinfo))
! 335: return(mnt);
! 336: }
! 337:
! 338: error("%s: Could not find mount point", pathname);
! 339: return((mntent_t *) NULL);
! 340: }
! 341:
! 342: #endif /* NFS_CHECK || RO_CHECK */
! 343:
! 344: #if defined(NFS_CHECK)
! 345: /*
! 346: * Is "path" NFS mounted? Return 1 if it is, 0 if not, or -1 on error.
! 347: */
! 348: int is_nfs_mounted(path, statbuf, isvalid)
! 349: char *path;
! 350: struct stat *statbuf;
! 351: int *isvalid;
! 352: {
! 353: mntent_t *mnt;
! 354:
! 355: if ((mnt = (mntent_t *) getmntpt(path, statbuf, isvalid)) == NULL)
! 356: return(-1);
! 357:
! 358: if (strcmp(mnt->me_type, METYPE_NFS) == 0)
! 359: return(1);
! 360:
! 361: return(0);
! 362: }
! 363: #endif /* NFS_CHECK */
! 364:
! 365: #if defined(RO_CHECK)
! 366: /*
! 367: * Is "path" on a read-only mounted filesystem?
! 368: * Return 1 if it is, 0 if not, or -1 on error.
! 369: */
! 370: int is_ro_mounted(path, statbuf, isvalid)
! 371: char *path;
! 372: struct stat *statbuf;
! 373: int *isvalid;
! 374: {
! 375: mntent_t *mnt;
! 376:
! 377: if ((mnt = (mntent_t *) getmntpt(path, statbuf, isvalid)) == NULL)
! 378: return(-1);
! 379:
! 380: if (mnt->me_flags & MEFLAG_READONLY)
! 381: return(1);
! 382:
! 383: return(0);
! 384: }
! 385: #endif /* RO_CHECK */
! 386:
! 387: /*
! 388: * Is "path" a symlink?
! 389: * Return 1 if it is, 0 if not, or -1 on error.
! 390: */
! 391: int is_symlinked(path, statbuf, isvalid)
! 392: /*ARGSUSED*/
! 393: char *path;
! 394: struct stat *statbuf;
! 395: int *isvalid;
! 396: {
! 397: static struct stat stb;
! 398:
! 399: if (!(*isvalid)) {
! 400: if (lstat(path, &stb) != 0)
! 401: return(-1);
! 402: statbuf = &stb;
! 403: }
! 404:
! 405: if (S_ISLNK(statbuf->st_mode))
! 406: return(1);
! 407:
! 408: return(0);
! 409: }
! 410:
! 411: /*
! 412: * Get filesystem information for "file". Set freespace
! 413: * to the amount of free (available) space and number of free
! 414: * files (inodes) on the filesystem "file" resides on.
! 415: * Returns 0 on success or -1 on failure.
! 416: * Filesystem values < 0 indicate unsupported or unavailable
! 417: * information.
! 418: */
! 419: int getfilesysinfo(file, freespace, freefiles)
! 420: char *file;
! 421: long *freespace;
! 422: long *freefiles;
! 423: {
! 424: #if defined(STATFS_TYPE)
! 425: static statfs_t statfsbuf;
! 426: char *mntpt;
! 427: int t, r;
! 428:
! 429: /*
! 430: * Get the mount point of the file.
! 431: */
! 432: mntpt = find_file(file, NULL, &t);
! 433: if (!mntpt) {
! 434: debugmsg(DM_MISC, "unknown mount point for `%s'", file);
! 435: return(-1);
! 436: }
! 437:
! 438: /*
! 439: * Stat the filesystem (system specific)
! 440: */
! 441: #if STATFS_TYPE == STATFS_SYSV
! 442: r = statfs(mntpt, &statfsbuf, sizeof(statfs_t), 0);
! 443: #endif
! 444: #if STATFS_TYPE == STATFS_BSD
! 445: r = statfs(mntpt, &statfsbuf);
! 446: #endif
! 447: #if STATFS_TYPE == STATFS_OSF1
! 448: r = statfs(mntpt, &statfsbuf, sizeof(statfs_t));
! 449: #endif
! 450:
! 451: if (r < 0) {
! 452: error("%s: Cannot statfs filesystem: %s.", mntpt, SYSERR);
! 453: return(-1);
! 454: }
! 455:
! 456: /*
! 457: * If values are < 0, then assume the value is unsupported
! 458: * or unavailable for that filesystem type.
! 459: */
! 460: if (statfsbuf.f_bavail >= 0)
! 461: *freespace = (statfsbuf.f_bavail * (statfsbuf.f_bsize / 512))
! 462: / 2;
! 463:
! 464: /*
! 465: * BROKEN_STATFS means that statfs() does not set fields
! 466: * to < 0 if the field is unsupported for the filesystem type.
! 467: */
! 468: #if defined(BROKEN_STATFS)
! 469: if (statfsbuf.f_ffree > 0)
! 470: #else
! 471: if (statfsbuf.f_ffree >= 0)
! 472: #endif /* BROKEN_STATFS */
! 473: *freefiles = statfsbuf.f_ffree;
! 474:
! 475: #else /* !STATFS_TYPE */
! 476:
! 477: *freespace = *freefiles = -1;
! 478:
! 479: #endif /* STATFS_TYPE */
! 480:
! 481: return(0);
! 482: }