void quot(char *name, char *mp) { int i, fd; struct fs *fs; get_inode(-1, NULL, 0); /* flush cache */ inituser(); initfsizes(); /* * XXX this is completely broken. Of course you can't read a * directory, well, not anymore. How to fix this, though... */ if ((fd = open(name, 0)) < 0) { warn("%s", name); return; } for (i = 0; sblock_try[i] != -1; i++) { if (lseek(fd, sblock_try[i], 0) != sblock_try[i]) { close(fd); return; } if (read(fd, superblock, SBLOCKSIZE) != SBLOCKSIZE) { close(fd); return; } fs = (struct fs *)superblock; if ((fs->fs_magic == FS_UFS1_MAGIC || (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_sblockloc == sblock_try[i])) && fs->fs_bsize <= MAXBSIZE && fs->fs_bsize >= sizeof(struct fs)) break; } if (sblock_try[i] == -1) { warnx("%s: not a BSD filesystem", name); close(fd); return; } ffs_oldfscompat(fs); printf("%s:", name); if (mp) printf(" (%s)", mp); putchar('\n'); (*func)(fd, fs, name); close(fd); }
/* * Open a file. */ __compactcall int ufs_open(const char *path, struct open_file *f) { #ifndef LIBSA_FS_SINGLECOMPONENT const char *cp, *ncp; int c; #endif ino32_t inumber; struct file *fp; struct fs *fs; int rc; #ifndef LIBSA_NO_FS_SYMLINK ino32_t parent_inumber; int nlinks = 0; char namebuf[MAXPATHLEN+1]; char *buf; #endif /* allocate file system specific data structure */ fp = alloc(sizeof(struct file)); memset(fp, 0, sizeof(struct file)); f->f_fsdata = (void *)fp; /* allocate space and read super block */ fs = alloc(SBLOCKSIZE); fp->f_fs = fs; twiddle(); #ifdef LIBSA_FFSv2 rc = ffs_find_superblock(f, fs); if (rc) goto out; #else { size_t buf_size; rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, SBLOCKOFFSET / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size); if (rc) goto out; if (buf_size != SBLOCKSIZE || #ifdef LIBSA_FFS fs->lfs_version != REQUIRED_LFS_VERSION || #endif fs->fs_magic != FS_MAGIC) { rc = EINVAL; goto out; } } #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2 /* * XXX We should check the second superblock and use the eldest * of the two. See comments near the top of lfs_mountfs() * in sys/ufs/lfs/lfs_vfsops.c. * This may need a LIBSA_LFS_SMALL check as well. */ #endif #endif #ifdef LIBSA_FFSv1 ffs_oldfscompat(fs); #endif if (fs->fs_bsize > MAXBSIZE || (size_t)fs->fs_bsize < sizeof(struct fs)) { rc = EINVAL; goto out; } /* * Calculate indirect block levels. */ { indp_t mult; int ln2; /* * We note that the number of indirect blocks is always * a power of 2. This lets us use shifts and masks instead * of divide and remainder and avoinds pulling in the * 64bit division routine into the boot code. */ mult = UFS_NINDIR(fs); #ifdef DEBUG if (mult & (mult - 1)) { /* Hummm was't a power of 2 */ rc = EINVAL; goto out; } #endif for (ln2 = 0; mult != 1; ln2++) mult >>= 1; fp->f_nishift = ln2; } /* alloc a block sized buffer used for all fs transfers */ fp->f_buf = alloc(fs->fs_bsize); inumber = UFS_ROOTINO; if ((rc = read_inode(inumber, f)) != 0) goto out; #ifndef LIBSA_FS_SINGLECOMPONENT cp = path; while (*cp) { /* * Remove extra separators */ while (*cp == '/') cp++; if (*cp == '\0') break; /* * Check that current node is a directory. */ if ((fp->f_di.di_mode & IFMT) != IFDIR) { rc = ENOTDIR; goto out; } /* * Get next component of path name. */ ncp = cp; while ((c = *cp) != '\0' && c != '/') cp++; /* * Look up component in current directory. * Save directory inumber in case we find a * symbolic link. */ #ifndef LIBSA_NO_FS_SYMLINK parent_inumber = inumber; #endif rc = search_directory(ncp, cp - ncp, f, &inumber); if (rc) goto out; /* * Open next component. */ if ((rc = read_inode(inumber, f)) != 0) goto out; #ifndef LIBSA_NO_FS_SYMLINK /* * Check for symbolic link. */ if ((fp->f_di.di_mode & IFMT) == IFLNK) { int link_len = fp->f_di.di_size; int len; len = strlen(cp); if (link_len + len > MAXPATHLEN || ++nlinks > MAXSYMLINKS) { rc = ENOENT; goto out; } memmove(&namebuf[link_len], cp, len + 1); if (link_len < fs->fs_maxsymlinklen) { memcpy(namebuf, fp->f_di.di_db, link_len); } else { /* * Read file for symbolic link */ size_t buf_size; indp_t disk_block; buf = fp->f_buf; rc = block_map(f, (indp_t)0, &disk_block); if (rc) goto out; twiddle(); rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, FSBTODB(fs, disk_block), fs->fs_bsize, buf, &buf_size); if (rc) goto out; memcpy(namebuf, buf, link_len); } /* * If relative pathname, restart at parent directory. * If absolute pathname, restart at root. */ cp = namebuf; if (*cp != '/') inumber = parent_inumber; else inumber = (ino32_t)UFS_ROOTINO; if ((rc = read_inode(inumber, f)) != 0) goto out; } #endif /* !LIBSA_NO_FS_SYMLINK */ } /* * Found terminal component. */ rc = 0; #else /* !LIBSA_FS_SINGLECOMPONENT */ /* look up component in the current (root) directory */ rc = search_directory(path, strlen(path), f, &inumber); if (rc) goto out; /* open it */ rc = read_inode(inumber, f); #endif /* !LIBSA_FS_SINGLECOMPONENT */ fp->f_seekp = 0; /* reset seek pointer */ out: if (rc) ufs_close(f); #ifdef FSMOD /* Only defined for lfs */ else fsmod = FSMOD; #endif return rc; }
/* * Reload all incore data for a filesystem (used after running fsck on * the root filesystem and finding things to fix). The filesystem must * be mounted read-only. * * Things to do to update the mount: * 1) invalidate all cached meta-data. * 2) re-read superblock from disk. * 3) re-read summary information from disk. * 4) invalidate all inactive vnodes. * 5) invalidate all cached file data. * 6) re-read inode data for all active vnodes. */ int ffs_reload(struct mount *mountp, struct ucred *cred, struct proc *p) { struct vnode *devvp; caddr_t space; struct fs *fs, *newfs; struct partinfo dpart; int i, blks, size, error; int32_t *lp; struct buf *bp = NULL; struct ffs_reload_args fra; if ((mountp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); /* * Step 1: invalidate all cached meta-data. */ devvp = VFSTOUFS(mountp)->um_devvp; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = vinvalbuf(devvp, 0, cred, p, 0, 0); VOP_UNLOCK(devvp, 0, p); if (error) panic("ffs_reload: dirty1"); /* * Step 2: re-read superblock from disk. */ if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) size = DEV_BSIZE; else size = dpart.disklab->d_secsize; error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp); if (error) { brelse(bp); return (error); } newfs = (struct fs *)bp->b_data; if (ffs_validate(newfs) == 0) { brelse(bp); return (EINVAL); } fs = VFSTOUFS(mountp)->um_fs; /* * Copy pointer fields back into superblock before copying in XXX * new superblock. These should really be in the ufsmount. XXX * Note that important parameters (eg fs_ncg) are unchanged. */ newfs->fs_csp = fs->fs_csp; newfs->fs_maxcluster = fs->fs_maxcluster; newfs->fs_ronly = fs->fs_ronly; bcopy(newfs, fs, (u_int)fs->fs_sbsize); if (fs->fs_sbsize < SBSIZE) bp->b_flags |= B_INVAL; brelse(bp); mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; ffs1_compat_read(fs, VFSTOUFS(mountp), SBOFF); ffs_oldfscompat(fs); (void)ffs_statfs(mountp, &mountp->mnt_stat, p); /* * Step 3: re-read summary information from disk. */ blks = howmany(fs->fs_cssize, fs->fs_fsize); space = (caddr_t)fs->fs_csp; for (i = 0; i < blks; i += fs->fs_frag) { size = fs->fs_bsize; if (i + fs->fs_frag > blks) size = (blks - i) * fs->fs_fsize; error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, NOCRED, &bp); if (error) { brelse(bp); return (error); } bcopy(bp->b_data, space, (u_int)size); space += size; brelse(bp); } if ((fs->fs_flags & FS_DOSOFTDEP)) (void) softdep_mount(devvp, mountp, fs, cred); /* * We no longer know anything about clusters per cylinder group. */ if (fs->fs_contigsumsize > 0) { lp = fs->fs_maxcluster; for (i = 0; i < fs->fs_ncg; i++) *lp++ = fs->fs_contigsumsize; } fra.p = p; fra.cred = cred; fra.fs = fs; fra.devvp = devvp; error = vfs_mount_foreach_vnode(mountp, ffs_reload_vnode, &fra); return (error); }
/* * Common code for mount and mountroot */ int ffs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p) { struct ufsmount *ump; struct buf *bp; struct fs *fs; dev_t dev; struct partinfo dpart; caddr_t space; ufs2_daddr_t sbloc; int error, i, blks, size, ronly; int32_t *lp; size_t strsize; struct ucred *cred; u_int64_t maxfilesize; /* XXX */ dev = devvp->v_rdev; cred = p ? p->p_ucred : NOCRED; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use * (except for root, which might share swap device for miniroot). * Flush out any old buffers remaining from a previous use. */ if ((error = vfs_mountedon(devvp)) != 0) return (error); if (vcount(devvp) > 1 && devvp != rootvp) return (EBUSY); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0); VOP_UNLOCK(devvp, 0, p); if (error) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); if (error) return (error); if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) size = DEV_BSIZE; else size = dpart.disklab->d_secsize; bp = NULL; ump = NULL; /* * Try reading the super-block in each of its possible locations. */ for (i = 0; sbtry[i] != -1; i++) { if (bp != NULL) { bp->b_flags |= B_NOCACHE; brelse(bp); bp = NULL; } error = bread(devvp, sbtry[i] / size, SBSIZE, cred, &bp); if (error) goto out; fs = (struct fs *) bp->b_data; sbloc = sbtry[i]; #if 0 if (fs->fs_magic == FS_UFS2_MAGIC) { printf("ffs_mountfs(): Sorry, no UFS2 support (yet)\n"); error = EFTYPE; goto out; } #endif /* * Do not look for an FFS1 file system at SBLOCK_UFS2. Doing so * will find the wrong super-block for file systems with 64k * block size. */ if (fs->fs_magic == FS_UFS1_MAGIC && sbloc == SBLOCK_UFS2) continue; if (ffs_validate(fs)) break; /* Super block validated */ } if (sbtry[i] == -1) { error = EINVAL; goto out; } fs->fs_fmod = 0; fs->fs_flags &= ~FS_UNCLEAN; if (fs->fs_clean == 0) { fs->fs_flags |= FS_UNCLEAN; #if 0 /* * It is safe mount unclean file system * if it was previously mounted with softdep * but we may loss space and must * sometimes run fsck manually. */ if (fs->fs_flags & FS_DOSOFTDEP) printf( "WARNING: %s was not properly unmounted\n", fs->fs_fsmnt); else #endif if (ronly || (mp->mnt_flag & MNT_FORCE)) { printf( "WARNING: %s was not properly unmounted\n", fs->fs_fsmnt); } else { printf( "WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", fs->fs_fsmnt); error = EROFS; goto out; } } if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) { #ifndef SMALL_KERNEL printf("ffs_mountfs(): obsolete rotational table format, " "please use fsck_ffs(8) -c 1\n"); #endif error = EFTYPE; goto out; } ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); bzero(ump, sizeof *ump); ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, M_WAITOK); if (fs->fs_magic == FS_UFS1_MAGIC) ump->um_fstype = UM_UFS1; #ifdef FFS2 else ump->um_fstype = UM_UFS2; #endif bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize); if (fs->fs_sbsize < SBSIZE) bp->b_flags |= B_INVAL; brelse(bp); bp = NULL; fs = ump->um_fs; ffs1_compat_read(fs, ump, sbloc); fs->fs_ronly = ronly; size = fs->fs_cssize; blks = howmany(size, fs->fs_fsize); if (fs->fs_contigsumsize > 0) size += fs->fs_ncg * sizeof(int32_t); space = malloc((u_long)size, M_UFSMNT, M_WAITOK); fs->fs_csp = (struct csum *)space; for (i = 0; i < blks; i += fs->fs_frag) { size = fs->fs_bsize; if (i + fs->fs_frag > blks) size = (blks - i) * fs->fs_fsize; error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, cred, &bp); if (error) { free(fs->fs_csp, M_UFSMNT); goto out; } bcopy(bp->b_data, space, (u_int)size); space += size; brelse(bp); bp = NULL; } if (fs->fs_contigsumsize > 0) { fs->fs_maxcluster = lp = (int32_t *)space; for (i = 0; i < fs->fs_ncg; i++) *lp++ = fs->fs_contigsumsize; } mp->mnt_data = (qaddr_t)ump; mp->mnt_stat.f_fsid.val[0] = (long)dev; /* Use on-disk fsid if it exists, else fake it */ if (fs->fs_id[0] != 0 && fs->fs_id[1] != 0) mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1]; else mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; mp->mnt_flag |= MNT_LOCAL; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; ump->um_nindir = fs->fs_nindir; ump->um_bptrtodb = fs->fs_fsbtodb; ump->um_seqinc = fs->fs_frag; for (i = 0; i < MAXQUOTAS; i++) ump->um_quotas[i] = NULLVP; devvp->v_specmountpoint = mp; ffs_oldfscompat(fs); if (ronly) fs->fs_contigdirs = NULL; else { fs->fs_contigdirs = (u_int8_t*)malloc((u_long)fs->fs_ncg, M_UFSMNT, M_WAITOK); bzero(fs->fs_contigdirs, fs->fs_ncg); } /* * Set FS local "last mounted on" information (NULL pad) */ copystr(mp->mnt_stat.f_mntonname, /* mount point*/ fs->fs_fsmnt, /* copy area*/ sizeof(fs->fs_fsmnt) - 1, /* max size*/ &strsize); /* real size*/ bzero(fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize); #if 0 if( mp->mnt_flag & MNT_ROOTFS) { /* * Root mount; update timestamp in mount structure. * this will be used by the common root mount code * to update the system clock. */ mp->mnt_time = fs->fs_time; } #endif /* * XXX * Limit max file size. Even though ffs can handle files up to 16TB, * we do limit the max file to 2^31 pages to prevent overflow of * a 32-bit unsigned int. The buffer cache has its own checks but * a little added paranoia never hurts. */ ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */ maxfilesize = (u_int64_t)0x80000000 * MIN(PAGE_SIZE, fs->fs_bsize) - 1; if (fs->fs_maxfilesize > maxfilesize) /* XXX */ fs->fs_maxfilesize = maxfilesize; /* XXX */ if (ronly == 0) { if ((fs->fs_flags & FS_DOSOFTDEP) && (error = softdep_mount(devvp, mp, fs, cred)) != 0) { free(fs->fs_csp, M_UFSMNT); free(fs->fs_contigdirs, M_UFSMNT); goto out; } fs->fs_fmod = 1; fs->fs_clean = 0; if (mp->mnt_flag & MNT_SOFTDEP) fs->fs_flags |= FS_DOSOFTDEP; else fs->fs_flags &= ~FS_DOSOFTDEP; (void) ffs_sbupdate(ump, MNT_WAIT); } return (0); out: devvp->v_specmountpoint = NULL; if (bp) brelse(bp); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); VOP_UNLOCK(devvp, 0, p); if (ump) { free(ump->um_fs, M_UFSMNT); free(ump, M_UFSMNT); mp->mnt_data = (qaddr_t)0; } return (error); }
/* * Open a file. */ static int ufs_open(const char *upath, struct open_file *f) { char *cp, *ncp; int c; ino_t inumber, parent_inumber; struct file *fp; struct fs *fs; int rc; size_t buf_size; int nlinks = 0; char namebuf[MAXPATHLEN+1]; char *buf = NULL; char *path = NULL; /* allocate file system specific data structure */ fp = malloc(sizeof(struct file)); bzero(fp, sizeof(struct file)); f->f_fsdata = (void *)fp; /* allocate space and read super block */ fs = malloc(SBSIZE); fp->f_fs = fs; twiddle(); rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, SBOFF / DEV_BSIZE, SBSIZE, (char *)fs, &buf_size); if (rc) goto out; if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) { rc = EINVAL; goto out; } #ifdef COMPAT_UFS ffs_oldfscompat(fs); #endif /* * Calculate indirect block levels. */ { int omult; int mult; int level; omult = 0; mult = 1; for (level = 0; level < NIADDR; level++) { mult *= NINDIR(fs); if (mult < omult) mult = 0x7FFFFFFF; fp->f_nindir[level] = mult; omult = mult; } } inumber = ROOTINO; if ((rc = read_inode(inumber, f)) != 0) goto out; cp = path = strdup(upath); if (path == NULL) { rc = ENOMEM; goto out; } while (*cp) { /* * Remove extra separators */ while (*cp == '/') cp++; if (*cp == '\0') break; /* * Check that current node is a directory. */ if ((fp->f_di.di_mode & IFMT) != IFDIR) { rc = ENOTDIR; goto out; } /* * Get next component of path name. */ { int len = 0; ncp = cp; while ((c = *cp) != '\0' && c != '/') { if (++len > MAXNAMLEN) { rc = ENOENT; goto out; } cp++; } *cp = '\0'; } /* * Look up component in current directory. * Save directory inumber in case we find a * symbolic link. */ parent_inumber = inumber; rc = search_directory(ncp, f, &inumber); *cp = c; if (rc) goto out; /* * Open next component. */ if ((rc = read_inode(inumber, f)) != 0) goto out; /* * Check for symbolic link. */ if ((fp->f_di.di_mode & IFMT) == IFLNK) { int link_len = fp->f_di.di_size; int len; len = strlen(cp); if (link_len + len > MAXPATHLEN || ++nlinks > MAXSYMLINKS) { rc = ENOENT; goto out; } bcopy(cp, &namebuf[link_len], len + 1); if (link_len < fs->fs_maxsymlinklen) { bcopy(fp->f_di.di_shortlink, namebuf, (unsigned) link_len); } else { /* * Read file for symbolic link */ size_t buf_size; daddr_t disk_block; struct fs *fs = fp->f_fs; if (!buf) buf = malloc(fs->fs_bsize); rc = block_map(f, (daddr_t)0, &disk_block); if (rc) goto out; twiddle(); rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, fsbtodb(fs, disk_block), fs->fs_bsize, buf, &buf_size); if (rc) goto out; bcopy((char *)buf, namebuf, (unsigned)link_len); } /* * If relative pathname, restart at parent directory. * If absolute pathname, restart at root. */ cp = namebuf; if (*cp != '/') inumber = parent_inumber; else inumber = (ino_t)ROOTINO; if ((rc = read_inode(inumber, f)) != 0) goto out; } } /* * Found terminal component. */ fp->f_seekp = 0; rc = 0; out: if (buf) free(buf); if (path) free(path); if (rc) { f->f_fsdata = NULL; if (fp->f_buf) free(fp->f_buf); free(fp->f_fs); free(fp); } return (rc); }