diff --git a/lib/libufs/libufs.h b/lib/libufs/libufs.h index 63a8dc170997..5045117b5d7d 100644 --- a/lib/libufs/libufs.h +++ b/lib/libufs/libufs.h @@ -1,170 +1,171 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2002 Juli Mallett. All rights reserved. * * This software was written by Juli Mallett for the * FreeBSD project. Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the following * conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistribution 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * $FreeBSD$ */ #ifndef __LIBUFS_H__ #define __LIBUFS_H__ /* * libufs structures. */ union dinodep { struct ufs1_dinode *dp1; struct ufs2_dinode *dp2; }; /* * userland ufs disk. */ struct uufsd { const char *d_name; /* disk name */ int d_ufs; /* decimal UFS version */ int d_fd; /* raw device file descriptor */ long d_bsize; /* device bsize */ ufs2_daddr_t d_sblock; /* superblock location */ struct fs_summary_info *d_si; /* Superblock summary info */ caddr_t d_inoblock; /* inode block */ uint32_t d_inomin; /* low ino, not ino_t for ABI compat */ uint32_t d_inomax; /* high ino, not ino_t for ABI compat */ union dinodep d_dp; /* pointer to currently active inode */ union { struct fs d_fs; /* filesystem information */ char d_sb[MAXBSIZE]; /* superblock as buffer */ } d_sbunion; union { struct cg d_cg; /* cylinder group */ char d_buf[MAXBSIZE]; /* cylinder group storage */ } d_cgunion; int d_ccg; /* current cylinder group */ int d_lcg; /* last cylinder group (in d_cg) */ const char *d_error; /* human readable disk error */ + off_t d_sblockloc; /* where to look for the superblock */ int d_mine; /* internal flags */ #define d_fs d_sbunion.d_fs #define d_sb d_sbunion.d_sb #define d_cg d_cgunion.d_cg }; /* * libufs macros (internal, non-exported). */ #ifdef _LIBUFS /* * Trace steps through libufs, to be used at entry and erroneous return. */ static inline void ERROR(struct uufsd *u, const char *str) { #ifdef _LIBUFS_DEBUGGING if (str != NULL) { fprintf(stderr, "libufs: %s", str); if (errno != 0) fprintf(stderr, ": %s", strerror(errno)); fprintf(stderr, "\n"); } #endif if (u != NULL) u->d_error = str; } #endif /* _LIBUFS */ __BEGIN_DECLS /* * libufs prototypes. */ /* * ffs_subr.c */ void ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t); void ffs_clusteracct(struct fs *, struct cg *, ufs1_daddr_t, int); void ffs_fragacct(struct fs *, int, int32_t [], int); int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t); int ffs_isfreeblock(struct fs *, u_char *, ufs1_daddr_t); void ffs_setblock(struct fs *, u_char *, ufs1_daddr_t); int ffs_sbget(void *, struct fs **, off_t, char *, int (*)(void *, off_t, void **, int)); int ffs_sbput(void *, struct fs *, off_t, int (*)(void *, off_t, void *, int)); void ffs_update_dinode_ckhash(struct fs *, struct ufs2_dinode *); int ffs_verify_dinode_ckhash(struct fs *, struct ufs2_dinode *); /* * block.c */ ssize_t bread(struct uufsd *, ufs2_daddr_t, void *, size_t); ssize_t bwrite(struct uufsd *, ufs2_daddr_t, const void *, size_t); int berase(struct uufsd *, ufs2_daddr_t, ufs2_daddr_t); /* * cgroup.c */ ufs2_daddr_t cgballoc(struct uufsd *); int cgbfree(struct uufsd *, ufs2_daddr_t, long); ino_t cgialloc(struct uufsd *); int cgget(int, struct fs *, int, struct cg *); int cgput(int, struct fs *, struct cg *); int cgread(struct uufsd *); int cgread1(struct uufsd *, int); int cgwrite(struct uufsd *); int cgwrite1(struct uufsd *, int); /* * inode.c */ int getinode(struct uufsd *, union dinodep *, ino_t); int putinode(struct uufsd *); /* * sblock.c */ int sbread(struct uufsd *); int sbwrite(struct uufsd *, int); /* low level superblock read/write functions */ int sbget(int, struct fs **, off_t); int sbput(int, struct fs *, int); /* * type.c */ int ufs_disk_close(struct uufsd *); int ufs_disk_fillout(struct uufsd *, const char *); int ufs_disk_fillout_blank(struct uufsd *, const char *); int ufs_disk_write(struct uufsd *); /* * crc32c.c */ uint32_t calculate_crc32c(uint32_t, const void *, size_t); __END_DECLS #endif /* __LIBUFS_H__ */ diff --git a/lib/libufs/sblock.c b/lib/libufs/sblock.c index 3b65e79b02b5..9ba012400f1d 100644 --- a/lib/libufs/sblock.c +++ b/lib/libufs/sblock.c @@ -1,211 +1,227 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2002 Juli Mallett. All rights reserved. * * This software was written by Juli Mallett for the * FreeBSD project. Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the following * conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistribution 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +static int handle_disk_read(struct uufsd *, struct fs *, int); + +/* + * Read the standard superblock. + */ int sbread(struct uufsd *disk) { struct fs *fs; + int error; - ERROR(disk, NULL); + error = sbget(disk->d_fd, &fs, disk->d_sblockloc); + return (handle_disk_read(disk, fs, error)); +} - if ((errno = sbget(disk->d_fd, &fs, STDSB)) != 0) { - switch (errno) { +static int +handle_disk_read(struct uufsd *disk, struct fs *fs, int error) +{ + + ERROR(disk, NULL); + if (error != 0) { + switch (error) { case EIO: ERROR(disk, "non-existent or truncated superblock"); break; case ENOENT: ERROR(disk, "no usable known superblock found"); break; + case EINTEGRITY: + ERROR(disk, "superblock check-hash failure"); + break; case ENOSPC: ERROR(disk, "failed to allocate space for superblock " "information"); break; case EINVAL: ERROR(disk, "The previous newfs operation on this " "volume did not complete.\nYou must complete " "newfs before using this volume."); break; default: ERROR(disk, "unknown superblock read error"); errno = EIO; break; } disk->d_ufs = 0; return (-1); } memcpy(&disk->d_fs, fs, fs->fs_sbsize); free(fs); fs = &disk->d_fs; if (fs->fs_magic == FS_UFS1_MAGIC) disk->d_ufs = 1; if (fs->fs_magic == FS_UFS2_MAGIC) disk->d_ufs = 2; disk->d_bsize = fs->fs_fsize / fsbtodb(fs, 1); disk->d_sblock = fs->fs_sblockloc / disk->d_bsize; disk->d_si = fs->fs_si; return (0); } int sbwrite(struct uufsd *disk, int all) { struct fs *fs; int rv; ERROR(disk, NULL); rv = ufs_disk_write(disk); if (rv == -1) { ERROR(disk, "failed to open disk for writing"); return (-1); } fs = &disk->d_fs; if ((errno = sbput(disk->d_fd, fs, all ? fs->fs_ncg : 0)) != 0) { switch (errno) { case EIO: ERROR(disk, "failed to write superblock"); break; default: ERROR(disk, "unknown superblock write error"); errno = EIO; break; } return (-1); } return (0); } /* * These are the low-level functions that actually read and write * the superblock and its associated data. The actual work is done by * the functions ffs_sbget and ffs_sbput in /sys/ufs/ffs/ffs_subr.c. */ static int use_pread(void *devfd, off_t loc, void **bufp, int size); static int use_pwrite(void *devfd, off_t loc, void *buf, int size); /* * Read a superblock from the devfd device allocating memory returned * in fsp. Also read the superblock summary information. */ int sbget(int devfd, struct fs **fsp, off_t sblockloc) { return (ffs_sbget(&devfd, fsp, sblockloc, "user", use_pread)); } /* * A read function for use by user-level programs using libufs. */ static int use_pread(void *devfd, off_t loc, void **bufp, int size) { int fd; fd = *(int *)devfd; if ((*bufp = malloc(size)) == NULL) return (ENOSPC); if (pread(fd, *bufp, size, loc) != size) return (EIO); return (0); } /* * Write a superblock to the devfd device from the memory pointed to by fs. * Also write out the superblock summary information but do not free the * summary information memory. * * Additionally write out numaltwrite of the alternate superblocks. Use * fs->fs_ncg to write out all of the alternate superblocks. */ int sbput(int devfd, struct fs *fs, int numaltwrite) { struct csum *savedcsp; off_t savedactualloc; int i, error; if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, use_pwrite)) != 0) return (error); if (numaltwrite == 0) return (0); savedactualloc = fs->fs_sblockactualloc; savedcsp = fs->fs_csp; fs->fs_csp = NULL; for (i = 0; i < numaltwrite; i++) { fs->fs_sblockactualloc = dbtob(fsbtodb(fs, cgsblock(fs, i))); if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, use_pwrite)) != 0) { fs->fs_sblockactualloc = savedactualloc; fs->fs_csp = savedcsp; return (error); } } fs->fs_sblockactualloc = savedactualloc; fs->fs_csp = savedcsp; return (0); } /* * A write function for use by user-level programs using sbput in libufs. */ static int use_pwrite(void *devfd, off_t loc, void *buf, int size) { int fd; fd = *(int *)devfd; if (pwrite(fd, buf, size, loc) != size) return (EIO); return (0); } diff --git a/lib/libufs/type.c b/lib/libufs/type.c index a060f8ec5abf..ac5b8d17e84c 100644 --- a/lib/libufs/type.c +++ b/lib/libufs/type.c @@ -1,206 +1,207 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2002 Juli Mallett. All rights reserved. * * This software was written by Juli Mallett for the * FreeBSD project. Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the following * conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistribution 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Internally, track the 'name' value, it's ours. */ #define MINE_NAME 0x01 /* Track if its fd points to a writable device. */ #define MINE_WRITE 0x02 int ufs_disk_close(struct uufsd *disk) { ERROR(disk, NULL); close(disk->d_fd); disk->d_fd = -1; if (disk->d_inoblock != NULL) { free(disk->d_inoblock); disk->d_inoblock = NULL; } if (disk->d_mine & MINE_NAME) { free((char *)(uintptr_t)disk->d_name); disk->d_name = NULL; } if (disk->d_si != NULL) { free(disk->d_si->si_csp); free(disk->d_si); disk->d_si = NULL; } return (0); } int ufs_disk_fillout(struct uufsd *disk, const char *name) { if (ufs_disk_fillout_blank(disk, name) == -1) { return (-1); } if (sbread(disk) == -1) { ERROR(disk, "could not read superblock to fill out disk"); ufs_disk_close(disk); return (-1); } return (0); } int ufs_disk_fillout_blank(struct uufsd *disk, const char *name) { struct stat st; struct fstab *fs; struct statfs sfs; const char *oname; char dev[MAXPATHLEN]; int fd, ret; ERROR(disk, NULL); oname = name; again: if ((ret = stat(name, &st)) < 0) { if (*name != '/') { snprintf(dev, sizeof(dev), "%s%s", _PATH_DEV, name); name = dev; goto again; } /* * The given object doesn't exist, but don't panic just yet - * it may be still mount point listed in /etc/fstab, but without * existing corresponding directory. */ name = oname; } if (ret >= 0 && S_ISREG(st.st_mode)) { /* Possibly a disk image, give it a try. */ ; } else if (ret >= 0 && S_ISCHR(st.st_mode)) { /* This is what we need, do nothing. */ ; } else if ((fs = getfsfile(name)) != NULL) { /* * The given mount point is listed in /etc/fstab. * It is possible that someone unmounted file system by hand * and different file system is mounted on this mount point, * but we still prefer /etc/fstab entry, because on the other * hand, there could be /etc/fstab entry for this mount * point, but file system is not mounted yet (eg. noauto) and * statfs(2) will point us at different file system. */ name = fs->fs_spec; } else if (ret >= 0 && S_ISDIR(st.st_mode)) { /* * The mount point is not listed in /etc/fstab, so it may be * file system mounted by hand. */ if (statfs(name, &sfs) < 0) { ERROR(disk, "could not find special device"); return (-1); } strlcpy(dev, sfs.f_mntfromname, sizeof(dev)); name = dev; } else { ERROR(disk, "could not find special device"); return (-1); } fd = open(name, O_RDONLY); if (fd == -1) { ERROR(disk, "could not open special device"); return (-1); } disk->d_bsize = 1; disk->d_ccg = 0; disk->d_fd = fd; disk->d_inoblock = NULL; disk->d_inomin = 0; disk->d_inomax = 0; disk->d_lcg = 0; disk->d_mine = 0; disk->d_ufs = 0; disk->d_error = NULL; disk->d_si = NULL; + disk->d_sblockloc = STDSB; if (oname != name) { name = strdup(name); if (name == NULL) { ERROR(disk, "could not allocate memory for disk name"); return (-1); } disk->d_mine |= MINE_NAME; } disk->d_name = name; return (0); } int ufs_disk_write(struct uufsd *disk) { int fd; ERROR(disk, NULL); if (disk->d_mine & MINE_WRITE) return (0); fd = open(disk->d_name, O_RDWR); if (fd < 0) { ERROR(disk, "failed to open disk for writing"); return (-1); } close(disk->d_fd); disk->d_fd = fd; disk->d_mine |= MINE_WRITE; return (0); }