1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 * The following option flags can be or'ed into disk->d_lookupflags: 58 * 59 * UFS_NOMSG indicates that superblock inconsistency error messages 60 * should not be printed. 61 * 62 * UFS_NOCSUM causes only the superblock itself to be returned, but does 63 * not read in any auxillary data structures like the cylinder group 64 * summary information. 65 */ 66 int 67 sbread(struct uufsd *disk) 68 { 69 struct fs *fs; 70 int error; 71 72 error = sbget(disk->d_fd, &fs, disk->d_sblockloc, disk->d_lookupflags); 73 return (handle_disk_read(disk, fs, error)); 74 } 75 76 /* 77 * Make an extensive search to find a superblock. If the superblock 78 * in the standard place cannot be used, try looking for one of the 79 * backup superblocks. 80 * 81 * The flags parameter is made up of the following or'ed together options: 82 * 83 * UFS_NOMSG indicates that superblock inconsistency error messages 84 * should not be printed. 85 * 86 * UFS_NOCSUM causes only the superblock itself to be returned, but does 87 * not read in any auxillary data structures like the cylinder group 88 * summary information. 89 */ 90 int 91 sbfind(struct uufsd *disk, int flags) 92 { 93 struct fs *fs; 94 int error; 95 96 error = sbsearch(disk->d_fd, &fs, flags); 97 return (handle_disk_read(disk, fs, error)); 98 } 99 100 static int 101 handle_disk_read(struct uufsd *disk, struct fs *fs, int error) 102 { 103 104 ERROR(disk, NULL); 105 if (error != 0) { 106 switch (error) { 107 case EIO: 108 ERROR(disk, "non-existent or truncated superblock"); 109 break; 110 case ENOENT: 111 ERROR(disk, "no usable known superblock found"); 112 break; 113 case EINTEGRITY: 114 ERROR(disk, "superblock check-hash failure"); 115 break; 116 case ENOSPC: 117 ERROR(disk, "failed to allocate space for superblock " 118 "information"); 119 break; 120 case EINVAL: 121 ERROR(disk, "The previous newfs operation on this " 122 "volume did not complete.\nYou must complete " 123 "newfs before using this volume."); 124 break; 125 default: 126 ERROR(disk, "unknown superblock read error"); 127 errno = EIO; 128 break; 129 } 130 disk->d_ufs = 0; 131 return (-1); 132 } 133 memcpy(&disk->d_fs, fs, fs->fs_sbsize); 134 free(fs); 135 fs = &disk->d_fs; 136 if (fs->fs_magic == FS_UFS1_MAGIC) 137 disk->d_ufs = 1; 138 if (fs->fs_magic == FS_UFS2_MAGIC) 139 disk->d_ufs = 2; 140 disk->d_bsize = fs->fs_fsize / fsbtodb(fs, 1); 141 disk->d_sblock = fs->fs_sblockloc / disk->d_bsize; 142 disk->d_si = fs->fs_si; 143 return (0); 144 } 145 146 int 147 sbwrite(struct uufsd *disk, int all) 148 { 149 struct fs *fs; 150 int rv; 151 152 ERROR(disk, NULL); 153 154 rv = ufs_disk_write(disk); 155 if (rv == -1) { 156 ERROR(disk, "failed to open disk for writing"); 157 return (-1); 158 } 159 160 fs = &disk->d_fs; 161 if ((errno = sbput(disk->d_fd, fs, all ? fs->fs_ncg : 0)) != 0) { 162 switch (errno) { 163 case EIO: 164 ERROR(disk, "failed to write superblock"); 165 break; 166 default: 167 ERROR(disk, "unknown superblock write error"); 168 errno = EIO; 169 break; 170 } 171 return (-1); 172 } 173 return (0); 174 } 175 176 /* 177 * These are the low-level functions that actually read and write 178 * the superblock and its associated data. The actual work is done by 179 * the functions ffs_sbget and ffs_sbput in /sys/ufs/ffs/ffs_subr.c. 180 */ 181 static int use_pread(void *devfd, off_t loc, void **bufp, int size); 182 static int use_pwrite(void *devfd, off_t loc, void *buf, int size); 183 184 /* 185 * The following two functions read a superblock. Their flags 186 * parameter are made up of the following or'ed together options: 187 * 188 * UFS_NOMSG indicates that superblock inconsistency error messages 189 * should not be printed. 190 * 191 * UFS_NOCSUM causes only the superblock itself to be returned, but does 192 * not read in any auxillary data structures like the cylinder group 193 * summary information. 194 * 195 * Read a superblock from the devfd device allocating memory returned 196 * in fsp. 197 */ 198 int 199 sbget(int devfd, struct fs **fsp, off_t sblockloc, int flags) 200 { 201 int error; 202 203 error = ffs_sbget(&devfd, fsp, sblockloc, flags, "user", use_pread); 204 fflush(NULL); /* flush any messages */ 205 return (error); 206 } 207 208 /* 209 * Make an extensive search of the devfd device to find a superblock. 210 * If the superblock in the standard place cannot be used, try looking 211 * for one of the backup superblocks. If found, memory is allocated and 212 * returned in fsp. 213 */ 214 int 215 sbsearch(int devfd, struct fs **fsp, int flags) 216 { 217 int error; 218 219 error = ffs_sbsearch(&devfd, fsp, flags, "user", use_pread); 220 fflush(NULL); /* flush any messages */ 221 return (error); 222 } 223 224 /* 225 * A read function for use by user-level programs using libufs. 226 */ 227 static int 228 use_pread(void *devfd, off_t loc, void **bufp, int size) 229 { 230 int fd; 231 232 fd = *(int *)devfd; 233 if ((*bufp = malloc(size)) == NULL) 234 return (ENOSPC); 235 if (pread(fd, *bufp, size, loc) != size) 236 return (EIO); 237 return (0); 238 } 239 240 /* 241 * Write a superblock to the devfd device from the memory pointed to by fs. 242 * Also write out the superblock summary information but do not free the 243 * summary information memory. 244 * 245 * Additionally write out numaltwrite of the alternate superblocks. Use 246 * fs->fs_ncg to write out all of the alternate superblocks. 247 */ 248 int 249 sbput(int devfd, struct fs *fs, int numaltwrite) 250 { 251 struct csum *savedcsp; 252 off_t savedactualloc; 253 int i, error; 254 255 error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, use_pwrite); 256 fflush(NULL); /* flush any messages */ 257 if (error != 0 || numaltwrite == 0) 258 return (error); 259 savedactualloc = fs->fs_sblockactualloc; 260 if (fs->fs_si != NULL) { 261 savedcsp = fs->fs_csp; 262 fs->fs_csp = NULL; 263 } 264 for (i = 0; i < numaltwrite; i++) { 265 fs->fs_sblockactualloc = dbtob(fsbtodb(fs, cgsblock(fs, i))); 266 if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, 267 use_pwrite)) != 0) { 268 fflush(NULL); /* flush any messages */ 269 fs->fs_sblockactualloc = savedactualloc; 270 fs->fs_csp = savedcsp; 271 return (error); 272 } 273 } 274 fs->fs_sblockactualloc = savedactualloc; 275 if (fs->fs_si != NULL) 276 fs->fs_csp = savedcsp; 277 fflush(NULL); /* flush any messages */ 278 return (0); 279 } 280 281 /* 282 * A write function for use by user-level programs using sbput in libufs. 283 */ 284 static int 285 use_pwrite(void *devfd, off_t loc, void *buf, int size) 286 { 287 int fd; 288 289 fd = *(int *)devfd; 290 if (pwrite(fd, buf, size, loc) != size) 291 return (EIO); 292 return (0); 293 } 294