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