1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2002 Juli Mallett. All rights reserved. 5 * 6 * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the 7 * FreeBSD project. Redistribution and use in source and binary forms, with 8 * or without modification, are permitted provided that the following 9 * conditions are met: 10 * 11 * 1. Redistribution of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * 2. Redistribution in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/mount.h> 35 #include <sys/disklabel.h> 36 #include <sys/stat.h> 37 38 #include <ufs/ufs/extattr.h> 39 #include <ufs/ufs/quota.h> 40 #include <ufs/ufs/ufsmount.h> 41 #include <ufs/ufs/dinode.h> 42 #include <ufs/ffs/fs.h> 43 44 #include <errno.h> 45 #include <stdio.h> 46 #include <string.h> 47 #include <stdlib.h> 48 #include <unistd.h> 49 50 #include <libufs.h> 51 52 static int handle_disk_read(struct uufsd *, struct fs *, int); 53 54 /* 55 * Read the standard superblock. 56 */ 57 int 58 sbread(struct uufsd *disk) 59 { 60 struct fs *fs; 61 int error; 62 63 error = sbget(disk->d_fd, &fs, disk->d_sblockloc); 64 return (handle_disk_read(disk, fs, error)); 65 } 66 67 static int 68 handle_disk_read(struct uufsd *disk, struct fs *fs, int error) 69 { 70 71 ERROR(disk, NULL); 72 if (error != 0) { 73 switch (error) { 74 case EIO: 75 ERROR(disk, "non-existent or truncated superblock"); 76 break; 77 case ENOENT: 78 ERROR(disk, "no usable known superblock found"); 79 break; 80 case EINTEGRITY: 81 ERROR(disk, "superblock check-hash failure"); 82 break; 83 case ENOSPC: 84 ERROR(disk, "failed to allocate space for superblock " 85 "information"); 86 break; 87 case EINVAL: 88 ERROR(disk, "The previous newfs operation on this " 89 "volume did not complete.\nYou must complete " 90 "newfs before using this volume."); 91 break; 92 default: 93 ERROR(disk, "unknown superblock read error"); 94 errno = EIO; 95 break; 96 } 97 disk->d_ufs = 0; 98 return (-1); 99 } 100 memcpy(&disk->d_fs, fs, fs->fs_sbsize); 101 free(fs); 102 fs = &disk->d_fs; 103 if (fs->fs_magic == FS_UFS1_MAGIC) 104 disk->d_ufs = 1; 105 if (fs->fs_magic == FS_UFS2_MAGIC) 106 disk->d_ufs = 2; 107 disk->d_bsize = fs->fs_fsize / fsbtodb(fs, 1); 108 disk->d_sblock = fs->fs_sblockloc / disk->d_bsize; 109 disk->d_si = fs->fs_si; 110 return (0); 111 } 112 113 int 114 sbwrite(struct uufsd *disk, int all) 115 { 116 struct fs *fs; 117 int rv; 118 119 ERROR(disk, NULL); 120 121 rv = ufs_disk_write(disk); 122 if (rv == -1) { 123 ERROR(disk, "failed to open disk for writing"); 124 return (-1); 125 } 126 127 fs = &disk->d_fs; 128 if ((errno = sbput(disk->d_fd, fs, all ? fs->fs_ncg : 0)) != 0) { 129 switch (errno) { 130 case EIO: 131 ERROR(disk, "failed to write superblock"); 132 break; 133 default: 134 ERROR(disk, "unknown superblock write error"); 135 errno = EIO; 136 break; 137 } 138 return (-1); 139 } 140 return (0); 141 } 142 143 /* 144 * These are the low-level functions that actually read and write 145 * the superblock and its associated data. The actual work is done by 146 * the functions ffs_sbget and ffs_sbput in /sys/ufs/ffs/ffs_subr.c. 147 */ 148 static int use_pread(void *devfd, off_t loc, void **bufp, int size); 149 static int use_pwrite(void *devfd, off_t loc, void *buf, int size); 150 151 /* 152 * Read a superblock from the devfd device allocating memory returned 153 * in fsp. Also read the superblock summary information. 154 */ 155 int 156 sbget(int devfd, struct fs **fsp, off_t sblockloc) 157 { 158 159 return (ffs_sbget(&devfd, fsp, sblockloc, "user", use_pread)); 160 } 161 162 /* 163 * A read function for use by user-level programs using libufs. 164 */ 165 static int 166 use_pread(void *devfd, off_t loc, void **bufp, int size) 167 { 168 int fd; 169 170 fd = *(int *)devfd; 171 if ((*bufp = malloc(size)) == NULL) 172 return (ENOSPC); 173 if (pread(fd, *bufp, size, loc) != size) 174 return (EIO); 175 return (0); 176 } 177 178 /* 179 * Write a superblock to the devfd device from the memory pointed to by fs. 180 * Also write out the superblock summary information but do not free the 181 * summary information memory. 182 * 183 * Additionally write out numaltwrite of the alternate superblocks. Use 184 * fs->fs_ncg to write out all of the alternate superblocks. 185 */ 186 int 187 sbput(int devfd, struct fs *fs, int numaltwrite) 188 { 189 struct csum *savedcsp; 190 off_t savedactualloc; 191 int i, error; 192 193 if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, 194 use_pwrite)) != 0) 195 return (error); 196 if (numaltwrite == 0) 197 return (0); 198 savedactualloc = fs->fs_sblockactualloc; 199 savedcsp = fs->fs_csp; 200 fs->fs_csp = NULL; 201 for (i = 0; i < numaltwrite; i++) { 202 fs->fs_sblockactualloc = dbtob(fsbtodb(fs, cgsblock(fs, i))); 203 if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, 204 use_pwrite)) != 0) { 205 fs->fs_sblockactualloc = savedactualloc; 206 fs->fs_csp = savedcsp; 207 return (error); 208 } 209 } 210 fs->fs_sblockactualloc = savedactualloc; 211 fs->fs_csp = savedcsp; 212 return (0); 213 } 214 215 /* 216 * A write function for use by user-level programs using sbput in libufs. 217 */ 218 static int 219 use_pwrite(void *devfd, off_t loc, void *buf, int size) 220 { 221 int fd; 222 223 fd = *(int *)devfd; 224 if (pwrite(fd, buf, size, loc) != size) 225 return (EIO); 226 return (0); 227 } 228