18fae3551SRodney W. Grimes /* 28fae3551SRodney W. Grimes * Copyright (c) 1980, 1986, 1993 38fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 48fae3551SRodney W. Grimes * 58fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 68fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 78fae3551SRodney W. Grimes * are met: 88fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 98fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 108fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 118fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 128fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 13fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 148fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 158fae3551SRodney W. Grimes * without specific prior written permission. 168fae3551SRodney W. Grimes * 178fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 188fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 198fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 208fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 218fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 228fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 238fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 248fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 258fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 268fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 278fae3551SRodney W. Grimes * SUCH DAMAGE. 288fae3551SRodney W. Grimes */ 298fae3551SRodney W. Grimes 306b100474SJulian Elischer #if 0 31c69284caSDavid E. O'Brien #ifndef lint 32780a5c1eSPeter Wemm static const char sccsid[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95"; 338fae3551SRodney W. Grimes #endif /* not lint */ 34c69284caSDavid E. O'Brien #endif 35c69284caSDavid E. O'Brien #include <sys/cdefs.h> 36c69284caSDavid E. O'Brien __FBSDID("$FreeBSD$"); 378fae3551SRodney W. Grimes 388fae3551SRodney W. Grimes #include <sys/param.h> 39*855662c6SKirk 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 588fae3551SRodney W. Grimes struct bufarea asblk; 598fae3551SRodney W. Grimes #define altsblock (*asblk.b_un.b_fs) 608fae3551SRodney W. Grimes #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 618fae3551SRodney W. Grimes 6277b63aa0SKirk McKusick static int calcsb(char *dev, int devfd, struct fs *fs); 6377b63aa0SKirk McKusick static void saverecovery(int readfd, int writefd); 6477b63aa0SKirk McKusick static int chkrecovery(int devfd); 6577b63aa0SKirk McKusick 66780a5c1eSPeter Wemm /* 67780a5c1eSPeter Wemm * Read in a superblock finding an alternate if necessary. 68780a5c1eSPeter Wemm * Return 1 if successful, 0 if unsuccessful, -1 if file system 69111a5220SDavid E. O'Brien * is already clean (ckclean and preen mode only). 70780a5c1eSPeter Wemm */ 7131f4ab50SBruce Evans int 72b70cd7eeSWarner Losh setup(char *dev) 738fae3551SRodney W. Grimes { 7477b63aa0SKirk McKusick long cg, asked, i, j; 7538375c40SKirk McKusick long bmapsize; 768fae3551SRodney W. Grimes struct stat statb; 7777b63aa0SKirk McKusick struct fs proto; 78bf58d635SIan Dowse size_t size; 798fae3551SRodney W. Grimes 808fae3551SRodney W. Grimes havesb = 0; 818fae3551SRodney W. Grimes fswritefd = -1; 82142d8d2fSKirk McKusick cursnapshot = 0; 838fae3551SRodney W. Grimes if (stat(dev, &statb) < 0) { 848fae3551SRodney W. Grimes printf("Can't stat %s: %s\n", dev, strerror(errno)); 857578c6abSKirk McKusick if (bkgrdflag) { 867578c6abSKirk McKusick unlink(snapname); 877578c6abSKirk McKusick bkgrdflag = 0; 887578c6abSKirk McKusick } 898fae3551SRodney W. Grimes return (0); 908fae3551SRodney W. Grimes } 91ff180522SPoul-Henning Kamp if ((statb.st_mode & S_IFMT) != S_IFCHR && 92ff180522SPoul-Henning Kamp (statb.st_mode & S_IFMT) != S_IFBLK) { 937578c6abSKirk McKusick if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) { 947578c6abSKirk McKusick unlink(snapname); 957578c6abSKirk McKusick printf("background fsck lacks a snapshot\n"); 967578c6abSKirk McKusick exit(EEXIT); 977578c6abSKirk McKusick } 987578c6abSKirk McKusick if ((statb.st_flags & SF_SNAPSHOT) != 0 && cvtlevel == 0) { 99142d8d2fSKirk McKusick cursnapshot = statb.st_ino; 100142d8d2fSKirk McKusick } else { 1017578c6abSKirk McKusick if (cvtlevel == 0 || 1027578c6abSKirk McKusick (statb.st_flags & SF_SNAPSHOT) == 0) { 1037578c6abSKirk McKusick if (preen && bkgrdflag) { 1047578c6abSKirk McKusick unlink(snapname); 1057578c6abSKirk McKusick bkgrdflag = 0; 1067578c6abSKirk McKusick } 107ff180522SPoul-Henning Kamp pfatal("%s is not a disk device", dev); 1087578c6abSKirk McKusick if (reply("CONTINUE") == 0) { 1097578c6abSKirk McKusick if (bkgrdflag) { 1107578c6abSKirk McKusick unlink(snapname); 1117578c6abSKirk McKusick bkgrdflag = 0; 1127578c6abSKirk McKusick } 1138fae3551SRodney W. Grimes return (0); 1148fae3551SRodney W. Grimes } 1157578c6abSKirk McKusick } else { 1167578c6abSKirk McKusick if (bkgrdflag) { 1177578c6abSKirk McKusick unlink(snapname); 1187578c6abSKirk McKusick bkgrdflag = 0; 1197578c6abSKirk McKusick } 1207578c6abSKirk McKusick pfatal("cannot convert a snapshot"); 1217578c6abSKirk McKusick exit(EEXIT); 1227578c6abSKirk McKusick } 1237578c6abSKirk McKusick } 124142d8d2fSKirk McKusick } 1258fae3551SRodney W. Grimes if ((fsreadfd = open(dev, O_RDONLY)) < 0) { 1267578c6abSKirk McKusick if (bkgrdflag) { 1277578c6abSKirk McKusick unlink(snapname); 1287578c6abSKirk McKusick bkgrdflag = 0; 1297578c6abSKirk McKusick } 1308fae3551SRodney W. Grimes printf("Can't open %s: %s\n", dev, strerror(errno)); 1318fae3551SRodney W. Grimes return (0); 1328fae3551SRodney W. Grimes } 1337578c6abSKirk McKusick if (bkgrdflag) { 1347578c6abSKirk McKusick unlink(snapname); 1357578c6abSKirk McKusick size = MIBSIZE; 1367578c6abSKirk McKusick if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0|| 1377578c6abSKirk McKusick sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0|| 1387578c6abSKirk McKusick sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0|| 1397578c6abSKirk McKusick sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 || 1407578c6abSKirk McKusick sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) { 1417578c6abSKirk McKusick pfatal("kernel lacks background fsck support\n"); 1427578c6abSKirk McKusick exit(EEXIT); 1437578c6abSKirk McKusick } 144c0ed8991SXin LI /* 145c0ed8991SXin LI * When kernel is lack of runtime bgfsck superblock summary 146c0ed8991SXin LI * adjustment functionality, it does not mean we can not 147c0ed8991SXin LI * continue, as old kernels will recompute the summary at 148c0ed8991SXin LI * mount time. However, it will be an unexpected softupdates 149c0ed8991SXin LI * inconsistency if it turns out that the summary is still 150c0ed8991SXin LI * incorrect. Set a flag so subsequent operation can know 151c0ed8991SXin LI * this. 152c0ed8991SXin LI */ 153c0ed8991SXin LI bkgrdsumadj = 1; 154c0ed8991SXin LI if (sysctlnametomib("vfs.ffs.adjndir", adjndir, &size) < 0 || 155c0ed8991SXin LI sysctlnametomib("vfs.ffs.adjnbfree", adjnbfree, &size) < 0 || 156c0ed8991SXin LI sysctlnametomib("vfs.ffs.adjnifree", adjnifree, &size) < 0 || 157c0ed8991SXin LI sysctlnametomib("vfs.ffs.adjnffree", adjnffree, &size) < 0 || 158c0ed8991SXin LI sysctlnametomib("vfs.ffs.adjnumclusters", adjnumclusters, &size) < 0) { 159c0ed8991SXin LI bkgrdsumadj = 0; 160c0ed8991SXin LI pwarn("kernel lacks runtime superblock summary adjustment support"); 161c0ed8991SXin LI } 1627578c6abSKirk McKusick cmd.version = FFS_CMD_VERSION; 1637578c6abSKirk McKusick cmd.handle = fsreadfd; 1647578c6abSKirk McKusick fswritefd = -1; 1657578c6abSKirk McKusick } 1668fae3551SRodney W. Grimes if (preen == 0) 1678fae3551SRodney W. Grimes printf("** %s", dev); 1687578c6abSKirk McKusick if (bkgrdflag == 0 && 1697578c6abSKirk McKusick (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) { 1708fae3551SRodney W. Grimes fswritefd = -1; 1718fae3551SRodney W. Grimes if (preen) 1728fae3551SRodney W. Grimes pfatal("NO WRITE ACCESS"); 1738fae3551SRodney W. Grimes printf(" (NO WRITE)"); 1748fae3551SRodney W. Grimes } 1758fae3551SRodney W. Grimes if (preen == 0) 1768fae3551SRodney W. Grimes printf("\n"); 1778fae3551SRodney W. Grimes /* 1788fae3551SRodney W. Grimes * Read in the superblock, looking for alternates if necessary 1798fae3551SRodney W. Grimes */ 1808fae3551SRodney W. Grimes if (readsb(1) == 0) { 181780a5c1eSPeter Wemm skipclean = 0; 18277b63aa0SKirk McKusick if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) 1838fae3551SRodney W. Grimes return(0); 18477b63aa0SKirk McKusick if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) 1858fae3551SRodney W. Grimes return (0); 18677b63aa0SKirk McKusick for (cg = 0; cg < proto.fs_ncg; cg++) { 18777b63aa0SKirk McKusick bflag = fsbtodb(&proto, cgsblock(&proto, cg)); 18877b63aa0SKirk McKusick if (readsb(0) != 0) 18977b63aa0SKirk McKusick break; 19077b63aa0SKirk McKusick } 19177b63aa0SKirk McKusick if (cg >= proto.fs_ncg) { 19277b63aa0SKirk McKusick printf("%s %s\n%s %s\n%s %s\n", 19377b63aa0SKirk McKusick "SEARCH FOR ALTERNATE SUPER-BLOCK", 19477b63aa0SKirk McKusick "FAILED. YOU MUST USE THE", 19577b63aa0SKirk McKusick "-b OPTION TO FSCK TO SPECIFY THE", 19677b63aa0SKirk McKusick "LOCATION OF AN ALTERNATE", 19777b63aa0SKirk McKusick "SUPER-BLOCK TO SUPPLY NEEDED", 19877b63aa0SKirk McKusick "INFORMATION; SEE fsck_ffs(8)."); 19977b63aa0SKirk McKusick bflag = 0; 20077b63aa0SKirk McKusick return(0); 20177b63aa0SKirk McKusick } 20277b63aa0SKirk McKusick pwarn("USING ALTERNATE SUPERBLOCK AT %jd\n", bflag); 20377b63aa0SKirk McKusick bflag = 0; 2048fae3551SRodney W. Grimes } 205111a5220SDavid E. O'Brien if (skipclean && ckclean && sblock.fs_clean) { 206d33e92f9SJulian Elischer pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); 207d33e92f9SJulian Elischer return (-1); 208d33e92f9SJulian Elischer } 2098fae3551SRodney W. Grimes maxfsblock = sblock.fs_size; 2108fae3551SRodney W. Grimes maxino = sblock.fs_ncg * sblock.fs_ipg; 2118fae3551SRodney W. Grimes /* 2128fae3551SRodney W. Grimes * Check and potentially fix certain fields in the super block. 2138fae3551SRodney W. Grimes */ 2148fae3551SRodney W. Grimes if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { 2158fae3551SRodney W. Grimes pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); 2168fae3551SRodney W. Grimes if (reply("SET TO DEFAULT") == 1) { 2178fae3551SRodney W. Grimes sblock.fs_optim = FS_OPTTIME; 2188fae3551SRodney W. Grimes sbdirty(); 2198fae3551SRodney W. Grimes } 2208fae3551SRodney W. Grimes } 2218fae3551SRodney W. Grimes if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { 2228fae3551SRodney W. Grimes pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 2238fae3551SRodney W. Grimes sblock.fs_minfree); 2248fae3551SRodney W. Grimes if (reply("SET TO DEFAULT") == 1) { 2258fae3551SRodney W. Grimes sblock.fs_minfree = 10; 2268fae3551SRodney W. Grimes sbdirty(); 2278fae3551SRodney W. Grimes } 2288fae3551SRodney W. Grimes } 2291c85e6a3SKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC && 2301c85e6a3SKirk McKusick sblock.fs_old_inodefmt < FS_44INODEFMT) { 231381ee4c2SPoul-Henning Kamp pwarn("Format of file system is too old.\n"); 232381ee4c2SPoul-Henning Kamp pwarn("Must update to modern format using a version of fsck\n"); 233381ee4c2SPoul-Henning Kamp pfatal("from before 2002 with the command ``fsck -c 2''\n"); 234381ee4c2SPoul-Henning Kamp exit(EEXIT); 2358fae3551SRodney W. Grimes } 236780a5c1eSPeter Wemm if (asblk.b_dirty && !bflag) { 237780a5c1eSPeter Wemm memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize); 2388fae3551SRodney W. Grimes flush(fswritefd, &asblk); 2398fae3551SRodney W. Grimes } 24077b63aa0SKirk McKusick if (preen == 0 && yflag == 0 && sblock.fs_magic == FS_UFS2_MAGIC && 24177b63aa0SKirk McKusick fswritefd != -1 && chkrecovery(fsreadfd) == 0 && 24277b63aa0SKirk McKusick reply("SAVE DATA TO FIND ALTERNATE SUPERBLOCKS") != 0) 24377b63aa0SKirk McKusick saverecovery(fsreadfd, fswritefd); 2448fae3551SRodney W. Grimes /* 2458fae3551SRodney W. Grimes * read in the summary info. 2468fae3551SRodney W. Grimes */ 2478fae3551SRodney W. Grimes asked = 0; 24881fbded2SKirk McKusick sblock.fs_csp = Calloc(1, sblock.fs_cssize); 24996e3efc0SColin Percival if (sblock.fs_csp == NULL) { 25096e3efc0SColin Percival printf("cannot alloc %u bytes for cg summary info\n", 25196e3efc0SColin Percival (unsigned)sblock.fs_cssize); 25296e3efc0SColin Percival goto badsb; 25396e3efc0SColin Percival } 2548fae3551SRodney W. Grimes for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 2551120faabSMarcelo Araujo size = MIN(sblock.fs_cssize - i, sblock.fs_bsize); 256ed75b5a1SKirk McKusick readcnt[sblk.b_type]++; 257aef8d244SPawel Jakub Dawidek if (blread(fsreadfd, (char *)sblock.fs_csp + i, 2588fae3551SRodney W. Grimes fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 2598fae3551SRodney W. Grimes size) != 0 && !asked) { 2608fae3551SRodney W. Grimes pfatal("BAD SUMMARY INFORMATION"); 261b1897c19SJulian Elischer if (reply("CONTINUE") == 0) { 262b1897c19SJulian Elischer ckfini(0); 263780a5c1eSPeter Wemm exit(EEXIT); 264b1897c19SJulian Elischer } 2658fae3551SRodney W. Grimes asked++; 2668fae3551SRodney W. Grimes } 2678fae3551SRodney W. Grimes } 2688fae3551SRodney W. Grimes /* 2698fae3551SRodney W. Grimes * allocate and initialize the necessary maps 2708fae3551SRodney W. Grimes */ 27189fdc4e1SMike Barcroft bmapsize = roundup(howmany(maxfsblock, CHAR_BIT), sizeof(short)); 27281fbded2SKirk McKusick blockmap = Calloc((unsigned)bmapsize, sizeof (char)); 2738fae3551SRodney W. Grimes if (blockmap == NULL) { 2748fae3551SRodney W. Grimes printf("cannot alloc %u bytes for blockmap\n", 2758fae3551SRodney W. Grimes (unsigned)bmapsize); 2768fae3551SRodney W. Grimes goto badsb; 2778fae3551SRodney W. Grimes } 278f6717697SPedro F. Giffuni inostathead = Calloc(sblock.fs_ncg, sizeof(struct inostatlist)); 279d33e92f9SJulian Elischer if (inostathead == NULL) { 280d33e92f9SJulian Elischer printf("cannot alloc %u bytes for inostathead\n", 281d33e92f9SJulian Elischer (unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg))); 2828fae3551SRodney W. Grimes goto badsb; 2838fae3551SRodney W. Grimes } 284f033309fSKirk McKusick numdirs = MAX(sblock.fs_cstotal.cs_ndir, 128); 285e50342e6SKirk McKusick dirhash = numdirs; 2868fae3551SRodney W. Grimes inplast = 0; 2878fae3551SRodney W. Grimes listmax = numdirs + 10; 288f6717697SPedro F. Giffuni inpsort = (struct inoinfo **)Calloc(listmax, sizeof(struct inoinfo *)); 289f6717697SPedro F. Giffuni inphead = (struct inoinfo **)Calloc(numdirs, sizeof(struct inoinfo *)); 2908fae3551SRodney W. Grimes if (inpsort == NULL || inphead == NULL) { 29184fc0d7eSMaxime Henrion printf("cannot alloc %ju bytes for inphead\n", 29284fc0d7eSMaxime Henrion (uintmax_t)numdirs * sizeof(struct inoinfo *)); 2938fae3551SRodney W. Grimes goto badsb; 2948fae3551SRodney W. Grimes } 2958fae3551SRodney W. Grimes bufinit(); 296b1897c19SJulian Elischer if (sblock.fs_flags & FS_DOSOFTDEP) 297b1897c19SJulian Elischer usedsoftdep = 1; 298b1897c19SJulian Elischer else 299b1897c19SJulian Elischer usedsoftdep = 0; 3008fae3551SRodney W. Grimes return (1); 3018fae3551SRodney W. Grimes 3028fae3551SRodney W. Grimes badsb: 303780a5c1eSPeter Wemm ckfini(0); 3048fae3551SRodney W. Grimes return (0); 3058fae3551SRodney W. Grimes } 3068fae3551SRodney W. Grimes 3078fae3551SRodney W. Grimes /* 3081c85e6a3SKirk McKusick * Possible superblock locations ordered from most to least likely. 3091c85e6a3SKirk McKusick */ 3101c85e6a3SKirk McKusick static int sblock_try[] = SBLOCKSEARCH; 3111c85e6a3SKirk McKusick 3123b7e1bf6SWes Peters #define BAD_MAGIC_MSG \ 3133b7e1bf6SWes Peters "The previous newfs operation on this volume did not complete.\n" \ 3143b7e1bf6SWes Peters "You must complete newfs before mounting this volume.\n" 3153b7e1bf6SWes Peters 3161c85e6a3SKirk McKusick /* 3178fae3551SRodney W. Grimes * Read in the super block and its summary info. 3188fae3551SRodney W. Grimes */ 31938375c40SKirk McKusick int 320b70cd7eeSWarner Losh readsb(int listerr) 3218fae3551SRodney W. Grimes { 3221c85e6a3SKirk McKusick ufs2_daddr_t super; 323e9e91828SWarner Losh int i, bad; 3248fae3551SRodney W. Grimes 3251c85e6a3SKirk McKusick if (bflag) { 3261c85e6a3SKirk McKusick super = bflag; 327ed75b5a1SKirk McKusick readcnt[sblk.b_type]++; 328aef8d244SPawel Jakub Dawidek if ((blread(fsreadfd, (char *)&sblock, super, (long)SBLOCKSIZE))) 3298fae3551SRodney W. Grimes return (0); 330b72ea57fSJohn Baldwin if (sblock.fs_magic == FS_BAD_MAGIC) { 3313b7e1bf6SWes Peters fprintf(stderr, BAD_MAGIC_MSG); 3323b7e1bf6SWes Peters exit(11); 3333b7e1bf6SWes Peters } 334f033309fSKirk McKusick if (sblock.fs_magic != FS_UFS1_MAGIC && 335f033309fSKirk McKusick sblock.fs_magic != FS_UFS2_MAGIC) { 3366a5972dbSKirk McKusick fprintf(stderr, "%jd is not a file system superblock\n", 337f033309fSKirk McKusick bflag); 338f033309fSKirk McKusick return (0); 339f033309fSKirk McKusick } 3401c85e6a3SKirk McKusick } else { 3411c85e6a3SKirk McKusick for (i = 0; sblock_try[i] != -1; i++) { 3421c85e6a3SKirk McKusick super = sblock_try[i] / dev_bsize; 343ed75b5a1SKirk McKusick readcnt[sblk.b_type]++; 344aef8d244SPawel Jakub Dawidek if ((blread(fsreadfd, (char *)&sblock, super, 3451c85e6a3SKirk McKusick (long)SBLOCKSIZE))) 3461c85e6a3SKirk McKusick return (0); 347b72ea57fSJohn Baldwin if (sblock.fs_magic == FS_BAD_MAGIC) { 3483b7e1bf6SWes Peters fprintf(stderr, BAD_MAGIC_MSG); 3493b7e1bf6SWes Peters exit(11); 3503b7e1bf6SWes Peters } 3511c85e6a3SKirk McKusick if ((sblock.fs_magic == FS_UFS1_MAGIC || 3521c85e6a3SKirk McKusick (sblock.fs_magic == FS_UFS2_MAGIC && 353ada981b2SKirk McKusick sblock.fs_sblockloc == sblock_try[i])) && 3541c85e6a3SKirk McKusick sblock.fs_ncg >= 1 && 3551546eccdSKirk McKusick sblock.fs_bsize >= MINBSIZE && 3568f093117SXin LI sblock.fs_sbsize >= roundup(sizeof(struct fs), dev_bsize)) 3571c85e6a3SKirk McKusick break; 3581c85e6a3SKirk McKusick } 3591c85e6a3SKirk McKusick if (sblock_try[i] == -1) { 3601c85e6a3SKirk McKusick fprintf(stderr, "Cannot find file system superblock\n"); 3611c85e6a3SKirk McKusick return (0); 3621c85e6a3SKirk McKusick } 3631c85e6a3SKirk McKusick } 3648fae3551SRodney W. Grimes /* 3658fae3551SRodney W. Grimes * Compute block size that the file system is based on, 3668fae3551SRodney W. Grimes * according to fsbtodb, and adjust superblock block number 3678fae3551SRodney W. Grimes * so we can tell if this is an alternate later. 3688fae3551SRodney W. Grimes */ 3698fae3551SRodney W. Grimes super *= dev_bsize; 3708fae3551SRodney W. Grimes dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 3718fae3551SRodney W. Grimes sblk.b_bno = super / dev_bsize; 3721c85e6a3SKirk McKusick sblk.b_size = SBLOCKSIZE; 3738fae3551SRodney W. Grimes /* 374cdd5d266SKirk McKusick * Compare all fields that should not differ in alternate super block. 3758fae3551SRodney W. Grimes * When an alternate super-block is specified this check is skipped. 3768fae3551SRodney W. Grimes */ 377e9e91828SWarner Losh if (bflag) 378e9e91828SWarner Losh goto out; 3798fae3551SRodney W. Grimes getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize); 3808fae3551SRodney W. Grimes if (asblk.b_errs) 3818fae3551SRodney W. Grimes return (0); 382e9e91828SWarner Losh bad = 0; 383e9e91828SWarner Losh #define CHK(x, y) \ 384e9e91828SWarner Losh if (altsblock.x != sblock.x) { \ 385e9e91828SWarner Losh bad++; \ 386e9e91828SWarner Losh if (listerr && debug) \ 387e9e91828SWarner Losh printf("SUPER BLOCK VS ALTERNATE MISMATCH %s: " y " vs " y "\n", \ 388e9e91828SWarner Losh #x, (intmax_t)sblock.x, (intmax_t)altsblock.x); \ 389e9e91828SWarner Losh } 390e9e91828SWarner Losh CHK(fs_sblkno, "%jd"); 391e9e91828SWarner Losh CHK(fs_cblkno, "%jd"); 392e9e91828SWarner Losh CHK(fs_iblkno, "%jd"); 393e9e91828SWarner Losh CHK(fs_dblkno, "%jd"); 394e9e91828SWarner Losh CHK(fs_ncg, "%jd"); 395e9e91828SWarner Losh CHK(fs_bsize, "%jd"); 396e9e91828SWarner Losh CHK(fs_fsize, "%jd"); 397e9e91828SWarner Losh CHK(fs_frag, "%jd"); 398e9e91828SWarner Losh CHK(fs_bmask, "%#jx"); 399e9e91828SWarner Losh CHK(fs_fmask, "%#jx"); 400e9e91828SWarner Losh CHK(fs_bshift, "%jd"); 401e9e91828SWarner Losh CHK(fs_fshift, "%jd"); 402e9e91828SWarner Losh CHK(fs_fragshift, "%jd"); 403e9e91828SWarner Losh CHK(fs_fsbtodb, "%jd"); 404e9e91828SWarner Losh CHK(fs_sbsize, "%jd"); 405e9e91828SWarner Losh CHK(fs_nindir, "%jd"); 406e9e91828SWarner Losh CHK(fs_inopb, "%jd"); 407e9e91828SWarner Losh CHK(fs_cssize, "%jd"); 408e9e91828SWarner Losh CHK(fs_ipg, "%jd"); 409e9e91828SWarner Losh CHK(fs_fpg, "%jd"); 410e9e91828SWarner Losh CHK(fs_magic, "%#jx"); 411e9e91828SWarner Losh #undef CHK 412e9e91828SWarner Losh if (bad) { 413bb10d553SWarner Losh if (listerr == 0) 414bb10d553SWarner Losh return (0); 415bb10d553SWarner Losh if (preen) 416bb10d553SWarner Losh printf("%s: ", cdevname); 417bb10d553SWarner Losh printf( 418bb10d553SWarner Losh "VALUES IN SUPER BLOCK LSB=%jd DISAGREE WITH THOSE IN\n" 419e9e91828SWarner Losh "LAST ALTERNATE LSB=%jd\n", 420bb10d553SWarner Losh sblk.b_bno, asblk.b_bno); 421bb10d553SWarner Losh if (reply("IGNORE ALTERNATE SUPER BLOCK") == 0) 4228fae3551SRodney W. Grimes return (0); 4238fae3551SRodney W. Grimes } 424f033309fSKirk McKusick out: 4251c85e6a3SKirk McKusick /* 4261c85e6a3SKirk McKusick * If not yet done, update UFS1 superblock with new wider fields. 4271c85e6a3SKirk McKusick */ 4281c85e6a3SKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC && 4291c85e6a3SKirk McKusick sblock.fs_maxbsize != sblock.fs_bsize) { 4301c85e6a3SKirk McKusick sblock.fs_maxbsize = sblock.fs_bsize; 4311c85e6a3SKirk McKusick sblock.fs_time = sblock.fs_old_time; 4321c85e6a3SKirk McKusick sblock.fs_size = sblock.fs_old_size; 4331c85e6a3SKirk McKusick sblock.fs_dsize = sblock.fs_old_dsize; 4341c85e6a3SKirk McKusick sblock.fs_csaddr = sblock.fs_old_csaddr; 4351c85e6a3SKirk McKusick sblock.fs_cstotal.cs_ndir = sblock.fs_old_cstotal.cs_ndir; 4361c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nbfree = sblock.fs_old_cstotal.cs_nbfree; 4371c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nifree = sblock.fs_old_cstotal.cs_nifree; 4381c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nffree = sblock.fs_old_cstotal.cs_nffree; 4391c85e6a3SKirk McKusick } 4408fae3551SRodney W. Grimes havesb = 1; 4418fae3551SRodney W. Grimes return (1); 4428fae3551SRodney W. Grimes } 4438fae3551SRodney W. Grimes 444d164d805SIan Dowse void 445b70cd7eeSWarner Losh sblock_init(void) 44638375c40SKirk McKusick { 44738375c40SKirk McKusick 44838375c40SKirk McKusick fswritefd = -1; 44938375c40SKirk McKusick fsmodified = 0; 45038375c40SKirk McKusick lfdir = 0; 451ed75b5a1SKirk McKusick initbarea(&sblk, BT_SUPERBLK); 452ed75b5a1SKirk McKusick initbarea(&asblk, BT_SUPERBLK); 45381fbded2SKirk McKusick sblk.b_un.b_buf = Malloc(SBLOCKSIZE); 45481fbded2SKirk McKusick asblk.b_un.b_buf = Malloc(SBLOCKSIZE); 45538375c40SKirk McKusick if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) 45638375c40SKirk McKusick errx(EEXIT, "cannot allocate space for superblock"); 45738375c40SKirk McKusick dev_bsize = secsize = DEV_BSIZE; 45838375c40SKirk McKusick } 45977b63aa0SKirk McKusick 46077b63aa0SKirk McKusick /* 46177b63aa0SKirk McKusick * Calculate a prototype superblock based on information in the boot area. 46277b63aa0SKirk McKusick * When done the cgsblock macro can be calculated and the fs_ncg field 46377b63aa0SKirk McKusick * can be used. Do NOT attempt to use other macros without verifying that 46477b63aa0SKirk McKusick * their needed information is available! 46577b63aa0SKirk McKusick */ 46677b63aa0SKirk McKusick static int 46777b63aa0SKirk McKusick calcsb(char *dev, int devfd, struct fs *fs) 46877b63aa0SKirk McKusick { 469*855662c6SKirk McKusick struct fsrecovery *fsr; 470*855662c6SKirk McKusick char *fsrbuf; 471*855662c6SKirk McKusick u_int secsize; 47277b63aa0SKirk McKusick 47377b63aa0SKirk McKusick /* 47477b63aa0SKirk McKusick * We need fragments-per-group and the partition-size. 47577b63aa0SKirk McKusick * 47677b63aa0SKirk McKusick * Newfs stores these details at the end of the boot block area 47777b63aa0SKirk McKusick * at the start of the filesystem partition. If they have been 47877b63aa0SKirk McKusick * overwritten by a boot block, we fail. But usually they are 47977b63aa0SKirk McKusick * there and we can use them. 48077b63aa0SKirk McKusick */ 481*855662c6SKirk McKusick if (ioctl(devfd, DIOCGSECTORSIZE, &secsize) == -1) 482*855662c6SKirk McKusick return (0); 483*855662c6SKirk McKusick fsrbuf = Malloc(secsize); 484*855662c6SKirk McKusick if (fsrbuf == NULL) 485*855662c6SKirk McKusick errx(EEXIT, "calcsb: cannot allocate recovery buffer"); 486*855662c6SKirk McKusick if (blread(devfd, fsrbuf, 487*855662c6SKirk McKusick (SBLOCK_UFS2 - secsize) / dev_bsize, secsize) != 0) 488*855662c6SKirk McKusick return (0); 489*855662c6SKirk McKusick fsr = (struct fsrecovery *)&fsrbuf[secsize - sizeof *fsr]; 490*855662c6SKirk McKusick if (fsr->fsr_magic != FS_UFS2_MAGIC) 49177b63aa0SKirk McKusick return (0); 49277b63aa0SKirk McKusick memset(fs, 0, sizeof(struct fs)); 493*855662c6SKirk McKusick fs->fs_fpg = fsr->fsr_fpg; 494*855662c6SKirk McKusick fs->fs_fsbtodb = fsr->fsr_fsbtodb; 495*855662c6SKirk McKusick fs->fs_sblkno = fsr->fsr_sblkno; 496*855662c6SKirk McKusick fs->fs_magic = fsr->fsr_magic; 497*855662c6SKirk McKusick fs->fs_ncg = fsr->fsr_ncg; 498*855662c6SKirk McKusick free(fsrbuf); 49977b63aa0SKirk McKusick return (1); 50077b63aa0SKirk McKusick } 50177b63aa0SKirk McKusick 50277b63aa0SKirk McKusick /* 50377b63aa0SKirk McKusick * Check to see if recovery information exists. 504*855662c6SKirk McKusick * Return 1 if it exists or cannot be created. 505*855662c6SKirk McKusick * Return 0 if it does not exist and can be created. 50677b63aa0SKirk McKusick */ 50777b63aa0SKirk McKusick static int 50877b63aa0SKirk McKusick chkrecovery(int devfd) 50977b63aa0SKirk McKusick { 510*855662c6SKirk McKusick struct fsrecovery *fsr; 511*855662c6SKirk McKusick char *fsrbuf; 512*855662c6SKirk McKusick u_int secsize; 51377b63aa0SKirk McKusick 514*855662c6SKirk McKusick /* 515*855662c6SKirk McKusick * Could not determine if backup material exists, so do not 516*855662c6SKirk McKusick * offer to create it. 517*855662c6SKirk McKusick */ 518*855662c6SKirk McKusick if (ioctl(devfd, DIOCGSECTORSIZE, &secsize) == -1 || 519*855662c6SKirk McKusick (fsrbuf = Malloc(secsize)) == NULL || 520*855662c6SKirk McKusick blread(devfd, fsrbuf, (SBLOCK_UFS2 - secsize) / dev_bsize, 521*855662c6SKirk McKusick secsize) != 0) 52277b63aa0SKirk McKusick return (1); 523*855662c6SKirk McKusick /* 524*855662c6SKirk McKusick * Recovery material has already been created, so do not 525*855662c6SKirk McKusick * need to create it again. 526*855662c6SKirk McKusick */ 527*855662c6SKirk McKusick fsr = (struct fsrecovery *)&fsrbuf[secsize - sizeof *fsr]; 528*855662c6SKirk McKusick if (fsr->fsr_magic == FS_UFS2_MAGIC) { 529*855662c6SKirk McKusick free(fsrbuf); 530*855662c6SKirk McKusick return (1); 531*855662c6SKirk McKusick } 532*855662c6SKirk McKusick /* 533*855662c6SKirk McKusick * Recovery material has not been created and can be if desired. 534*855662c6SKirk McKusick */ 535*855662c6SKirk McKusick free(fsrbuf); 536*855662c6SKirk McKusick return (0); 53777b63aa0SKirk McKusick } 53877b63aa0SKirk McKusick 53977b63aa0SKirk McKusick /* 54077b63aa0SKirk McKusick * Read the last sector of the boot block, replace the last 54177b63aa0SKirk McKusick * 20 bytes with the recovery information, then write it back. 54277b63aa0SKirk McKusick * The recovery information only works for UFS2 filesystems. 54377b63aa0SKirk McKusick */ 54477b63aa0SKirk McKusick static void 54577b63aa0SKirk McKusick saverecovery(int readfd, int writefd) 54677b63aa0SKirk McKusick { 547*855662c6SKirk McKusick struct fsrecovery *fsr; 548*855662c6SKirk McKusick char *fsrbuf; 549*855662c6SKirk McKusick u_int secsize; 55077b63aa0SKirk McKusick 55177b63aa0SKirk McKusick if (sblock.fs_magic != FS_UFS2_MAGIC || 552*855662c6SKirk McKusick ioctl(readfd, DIOCGSECTORSIZE, &secsize) == -1 || 553*855662c6SKirk McKusick (fsrbuf = Malloc(secsize)) == NULL || 554*855662c6SKirk McKusick blread(readfd, fsrbuf, (SBLOCK_UFS2 - secsize) / dev_bsize, 555*855662c6SKirk McKusick secsize) != 0) { 556*855662c6SKirk McKusick printf("RECOVERY DATA COULD NOT BE CREATED\n"); 55777b63aa0SKirk McKusick return; 558*855662c6SKirk McKusick } 559*855662c6SKirk McKusick fsr = (struct fsrecovery *)&fsrbuf[secsize - sizeof *fsr]; 560*855662c6SKirk McKusick fsr->fsr_magic = sblock.fs_magic; 561*855662c6SKirk McKusick fsr->fsr_fpg = sblock.fs_fpg; 562*855662c6SKirk McKusick fsr->fsr_fsbtodb = sblock.fs_fsbtodb; 563*855662c6SKirk McKusick fsr->fsr_sblkno = sblock.fs_sblkno; 564*855662c6SKirk McKusick fsr->fsr_ncg = sblock.fs_ncg; 565*855662c6SKirk McKusick blwrite(writefd, fsrbuf, (SBLOCK_UFS2 - secsize) / secsize, secsize); 566*855662c6SKirk McKusick free(fsrbuf); 56777b63aa0SKirk McKusick } 568