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 615cc52631SKirk McKusick struct inoinfo **inphead, **inpsort; /* info about all inodes */ 62c3e9752eSKyle Evans 638fae3551SRodney W. Grimes struct bufarea asblk; 648fae3551SRodney W. Grimes #define altsblock (*asblk.b_un.b_fs) 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); 7077b63aa0SKirk McKusick 71780a5c1eSPeter Wemm /* 72780a5c1eSPeter Wemm * Read in a superblock finding an alternate if necessary. 73780a5c1eSPeter Wemm * Return 1 if successful, 0 if unsuccessful, -1 if file system 74111a5220SDavid E. O'Brien * is already clean (ckclean and preen mode only). 75780a5c1eSPeter Wemm */ 7631f4ab50SBruce Evans int 77b70cd7eeSWarner Losh setup(char *dev) 788fae3551SRodney W. Grimes { 79c0bfa109SKirk McKusick long cg, bmapsize; 8077b63aa0SKirk McKusick struct fs proto; 818fae3551SRodney W. Grimes 82c0ed8991SXin LI /* 83c0bfa109SKirk McKusick * We are expected to have an open file descriptor 84c0ed8991SXin LI */ 85c0bfa109SKirk McKusick if (fsreadfd < 0) 86c0bfa109SKirk McKusick return (0); 87c0bfa109SKirk McKusick /* 88c0bfa109SKirk McKusick * If we do not yet have a superblock, read it in looking 89c0bfa109SKirk McKusick * for alternates if necessary. 90c0bfa109SKirk McKusick */ 91c0bfa109SKirk McKusick if (havesb == 0 && readsb(1) == 0) { 92c0bfa109SKirk McKusick skipclean = 0; 93c0bfa109SKirk McKusick if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) 94c0bfa109SKirk McKusick return(0); 95c0bfa109SKirk McKusick if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) 96c0bfa109SKirk McKusick return (0); 97c0bfa109SKirk McKusick for (cg = 0; cg < proto.fs_ncg; cg++) { 98c0bfa109SKirk McKusick bflag = fsbtodb(&proto, cgsblock(&proto, cg)); 99c0bfa109SKirk McKusick if (readsb(0) != 0) 100c0bfa109SKirk McKusick break; 101c0ed8991SXin LI } 102c0bfa109SKirk McKusick if (cg >= proto.fs_ncg) { 103c0bfa109SKirk McKusick printf("SEARCH FOR ALTERNATE SUPER-BLOCK FAILED. " 104c0bfa109SKirk McKusick "YOU MUST USE THE\n-b OPTION TO FSCK TO SPECIFY " 105c0bfa109SKirk McKusick "THE LOCATION OF AN ALTERNATE\nSUPER-BLOCK TO " 106c0bfa109SKirk McKusick "SUPPLY NEEDED INFORMATION; SEE fsck_ffs(8).\n"); 107c0bfa109SKirk McKusick bflag = 0; 108c0bfa109SKirk McKusick return(0); 109c0bfa109SKirk McKusick } 110c0bfa109SKirk McKusick pwarn("USING ALTERNATE SUPERBLOCK AT %jd\n", bflag); 111c0bfa109SKirk McKusick bflag = 0; 1127578c6abSKirk McKusick } 1138fae3551SRodney W. Grimes if (preen == 0) 1148fae3551SRodney W. Grimes printf("** %s", dev); 1157578c6abSKirk McKusick if (bkgrdflag == 0 && 1165cc52631SKirk McKusick (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) { 1178fae3551SRodney W. Grimes fswritefd = -1; 1188fae3551SRodney W. Grimes if (preen) 1198fae3551SRodney W. Grimes pfatal("NO WRITE ACCESS"); 1208fae3551SRodney W. Grimes printf(" (NO WRITE)"); 1218fae3551SRodney W. Grimes } 1228fae3551SRodney W. Grimes if (preen == 0) 1238fae3551SRodney W. Grimes printf("\n"); 124c0bfa109SKirk McKusick if (sbhashfailed != 0) { 125c0bfa109SKirk McKusick pwarn("SUPERBLOCK CHECK HASH FAILED"); 126c0bfa109SKirk McKusick if (fswritefd == -1) 127c0bfa109SKirk McKusick pwarn("OPENED READONLY SO CANNOT CORRECT CHECK HASH\n"); 128c0bfa109SKirk McKusick else if (preen || reply("CORRECT CHECK HASH") != 0) { 129c0bfa109SKirk McKusick if (preen) 130c0bfa109SKirk McKusick printf(" (CORRECTED)\n"); 131c0bfa109SKirk McKusick sblock.fs_clean = 0; 132c0bfa109SKirk McKusick sbdirty(); 13377b63aa0SKirk McKusick } 1348fae3551SRodney W. Grimes } 135111a5220SDavid E. O'Brien if (skipclean && ckclean && sblock.fs_clean) { 136d33e92f9SJulian Elischer pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); 137d33e92f9SJulian Elischer return (-1); 138d33e92f9SJulian Elischer } 1398fae3551SRodney W. Grimes maxfsblock = sblock.fs_size; 1408fae3551SRodney W. Grimes maxino = sblock.fs_ncg * sblock.fs_ipg; 1418fae3551SRodney W. Grimes /* 1428fae3551SRodney W. Grimes * Check and potentially fix certain fields in the super block. 1438fae3551SRodney W. Grimes */ 1448fae3551SRodney W. Grimes if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { 1458fae3551SRodney W. Grimes pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); 1468fae3551SRodney W. Grimes if (reply("SET TO DEFAULT") == 1) { 1478fae3551SRodney W. Grimes sblock.fs_optim = FS_OPTTIME; 1488fae3551SRodney W. Grimes sbdirty(); 1498fae3551SRodney W. Grimes } 1508fae3551SRodney W. Grimes } 1518fae3551SRodney W. Grimes if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { 1528fae3551SRodney W. Grimes pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 1538fae3551SRodney W. Grimes sblock.fs_minfree); 1548fae3551SRodney W. Grimes if (reply("SET TO DEFAULT") == 1) { 1558fae3551SRodney W. Grimes sblock.fs_minfree = 10; 1568fae3551SRodney W. Grimes sbdirty(); 1578fae3551SRodney W. Grimes } 1588fae3551SRodney W. Grimes } 1591c85e6a3SKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC && 1601c85e6a3SKirk McKusick sblock.fs_old_inodefmt < FS_44INODEFMT) { 161381ee4c2SPoul-Henning Kamp pwarn("Format of file system is too old.\n"); 162381ee4c2SPoul-Henning Kamp pwarn("Must update to modern format using a version of fsck\n"); 163381ee4c2SPoul-Henning Kamp pfatal("from before 2002 with the command ``fsck -c 2''\n"); 164381ee4c2SPoul-Henning Kamp exit(EEXIT); 1658fae3551SRodney W. Grimes } 1665cc52631SKirk McKusick if ((asblk.b_flags & B_DIRTY) != 0 && !bflag) { 167780a5c1eSPeter Wemm memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize); 1688fae3551SRodney W. Grimes flush(fswritefd, &asblk); 1698fae3551SRodney W. Grimes } 17077b63aa0SKirk McKusick if (preen == 0 && yflag == 0 && sblock.fs_magic == FS_UFS2_MAGIC && 17177b63aa0SKirk McKusick fswritefd != -1 && chkrecovery(fsreadfd) == 0 && 17277b63aa0SKirk McKusick reply("SAVE DATA TO FIND ALTERNATE SUPERBLOCKS") != 0) 17377b63aa0SKirk McKusick saverecovery(fsreadfd, fswritefd); 1748fae3551SRodney W. Grimes /* 1758fae3551SRodney W. Grimes * allocate and initialize the necessary maps 1768fae3551SRodney W. Grimes */ 17789fdc4e1SMike Barcroft bmapsize = roundup(howmany(maxfsblock, CHAR_BIT), sizeof(short)); 17881fbded2SKirk McKusick blockmap = Calloc((unsigned)bmapsize, sizeof (char)); 1798fae3551SRodney W. Grimes if (blockmap == NULL) { 1808fae3551SRodney W. Grimes printf("cannot alloc %u bytes for blockmap\n", 1818fae3551SRodney W. Grimes (unsigned)bmapsize); 1828fae3551SRodney W. Grimes goto badsb; 1838fae3551SRodney W. Grimes } 184f6717697SPedro F. Giffuni inostathead = Calloc(sblock.fs_ncg, sizeof(struct inostatlist)); 185d33e92f9SJulian Elischer if (inostathead == NULL) { 186d33e92f9SJulian Elischer printf("cannot alloc %u bytes for inostathead\n", 187d33e92f9SJulian Elischer (unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg))); 1888fae3551SRodney W. Grimes goto badsb; 1898fae3551SRodney W. Grimes } 190f033309fSKirk McKusick numdirs = MAX(sblock.fs_cstotal.cs_ndir, 128); 191e50342e6SKirk McKusick dirhash = numdirs; 1928fae3551SRodney W. Grimes inplast = 0; 1938fae3551SRodney W. Grimes listmax = numdirs + 10; 194f6717697SPedro F. Giffuni inpsort = (struct inoinfo **)Calloc(listmax, sizeof(struct inoinfo *)); 195f6717697SPedro F. Giffuni inphead = (struct inoinfo **)Calloc(numdirs, sizeof(struct inoinfo *)); 1968fae3551SRodney W. Grimes if (inpsort == NULL || inphead == NULL) { 19784fc0d7eSMaxime Henrion printf("cannot alloc %ju bytes for inphead\n", 19884fc0d7eSMaxime Henrion (uintmax_t)numdirs * sizeof(struct inoinfo *)); 1998fae3551SRodney W. Grimes goto badsb; 2008fae3551SRodney W. Grimes } 2019b0f1d64SRobert Wing bufinit(); 202b1897c19SJulian Elischer if (sblock.fs_flags & FS_DOSOFTDEP) 203b1897c19SJulian Elischer usedsoftdep = 1; 204b1897c19SJulian Elischer else 205b1897c19SJulian Elischer usedsoftdep = 0; 2068fae3551SRodney W. Grimes return (1); 2078fae3551SRodney W. Grimes 2088fae3551SRodney W. Grimes badsb: 209780a5c1eSPeter Wemm ckfini(0); 2108fae3551SRodney W. Grimes return (0); 2118fae3551SRodney W. Grimes } 2128fae3551SRodney W. Grimes 2138fae3551SRodney W. Grimes /* 214*c5d476c9SKirk McKusick * Open a device or file to be checked by fsck. 215*c5d476c9SKirk McKusick */ 216*c5d476c9SKirk McKusick int 217*c5d476c9SKirk McKusick openfilesys(char *dev) 218*c5d476c9SKirk McKusick { 219*c5d476c9SKirk McKusick struct stat statb; 220*c5d476c9SKirk McKusick int saved_fsreadfd; 221*c5d476c9SKirk McKusick 222*c5d476c9SKirk McKusick if (stat(dev, &statb) < 0) { 223*c5d476c9SKirk McKusick pfatal("CANNOT STAT %s: %s\n", dev, strerror(errno)); 224*c5d476c9SKirk McKusick return (0); 225*c5d476c9SKirk McKusick } 226*c5d476c9SKirk McKusick if ((statb.st_mode & S_IFMT) != S_IFCHR && 227*c5d476c9SKirk McKusick (statb.st_mode & S_IFMT) != S_IFBLK) { 228*c5d476c9SKirk McKusick if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) { 229*c5d476c9SKirk McKusick pfatal("BACKGROUND FSCK LACKS A SNAPSHOT\n"); 230*c5d476c9SKirk McKusick exit(EEXIT); 231*c5d476c9SKirk McKusick } 232*c5d476c9SKirk McKusick if (bkgrdflag != 0) { 233*c5d476c9SKirk McKusick cursnapshot = statb.st_ino; 234*c5d476c9SKirk McKusick } else { 235*c5d476c9SKirk McKusick pfatal("%s IS NOT A DISK DEVICE\n", dev); 236*c5d476c9SKirk McKusick if (reply("CONTINUE") == 0) 237*c5d476c9SKirk McKusick return (0); 238*c5d476c9SKirk McKusick } 239*c5d476c9SKirk McKusick } 240*c5d476c9SKirk McKusick saved_fsreadfd = fsreadfd; 241*c5d476c9SKirk McKusick if ((fsreadfd = open(dev, O_RDONLY)) < 0) { 242*c5d476c9SKirk McKusick fsreadfd = saved_fsreadfd; 243*c5d476c9SKirk McKusick pfatal("CANNOT OPEN %s: %s\n", dev, strerror(errno)); 244*c5d476c9SKirk McKusick return (0); 245*c5d476c9SKirk McKusick } 246*c5d476c9SKirk McKusick if (saved_fsreadfd != -1) 247*c5d476c9SKirk McKusick close(saved_fsreadfd); 248*c5d476c9SKirk McKusick return (1); 249*c5d476c9SKirk McKusick } 250*c5d476c9SKirk McKusick 251*c5d476c9SKirk McKusick /* 2528fae3551SRodney W. Grimes * Read in the super block and its summary info. 2538fae3551SRodney W. Grimes */ 25438375c40SKirk McKusick int 255b70cd7eeSWarner Losh readsb(int listerr) 2568fae3551SRodney W. Grimes { 257dffce215SKirk McKusick off_t super; 258dffce215SKirk McKusick int bad, ret; 259dffce215SKirk McKusick struct fs *fs; 2608fae3551SRodney W. Grimes 261c0bfa109SKirk McKusick super = bflag ? bflag * dev_bsize : 262c0bfa109SKirk McKusick sbhashfailed ? STDSB_NOHASHFAIL_NOMSG : STDSB_NOMSG; 263ed75b5a1SKirk McKusick readcnt[sblk.b_type]++; 264c0bfa109SKirk McKusick while ((ret = sbget(fsreadfd, &fs, super)) != 0) { 265dffce215SKirk McKusick switch (ret) { 266c0bfa109SKirk McKusick case EINTEGRITY: 267c0bfa109SKirk McKusick if (bflag || super == STDSB_NOHASHFAIL_NOMSG) 268038c170fSKirk McKusick return (0); 269c0bfa109SKirk McKusick super = STDSB_NOHASHFAIL_NOMSG; 270c0bfa109SKirk McKusick sbhashfailed = 1; 271c0bfa109SKirk McKusick continue; 272dffce215SKirk McKusick case ENOENT: 273dffce215SKirk McKusick if (bflag) 274e8337044SChuck Silvers printf("%jd is not a file system " 275dffce215SKirk McKusick "superblock\n", super / dev_bsize); 276dffce215SKirk McKusick else 277e8337044SChuck Silvers printf("Cannot find file system " 278dffce215SKirk McKusick "superblock\n"); 279f033309fSKirk McKusick return (0); 280dffce215SKirk McKusick case EIO: 281dffce215SKirk McKusick default: 282e8337044SChuck Silvers printf("I/O error reading %jd\n", 283dffce215SKirk McKusick super / dev_bsize); 2841c85e6a3SKirk McKusick return (0); 2851c85e6a3SKirk McKusick } 2861c85e6a3SKirk McKusick } 287dffce215SKirk McKusick memcpy(&sblock, fs, fs->fs_sbsize); 288dffce215SKirk McKusick free(fs); 2898fae3551SRodney W. Grimes /* 2908fae3551SRodney W. Grimes * Compute block size that the file system is based on, 2918fae3551SRodney W. Grimes * according to fsbtodb, and adjust superblock block number 2928fae3551SRodney W. Grimes * so we can tell if this is an alternate later. 2938fae3551SRodney W. Grimes */ 2948fae3551SRodney W. Grimes dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 295dffce215SKirk McKusick sblk.b_bno = sblock.fs_sblockactualloc / dev_bsize; 2961c85e6a3SKirk McKusick sblk.b_size = SBLOCKSIZE; 2978fae3551SRodney W. Grimes /* 298cdd5d266SKirk McKusick * Compare all fields that should not differ in alternate super block. 2998fae3551SRodney W. Grimes * When an alternate super-block is specified this check is skipped. 3008fae3551SRodney W. Grimes */ 301e9e91828SWarner Losh if (bflag) 302e9e91828SWarner Losh goto out; 3038fae3551SRodney W. Grimes getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize); 3048fae3551SRodney W. Grimes if (asblk.b_errs) 3058fae3551SRodney W. Grimes return (0); 306e9e91828SWarner Losh bad = 0; 307e9e91828SWarner Losh #define CHK(x, y) \ 308e9e91828SWarner Losh if (altsblock.x != sblock.x) { \ 309e9e91828SWarner Losh bad++; \ 310e9e91828SWarner Losh if (listerr && debug) \ 311e9e91828SWarner Losh printf("SUPER BLOCK VS ALTERNATE MISMATCH %s: " y " vs " y "\n", \ 312e9e91828SWarner Losh #x, (intmax_t)sblock.x, (intmax_t)altsblock.x); \ 313e9e91828SWarner Losh } 314e9e91828SWarner Losh CHK(fs_sblkno, "%jd"); 315e9e91828SWarner Losh CHK(fs_cblkno, "%jd"); 316e9e91828SWarner Losh CHK(fs_iblkno, "%jd"); 317e9e91828SWarner Losh CHK(fs_dblkno, "%jd"); 318e9e91828SWarner Losh CHK(fs_ncg, "%jd"); 319e9e91828SWarner Losh CHK(fs_bsize, "%jd"); 320e9e91828SWarner Losh CHK(fs_fsize, "%jd"); 321e9e91828SWarner Losh CHK(fs_frag, "%jd"); 322e9e91828SWarner Losh CHK(fs_bmask, "%#jx"); 323e9e91828SWarner Losh CHK(fs_fmask, "%#jx"); 324e9e91828SWarner Losh CHK(fs_bshift, "%jd"); 325e9e91828SWarner Losh CHK(fs_fshift, "%jd"); 326e9e91828SWarner Losh CHK(fs_fragshift, "%jd"); 327e9e91828SWarner Losh CHK(fs_fsbtodb, "%jd"); 328e9e91828SWarner Losh CHK(fs_sbsize, "%jd"); 329e9e91828SWarner Losh CHK(fs_nindir, "%jd"); 330e9e91828SWarner Losh CHK(fs_inopb, "%jd"); 331e9e91828SWarner Losh CHK(fs_cssize, "%jd"); 332e9e91828SWarner Losh CHK(fs_ipg, "%jd"); 333e9e91828SWarner Losh CHK(fs_fpg, "%jd"); 334e9e91828SWarner Losh CHK(fs_magic, "%#jx"); 335e9e91828SWarner Losh #undef CHK 336e9e91828SWarner Losh if (bad) { 337bb10d553SWarner Losh if (listerr == 0) 338bb10d553SWarner Losh return (0); 339bb10d553SWarner Losh if (preen) 340bb10d553SWarner Losh printf("%s: ", cdevname); 341bb10d553SWarner Losh printf( 342bb10d553SWarner Losh "VALUES IN SUPER BLOCK LSB=%jd DISAGREE WITH THOSE IN\n" 343e9e91828SWarner Losh "LAST ALTERNATE LSB=%jd\n", 344bb10d553SWarner Losh sblk.b_bno, asblk.b_bno); 345bb10d553SWarner Losh if (reply("IGNORE ALTERNATE SUPER BLOCK") == 0) 3468fae3551SRodney W. Grimes return (0); 3478fae3551SRodney W. Grimes } 348f033309fSKirk McKusick out: 3491c85e6a3SKirk McKusick /* 3501c85e6a3SKirk McKusick * If not yet done, update UFS1 superblock with new wider fields. 3511c85e6a3SKirk McKusick */ 3521c85e6a3SKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC && 3531c85e6a3SKirk McKusick sblock.fs_maxbsize != sblock.fs_bsize) { 3541c85e6a3SKirk McKusick sblock.fs_maxbsize = sblock.fs_bsize; 3551c85e6a3SKirk McKusick sblock.fs_time = sblock.fs_old_time; 3561c85e6a3SKirk McKusick sblock.fs_size = sblock.fs_old_size; 3571c85e6a3SKirk McKusick sblock.fs_dsize = sblock.fs_old_dsize; 3581c85e6a3SKirk McKusick sblock.fs_csaddr = sblock.fs_old_csaddr; 3591c85e6a3SKirk McKusick sblock.fs_cstotal.cs_ndir = sblock.fs_old_cstotal.cs_ndir; 3601c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nbfree = sblock.fs_old_cstotal.cs_nbfree; 3611c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nifree = sblock.fs_old_cstotal.cs_nifree; 3621c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nffree = sblock.fs_old_cstotal.cs_nffree; 3631c85e6a3SKirk McKusick } 3648fae3551SRodney W. Grimes havesb = 1; 3658fae3551SRodney W. Grimes return (1); 3668fae3551SRodney W. Grimes } 3678fae3551SRodney W. Grimes 368d164d805SIan Dowse void 369b70cd7eeSWarner Losh sblock_init(void) 37038375c40SKirk McKusick { 37138375c40SKirk McKusick 372*c5d476c9SKirk McKusick fsreadfd = -1; 37338375c40SKirk McKusick fswritefd = -1; 37438375c40SKirk McKusick fsmodified = 0; 37538375c40SKirk McKusick lfdir = 0; 376ed75b5a1SKirk McKusick initbarea(&sblk, BT_SUPERBLK); 377ed75b5a1SKirk McKusick initbarea(&asblk, BT_SUPERBLK); 37881fbded2SKirk McKusick sblk.b_un.b_buf = Malloc(SBLOCKSIZE); 37981fbded2SKirk McKusick asblk.b_un.b_buf = Malloc(SBLOCKSIZE); 38038375c40SKirk McKusick if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) 38138375c40SKirk McKusick errx(EEXIT, "cannot allocate space for superblock"); 38238375c40SKirk McKusick dev_bsize = secsize = DEV_BSIZE; 38338375c40SKirk McKusick } 38477b63aa0SKirk McKusick 38577b63aa0SKirk McKusick /* 38677b63aa0SKirk McKusick * Calculate a prototype superblock based on information in the boot area. 38777b63aa0SKirk McKusick * When done the cgsblock macro can be calculated and the fs_ncg field 38877b63aa0SKirk McKusick * can be used. Do NOT attempt to use other macros without verifying that 38977b63aa0SKirk McKusick * their needed information is available! 39077b63aa0SKirk McKusick */ 39177b63aa0SKirk McKusick static int 39277b63aa0SKirk McKusick calcsb(char *dev, int devfd, struct fs *fs) 39377b63aa0SKirk McKusick { 394855662c6SKirk McKusick struct fsrecovery *fsr; 395855662c6SKirk McKusick char *fsrbuf; 396855662c6SKirk McKusick u_int secsize; 39777b63aa0SKirk McKusick 39877b63aa0SKirk McKusick /* 39977b63aa0SKirk McKusick * We need fragments-per-group and the partition-size. 40077b63aa0SKirk McKusick * 40177b63aa0SKirk McKusick * Newfs stores these details at the end of the boot block area 40277b63aa0SKirk McKusick * at the start of the filesystem partition. If they have been 40377b63aa0SKirk McKusick * overwritten by a boot block, we fail. But usually they are 40477b63aa0SKirk McKusick * there and we can use them. 40577b63aa0SKirk McKusick */ 406855662c6SKirk McKusick if (ioctl(devfd, DIOCGSECTORSIZE, &secsize) == -1) 407855662c6SKirk McKusick return (0); 408855662c6SKirk McKusick fsrbuf = Malloc(secsize); 409855662c6SKirk McKusick if (fsrbuf == NULL) 410855662c6SKirk McKusick errx(EEXIT, "calcsb: cannot allocate recovery buffer"); 411855662c6SKirk McKusick if (blread(devfd, fsrbuf, 41215da40b0SEric van Gyzen (SBLOCK_UFS2 - secsize) / dev_bsize, secsize) != 0) { 41315da40b0SEric van Gyzen free(fsrbuf); 414855662c6SKirk McKusick return (0); 41515da40b0SEric van Gyzen } 416855662c6SKirk McKusick fsr = (struct fsrecovery *)&fsrbuf[secsize - sizeof *fsr]; 41715da40b0SEric van Gyzen if (fsr->fsr_magic != FS_UFS2_MAGIC) { 41815da40b0SEric van Gyzen free(fsrbuf); 41977b63aa0SKirk McKusick return (0); 42015da40b0SEric van Gyzen } 42177b63aa0SKirk McKusick memset(fs, 0, sizeof(struct fs)); 422855662c6SKirk McKusick fs->fs_fpg = fsr->fsr_fpg; 423855662c6SKirk McKusick fs->fs_fsbtodb = fsr->fsr_fsbtodb; 424855662c6SKirk McKusick fs->fs_sblkno = fsr->fsr_sblkno; 425855662c6SKirk McKusick fs->fs_magic = fsr->fsr_magic; 426855662c6SKirk McKusick fs->fs_ncg = fsr->fsr_ncg; 427855662c6SKirk McKusick free(fsrbuf); 42877b63aa0SKirk McKusick return (1); 42977b63aa0SKirk McKusick } 43077b63aa0SKirk McKusick 43177b63aa0SKirk McKusick /* 43277b63aa0SKirk McKusick * Check to see if recovery information exists. 433855662c6SKirk McKusick * Return 1 if it exists or cannot be created. 434855662c6SKirk McKusick * Return 0 if it does not exist and can be created. 43577b63aa0SKirk McKusick */ 43677b63aa0SKirk McKusick static int 43777b63aa0SKirk McKusick chkrecovery(int devfd) 43877b63aa0SKirk McKusick { 439855662c6SKirk McKusick struct fsrecovery *fsr; 440855662c6SKirk McKusick char *fsrbuf; 4417a1c1f6aSKirk McKusick u_int secsize, rdsize; 44277b63aa0SKirk McKusick 443855662c6SKirk McKusick /* 444855662c6SKirk McKusick * Could not determine if backup material exists, so do not 445855662c6SKirk McKusick * offer to create it. 446855662c6SKirk McKusick */ 44715da40b0SEric van Gyzen fsrbuf = NULL; 4487a1c1f6aSKirk McKusick rdsize = sblock.fs_fsize; 449855662c6SKirk McKusick if (ioctl(devfd, DIOCGSECTORSIZE, &secsize) == -1 || 4507a1c1f6aSKirk McKusick rdsize % secsize != 0 || 4517a1c1f6aSKirk McKusick (fsrbuf = Malloc(rdsize)) == NULL || 4527a1c1f6aSKirk McKusick blread(devfd, fsrbuf, (SBLOCK_UFS2 - rdsize) / dev_bsize, 4537a1c1f6aSKirk McKusick rdsize) != 0) { 45415da40b0SEric van Gyzen free(fsrbuf); 45577b63aa0SKirk McKusick return (1); 45615da40b0SEric van Gyzen } 457855662c6SKirk McKusick /* 458855662c6SKirk McKusick * Recovery material has already been created, so do not 459855662c6SKirk McKusick * need to create it again. 460855662c6SKirk McKusick */ 4617a1c1f6aSKirk McKusick fsr = (struct fsrecovery *)&fsrbuf[rdsize - sizeof *fsr]; 462855662c6SKirk McKusick if (fsr->fsr_magic == FS_UFS2_MAGIC) { 463855662c6SKirk McKusick free(fsrbuf); 464855662c6SKirk McKusick return (1); 465855662c6SKirk McKusick } 466855662c6SKirk McKusick /* 467855662c6SKirk McKusick * Recovery material has not been created and can be if desired. 468855662c6SKirk McKusick */ 469855662c6SKirk McKusick free(fsrbuf); 470855662c6SKirk McKusick return (0); 47177b63aa0SKirk McKusick } 47277b63aa0SKirk McKusick 47377b63aa0SKirk McKusick /* 4747a1c1f6aSKirk McKusick * Read the last filesystem-size piece of the boot block, replace the 4757a1c1f6aSKirk McKusick * last 20 bytes with the recovery information, then write it back. 47677b63aa0SKirk McKusick * The recovery information only works for UFS2 filesystems. 47777b63aa0SKirk McKusick */ 47877b63aa0SKirk McKusick static void 47977b63aa0SKirk McKusick saverecovery(int readfd, int writefd) 48077b63aa0SKirk McKusick { 481855662c6SKirk McKusick struct fsrecovery *fsr; 482855662c6SKirk McKusick char *fsrbuf; 4837a1c1f6aSKirk McKusick u_int secsize, rdsize; 48477b63aa0SKirk McKusick 48515da40b0SEric van Gyzen fsrbuf = NULL; 4867a1c1f6aSKirk McKusick rdsize = sblock.fs_fsize; 48777b63aa0SKirk McKusick if (sblock.fs_magic != FS_UFS2_MAGIC || 488855662c6SKirk McKusick ioctl(readfd, DIOCGSECTORSIZE, &secsize) == -1 || 4897a1c1f6aSKirk McKusick rdsize % secsize != 0 || 4907a1c1f6aSKirk McKusick (fsrbuf = Malloc(rdsize)) == NULL || 4917a1c1f6aSKirk McKusick blread(readfd, fsrbuf, (SBLOCK_UFS2 - rdsize) / dev_bsize, 4927a1c1f6aSKirk McKusick rdsize) != 0) { 493855662c6SKirk McKusick printf("RECOVERY DATA COULD NOT BE CREATED\n"); 49415da40b0SEric van Gyzen free(fsrbuf); 49577b63aa0SKirk McKusick return; 496855662c6SKirk McKusick } 4977a1c1f6aSKirk McKusick fsr = (struct fsrecovery *)&fsrbuf[rdsize - sizeof *fsr]; 498855662c6SKirk McKusick fsr->fsr_magic = sblock.fs_magic; 499855662c6SKirk McKusick fsr->fsr_fpg = sblock.fs_fpg; 500855662c6SKirk McKusick fsr->fsr_fsbtodb = sblock.fs_fsbtodb; 501855662c6SKirk McKusick fsr->fsr_sblkno = sblock.fs_sblkno; 502855662c6SKirk McKusick fsr->fsr_ncg = sblock.fs_ncg; 5037a1c1f6aSKirk McKusick blwrite(writefd, fsrbuf, (SBLOCK_UFS2 - rdsize) / dev_bsize, rdsize); 504855662c6SKirk McKusick free(fsrbuf); 50577b63aa0SKirk McKusick } 506