15e53a4f9SPedro F. Giffuni /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 35e53a4f9SPedro F. Giffuni * 420938dbfSJuli Mallett * Copyright (c) 2002 Juli Mallett. All rights reserved. 520938dbfSJuli Mallett * 620938dbfSJuli Mallett * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the 720938dbfSJuli Mallett * FreeBSD project. Redistribution and use in source and binary forms, with 820938dbfSJuli Mallett * or without modification, are permitted provided that the following 920938dbfSJuli Mallett * conditions are met: 1020938dbfSJuli Mallett * 1120938dbfSJuli Mallett * 1. Redistribution of source code must retain the above copyright notice, 1220938dbfSJuli Mallett * this list of conditions and the following disclaimer. 1320938dbfSJuli Mallett * 2. Redistribution in binary form must reproduce the above copyright 1420938dbfSJuli Mallett * notice, this list of conditions and the following disclaimer in the 1520938dbfSJuli Mallett * documentation and/or other materials provided with the distribution. 1620938dbfSJuli Mallett * 1720938dbfSJuli Mallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1820938dbfSJuli Mallett * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1920938dbfSJuli Mallett * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2020938dbfSJuli Mallett * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 2120938dbfSJuli Mallett * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2220938dbfSJuli Mallett * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2320938dbfSJuli Mallett * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2420938dbfSJuli Mallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2520938dbfSJuli Mallett * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 2620938dbfSJuli Mallett * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2720938dbfSJuli Mallett * POSSIBILITY OF SUCH DAMAGE. 2820938dbfSJuli Mallett */ 2920938dbfSJuli Mallett 3020938dbfSJuli Mallett #include <sys/cdefs.h> 3120938dbfSJuli Mallett __FBSDID("$FreeBSD$"); 3220938dbfSJuli Mallett 3320938dbfSJuli Mallett #include <sys/param.h> 3420938dbfSJuli Mallett #include <sys/mount.h> 3520938dbfSJuli Mallett #include <sys/disklabel.h> 3620938dbfSJuli Mallett #include <sys/stat.h> 3720938dbfSJuli Mallett 38d485c77fSKonstantin Belousov #include <ufs/ufs/extattr.h> 39d485c77fSKonstantin Belousov #include <ufs/ufs/quota.h> 4020938dbfSJuli Mallett #include <ufs/ufs/ufsmount.h> 4120938dbfSJuli Mallett #include <ufs/ufs/dinode.h> 4220938dbfSJuli Mallett #include <ufs/ffs/fs.h> 4320938dbfSJuli Mallett 4420938dbfSJuli Mallett #include <errno.h> 4520938dbfSJuli Mallett #include <stdio.h> 4620938dbfSJuli Mallett #include <string.h> 47113db2ddSJeff Roberson #include <stdlib.h> 4820938dbfSJuli Mallett #include <unistd.h> 4920938dbfSJuli Mallett 5020938dbfSJuli Mallett #include <libufs.h> 5120938dbfSJuli Mallett 5282e72f1dSKirk McKusick static int handle_disk_read(struct uufsd *, struct fs *, int); 5382e72f1dSKirk McKusick 5482e72f1dSKirk McKusick /* 5582e72f1dSKirk McKusick * Read the standard superblock. 56b21582eeSKirk McKusick * 57b21582eeSKirk McKusick * The following option flags can be or'ed into disk->d_lookupflags: 58b21582eeSKirk McKusick * 59b21582eeSKirk McKusick * UFS_NOMSG indicates that superblock inconsistency error messages 60b21582eeSKirk McKusick * should not be printed. 61b21582eeSKirk McKusick * 62b21582eeSKirk McKusick * UFS_NOCSUM causes only the superblock itself to be returned, but does 63b21582eeSKirk McKusick * not read in any auxillary data structures like the cylinder group 64b21582eeSKirk McKusick * summary information. 6582e72f1dSKirk McKusick */ 6620938dbfSJuli Mallett int 6720938dbfSJuli Mallett sbread(struct uufsd *disk) 6820938dbfSJuli Mallett { 6920938dbfSJuli Mallett struct fs *fs; 7082e72f1dSKirk McKusick int error; 7182e72f1dSKirk McKusick 72b21582eeSKirk McKusick error = sbget(disk->d_fd, &fs, disk->d_sblockloc, disk->d_lookupflags); 7382e72f1dSKirk McKusick return (handle_disk_read(disk, fs, error)); 7482e72f1dSKirk McKusick } 7582e72f1dSKirk McKusick 76e6886616SKirk McKusick /* 77e6886616SKirk McKusick * Make an extensive search to find a superblock. If the superblock 78e6886616SKirk McKusick * in the standard place cannot be used, try looking for one of the 79e6886616SKirk McKusick * backup superblocks. 80e6886616SKirk McKusick * 81e6886616SKirk McKusick * The flags parameter is made up of the following or'ed together options: 82e6886616SKirk McKusick * 83e6886616SKirk McKusick * UFS_NOMSG indicates that superblock inconsistency error messages 84e6886616SKirk McKusick * should not be printed. 85e6886616SKirk McKusick * 86e6886616SKirk McKusick * UFS_NOCSUM causes only the superblock itself to be returned, but does 87e6886616SKirk McKusick * not read in any auxillary data structures like the cylinder group 88e6886616SKirk McKusick * summary information. 89e6886616SKirk McKusick */ 90e6886616SKirk McKusick int 91e6886616SKirk McKusick sbfind(struct uufsd *disk, int flags) 92e6886616SKirk McKusick { 93e6886616SKirk McKusick struct fs *fs; 94e6886616SKirk McKusick int error; 95e6886616SKirk McKusick 96e6886616SKirk McKusick error = sbsearch(disk->d_fd, &fs, flags); 97e6886616SKirk McKusick return (handle_disk_read(disk, fs, error)); 98e6886616SKirk McKusick } 99e6886616SKirk McKusick 10082e72f1dSKirk McKusick static int 10182e72f1dSKirk McKusick handle_disk_read(struct uufsd *disk, struct fs *fs, int error) 10282e72f1dSKirk McKusick { 10320938dbfSJuli Mallett 10449b2a686SJuli Mallett ERROR(disk, NULL); 10582e72f1dSKirk McKusick if (error != 0) { 10682e72f1dSKirk McKusick switch (error) { 107dffce215SKirk McKusick case EIO: 10849b2a686SJuli Mallett ERROR(disk, "non-existent or truncated superblock"); 109dffce215SKirk McKusick break; 110dffce215SKirk McKusick case ENOENT: 111dffce215SKirk McKusick ERROR(disk, "no usable known superblock found"); 112dffce215SKirk McKusick break; 11382e72f1dSKirk McKusick case EINTEGRITY: 11482e72f1dSKirk McKusick ERROR(disk, "superblock check-hash failure"); 11582e72f1dSKirk McKusick break; 116dffce215SKirk McKusick case ENOSPC: 117dffce215SKirk McKusick ERROR(disk, "failed to allocate space for superblock " 118dffce215SKirk McKusick "information"); 119dffce215SKirk McKusick break; 120dffce215SKirk McKusick case EINVAL: 121dffce215SKirk McKusick ERROR(disk, "The previous newfs operation on this " 122dffce215SKirk McKusick "volume did not complete.\nYou must complete " 123dffce215SKirk McKusick "newfs before using this volume."); 124dffce215SKirk McKusick break; 125dffce215SKirk McKusick default: 126dffce215SKirk McKusick ERROR(disk, "unknown superblock read error"); 127dffce215SKirk McKusick errno = EIO; 12820938dbfSJuli Mallett break; 12920938dbfSJuli Mallett } 13020938dbfSJuli Mallett disk->d_ufs = 0; 1311081253fSJuli Mallett return (-1); 13220938dbfSJuli Mallett } 133dffce215SKirk McKusick memcpy(&disk->d_fs, fs, fs->fs_sbsize); 134dffce215SKirk McKusick free(fs); 135dffce215SKirk McKusick fs = &disk->d_fs; 136dffce215SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) 137dffce215SKirk McKusick disk->d_ufs = 1; 138dffce215SKirk McKusick if (fs->fs_magic == FS_UFS2_MAGIC) 139dffce215SKirk McKusick disk->d_ufs = 2; 14020938dbfSJuli Mallett disk->d_bsize = fs->fs_fsize / fsbtodb(fs, 1); 141dffce215SKirk McKusick disk->d_sblock = fs->fs_sblockloc / disk->d_bsize; 14292c839a1SKirk McKusick disk->d_si = fs->fs_si; 1431081253fSJuli Mallett return (0); 14420938dbfSJuli Mallett } 14520938dbfSJuli Mallett 14620938dbfSJuli Mallett int 14720938dbfSJuli Mallett sbwrite(struct uufsd *disk, int all) 14820938dbfSJuli Mallett { 14920938dbfSJuli Mallett struct fs *fs; 1508a9493deSKirk McKusick int rv; 15120938dbfSJuli Mallett 15249b2a686SJuli Mallett ERROR(disk, NULL); 153585e5402SJuli Mallett 1548a9493deSKirk McKusick rv = ufs_disk_write(disk); 1558a9493deSKirk McKusick if (rv == -1) { 1568a9493deSKirk McKusick ERROR(disk, "failed to open disk for writing"); 1578a9493deSKirk McKusick return (-1); 1588a9493deSKirk McKusick } 1598a9493deSKirk McKusick 16020938dbfSJuli Mallett fs = &disk->d_fs; 161dffce215SKirk McKusick if ((errno = sbput(disk->d_fd, fs, all ? fs->fs_ncg : 0)) != 0) { 162dffce215SKirk McKusick switch (errno) { 163dffce215SKirk McKusick case EIO: 16449b2a686SJuli Mallett ERROR(disk, "failed to write superblock"); 165dffce215SKirk McKusick break; 166dffce215SKirk McKusick default: 167dffce215SKirk McKusick ERROR(disk, "unknown superblock write error"); 168dffce215SKirk McKusick errno = EIO; 169dffce215SKirk McKusick break; 170dffce215SKirk McKusick } 1711081253fSJuli Mallett return (-1); 17220938dbfSJuli Mallett } 173dffce215SKirk McKusick return (0); 174dffce215SKirk McKusick } 175dffce215SKirk McKusick 176113db2ddSJeff Roberson /* 177dffce215SKirk McKusick * These are the low-level functions that actually read and write 178dffce215SKirk McKusick * the superblock and its associated data. The actual work is done by 179dffce215SKirk McKusick * the functions ffs_sbget and ffs_sbput in /sys/ufs/ffs/ffs_subr.c. 180113db2ddSJeff Roberson */ 181dffce215SKirk McKusick static int use_pread(void *devfd, off_t loc, void **bufp, int size); 182dffce215SKirk McKusick static int use_pwrite(void *devfd, off_t loc, void *buf, int size); 183dffce215SKirk McKusick 184dffce215SKirk McKusick /* 185b21582eeSKirk McKusick * The following two functions read a superblock. Their flags 186b21582eeSKirk McKusick * parameter are made up of the following or'ed together options: 187b21582eeSKirk McKusick * 188b21582eeSKirk McKusick * UFS_NOMSG indicates that superblock inconsistency error messages 189b21582eeSKirk McKusick * should not be printed. 190b21582eeSKirk McKusick * 191b21582eeSKirk McKusick * UFS_NOCSUM causes only the superblock itself to be returned, but does 192b21582eeSKirk McKusick * not read in any auxillary data structures like the cylinder group 193b21582eeSKirk McKusick * summary information. 194b21582eeSKirk McKusick * 195dffce215SKirk McKusick * Read a superblock from the devfd device allocating memory returned 196b21582eeSKirk McKusick * in fsp. 197dffce215SKirk McKusick */ 198dffce215SKirk McKusick int 199b21582eeSKirk McKusick sbget(int devfd, struct fs **fsp, off_t sblockloc, int flags) 200dffce215SKirk McKusick { 201e6886616SKirk McKusick int error; 202dffce215SKirk McKusick 203e6886616SKirk McKusick error = ffs_sbget(&devfd, fsp, sblockloc, flags, "user", use_pread); 204e6886616SKirk McKusick fflush(NULL); /* flush any messages */ 205e6886616SKirk McKusick return (error); 206e6886616SKirk McKusick } 207e6886616SKirk McKusick 208e6886616SKirk McKusick /* 209e6886616SKirk McKusick * Make an extensive search of the devfd device to find a superblock. 210e6886616SKirk McKusick * If the superblock in the standard place cannot be used, try looking 211e6886616SKirk McKusick * for one of the backup superblocks. If found, memory is allocated and 212e6886616SKirk McKusick * returned in fsp. 213e6886616SKirk McKusick */ 214e6886616SKirk McKusick int 215e6886616SKirk McKusick sbsearch(int devfd, struct fs **fsp, int flags) 216e6886616SKirk McKusick { 217e6886616SKirk McKusick int error; 218e6886616SKirk McKusick 219e6886616SKirk McKusick error = ffs_sbsearch(&devfd, fsp, flags, "user", use_pread); 220e6886616SKirk McKusick fflush(NULL); /* flush any messages */ 221e6886616SKirk McKusick return (error); 222113db2ddSJeff Roberson } 223dffce215SKirk McKusick 224dffce215SKirk McKusick /* 225dffce215SKirk McKusick * A read function for use by user-level programs using libufs. 226dffce215SKirk McKusick */ 227dffce215SKirk McKusick static int 228dffce215SKirk McKusick use_pread(void *devfd, off_t loc, void **bufp, int size) 229dffce215SKirk McKusick { 230dffce215SKirk McKusick int fd; 231dffce215SKirk McKusick 232dffce215SKirk McKusick fd = *(int *)devfd; 233dffce215SKirk McKusick if ((*bufp = malloc(size)) == NULL) 234dffce215SKirk McKusick return (ENOSPC); 235dffce215SKirk McKusick if (pread(fd, *bufp, size, loc) != size) 236dffce215SKirk McKusick return (EIO); 237dffce215SKirk McKusick return (0); 238113db2ddSJeff Roberson } 239dffce215SKirk McKusick 240dffce215SKirk McKusick /* 241dffce215SKirk McKusick * Write a superblock to the devfd device from the memory pointed to by fs. 242dffce215SKirk McKusick * Also write out the superblock summary information but do not free the 243dffce215SKirk McKusick * summary information memory. 244dffce215SKirk McKusick * 245dffce215SKirk McKusick * Additionally write out numaltwrite of the alternate superblocks. Use 246dffce215SKirk McKusick * fs->fs_ncg to write out all of the alternate superblocks. 247dffce215SKirk McKusick */ 248dffce215SKirk McKusick int 249dffce215SKirk McKusick sbput(int devfd, struct fs *fs, int numaltwrite) 250dffce215SKirk McKusick { 251dffce215SKirk McKusick struct csum *savedcsp; 252dffce215SKirk McKusick off_t savedactualloc; 253dffce215SKirk McKusick int i, error; 254dffce215SKirk McKusick 255e6886616SKirk McKusick error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, use_pwrite); 256e6886616SKirk McKusick fflush(NULL); /* flush any messages */ 257e6886616SKirk McKusick if (error != 0 || numaltwrite == 0) 258dffce215SKirk McKusick return (error); 259dffce215SKirk McKusick savedactualloc = fs->fs_sblockactualloc; 260b21582eeSKirk McKusick if (fs->fs_si != NULL) { 261dffce215SKirk McKusick savedcsp = fs->fs_csp; 262dffce215SKirk McKusick fs->fs_csp = NULL; 263b21582eeSKirk McKusick } 264dffce215SKirk McKusick for (i = 0; i < numaltwrite; i++) { 265dffce215SKirk McKusick fs->fs_sblockactualloc = dbtob(fsbtodb(fs, cgsblock(fs, i))); 266dffce215SKirk McKusick if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, 267dffce215SKirk McKusick use_pwrite)) != 0) { 268e6886616SKirk McKusick fflush(NULL); /* flush any messages */ 269dffce215SKirk McKusick fs->fs_sblockactualloc = savedactualloc; 270dffce215SKirk McKusick fs->fs_csp = savedcsp; 27185ee267aSKirk McKusick return (error); 27220938dbfSJuli Mallett } 27320938dbfSJuli Mallett } 274dffce215SKirk McKusick fs->fs_sblockactualloc = savedactualloc; 275b21582eeSKirk McKusick if (fs->fs_si != NULL) 276dffce215SKirk McKusick fs->fs_csp = savedcsp; 277e6886616SKirk McKusick fflush(NULL); /* flush any messages */ 278dffce215SKirk McKusick return (0); 279dffce215SKirk McKusick } 280dffce215SKirk McKusick 281dffce215SKirk McKusick /* 282dffce215SKirk McKusick * A write function for use by user-level programs using sbput in libufs. 283dffce215SKirk McKusick */ 284dffce215SKirk McKusick static int 285dffce215SKirk McKusick use_pwrite(void *devfd, off_t loc, void *buf, int size) 286dffce215SKirk McKusick { 287dffce215SKirk McKusick int fd; 288dffce215SKirk McKusick 289dffce215SKirk McKusick fd = *(int *)devfd; 290dffce215SKirk McKusick if (pwrite(fd, buf, size, loc) != size) 291dffce215SKirk McKusick return (EIO); 2921081253fSJuli Mallett return (0); 29320938dbfSJuli Mallett } 294