18a16b7a1SPedro F. Giffuni /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 48fae3551SRodney W. Grimes * Copyright (c) 1980, 1986, 1993 58fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 68fae3551SRodney W. Grimes * 78fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 88fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 98fae3551SRodney W. Grimes * are met: 108fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 118fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 128fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 138fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 148fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 168fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 178fae3551SRodney W. Grimes * without specific prior written permission. 188fae3551SRodney W. Grimes * 198fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 208fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 218fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 228fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 238fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 248fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 258fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 268fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 278fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 288fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 298fae3551SRodney W. Grimes * SUCH DAMAGE. 308fae3551SRodney W. Grimes */ 318fae3551SRodney W. Grimes 326b100474SJulian Elischer #if 0 33c69284caSDavid E. O'Brien #ifndef lint 34780a5c1eSPeter Wemm static const char sccsid[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95"; 358fae3551SRodney W. Grimes #endif /* not lint */ 36c69284caSDavid E. O'Brien #endif 37c69284caSDavid E. O'Brien #include <sys/cdefs.h> 388fae3551SRodney W. Grimes #include <sys/param.h> 39855662c6SKirk McKusick #include <sys/disk.h> 408fae3551SRodney W. Grimes #include <sys/stat.h> 41b35e6950SBosko Milekic #define FSTYPENAMES 428fae3551SRodney W. Grimes #include <sys/disklabel.h> 438fae3551SRodney W. Grimes #include <sys/file.h> 44bf58d635SIan Dowse #include <sys/sysctl.h> 45780a5c1eSPeter Wemm 46780a5c1eSPeter Wemm #include <ufs/ufs/dinode.h> 47780a5c1eSPeter Wemm #include <ufs/ffs/fs.h> 48780a5c1eSPeter Wemm 49780a5c1eSPeter Wemm #include <ctype.h> 50780a5c1eSPeter Wemm #include <err.h> 518fae3551SRodney W. Grimes #include <errno.h> 5289fdc4e1SMike Barcroft #include <limits.h> 5384fc0d7eSMaxime Henrion #include <stdint.h> 548fae3551SRodney W. Grimes #include <string.h> 55780a5c1eSPeter Wemm 568fae3551SRodney W. Grimes #include "fsck.h" 578fae3551SRodney W. Grimes 5852f97104SKirk McKusick struct inohash *inphash; /* hash list of directory inode info */ 5952f97104SKirk McKusick struct inoinfo **inpsort; /* disk order list of directory inodes */ 60460ed610SKirk McKusick struct inode snaplist[FSMAXSNAP + 1]; /* list of active snapshots */ 61460ed610SKirk McKusick int snapcnt; /* number of active snapshots */ 62460ed610SKirk McKusick char *copybuf; /* buffer to copy snapshot blocks */ 63c3e9752eSKyle Evans 64e6886616SKirk McKusick static int sbhashfailed; 658fae3551SRodney W. Grimes #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 668fae3551SRodney W. Grimes 6777b63aa0SKirk McKusick static int calcsb(char *dev, int devfd, struct fs *fs); 6877b63aa0SKirk McKusick static void saverecovery(int readfd, int writefd); 6977b63aa0SKirk McKusick static int chkrecovery(int devfd); 70460ed610SKirk McKusick static int getlbnblkno(struct inodesc *); 71460ed610SKirk McKusick static int checksnapinfo(struct inode *); 7277b63aa0SKirk McKusick 73780a5c1eSPeter Wemm /* 74780a5c1eSPeter Wemm * Read in a superblock finding an alternate if necessary. 75780a5c1eSPeter Wemm * Return 1 if successful, 0 if unsuccessful, -1 if file system 76111a5220SDavid E. O'Brien * is already clean (ckclean and preen mode only). 77780a5c1eSPeter Wemm */ 7831f4ab50SBruce Evans int 79b70cd7eeSWarner Losh setup(char *dev) 808fae3551SRodney W. Grimes { 81460ed610SKirk McKusick long i, bmapsize; 82460ed610SKirk McKusick struct inode ip; 838fae3551SRodney W. Grimes 84c0ed8991SXin LI /* 85e6886616SKirk McKusick * We are expected to have an open file descriptor and a superblock. 86c0ed8991SXin LI */ 87e6886616SKirk McKusick if (fsreadfd < 0 || havesb == 0) { 884b08a62eSKirk McKusick if (debug) { 894b08a62eSKirk McKusick if (fsreadfd < 0) 904b08a62eSKirk McKusick printf("setup: missing fsreadfd\n"); 914b08a62eSKirk McKusick else 924b08a62eSKirk McKusick printf("setup: missing superblock\n"); 934b08a62eSKirk McKusick } 94c0bfa109SKirk McKusick return (0); 957578c6abSKirk McKusick } 968fae3551SRodney W. Grimes if (preen == 0) 978fae3551SRodney W. Grimes printf("** %s", dev); 987578c6abSKirk McKusick if (bkgrdflag == 0 && 995cc52631SKirk McKusick (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) { 1008fae3551SRodney W. Grimes fswritefd = -1; 1018fae3551SRodney W. Grimes if (preen) 1028fae3551SRodney W. Grimes pfatal("NO WRITE ACCESS"); 1038fae3551SRodney W. Grimes printf(" (NO WRITE)"); 1048fae3551SRodney W. Grimes } 1058fae3551SRodney W. Grimes if (preen == 0) 1068fae3551SRodney W. Grimes printf("\n"); 107c0bfa109SKirk McKusick if (sbhashfailed != 0) { 108c0bfa109SKirk McKusick pwarn("SUPERBLOCK CHECK HASH FAILED"); 109c0bfa109SKirk McKusick if (fswritefd == -1) 110c0bfa109SKirk McKusick pwarn("OPENED READONLY SO CANNOT CORRECT CHECK HASH\n"); 111c0bfa109SKirk McKusick else if (preen || reply("CORRECT CHECK HASH") != 0) { 112c0bfa109SKirk McKusick if (preen) 113c0bfa109SKirk McKusick printf(" (CORRECTED)\n"); 114c0bfa109SKirk McKusick sblock.fs_clean = 0; 115c0bfa109SKirk McKusick sbdirty(); 11677b63aa0SKirk McKusick } 1178fae3551SRodney W. Grimes } 118111a5220SDavid E. O'Brien if (skipclean && ckclean && sblock.fs_clean) { 119d33e92f9SJulian Elischer pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); 120d33e92f9SJulian Elischer return (-1); 121d33e92f9SJulian Elischer } 1228fae3551SRodney W. Grimes maxfsblock = sblock.fs_size; 1238fae3551SRodney W. Grimes maxino = sblock.fs_ncg * sblock.fs_ipg; 1248fae3551SRodney W. Grimes /* 1258fae3551SRodney W. Grimes * Check and potentially fix certain fields in the super block. 1268fae3551SRodney W. Grimes */ 1278fae3551SRodney W. Grimes if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { 1288fae3551SRodney W. Grimes pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); 1298fae3551SRodney W. Grimes if (reply("SET TO DEFAULT") == 1) { 1308fae3551SRodney W. Grimes sblock.fs_optim = FS_OPTTIME; 1318fae3551SRodney W. Grimes sbdirty(); 1328fae3551SRodney W. Grimes } 1338fae3551SRodney W. Grimes } 1348fae3551SRodney W. Grimes if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { 1358fae3551SRodney W. Grimes pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 1368fae3551SRodney W. Grimes sblock.fs_minfree); 1378fae3551SRodney W. Grimes if (reply("SET TO DEFAULT") == 1) { 1388fae3551SRodney W. Grimes sblock.fs_minfree = 10; 1398fae3551SRodney W. Grimes sbdirty(); 1408fae3551SRodney W. Grimes } 1418fae3551SRodney W. Grimes } 1421c85e6a3SKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC && 1431c85e6a3SKirk McKusick sblock.fs_old_inodefmt < FS_44INODEFMT) { 144381ee4c2SPoul-Henning Kamp pwarn("Format of file system is too old.\n"); 145381ee4c2SPoul-Henning Kamp pwarn("Must update to modern format using a version of fsck\n"); 146381ee4c2SPoul-Henning Kamp pfatal("from before 2002 with the command ``fsck -c 2''\n"); 147381ee4c2SPoul-Henning Kamp exit(EEXIT); 1488fae3551SRodney W. Grimes } 14977b63aa0SKirk McKusick if (preen == 0 && yflag == 0 && sblock.fs_magic == FS_UFS2_MAGIC && 15077b63aa0SKirk McKusick fswritefd != -1 && chkrecovery(fsreadfd) == 0 && 15177b63aa0SKirk McKusick reply("SAVE DATA TO FIND ALTERNATE SUPERBLOCKS") != 0) 15277b63aa0SKirk McKusick saverecovery(fsreadfd, fswritefd); 1538fae3551SRodney W. Grimes /* 1548fae3551SRodney W. Grimes * allocate and initialize the necessary maps 1558fae3551SRodney W. Grimes */ 1566e821c35SKirk McKusick bufinit(); 15789fdc4e1SMike Barcroft bmapsize = roundup(howmany(maxfsblock, CHAR_BIT), sizeof(short)); 15881fbded2SKirk McKusick blockmap = Calloc((unsigned)bmapsize, sizeof (char)); 1598fae3551SRodney W. Grimes if (blockmap == NULL) { 1608fae3551SRodney W. Grimes printf("cannot alloc %u bytes for blockmap\n", 1618fae3551SRodney W. Grimes (unsigned)bmapsize); 1628fae3551SRodney W. Grimes goto badsb; 1638fae3551SRodney W. Grimes } 164f6717697SPedro F. Giffuni inostathead = Calloc(sblock.fs_ncg, sizeof(struct inostatlist)); 165d33e92f9SJulian Elischer if (inostathead == NULL) { 166d33e92f9SJulian Elischer printf("cannot alloc %u bytes for inostathead\n", 167d33e92f9SJulian Elischer (unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg))); 1688fae3551SRodney W. Grimes goto badsb; 1698fae3551SRodney W. Grimes } 17052f97104SKirk McKusick numdirs = sblock.fs_cstotal.cs_ndir; 17152f97104SKirk McKusick dirhash = MAX(numdirs / 2, 1); 1728fae3551SRodney W. Grimes inplast = 0; 1738fae3551SRodney W. Grimes listmax = numdirs + 10; 174f6717697SPedro F. Giffuni inpsort = (struct inoinfo **)Calloc(listmax, sizeof(struct inoinfo *)); 17552f97104SKirk McKusick inphash = (struct inohash *)Calloc(dirhash, sizeof(struct inohash)); 17652f97104SKirk McKusick if (inpsort == NULL || inphash == NULL) { 17752f97104SKirk McKusick printf("cannot alloc %ju bytes for inphash\n", 17884fc0d7eSMaxime Henrion (uintmax_t)numdirs * sizeof(struct inoinfo *)); 1798fae3551SRodney W. Grimes goto badsb; 1808fae3551SRodney W. Grimes } 181b1897c19SJulian Elischer if (sblock.fs_flags & FS_DOSOFTDEP) 182b1897c19SJulian Elischer usedsoftdep = 1; 183b1897c19SJulian Elischer else 184b1897c19SJulian Elischer usedsoftdep = 0; 185460ed610SKirk McKusick /* 186460ed610SKirk McKusick * Collect any snapshot inodes so that we can allow them to 187460ed610SKirk McKusick * claim any blocks that we free. The code for doing this is 188460ed610SKirk McKusick * imported here and into inode.c from sys/ufs/ffs/ffs_snapshot.c. 189460ed610SKirk McKusick */ 190460ed610SKirk McKusick for (snapcnt = 0; snapcnt < FSMAXSNAP; snapcnt++) { 191460ed610SKirk McKusick if (sblock.fs_snapinum[snapcnt] == 0) 192460ed610SKirk McKusick break; 193460ed610SKirk McKusick ginode(sblock.fs_snapinum[snapcnt], &ip); 194460ed610SKirk McKusick if ((DIP(ip.i_dp, di_mode) & IFMT) == IFREG && 195460ed610SKirk McKusick (DIP(ip.i_dp, di_flags) & SF_SNAPSHOT) != 0 && 196460ed610SKirk McKusick checksnapinfo(&ip)) { 197460ed610SKirk McKusick if (debug) 198460ed610SKirk McKusick printf("Load snapshot %jd\n", 199460ed610SKirk McKusick (intmax_t)sblock.fs_snapinum[snapcnt]); 200460ed610SKirk McKusick snaplist[snapcnt] = ip; 201460ed610SKirk McKusick continue; 202460ed610SKirk McKusick } 203460ed610SKirk McKusick printf("Removing non-snapshot inode %ju from snapshot list\n", 204460ed610SKirk McKusick (uintmax_t)sblock.fs_snapinum[snapcnt]); 205460ed610SKirk McKusick irelse(&ip); 206460ed610SKirk McKusick for (i = snapcnt + 1; i < FSMAXSNAP; i++) { 207460ed610SKirk McKusick if (sblock.fs_snapinum[i] == 0) 208460ed610SKirk McKusick break; 209460ed610SKirk McKusick sblock.fs_snapinum[i - 1] = sblock.fs_snapinum[i]; 210460ed610SKirk McKusick } 211460ed610SKirk McKusick sblock.fs_snapinum[i - 1] = 0; 212460ed610SKirk McKusick snapcnt--; 213460ed610SKirk McKusick sbdirty(); 214460ed610SKirk McKusick } 215460ed610SKirk McKusick if (snapcnt > 0 && copybuf == NULL) { 216*772430ddSKirk McKusick copybuf = Balloc(sblock.fs_bsize); 217460ed610SKirk McKusick if (copybuf == NULL) 218460ed610SKirk McKusick errx(EEXIT, "cannot allocate space for snapshot " 219460ed610SKirk McKusick "copy buffer"); 220460ed610SKirk McKusick } 2218fae3551SRodney W. Grimes return (1); 2228fae3551SRodney W. Grimes 2238fae3551SRodney W. Grimes badsb: 224780a5c1eSPeter Wemm ckfini(0); 2258fae3551SRodney W. Grimes return (0); 2268fae3551SRodney W. Grimes } 2278fae3551SRodney W. Grimes 2288fae3551SRodney W. Grimes /* 229460ed610SKirk McKusick * Check for valid snapshot information. 230460ed610SKirk McKusick * 231460ed610SKirk McKusick * Each snapshot has a list of blocks that have been copied. This list 232460ed610SKirk McKusick * is consulted before checking the snapshot inode. Its purpose is to 233460ed610SKirk McKusick * speed checking of commonly checked blocks and to avoid recursive 234460ed610SKirk McKusick * checks of the snapshot inode. In particular, the list must contain 235460ed610SKirk McKusick * the superblock, the superblock summary information, and all the 236460ed610SKirk McKusick * cylinder group blocks. The list may contain other commonly checked 237460ed610SKirk McKusick * pointers such as those of the blocks that contain the snapshot inodes. 238460ed610SKirk McKusick * The list is sorted into block order to allow binary search lookup. 239460ed610SKirk McKusick * 240460ed610SKirk McKusick * The twelve direct direct block pointers of the snapshot are always 241460ed610SKirk McKusick * copied, so we test for them first before checking the list itself 242460ed610SKirk McKusick * (i.e., they are not in the list). 243460ed610SKirk McKusick * 244460ed610SKirk McKusick * The checksnapinfo() routine needs to ensure that the list contains at 245460ed610SKirk McKusick * least the super block, its summary information, and the cylinder groups. 246460ed610SKirk McKusick * Here we check the list first for the superblock, zero or more cylinder 247460ed610SKirk McKusick * groups up to the location of the superblock summary information, the 248460ed610SKirk McKusick * summary group information, and any remaining cylinder group maps that 249460ed610SKirk McKusick * follow it. We skip over any other entries in the list. 250460ed610SKirk McKusick */ 251460ed610SKirk McKusick #define CHKBLKINLIST(chkblk) \ 252460ed610SKirk McKusick /* All UFS_NDADDR blocks are copied */ \ 253460ed610SKirk McKusick if ((chkblk) >= UFS_NDADDR) { \ 254460ed610SKirk McKusick /* Skip over blocks that are not of interest */ \ 255460ed610SKirk McKusick while (*blkp < (chkblk) && blkp < lastblkp) \ 256460ed610SKirk McKusick blkp++; \ 257460ed610SKirk McKusick /* Fail if end of list and not all blocks found */ \ 258460ed610SKirk McKusick if (blkp >= lastblkp) { \ 259460ed610SKirk McKusick pwarn("UFS%d snapshot inode %jd failed: " \ 260460ed610SKirk McKusick "improper block list length (%jd)\n", \ 261460ed610SKirk McKusick sblock.fs_magic == FS_UFS1_MAGIC ? 1 : 2, \ 262460ed610SKirk McKusick (intmax_t)snapip->i_number, \ 263460ed610SKirk McKusick (intmax_t)(lastblkp - &snapblklist[0])); \ 264460ed610SKirk McKusick status = 0; \ 265460ed610SKirk McKusick } \ 266460ed610SKirk McKusick /* Fail if block we seek is missing */ \ 267460ed610SKirk McKusick else if (*blkp++ != (chkblk)) { \ 268460ed610SKirk McKusick pwarn("UFS%d snapshot inode %jd failed: " \ 269460ed610SKirk McKusick "block list (%jd) != %s (%jd)\n", \ 270460ed610SKirk McKusick sblock.fs_magic == FS_UFS1_MAGIC ? 1 : 2, \ 271460ed610SKirk McKusick (intmax_t)snapip->i_number, \ 272460ed610SKirk McKusick (intmax_t)blkp[-1], #chkblk, \ 273460ed610SKirk McKusick (intmax_t)chkblk); \ 274460ed610SKirk McKusick status = 0; \ 275460ed610SKirk McKusick } \ 276460ed610SKirk McKusick } 277460ed610SKirk McKusick 278460ed610SKirk McKusick static int 279460ed610SKirk McKusick checksnapinfo(struct inode *snapip) 280460ed610SKirk McKusick { 281460ed610SKirk McKusick struct fs *fs; 282460ed610SKirk McKusick struct bufarea *bp; 283460ed610SKirk McKusick struct inodesc idesc; 284460ed610SKirk McKusick daddr_t *snapblklist, *blkp, *lastblkp, csblkno; 285460ed610SKirk McKusick int cg, loc, len, status; 286460ed610SKirk McKusick ufs_lbn_t lbn; 287460ed610SKirk McKusick size_t size; 288460ed610SKirk McKusick 289460ed610SKirk McKusick fs = &sblock; 290460ed610SKirk McKusick memset(&idesc, 0, sizeof(struct inodesc)); 291460ed610SKirk McKusick idesc.id_type = ADDR; 292460ed610SKirk McKusick idesc.id_func = getlbnblkno; 293460ed610SKirk McKusick idesc.id_number = snapip->i_number; 294460ed610SKirk McKusick lbn = howmany(fs->fs_size, fs->fs_frag); 295460ed610SKirk McKusick idesc.id_parent = lbn; /* sought after blkno */ 296460ed610SKirk McKusick if ((ckinode(snapip->i_dp, &idesc) & FOUND) == 0) 297460ed610SKirk McKusick return (0); 298460ed610SKirk McKusick size = fragroundup(fs, 299460ed610SKirk McKusick DIP(snapip->i_dp, di_size) - lblktosize(fs, lbn)); 300460ed610SKirk McKusick bp = getdatablk(idesc.id_parent, size, BT_DATA); 3011e39a088SKirk McKusick if (bp->b_errs != 0) 3021e39a088SKirk McKusick return (0); 303460ed610SKirk McKusick snapblklist = (daddr_t *)bp->b_un.b_buf; 304460ed610SKirk McKusick /* 305460ed610SKirk McKusick * snapblklist[0] is the size of the list 306460ed610SKirk McKusick * snapblklist[1] is the first element of the list 307460ed610SKirk McKusick * 308460ed610SKirk McKusick * We need to be careful to bound the size of the list and verify 309460ed610SKirk McKusick * that we have not run off the end of it if it or its size has 310460ed610SKirk McKusick * been corrupted. 311460ed610SKirk McKusick */ 312460ed610SKirk McKusick blkp = &snapblklist[1]; 313460ed610SKirk McKusick lastblkp = &snapblklist[MAX(0, 314460ed610SKirk McKusick MIN(snapblklist[0] + 1, size / sizeof(daddr_t)))]; 315460ed610SKirk McKusick status = 1; 316460ed610SKirk McKusick /* Check that the superblock is listed. */ 317460ed610SKirk McKusick CHKBLKINLIST(lblkno(fs, fs->fs_sblockloc)); 318460ed610SKirk McKusick if (status == 0) 319460ed610SKirk McKusick goto out; 320460ed610SKirk McKusick /* 321460ed610SKirk McKusick * Calculate where the summary information is located. 322460ed610SKirk McKusick * Usually it is in the first cylinder group, but growfs 323460ed610SKirk McKusick * may move it to the first cylinder group that it adds. 324460ed610SKirk McKusick * 325460ed610SKirk McKusick * Check all cylinder groups up to the summary information. 326460ed610SKirk McKusick */ 327460ed610SKirk McKusick csblkno = fragstoblks(fs, fs->fs_csaddr); 328460ed610SKirk McKusick for (cg = 0; cg < fs->fs_ncg; cg++) { 329460ed610SKirk McKusick if (fragstoblks(fs, cgtod(fs, cg)) > csblkno) 330460ed610SKirk McKusick break; 331460ed610SKirk McKusick CHKBLKINLIST(fragstoblks(fs, cgtod(fs, cg))); 332460ed610SKirk McKusick if (status == 0) 333460ed610SKirk McKusick goto out; 334460ed610SKirk McKusick } 335460ed610SKirk McKusick /* Check the summary information block(s). */ 336460ed610SKirk McKusick len = howmany(fs->fs_cssize, fs->fs_bsize); 337460ed610SKirk McKusick for (loc = 0; loc < len; loc++) { 338460ed610SKirk McKusick CHKBLKINLIST(csblkno + loc); 339460ed610SKirk McKusick if (status == 0) 340460ed610SKirk McKusick goto out; 341460ed610SKirk McKusick } 342460ed610SKirk McKusick /* Check the remaining cylinder groups. */ 343460ed610SKirk McKusick for (; cg < fs->fs_ncg; cg++) { 344460ed610SKirk McKusick CHKBLKINLIST(fragstoblks(fs, cgtod(fs, cg))); 345460ed610SKirk McKusick if (status == 0) 346460ed610SKirk McKusick goto out; 347460ed610SKirk McKusick } 348460ed610SKirk McKusick out: 349460ed610SKirk McKusick brelse(bp); 350460ed610SKirk McKusick return (status); 351460ed610SKirk McKusick } 352460ed610SKirk McKusick 353460ed610SKirk McKusick /* 354460ed610SKirk McKusick * Return the block number associated with a specified inode lbn. 355460ed610SKirk McKusick * Requested lbn is in id_parent. If found, block is returned in 356460ed610SKirk McKusick * id_parent. 357460ed610SKirk McKusick */ 358460ed610SKirk McKusick static int 359460ed610SKirk McKusick getlbnblkno(struct inodesc *idesc) 360460ed610SKirk McKusick { 361460ed610SKirk McKusick 362460ed610SKirk McKusick if (idesc->id_lbn < idesc->id_parent) 363460ed610SKirk McKusick return (KEEPON); 364460ed610SKirk McKusick idesc->id_parent = idesc->id_blkno; 365460ed610SKirk McKusick return (STOP | FOUND); 366460ed610SKirk McKusick } 367460ed610SKirk McKusick 368460ed610SKirk McKusick /* 369c5d476c9SKirk McKusick * Open a device or file to be checked by fsck. 370c5d476c9SKirk McKusick */ 371c5d476c9SKirk McKusick int 372c5d476c9SKirk McKusick openfilesys(char *dev) 373c5d476c9SKirk McKusick { 374c5d476c9SKirk McKusick struct stat statb; 375c5d476c9SKirk McKusick int saved_fsreadfd; 376c5d476c9SKirk McKusick 3772983ec0aSKirk McKusick if (stat(dev, &statb) < 0) 378c5d476c9SKirk McKusick return (0); 379c5d476c9SKirk McKusick if ((statb.st_mode & S_IFMT) != S_IFCHR && 380c5d476c9SKirk McKusick (statb.st_mode & S_IFMT) != S_IFBLK) { 381c5d476c9SKirk McKusick if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) { 382d3a36e4bSKirk McKusick pwarn("BACKGROUND FSCK LACKS A SNAPSHOT\n"); 383d3a36e4bSKirk McKusick return (0); 384c5d476c9SKirk McKusick } 385c5d476c9SKirk McKusick if (bkgrdflag != 0) { 386c5d476c9SKirk McKusick cursnapshot = statb.st_ino; 387c5d476c9SKirk McKusick } else { 388d3a36e4bSKirk McKusick pwarn("%s IS NOT A DISK DEVICE\n", dev); 389d3a36e4bSKirk McKusick if (preen || reply("CONTINUE") == 0) 390c5d476c9SKirk McKusick return (0); 391c5d476c9SKirk McKusick } 392c5d476c9SKirk McKusick } 393c5d476c9SKirk McKusick saved_fsreadfd = fsreadfd; 394c5d476c9SKirk McKusick if ((fsreadfd = open(dev, O_RDONLY)) < 0) { 395c5d476c9SKirk McKusick fsreadfd = saved_fsreadfd; 396c5d476c9SKirk McKusick return (0); 397c5d476c9SKirk McKusick } 398c5d476c9SKirk McKusick if (saved_fsreadfd != -1) 399c5d476c9SKirk McKusick close(saved_fsreadfd); 400c5d476c9SKirk McKusick return (1); 401c5d476c9SKirk McKusick } 402c5d476c9SKirk McKusick 403c5d476c9SKirk McKusick /* 4048fae3551SRodney W. Grimes * Read in the super block and its summary info. 4058fae3551SRodney W. Grimes */ 40638375c40SKirk McKusick int 407e6886616SKirk McKusick readsb(void) 4088fae3551SRodney W. Grimes { 409dffce215SKirk McKusick struct fs *fs; 4108fae3551SRodney W. Grimes 411e6886616SKirk McKusick sbhashfailed = 0; 412ed75b5a1SKirk McKusick readcnt[sblk.b_type]++; 413e6886616SKirk McKusick /* 414e6886616SKirk McKusick * If bflag is given, then check just that superblock. 415e6886616SKirk McKusick */ 416e6886616SKirk McKusick if (bflag) { 4174f9606c9SKirk McKusick switch (sbget(fsreadfd, &fs, bflag * dev_bsize, 0)) { 418e6886616SKirk McKusick case 0: 419e6886616SKirk McKusick goto goodsb; 420c0bfa109SKirk McKusick case EINTEGRITY: 421e6886616SKirk McKusick printf("Check hash failed for superblock at %jd\n", 422e6886616SKirk McKusick bflag); 423038c170fSKirk McKusick return (0); 424dffce215SKirk McKusick case ENOENT: 425e6886616SKirk McKusick printf("%jd is not a file system superblock\n", bflag); 426f033309fSKirk McKusick return (0); 427dffce215SKirk McKusick case EIO: 428dffce215SKirk McKusick default: 429e6886616SKirk McKusick printf("I/O error reading %jd\n", bflag); 4301c85e6a3SKirk McKusick return (0); 4311c85e6a3SKirk McKusick } 4321c85e6a3SKirk McKusick } 433e6886616SKirk McKusick /* 434e6886616SKirk McKusick * Check for the standard superblock and use it if good. 435e6886616SKirk McKusick */ 436e6886616SKirk McKusick if (sbget(fsreadfd, &fs, UFS_STDSB, UFS_NOMSG) == 0) 437e6886616SKirk McKusick goto goodsb; 438e6886616SKirk McKusick /* 439e6886616SKirk McKusick * Check if the only problem is a check-hash failure. 440e6886616SKirk McKusick */ 441e6886616SKirk McKusick skipclean = 0; 442e6886616SKirk McKusick if (sbget(fsreadfd, &fs, UFS_STDSB, UFS_NOMSG | UFS_NOHASHFAIL) == 0) { 443e6886616SKirk McKusick sbhashfailed = 1; 444e6886616SKirk McKusick goto goodsb; 445e6886616SKirk McKusick } 446e6886616SKirk McKusick /* 447e6886616SKirk McKusick * Do an exhaustive search for a usable superblock. 448e6886616SKirk McKusick */ 449e6886616SKirk McKusick switch (sbsearch(fsreadfd, &fs, 0)) { 450e6886616SKirk McKusick case 0: 451e6886616SKirk McKusick goto goodsb; 452e6886616SKirk McKusick case ENOENT: 453e6886616SKirk McKusick printf("SEARCH FOR ALTERNATE SUPER-BLOCK FAILED. " 454e6886616SKirk McKusick "YOU MUST USE THE\n-b OPTION TO FSCK TO SPECIFY " 455e6886616SKirk McKusick "THE LOCATION OF AN ALTERNATE\nSUPER-BLOCK TO " 456e6886616SKirk McKusick "SUPPLY NEEDED INFORMATION; SEE fsck_ffs(8).\n"); 457e6886616SKirk McKusick return (0); 458e6886616SKirk McKusick case EIO: 459e6886616SKirk McKusick default: 460e6886616SKirk McKusick printf("I/O error reading a usable superblock\n"); 461e6886616SKirk McKusick return (0); 462e6886616SKirk McKusick } 463e6886616SKirk McKusick 464e6886616SKirk McKusick goodsb: 465dffce215SKirk McKusick memcpy(&sblock, fs, fs->fs_sbsize); 466dffce215SKirk McKusick free(fs); 4678fae3551SRodney W. Grimes /* 4688fae3551SRodney W. Grimes * Compute block size that the file system is based on, 4698fae3551SRodney W. Grimes * according to fsbtodb, and adjust superblock block number 4708fae3551SRodney W. Grimes * so we can tell if this is an alternate later. 4718fae3551SRodney W. Grimes */ 4728fae3551SRodney W. Grimes dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 473dffce215SKirk McKusick sblk.b_bno = sblock.fs_sblockactualloc / dev_bsize; 4741c85e6a3SKirk McKusick sblk.b_size = SBLOCKSIZE; 4758fae3551SRodney W. Grimes /* 4761c85e6a3SKirk McKusick * If not yet done, update UFS1 superblock with new wider fields. 4771c85e6a3SKirk McKusick */ 4781c85e6a3SKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC && 4791c85e6a3SKirk McKusick sblock.fs_maxbsize != sblock.fs_bsize) { 4801c85e6a3SKirk McKusick sblock.fs_maxbsize = sblock.fs_bsize; 4811c85e6a3SKirk McKusick sblock.fs_time = sblock.fs_old_time; 4821c85e6a3SKirk McKusick sblock.fs_size = sblock.fs_old_size; 4831c85e6a3SKirk McKusick sblock.fs_dsize = sblock.fs_old_dsize; 4841c85e6a3SKirk McKusick sblock.fs_csaddr = sblock.fs_old_csaddr; 4851c85e6a3SKirk McKusick sblock.fs_cstotal.cs_ndir = sblock.fs_old_cstotal.cs_ndir; 4861c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nbfree = sblock.fs_old_cstotal.cs_nbfree; 4871c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nifree = sblock.fs_old_cstotal.cs_nifree; 4881c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nffree = sblock.fs_old_cstotal.cs_nffree; 4891c85e6a3SKirk McKusick } 4908fae3551SRodney W. Grimes havesb = 1; 4918fae3551SRodney W. Grimes return (1); 4928fae3551SRodney W. Grimes } 4938fae3551SRodney W. Grimes 494d164d805SIan Dowse void 495b70cd7eeSWarner Losh sblock_init(void) 49638375c40SKirk McKusick { 49738375c40SKirk McKusick 498c5d476c9SKirk McKusick fsreadfd = -1; 49938375c40SKirk McKusick fswritefd = -1; 50038375c40SKirk McKusick fsmodified = 0; 50138375c40SKirk McKusick lfdir = 0; 502ed75b5a1SKirk McKusick initbarea(&sblk, BT_SUPERBLK); 503*772430ddSKirk McKusick sblk.b_un.b_buf = Balloc(SBLOCKSIZE); 50423c8b19cSKirk McKusick if (sblk.b_un.b_buf == NULL) 50538375c40SKirk McKusick errx(EEXIT, "cannot allocate space for superblock"); 50638375c40SKirk McKusick dev_bsize = secsize = DEV_BSIZE; 50738375c40SKirk McKusick } 50877b63aa0SKirk McKusick 50977b63aa0SKirk McKusick /* 51077b63aa0SKirk McKusick * Calculate a prototype superblock based on information in the boot area. 51177b63aa0SKirk McKusick * When done the cgsblock macro can be calculated and the fs_ncg field 51277b63aa0SKirk McKusick * can be used. Do NOT attempt to use other macros without verifying that 51377b63aa0SKirk McKusick * their needed information is available! 51477b63aa0SKirk McKusick */ 51577b63aa0SKirk McKusick static int 51677b63aa0SKirk McKusick calcsb(char *dev, int devfd, struct fs *fs) 51777b63aa0SKirk McKusick { 518855662c6SKirk McKusick struct fsrecovery *fsr; 519855662c6SKirk McKusick char *fsrbuf; 520855662c6SKirk McKusick u_int secsize; 52177b63aa0SKirk McKusick 52277b63aa0SKirk McKusick /* 52377b63aa0SKirk McKusick * We need fragments-per-group and the partition-size. 52477b63aa0SKirk McKusick * 52577b63aa0SKirk McKusick * Newfs stores these details at the end of the boot block area 52677b63aa0SKirk McKusick * at the start of the filesystem partition. If they have been 52777b63aa0SKirk McKusick * overwritten by a boot block, we fail. But usually they are 52877b63aa0SKirk McKusick * there and we can use them. 52977b63aa0SKirk McKusick */ 530855662c6SKirk McKusick if (ioctl(devfd, DIOCGSECTORSIZE, &secsize) == -1) 531855662c6SKirk McKusick return (0); 532*772430ddSKirk McKusick fsrbuf = Balloc(secsize); 533855662c6SKirk McKusick if (fsrbuf == NULL) 534855662c6SKirk McKusick errx(EEXIT, "calcsb: cannot allocate recovery buffer"); 535855662c6SKirk McKusick if (blread(devfd, fsrbuf, 53615da40b0SEric van Gyzen (SBLOCK_UFS2 - secsize) / dev_bsize, secsize) != 0) { 53715da40b0SEric van Gyzen free(fsrbuf); 538855662c6SKirk McKusick return (0); 53915da40b0SEric van Gyzen } 540855662c6SKirk McKusick fsr = (struct fsrecovery *)&fsrbuf[secsize - sizeof *fsr]; 54115da40b0SEric van Gyzen if (fsr->fsr_magic != FS_UFS2_MAGIC) { 54215da40b0SEric van Gyzen free(fsrbuf); 54377b63aa0SKirk McKusick return (0); 54415da40b0SEric van Gyzen } 54577b63aa0SKirk McKusick memset(fs, 0, sizeof(struct fs)); 546855662c6SKirk McKusick fs->fs_fpg = fsr->fsr_fpg; 547855662c6SKirk McKusick fs->fs_fsbtodb = fsr->fsr_fsbtodb; 548855662c6SKirk McKusick fs->fs_sblkno = fsr->fsr_sblkno; 549855662c6SKirk McKusick fs->fs_magic = fsr->fsr_magic; 550855662c6SKirk McKusick fs->fs_ncg = fsr->fsr_ncg; 551855662c6SKirk McKusick free(fsrbuf); 55277b63aa0SKirk McKusick return (1); 55377b63aa0SKirk McKusick } 55477b63aa0SKirk McKusick 55577b63aa0SKirk McKusick /* 55677b63aa0SKirk McKusick * Check to see if recovery information exists. 557855662c6SKirk McKusick * Return 1 if it exists or cannot be created. 558855662c6SKirk McKusick * Return 0 if it does not exist and can be created. 55977b63aa0SKirk McKusick */ 56077b63aa0SKirk McKusick static int 56177b63aa0SKirk McKusick chkrecovery(int devfd) 56277b63aa0SKirk McKusick { 563855662c6SKirk McKusick struct fsrecovery *fsr; 564855662c6SKirk McKusick char *fsrbuf; 5657a1c1f6aSKirk McKusick u_int secsize, rdsize; 56677b63aa0SKirk McKusick 567855662c6SKirk McKusick /* 568855662c6SKirk McKusick * Could not determine if backup material exists, so do not 569855662c6SKirk McKusick * offer to create it. 570855662c6SKirk McKusick */ 57115da40b0SEric van Gyzen fsrbuf = NULL; 5727a1c1f6aSKirk McKusick rdsize = sblock.fs_fsize; 573855662c6SKirk McKusick if (ioctl(devfd, DIOCGSECTORSIZE, &secsize) == -1 || 5747a1c1f6aSKirk McKusick rdsize % secsize != 0 || 575*772430ddSKirk McKusick (fsrbuf = Balloc(rdsize)) == NULL || 5767a1c1f6aSKirk McKusick blread(devfd, fsrbuf, (SBLOCK_UFS2 - rdsize) / dev_bsize, 5777a1c1f6aSKirk McKusick rdsize) != 0) { 57815da40b0SEric van Gyzen free(fsrbuf); 57977b63aa0SKirk McKusick return (1); 58015da40b0SEric van Gyzen } 581855662c6SKirk McKusick /* 582855662c6SKirk McKusick * Recovery material has already been created, so do not 583855662c6SKirk McKusick * need to create it again. 584855662c6SKirk McKusick */ 5857a1c1f6aSKirk McKusick fsr = (struct fsrecovery *)&fsrbuf[rdsize - sizeof *fsr]; 586855662c6SKirk McKusick if (fsr->fsr_magic == FS_UFS2_MAGIC) { 587855662c6SKirk McKusick free(fsrbuf); 588855662c6SKirk McKusick return (1); 589855662c6SKirk McKusick } 590855662c6SKirk McKusick /* 591855662c6SKirk McKusick * Recovery material has not been created and can be if desired. 592855662c6SKirk McKusick */ 593855662c6SKirk McKusick free(fsrbuf); 594855662c6SKirk McKusick return (0); 59577b63aa0SKirk McKusick } 59677b63aa0SKirk McKusick 59777b63aa0SKirk McKusick /* 5987a1c1f6aSKirk McKusick * Read the last filesystem-size piece of the boot block, replace the 5997a1c1f6aSKirk McKusick * last 20 bytes with the recovery information, then write it back. 60077b63aa0SKirk McKusick * The recovery information only works for UFS2 filesystems. 60177b63aa0SKirk McKusick */ 60277b63aa0SKirk McKusick static void 60377b63aa0SKirk McKusick saverecovery(int readfd, int writefd) 60477b63aa0SKirk McKusick { 605855662c6SKirk McKusick struct fsrecovery *fsr; 606855662c6SKirk McKusick char *fsrbuf; 6077a1c1f6aSKirk McKusick u_int secsize, rdsize; 60877b63aa0SKirk McKusick 60915da40b0SEric van Gyzen fsrbuf = NULL; 6107a1c1f6aSKirk McKusick rdsize = sblock.fs_fsize; 61177b63aa0SKirk McKusick if (sblock.fs_magic != FS_UFS2_MAGIC || 612855662c6SKirk McKusick ioctl(readfd, DIOCGSECTORSIZE, &secsize) == -1 || 6137a1c1f6aSKirk McKusick rdsize % secsize != 0 || 614*772430ddSKirk McKusick (fsrbuf = Balloc(rdsize)) == NULL || 6157a1c1f6aSKirk McKusick blread(readfd, fsrbuf, (SBLOCK_UFS2 - rdsize) / dev_bsize, 6167a1c1f6aSKirk McKusick rdsize) != 0) { 617855662c6SKirk McKusick printf("RECOVERY DATA COULD NOT BE CREATED\n"); 61815da40b0SEric van Gyzen free(fsrbuf); 61977b63aa0SKirk McKusick return; 620855662c6SKirk McKusick } 6217a1c1f6aSKirk McKusick fsr = (struct fsrecovery *)&fsrbuf[rdsize - sizeof *fsr]; 622855662c6SKirk McKusick fsr->fsr_magic = sblock.fs_magic; 623855662c6SKirk McKusick fsr->fsr_fpg = sblock.fs_fpg; 624855662c6SKirk McKusick fsr->fsr_fsbtodb = sblock.fs_fsbtodb; 625855662c6SKirk McKusick fsr->fsr_sblkno = sblock.fs_sblkno; 626855662c6SKirk McKusick fsr->fsr_ncg = sblock.fs_ncg; 6277a1c1f6aSKirk McKusick blwrite(writefd, fsrbuf, (SBLOCK_UFS2 - rdsize) / dev_bsize, rdsize); 628855662c6SKirk McKusick free(fsrbuf); 62977b63aa0SKirk McKusick } 630