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> 38c69284caSDavid E. O'Brien __FBSDID("$FreeBSD$"); 398fae3551SRodney W. Grimes 408fae3551SRodney W. Grimes #include <sys/param.h> 41855662c6SKirk McKusick #include <sys/disk.h> 428fae3551SRodney W. Grimes #include <sys/stat.h> 43b35e6950SBosko Milekic #define FSTYPENAMES 448fae3551SRodney W. Grimes #include <sys/disklabel.h> 458fae3551SRodney W. Grimes #include <sys/file.h> 46bf58d635SIan Dowse #include <sys/sysctl.h> 47780a5c1eSPeter Wemm 48780a5c1eSPeter Wemm #include <ufs/ufs/dinode.h> 49780a5c1eSPeter Wemm #include <ufs/ffs/fs.h> 50780a5c1eSPeter Wemm 51780a5c1eSPeter Wemm #include <ctype.h> 52780a5c1eSPeter Wemm #include <err.h> 538fae3551SRodney W. Grimes #include <errno.h> 5489fdc4e1SMike Barcroft #include <limits.h> 5584fc0d7eSMaxime Henrion #include <stdint.h> 568fae3551SRodney W. Grimes #include <string.h> 57a6bbdf81SKirk McKusick #include <libufs.h> 58780a5c1eSPeter Wemm 598fae3551SRodney W. Grimes #include "fsck.h" 608fae3551SRodney W. Grimes 61*52f97104SKirk McKusick struct inohash *inphash; /* hash list of directory inode info */ 62*52f97104SKirk McKusick struct inoinfo **inpsort; /* disk order list of directory inodes */ 63460ed610SKirk McKusick struct inode snaplist[FSMAXSNAP + 1]; /* list of active snapshots */ 64460ed610SKirk McKusick int snapcnt; /* number of active snapshots */ 65460ed610SKirk McKusick char *copybuf; /* buffer to copy snapshot blocks */ 66c3e9752eSKyle Evans 67e6886616SKirk McKusick static int sbhashfailed; 688fae3551SRodney W. Grimes #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 698fae3551SRodney W. Grimes 7077b63aa0SKirk McKusick static int calcsb(char *dev, int devfd, struct fs *fs); 7177b63aa0SKirk McKusick static void saverecovery(int readfd, int writefd); 7277b63aa0SKirk McKusick static int chkrecovery(int devfd); 73460ed610SKirk McKusick static int getlbnblkno(struct inodesc *); 74460ed610SKirk McKusick static int checksnapinfo(struct inode *); 7577b63aa0SKirk McKusick 76780a5c1eSPeter Wemm /* 77780a5c1eSPeter Wemm * Read in a superblock finding an alternate if necessary. 78780a5c1eSPeter Wemm * Return 1 if successful, 0 if unsuccessful, -1 if file system 79111a5220SDavid E. O'Brien * is already clean (ckclean and preen mode only). 80780a5c1eSPeter Wemm */ 8131f4ab50SBruce Evans int 82b70cd7eeSWarner Losh setup(char *dev) 838fae3551SRodney W. Grimes { 84460ed610SKirk McKusick long i, bmapsize; 85460ed610SKirk McKusick struct inode ip; 868fae3551SRodney W. Grimes 87c0ed8991SXin LI /* 88e6886616SKirk McKusick * We are expected to have an open file descriptor and a superblock. 89c0ed8991SXin LI */ 90e6886616SKirk McKusick if (fsreadfd < 0 || havesb == 0) { 91e6886616SKirk McKusick if (debug) 92e6886616SKirk McKusick printf("setup: bad fsreadfd or missing superblock\n"); 93c0bfa109SKirk McKusick return (0); 947578c6abSKirk McKusick } 958fae3551SRodney W. Grimes if (preen == 0) 968fae3551SRodney W. Grimes printf("** %s", dev); 977578c6abSKirk McKusick if (bkgrdflag == 0 && 985cc52631SKirk McKusick (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) { 998fae3551SRodney W. Grimes fswritefd = -1; 1008fae3551SRodney W. Grimes if (preen) 1018fae3551SRodney W. Grimes pfatal("NO WRITE ACCESS"); 1028fae3551SRodney W. Grimes printf(" (NO WRITE)"); 1038fae3551SRodney W. Grimes } 1048fae3551SRodney W. Grimes if (preen == 0) 1058fae3551SRodney W. Grimes printf("\n"); 106c0bfa109SKirk McKusick if (sbhashfailed != 0) { 107c0bfa109SKirk McKusick pwarn("SUPERBLOCK CHECK HASH FAILED"); 108c0bfa109SKirk McKusick if (fswritefd == -1) 109c0bfa109SKirk McKusick pwarn("OPENED READONLY SO CANNOT CORRECT CHECK HASH\n"); 110c0bfa109SKirk McKusick else if (preen || reply("CORRECT CHECK HASH") != 0) { 111c0bfa109SKirk McKusick if (preen) 112c0bfa109SKirk McKusick printf(" (CORRECTED)\n"); 113c0bfa109SKirk McKusick sblock.fs_clean = 0; 114c0bfa109SKirk McKusick sbdirty(); 11577b63aa0SKirk McKusick } 1168fae3551SRodney W. Grimes } 117111a5220SDavid E. O'Brien if (skipclean && ckclean && sblock.fs_clean) { 118d33e92f9SJulian Elischer pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); 119d33e92f9SJulian Elischer return (-1); 120d33e92f9SJulian Elischer } 1218fae3551SRodney W. Grimes maxfsblock = sblock.fs_size; 1228fae3551SRodney W. Grimes maxino = sblock.fs_ncg * sblock.fs_ipg; 1238fae3551SRodney W. Grimes /* 1248fae3551SRodney W. Grimes * Check and potentially fix certain fields in the super block. 1258fae3551SRodney W. Grimes */ 1268fae3551SRodney W. Grimes if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { 1278fae3551SRodney W. Grimes pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); 1288fae3551SRodney W. Grimes if (reply("SET TO DEFAULT") == 1) { 1298fae3551SRodney W. Grimes sblock.fs_optim = FS_OPTTIME; 1308fae3551SRodney W. Grimes sbdirty(); 1318fae3551SRodney W. Grimes } 1328fae3551SRodney W. Grimes } 1338fae3551SRodney W. Grimes if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { 1348fae3551SRodney W. Grimes pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 1358fae3551SRodney W. Grimes sblock.fs_minfree); 1368fae3551SRodney W. Grimes if (reply("SET TO DEFAULT") == 1) { 1378fae3551SRodney W. Grimes sblock.fs_minfree = 10; 1388fae3551SRodney W. Grimes sbdirty(); 1398fae3551SRodney W. Grimes } 1408fae3551SRodney W. Grimes } 1411c85e6a3SKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC && 1421c85e6a3SKirk McKusick sblock.fs_old_inodefmt < FS_44INODEFMT) { 143381ee4c2SPoul-Henning Kamp pwarn("Format of file system is too old.\n"); 144381ee4c2SPoul-Henning Kamp pwarn("Must update to modern format using a version of fsck\n"); 145381ee4c2SPoul-Henning Kamp pfatal("from before 2002 with the command ``fsck -c 2''\n"); 146381ee4c2SPoul-Henning Kamp exit(EEXIT); 1478fae3551SRodney W. Grimes } 14877b63aa0SKirk McKusick if (preen == 0 && yflag == 0 && sblock.fs_magic == FS_UFS2_MAGIC && 14977b63aa0SKirk McKusick fswritefd != -1 && chkrecovery(fsreadfd) == 0 && 15077b63aa0SKirk McKusick reply("SAVE DATA TO FIND ALTERNATE SUPERBLOCKS") != 0) 15177b63aa0SKirk McKusick saverecovery(fsreadfd, fswritefd); 1528fae3551SRodney W. Grimes /* 1538fae3551SRodney W. Grimes * allocate and initialize the necessary maps 1548fae3551SRodney W. Grimes */ 1556e821c35SKirk McKusick bufinit(); 15689fdc4e1SMike Barcroft bmapsize = roundup(howmany(maxfsblock, CHAR_BIT), sizeof(short)); 15781fbded2SKirk McKusick blockmap = Calloc((unsigned)bmapsize, sizeof (char)); 1588fae3551SRodney W. Grimes if (blockmap == NULL) { 1598fae3551SRodney W. Grimes printf("cannot alloc %u bytes for blockmap\n", 1608fae3551SRodney W. Grimes (unsigned)bmapsize); 1618fae3551SRodney W. Grimes goto badsb; 1628fae3551SRodney W. Grimes } 163f6717697SPedro F. Giffuni inostathead = Calloc(sblock.fs_ncg, sizeof(struct inostatlist)); 164d33e92f9SJulian Elischer if (inostathead == NULL) { 165d33e92f9SJulian Elischer printf("cannot alloc %u bytes for inostathead\n", 166d33e92f9SJulian Elischer (unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg))); 1678fae3551SRodney W. Grimes goto badsb; 1688fae3551SRodney W. Grimes } 169*52f97104SKirk McKusick numdirs = sblock.fs_cstotal.cs_ndir; 170*52f97104SKirk McKusick dirhash = MAX(numdirs / 2, 1); 1718fae3551SRodney W. Grimes inplast = 0; 1728fae3551SRodney W. Grimes listmax = numdirs + 10; 173f6717697SPedro F. Giffuni inpsort = (struct inoinfo **)Calloc(listmax, sizeof(struct inoinfo *)); 174*52f97104SKirk McKusick inphash = (struct inohash *)Calloc(dirhash, sizeof(struct inohash)); 175*52f97104SKirk McKusick if (inpsort == NULL || inphash == NULL) { 176*52f97104SKirk McKusick printf("cannot alloc %ju bytes for inphash\n", 17784fc0d7eSMaxime Henrion (uintmax_t)numdirs * sizeof(struct inoinfo *)); 1788fae3551SRodney W. Grimes goto badsb; 1798fae3551SRodney W. Grimes } 180b1897c19SJulian Elischer if (sblock.fs_flags & FS_DOSOFTDEP) 181b1897c19SJulian Elischer usedsoftdep = 1; 182b1897c19SJulian Elischer else 183b1897c19SJulian Elischer usedsoftdep = 0; 184460ed610SKirk McKusick /* 185460ed610SKirk McKusick * Collect any snapshot inodes so that we can allow them to 186460ed610SKirk McKusick * claim any blocks that we free. The code for doing this is 187460ed610SKirk McKusick * imported here and into inode.c from sys/ufs/ffs/ffs_snapshot.c. 188460ed610SKirk McKusick */ 189460ed610SKirk McKusick for (snapcnt = 0; snapcnt < FSMAXSNAP; snapcnt++) { 190460ed610SKirk McKusick if (sblock.fs_snapinum[snapcnt] == 0) 191460ed610SKirk McKusick break; 192460ed610SKirk McKusick ginode(sblock.fs_snapinum[snapcnt], &ip); 193460ed610SKirk McKusick if ((DIP(ip.i_dp, di_mode) & IFMT) == IFREG && 194460ed610SKirk McKusick (DIP(ip.i_dp, di_flags) & SF_SNAPSHOT) != 0 && 195460ed610SKirk McKusick checksnapinfo(&ip)) { 196460ed610SKirk McKusick if (debug) 197460ed610SKirk McKusick printf("Load snapshot %jd\n", 198460ed610SKirk McKusick (intmax_t)sblock.fs_snapinum[snapcnt]); 199460ed610SKirk McKusick snaplist[snapcnt] = ip; 200460ed610SKirk McKusick continue; 201460ed610SKirk McKusick } 202460ed610SKirk McKusick printf("Removing non-snapshot inode %ju from snapshot list\n", 203460ed610SKirk McKusick (uintmax_t)sblock.fs_snapinum[snapcnt]); 204460ed610SKirk McKusick irelse(&ip); 205460ed610SKirk McKusick for (i = snapcnt + 1; i < FSMAXSNAP; i++) { 206460ed610SKirk McKusick if (sblock.fs_snapinum[i] == 0) 207460ed610SKirk McKusick break; 208460ed610SKirk McKusick sblock.fs_snapinum[i - 1] = sblock.fs_snapinum[i]; 209460ed610SKirk McKusick } 210460ed610SKirk McKusick sblock.fs_snapinum[i - 1] = 0; 211460ed610SKirk McKusick snapcnt--; 212460ed610SKirk McKusick sbdirty(); 213460ed610SKirk McKusick } 214460ed610SKirk McKusick if (snapcnt > 0 && copybuf == NULL) { 215460ed610SKirk McKusick copybuf = Malloc(sblock.fs_bsize); 216460ed610SKirk McKusick if (copybuf == NULL) 217460ed610SKirk McKusick errx(EEXIT, "cannot allocate space for snapshot " 218460ed610SKirk McKusick "copy buffer"); 219460ed610SKirk McKusick } 2208fae3551SRodney W. Grimes return (1); 2218fae3551SRodney W. Grimes 2228fae3551SRodney W. Grimes badsb: 223780a5c1eSPeter Wemm ckfini(0); 2248fae3551SRodney W. Grimes return (0); 2258fae3551SRodney W. Grimes } 2268fae3551SRodney W. Grimes 2278fae3551SRodney W. Grimes /* 228460ed610SKirk McKusick * Check for valid snapshot information. 229460ed610SKirk McKusick * 230460ed610SKirk McKusick * Each snapshot has a list of blocks that have been copied. This list 231460ed610SKirk McKusick * is consulted before checking the snapshot inode. Its purpose is to 232460ed610SKirk McKusick * speed checking of commonly checked blocks and to avoid recursive 233460ed610SKirk McKusick * checks of the snapshot inode. In particular, the list must contain 234460ed610SKirk McKusick * the superblock, the superblock summary information, and all the 235460ed610SKirk McKusick * cylinder group blocks. The list may contain other commonly checked 236460ed610SKirk McKusick * pointers such as those of the blocks that contain the snapshot inodes. 237460ed610SKirk McKusick * The list is sorted into block order to allow binary search lookup. 238460ed610SKirk McKusick * 239460ed610SKirk McKusick * The twelve direct direct block pointers of the snapshot are always 240460ed610SKirk McKusick * copied, so we test for them first before checking the list itself 241460ed610SKirk McKusick * (i.e., they are not in the list). 242460ed610SKirk McKusick * 243460ed610SKirk McKusick * The checksnapinfo() routine needs to ensure that the list contains at 244460ed610SKirk McKusick * least the super block, its summary information, and the cylinder groups. 245460ed610SKirk McKusick * Here we check the list first for the superblock, zero or more cylinder 246460ed610SKirk McKusick * groups up to the location of the superblock summary information, the 247460ed610SKirk McKusick * summary group information, and any remaining cylinder group maps that 248460ed610SKirk McKusick * follow it. We skip over any other entries in the list. 249460ed610SKirk McKusick */ 250460ed610SKirk McKusick #define CHKBLKINLIST(chkblk) \ 251460ed610SKirk McKusick /* All UFS_NDADDR blocks are copied */ \ 252460ed610SKirk McKusick if ((chkblk) >= UFS_NDADDR) { \ 253460ed610SKirk McKusick /* Skip over blocks that are not of interest */ \ 254460ed610SKirk McKusick while (*blkp < (chkblk) && blkp < lastblkp) \ 255460ed610SKirk McKusick blkp++; \ 256460ed610SKirk McKusick /* Fail if end of list and not all blocks found */ \ 257460ed610SKirk McKusick if (blkp >= lastblkp) { \ 258460ed610SKirk McKusick pwarn("UFS%d snapshot inode %jd failed: " \ 259460ed610SKirk McKusick "improper block list length (%jd)\n", \ 260460ed610SKirk McKusick sblock.fs_magic == FS_UFS1_MAGIC ? 1 : 2, \ 261460ed610SKirk McKusick (intmax_t)snapip->i_number, \ 262460ed610SKirk McKusick (intmax_t)(lastblkp - &snapblklist[0])); \ 263460ed610SKirk McKusick status = 0; \ 264460ed610SKirk McKusick } \ 265460ed610SKirk McKusick /* Fail if block we seek is missing */ \ 266460ed610SKirk McKusick else if (*blkp++ != (chkblk)) { \ 267460ed610SKirk McKusick pwarn("UFS%d snapshot inode %jd failed: " \ 268460ed610SKirk McKusick "block list (%jd) != %s (%jd)\n", \ 269460ed610SKirk McKusick sblock.fs_magic == FS_UFS1_MAGIC ? 1 : 2, \ 270460ed610SKirk McKusick (intmax_t)snapip->i_number, \ 271460ed610SKirk McKusick (intmax_t)blkp[-1], #chkblk, \ 272460ed610SKirk McKusick (intmax_t)chkblk); \ 273460ed610SKirk McKusick status = 0; \ 274460ed610SKirk McKusick } \ 275460ed610SKirk McKusick } 276460ed610SKirk McKusick 277460ed610SKirk McKusick static int 278460ed610SKirk McKusick checksnapinfo(struct inode *snapip) 279460ed610SKirk McKusick { 280460ed610SKirk McKusick struct fs *fs; 281460ed610SKirk McKusick struct bufarea *bp; 282460ed610SKirk McKusick struct inodesc idesc; 283460ed610SKirk McKusick daddr_t *snapblklist, *blkp, *lastblkp, csblkno; 284460ed610SKirk McKusick int cg, loc, len, status; 285460ed610SKirk McKusick ufs_lbn_t lbn; 286460ed610SKirk McKusick size_t size; 287460ed610SKirk McKusick 288460ed610SKirk McKusick fs = &sblock; 289460ed610SKirk McKusick memset(&idesc, 0, sizeof(struct inodesc)); 290460ed610SKirk McKusick idesc.id_type = ADDR; 291460ed610SKirk McKusick idesc.id_func = getlbnblkno; 292460ed610SKirk McKusick idesc.id_number = snapip->i_number; 293460ed610SKirk McKusick lbn = howmany(fs->fs_size, fs->fs_frag); 294460ed610SKirk McKusick idesc.id_parent = lbn; /* sought after blkno */ 295460ed610SKirk McKusick if ((ckinode(snapip->i_dp, &idesc) & FOUND) == 0) 296460ed610SKirk McKusick return (0); 297460ed610SKirk McKusick size = fragroundup(fs, 298460ed610SKirk McKusick DIP(snapip->i_dp, di_size) - lblktosize(fs, lbn)); 299460ed610SKirk McKusick bp = getdatablk(idesc.id_parent, size, BT_DATA); 300460ed610SKirk McKusick snapblklist = (daddr_t *)bp->b_un.b_buf; 301460ed610SKirk McKusick /* 302460ed610SKirk McKusick * snapblklist[0] is the size of the list 303460ed610SKirk McKusick * snapblklist[1] is the first element of the list 304460ed610SKirk McKusick * 305460ed610SKirk McKusick * We need to be careful to bound the size of the list and verify 306460ed610SKirk McKusick * that we have not run off the end of it if it or its size has 307460ed610SKirk McKusick * been corrupted. 308460ed610SKirk McKusick */ 309460ed610SKirk McKusick blkp = &snapblklist[1]; 310460ed610SKirk McKusick lastblkp = &snapblklist[MAX(0, 311460ed610SKirk McKusick MIN(snapblklist[0] + 1, size / sizeof(daddr_t)))]; 312460ed610SKirk McKusick status = 1; 313460ed610SKirk McKusick /* Check that the superblock is listed. */ 314460ed610SKirk McKusick CHKBLKINLIST(lblkno(fs, fs->fs_sblockloc)); 315460ed610SKirk McKusick if (status == 0) 316460ed610SKirk McKusick goto out; 317460ed610SKirk McKusick /* 318460ed610SKirk McKusick * Calculate where the summary information is located. 319460ed610SKirk McKusick * Usually it is in the first cylinder group, but growfs 320460ed610SKirk McKusick * may move it to the first cylinder group that it adds. 321460ed610SKirk McKusick * 322460ed610SKirk McKusick * Check all cylinder groups up to the summary information. 323460ed610SKirk McKusick */ 324460ed610SKirk McKusick csblkno = fragstoblks(fs, fs->fs_csaddr); 325460ed610SKirk McKusick for (cg = 0; cg < fs->fs_ncg; cg++) { 326460ed610SKirk McKusick if (fragstoblks(fs, cgtod(fs, cg)) > csblkno) 327460ed610SKirk McKusick break; 328460ed610SKirk McKusick CHKBLKINLIST(fragstoblks(fs, cgtod(fs, cg))); 329460ed610SKirk McKusick if (status == 0) 330460ed610SKirk McKusick goto out; 331460ed610SKirk McKusick } 332460ed610SKirk McKusick /* Check the summary information block(s). */ 333460ed610SKirk McKusick len = howmany(fs->fs_cssize, fs->fs_bsize); 334460ed610SKirk McKusick for (loc = 0; loc < len; loc++) { 335460ed610SKirk McKusick CHKBLKINLIST(csblkno + loc); 336460ed610SKirk McKusick if (status == 0) 337460ed610SKirk McKusick goto out; 338460ed610SKirk McKusick } 339460ed610SKirk McKusick /* Check the remaining cylinder groups. */ 340460ed610SKirk McKusick for (; cg < fs->fs_ncg; cg++) { 341460ed610SKirk McKusick CHKBLKINLIST(fragstoblks(fs, cgtod(fs, cg))); 342460ed610SKirk McKusick if (status == 0) 343460ed610SKirk McKusick goto out; 344460ed610SKirk McKusick } 345460ed610SKirk McKusick out: 346460ed610SKirk McKusick brelse(bp); 347460ed610SKirk McKusick return (status); 348460ed610SKirk McKusick } 349460ed610SKirk McKusick 350460ed610SKirk McKusick /* 351460ed610SKirk McKusick * Return the block number associated with a specified inode lbn. 352460ed610SKirk McKusick * Requested lbn is in id_parent. If found, block is returned in 353460ed610SKirk McKusick * id_parent. 354460ed610SKirk McKusick */ 355460ed610SKirk McKusick static int 356460ed610SKirk McKusick getlbnblkno(struct inodesc *idesc) 357460ed610SKirk McKusick { 358460ed610SKirk McKusick 359460ed610SKirk McKusick if (idesc->id_lbn < idesc->id_parent) 360460ed610SKirk McKusick return (KEEPON); 361460ed610SKirk McKusick idesc->id_parent = idesc->id_blkno; 362460ed610SKirk McKusick return (STOP | FOUND); 363460ed610SKirk McKusick } 364460ed610SKirk McKusick 365460ed610SKirk McKusick /* 366c5d476c9SKirk McKusick * Open a device or file to be checked by fsck. 367c5d476c9SKirk McKusick */ 368c5d476c9SKirk McKusick int 369c5d476c9SKirk McKusick openfilesys(char *dev) 370c5d476c9SKirk McKusick { 371c5d476c9SKirk McKusick struct stat statb; 372c5d476c9SKirk McKusick int saved_fsreadfd; 373c5d476c9SKirk McKusick 3742983ec0aSKirk McKusick if (stat(dev, &statb) < 0) 375c5d476c9SKirk McKusick return (0); 376c5d476c9SKirk McKusick if ((statb.st_mode & S_IFMT) != S_IFCHR && 377c5d476c9SKirk McKusick (statb.st_mode & S_IFMT) != S_IFBLK) { 378c5d476c9SKirk McKusick if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) { 379c5d476c9SKirk McKusick pfatal("BACKGROUND FSCK LACKS A SNAPSHOT\n"); 380c5d476c9SKirk McKusick exit(EEXIT); 381c5d476c9SKirk McKusick } 382c5d476c9SKirk McKusick if (bkgrdflag != 0) { 383c5d476c9SKirk McKusick cursnapshot = statb.st_ino; 384c5d476c9SKirk McKusick } else { 385c5d476c9SKirk McKusick pfatal("%s IS NOT A DISK DEVICE\n", dev); 386c5d476c9SKirk McKusick if (reply("CONTINUE") == 0) 387c5d476c9SKirk McKusick return (0); 388c5d476c9SKirk McKusick } 389c5d476c9SKirk McKusick } 390c5d476c9SKirk McKusick saved_fsreadfd = fsreadfd; 391c5d476c9SKirk McKusick if ((fsreadfd = open(dev, O_RDONLY)) < 0) { 392c5d476c9SKirk McKusick fsreadfd = saved_fsreadfd; 393c5d476c9SKirk McKusick return (0); 394c5d476c9SKirk McKusick } 395c5d476c9SKirk McKusick if (saved_fsreadfd != -1) 396c5d476c9SKirk McKusick close(saved_fsreadfd); 397c5d476c9SKirk McKusick return (1); 398c5d476c9SKirk McKusick } 399c5d476c9SKirk McKusick 400c5d476c9SKirk McKusick /* 4018fae3551SRodney W. Grimes * Read in the super block and its summary info. 4028fae3551SRodney W. Grimes */ 40338375c40SKirk McKusick int 404e6886616SKirk McKusick readsb(void) 4058fae3551SRodney W. Grimes { 406dffce215SKirk McKusick struct fs *fs; 4078fae3551SRodney W. Grimes 408e6886616SKirk McKusick sbhashfailed = 0; 409ed75b5a1SKirk McKusick readcnt[sblk.b_type]++; 410e6886616SKirk McKusick /* 411e6886616SKirk McKusick * If bflag is given, then check just that superblock. 412e6886616SKirk McKusick */ 413e6886616SKirk McKusick if (bflag) { 4144f9606c9SKirk McKusick switch (sbget(fsreadfd, &fs, bflag * dev_bsize, 0)) { 415e6886616SKirk McKusick case 0: 416e6886616SKirk McKusick goto goodsb; 417c0bfa109SKirk McKusick case EINTEGRITY: 418e6886616SKirk McKusick printf("Check hash failed for superblock at %jd\n", 419e6886616SKirk McKusick bflag); 420038c170fSKirk McKusick return (0); 421dffce215SKirk McKusick case ENOENT: 422e6886616SKirk McKusick printf("%jd is not a file system superblock\n", bflag); 423f033309fSKirk McKusick return (0); 424dffce215SKirk McKusick case EIO: 425dffce215SKirk McKusick default: 426e6886616SKirk McKusick printf("I/O error reading %jd\n", bflag); 4271c85e6a3SKirk McKusick return (0); 4281c85e6a3SKirk McKusick } 4291c85e6a3SKirk McKusick } 430e6886616SKirk McKusick /* 431e6886616SKirk McKusick * Check for the standard superblock and use it if good. 432e6886616SKirk McKusick */ 433e6886616SKirk McKusick if (sbget(fsreadfd, &fs, UFS_STDSB, UFS_NOMSG) == 0) 434e6886616SKirk McKusick goto goodsb; 435e6886616SKirk McKusick /* 436e6886616SKirk McKusick * Check if the only problem is a check-hash failure. 437e6886616SKirk McKusick */ 438e6886616SKirk McKusick skipclean = 0; 439e6886616SKirk McKusick if (sbget(fsreadfd, &fs, UFS_STDSB, UFS_NOMSG | UFS_NOHASHFAIL) == 0) { 440e6886616SKirk McKusick sbhashfailed = 1; 441e6886616SKirk McKusick goto goodsb; 442e6886616SKirk McKusick } 443e6886616SKirk McKusick /* 444e6886616SKirk McKusick * Do an exhaustive search for a usable superblock. 445e6886616SKirk McKusick */ 446e6886616SKirk McKusick switch (sbsearch(fsreadfd, &fs, 0)) { 447e6886616SKirk McKusick case 0: 448e6886616SKirk McKusick goto goodsb; 449e6886616SKirk McKusick case ENOENT: 450e6886616SKirk McKusick printf("SEARCH FOR ALTERNATE SUPER-BLOCK FAILED. " 451e6886616SKirk McKusick "YOU MUST USE THE\n-b OPTION TO FSCK TO SPECIFY " 452e6886616SKirk McKusick "THE LOCATION OF AN ALTERNATE\nSUPER-BLOCK TO " 453e6886616SKirk McKusick "SUPPLY NEEDED INFORMATION; SEE fsck_ffs(8).\n"); 454e6886616SKirk McKusick return (0); 455e6886616SKirk McKusick case EIO: 456e6886616SKirk McKusick default: 457e6886616SKirk McKusick printf("I/O error reading a usable superblock\n"); 458e6886616SKirk McKusick return (0); 459e6886616SKirk McKusick } 460e6886616SKirk McKusick 461e6886616SKirk McKusick goodsb: 462dffce215SKirk McKusick memcpy(&sblock, fs, fs->fs_sbsize); 463dffce215SKirk McKusick free(fs); 4648fae3551SRodney W. Grimes /* 4658fae3551SRodney W. Grimes * Compute block size that the file system is based on, 4668fae3551SRodney W. Grimes * according to fsbtodb, and adjust superblock block number 4678fae3551SRodney W. Grimes * so we can tell if this is an alternate later. 4688fae3551SRodney W. Grimes */ 4698fae3551SRodney W. Grimes dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 470dffce215SKirk McKusick sblk.b_bno = sblock.fs_sblockactualloc / dev_bsize; 4711c85e6a3SKirk McKusick sblk.b_size = SBLOCKSIZE; 4728fae3551SRodney W. Grimes /* 4731c85e6a3SKirk McKusick * If not yet done, update UFS1 superblock with new wider fields. 4741c85e6a3SKirk McKusick */ 4751c85e6a3SKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC && 4761c85e6a3SKirk McKusick sblock.fs_maxbsize != sblock.fs_bsize) { 4771c85e6a3SKirk McKusick sblock.fs_maxbsize = sblock.fs_bsize; 4781c85e6a3SKirk McKusick sblock.fs_time = sblock.fs_old_time; 4791c85e6a3SKirk McKusick sblock.fs_size = sblock.fs_old_size; 4801c85e6a3SKirk McKusick sblock.fs_dsize = sblock.fs_old_dsize; 4811c85e6a3SKirk McKusick sblock.fs_csaddr = sblock.fs_old_csaddr; 4821c85e6a3SKirk McKusick sblock.fs_cstotal.cs_ndir = sblock.fs_old_cstotal.cs_ndir; 4831c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nbfree = sblock.fs_old_cstotal.cs_nbfree; 4841c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nifree = sblock.fs_old_cstotal.cs_nifree; 4851c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nffree = sblock.fs_old_cstotal.cs_nffree; 4861c85e6a3SKirk McKusick } 4878fae3551SRodney W. Grimes havesb = 1; 4888fae3551SRodney W. Grimes return (1); 4898fae3551SRodney W. Grimes } 4908fae3551SRodney W. Grimes 491d164d805SIan Dowse void 492b70cd7eeSWarner Losh sblock_init(void) 49338375c40SKirk McKusick { 49438375c40SKirk McKusick 495c5d476c9SKirk McKusick fsreadfd = -1; 49638375c40SKirk McKusick fswritefd = -1; 49738375c40SKirk McKusick fsmodified = 0; 49838375c40SKirk McKusick lfdir = 0; 499ed75b5a1SKirk McKusick initbarea(&sblk, BT_SUPERBLK); 50081fbded2SKirk McKusick sblk.b_un.b_buf = Malloc(SBLOCKSIZE); 50123c8b19cSKirk McKusick if (sblk.b_un.b_buf == NULL) 50238375c40SKirk McKusick errx(EEXIT, "cannot allocate space for superblock"); 50338375c40SKirk McKusick dev_bsize = secsize = DEV_BSIZE; 50438375c40SKirk McKusick } 50577b63aa0SKirk McKusick 50677b63aa0SKirk McKusick /* 50777b63aa0SKirk McKusick * Calculate a prototype superblock based on information in the boot area. 50877b63aa0SKirk McKusick * When done the cgsblock macro can be calculated and the fs_ncg field 50977b63aa0SKirk McKusick * can be used. Do NOT attempt to use other macros without verifying that 51077b63aa0SKirk McKusick * their needed information is available! 51177b63aa0SKirk McKusick */ 51277b63aa0SKirk McKusick static int 51377b63aa0SKirk McKusick calcsb(char *dev, int devfd, struct fs *fs) 51477b63aa0SKirk McKusick { 515855662c6SKirk McKusick struct fsrecovery *fsr; 516855662c6SKirk McKusick char *fsrbuf; 517855662c6SKirk McKusick u_int secsize; 51877b63aa0SKirk McKusick 51977b63aa0SKirk McKusick /* 52077b63aa0SKirk McKusick * We need fragments-per-group and the partition-size. 52177b63aa0SKirk McKusick * 52277b63aa0SKirk McKusick * Newfs stores these details at the end of the boot block area 52377b63aa0SKirk McKusick * at the start of the filesystem partition. If they have been 52477b63aa0SKirk McKusick * overwritten by a boot block, we fail. But usually they are 52577b63aa0SKirk McKusick * there and we can use them. 52677b63aa0SKirk McKusick */ 527855662c6SKirk McKusick if (ioctl(devfd, DIOCGSECTORSIZE, &secsize) == -1) 528855662c6SKirk McKusick return (0); 529855662c6SKirk McKusick fsrbuf = Malloc(secsize); 530855662c6SKirk McKusick if (fsrbuf == NULL) 531855662c6SKirk McKusick errx(EEXIT, "calcsb: cannot allocate recovery buffer"); 532855662c6SKirk McKusick if (blread(devfd, fsrbuf, 53315da40b0SEric van Gyzen (SBLOCK_UFS2 - secsize) / dev_bsize, secsize) != 0) { 53415da40b0SEric van Gyzen free(fsrbuf); 535855662c6SKirk McKusick return (0); 53615da40b0SEric van Gyzen } 537855662c6SKirk McKusick fsr = (struct fsrecovery *)&fsrbuf[secsize - sizeof *fsr]; 53815da40b0SEric van Gyzen if (fsr->fsr_magic != FS_UFS2_MAGIC) { 53915da40b0SEric van Gyzen free(fsrbuf); 54077b63aa0SKirk McKusick return (0); 54115da40b0SEric van Gyzen } 54277b63aa0SKirk McKusick memset(fs, 0, sizeof(struct fs)); 543855662c6SKirk McKusick fs->fs_fpg = fsr->fsr_fpg; 544855662c6SKirk McKusick fs->fs_fsbtodb = fsr->fsr_fsbtodb; 545855662c6SKirk McKusick fs->fs_sblkno = fsr->fsr_sblkno; 546855662c6SKirk McKusick fs->fs_magic = fsr->fsr_magic; 547855662c6SKirk McKusick fs->fs_ncg = fsr->fsr_ncg; 548855662c6SKirk McKusick free(fsrbuf); 54977b63aa0SKirk McKusick return (1); 55077b63aa0SKirk McKusick } 55177b63aa0SKirk McKusick 55277b63aa0SKirk McKusick /* 55377b63aa0SKirk McKusick * Check to see if recovery information exists. 554855662c6SKirk McKusick * Return 1 if it exists or cannot be created. 555855662c6SKirk McKusick * Return 0 if it does not exist and can be created. 55677b63aa0SKirk McKusick */ 55777b63aa0SKirk McKusick static int 55877b63aa0SKirk McKusick chkrecovery(int devfd) 55977b63aa0SKirk McKusick { 560855662c6SKirk McKusick struct fsrecovery *fsr; 561855662c6SKirk McKusick char *fsrbuf; 5627a1c1f6aSKirk McKusick u_int secsize, rdsize; 56377b63aa0SKirk McKusick 564855662c6SKirk McKusick /* 565855662c6SKirk McKusick * Could not determine if backup material exists, so do not 566855662c6SKirk McKusick * offer to create it. 567855662c6SKirk McKusick */ 56815da40b0SEric van Gyzen fsrbuf = NULL; 5697a1c1f6aSKirk McKusick rdsize = sblock.fs_fsize; 570855662c6SKirk McKusick if (ioctl(devfd, DIOCGSECTORSIZE, &secsize) == -1 || 5717a1c1f6aSKirk McKusick rdsize % secsize != 0 || 5727a1c1f6aSKirk McKusick (fsrbuf = Malloc(rdsize)) == NULL || 5737a1c1f6aSKirk McKusick blread(devfd, fsrbuf, (SBLOCK_UFS2 - rdsize) / dev_bsize, 5747a1c1f6aSKirk McKusick rdsize) != 0) { 57515da40b0SEric van Gyzen free(fsrbuf); 57677b63aa0SKirk McKusick return (1); 57715da40b0SEric van Gyzen } 578855662c6SKirk McKusick /* 579855662c6SKirk McKusick * Recovery material has already been created, so do not 580855662c6SKirk McKusick * need to create it again. 581855662c6SKirk McKusick */ 5827a1c1f6aSKirk McKusick fsr = (struct fsrecovery *)&fsrbuf[rdsize - sizeof *fsr]; 583855662c6SKirk McKusick if (fsr->fsr_magic == FS_UFS2_MAGIC) { 584855662c6SKirk McKusick free(fsrbuf); 585855662c6SKirk McKusick return (1); 586855662c6SKirk McKusick } 587855662c6SKirk McKusick /* 588855662c6SKirk McKusick * Recovery material has not been created and can be if desired. 589855662c6SKirk McKusick */ 590855662c6SKirk McKusick free(fsrbuf); 591855662c6SKirk McKusick return (0); 59277b63aa0SKirk McKusick } 59377b63aa0SKirk McKusick 59477b63aa0SKirk McKusick /* 5957a1c1f6aSKirk McKusick * Read the last filesystem-size piece of the boot block, replace the 5967a1c1f6aSKirk McKusick * last 20 bytes with the recovery information, then write it back. 59777b63aa0SKirk McKusick * The recovery information only works for UFS2 filesystems. 59877b63aa0SKirk McKusick */ 59977b63aa0SKirk McKusick static void 60077b63aa0SKirk McKusick saverecovery(int readfd, int writefd) 60177b63aa0SKirk McKusick { 602855662c6SKirk McKusick struct fsrecovery *fsr; 603855662c6SKirk McKusick char *fsrbuf; 6047a1c1f6aSKirk McKusick u_int secsize, rdsize; 60577b63aa0SKirk McKusick 60615da40b0SEric van Gyzen fsrbuf = NULL; 6077a1c1f6aSKirk McKusick rdsize = sblock.fs_fsize; 60877b63aa0SKirk McKusick if (sblock.fs_magic != FS_UFS2_MAGIC || 609855662c6SKirk McKusick ioctl(readfd, DIOCGSECTORSIZE, &secsize) == -1 || 6107a1c1f6aSKirk McKusick rdsize % secsize != 0 || 6117a1c1f6aSKirk McKusick (fsrbuf = Malloc(rdsize)) == NULL || 6127a1c1f6aSKirk McKusick blread(readfd, fsrbuf, (SBLOCK_UFS2 - rdsize) / dev_bsize, 6137a1c1f6aSKirk McKusick rdsize) != 0) { 614855662c6SKirk McKusick printf("RECOVERY DATA COULD NOT BE CREATED\n"); 61515da40b0SEric van Gyzen free(fsrbuf); 61677b63aa0SKirk McKusick return; 617855662c6SKirk McKusick } 6187a1c1f6aSKirk McKusick fsr = (struct fsrecovery *)&fsrbuf[rdsize - sizeof *fsr]; 619855662c6SKirk McKusick fsr->fsr_magic = sblock.fs_magic; 620855662c6SKirk McKusick fsr->fsr_fpg = sblock.fs_fpg; 621855662c6SKirk McKusick fsr->fsr_fsbtodb = sblock.fs_fsbtodb; 622855662c6SKirk McKusick fsr->fsr_sblkno = sblock.fs_sblkno; 623855662c6SKirk McKusick fsr->fsr_ncg = sblock.fs_ncg; 6247a1c1f6aSKirk McKusick blwrite(writefd, fsrbuf, (SBLOCK_UFS2 - rdsize) / dev_bsize, rdsize); 625855662c6SKirk McKusick free(fsrbuf); 62677b63aa0SKirk McKusick } 627