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. 138fae3551SRodney W. Grimes * 4. 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> 398fae3551SRodney W. Grimes #include <sys/stat.h> 40b35e6950SBosko Milekic #define FSTYPENAMES 418fae3551SRodney W. Grimes #include <sys/disklabel.h> 428fae3551SRodney W. Grimes #include <sys/file.h> 43bf58d635SIan Dowse #include <sys/sysctl.h> 44780a5c1eSPeter Wemm 45780a5c1eSPeter Wemm #include <ufs/ufs/dinode.h> 46780a5c1eSPeter Wemm #include <ufs/ffs/fs.h> 47780a5c1eSPeter Wemm 48780a5c1eSPeter Wemm #include <ctype.h> 49780a5c1eSPeter Wemm #include <err.h> 508fae3551SRodney W. Grimes #include <errno.h> 5189fdc4e1SMike Barcroft #include <limits.h> 5284fc0d7eSMaxime Henrion #include <stdint.h> 538fae3551SRodney W. Grimes #include <string.h> 54780a5c1eSPeter Wemm 558fae3551SRodney W. Grimes #include "fsck.h" 568fae3551SRodney W. Grimes 578fae3551SRodney W. Grimes struct bufarea asblk; 588fae3551SRodney W. Grimes #define altsblock (*asblk.b_un.b_fs) 598fae3551SRodney W. Grimes #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 608fae3551SRodney W. Grimes 61599304a4SPoul-Henning Kamp static void badsb(int listerr, const char *s); 62b70cd7eeSWarner Losh static int calcsb(char *dev, int devfd, struct fs *fs); 63b70cd7eeSWarner Losh static struct disklabel *getdisklabel(char *s, int fd); 648fae3551SRodney W. Grimes 65780a5c1eSPeter Wemm /* 66780a5c1eSPeter Wemm * Read in a superblock finding an alternate if necessary. 67780a5c1eSPeter Wemm * Return 1 if successful, 0 if unsuccessful, -1 if file system 68780a5c1eSPeter Wemm * is already clean (preen mode only). 69780a5c1eSPeter Wemm */ 7031f4ab50SBruce Evans int 71b70cd7eeSWarner Losh setup(char *dev) 728fae3551SRodney W. Grimes { 73bf58d635SIan Dowse long cg, asked, i, j; 7438375c40SKirk McKusick long bmapsize; 758fae3551SRodney W. Grimes struct stat statb; 768fae3551SRodney W. Grimes struct fs proto; 77bf58d635SIan Dowse size_t size; 788fae3551SRodney W. Grimes 798fae3551SRodney W. Grimes havesb = 0; 808fae3551SRodney W. Grimes fswritefd = -1; 81142d8d2fSKirk McKusick cursnapshot = 0; 828fae3551SRodney W. Grimes if (stat(dev, &statb) < 0) { 838fae3551SRodney W. Grimes printf("Can't stat %s: %s\n", dev, strerror(errno)); 847578c6abSKirk McKusick if (bkgrdflag) { 857578c6abSKirk McKusick unlink(snapname); 867578c6abSKirk McKusick bkgrdflag = 0; 877578c6abSKirk McKusick } 888fae3551SRodney W. Grimes return (0); 898fae3551SRodney W. Grimes } 90ff180522SPoul-Henning Kamp if ((statb.st_mode & S_IFMT) != S_IFCHR && 91ff180522SPoul-Henning Kamp (statb.st_mode & S_IFMT) != S_IFBLK) { 927578c6abSKirk McKusick if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) { 937578c6abSKirk McKusick unlink(snapname); 947578c6abSKirk McKusick printf("background fsck lacks a snapshot\n"); 957578c6abSKirk McKusick exit(EEXIT); 967578c6abSKirk McKusick } 977578c6abSKirk McKusick if ((statb.st_flags & SF_SNAPSHOT) != 0 && cvtlevel == 0) { 98142d8d2fSKirk McKusick cursnapshot = statb.st_ino; 99142d8d2fSKirk McKusick } else { 1007578c6abSKirk McKusick if (cvtlevel == 0 || 1017578c6abSKirk McKusick (statb.st_flags & SF_SNAPSHOT) == 0) { 1027578c6abSKirk McKusick if (preen && bkgrdflag) { 1037578c6abSKirk McKusick unlink(snapname); 1047578c6abSKirk McKusick bkgrdflag = 0; 1057578c6abSKirk McKusick } 106ff180522SPoul-Henning Kamp pfatal("%s is not a disk device", dev); 1077578c6abSKirk McKusick if (reply("CONTINUE") == 0) { 1087578c6abSKirk McKusick if (bkgrdflag) { 1097578c6abSKirk McKusick unlink(snapname); 1107578c6abSKirk McKusick bkgrdflag = 0; 1117578c6abSKirk McKusick } 1128fae3551SRodney W. Grimes return (0); 1138fae3551SRodney W. Grimes } 1147578c6abSKirk McKusick } else { 1157578c6abSKirk McKusick if (bkgrdflag) { 1167578c6abSKirk McKusick unlink(snapname); 1177578c6abSKirk McKusick bkgrdflag = 0; 1187578c6abSKirk McKusick } 1197578c6abSKirk McKusick pfatal("cannot convert a snapshot"); 1207578c6abSKirk McKusick exit(EEXIT); 1217578c6abSKirk McKusick } 1227578c6abSKirk McKusick } 123142d8d2fSKirk McKusick } 1248fae3551SRodney W. Grimes if ((fsreadfd = open(dev, O_RDONLY)) < 0) { 1257578c6abSKirk McKusick if (bkgrdflag) { 1267578c6abSKirk McKusick unlink(snapname); 1277578c6abSKirk McKusick bkgrdflag = 0; 1287578c6abSKirk McKusick } 1298fae3551SRodney W. Grimes printf("Can't open %s: %s\n", dev, strerror(errno)); 1308fae3551SRodney W. Grimes return (0); 1318fae3551SRodney W. Grimes } 1327578c6abSKirk McKusick if (bkgrdflag) { 1337578c6abSKirk McKusick unlink(snapname); 1347578c6abSKirk McKusick size = MIBSIZE; 1357578c6abSKirk McKusick if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0|| 1367578c6abSKirk McKusick sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0|| 1377578c6abSKirk McKusick sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0|| 1387578c6abSKirk McKusick sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 || 1397578c6abSKirk McKusick sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) { 1407578c6abSKirk McKusick pfatal("kernel lacks background fsck support\n"); 1417578c6abSKirk McKusick exit(EEXIT); 1427578c6abSKirk McKusick } 143c0ed8991SXin LI /* 144c0ed8991SXin LI * When kernel is lack of runtime bgfsck superblock summary 145c0ed8991SXin LI * adjustment functionality, it does not mean we can not 146c0ed8991SXin LI * continue, as old kernels will recompute the summary at 147c0ed8991SXin LI * mount time. However, it will be an unexpected softupdates 148c0ed8991SXin LI * inconsistency if it turns out that the summary is still 149c0ed8991SXin LI * incorrect. Set a flag so subsequent operation can know 150c0ed8991SXin LI * this. 151c0ed8991SXin LI */ 152c0ed8991SXin LI bkgrdsumadj = 1; 153c0ed8991SXin LI if (sysctlnametomib("vfs.ffs.adjndir", adjndir, &size) < 0 || 154c0ed8991SXin LI sysctlnametomib("vfs.ffs.adjnbfree", adjnbfree, &size) < 0 || 155c0ed8991SXin LI sysctlnametomib("vfs.ffs.adjnifree", adjnifree, &size) < 0 || 156c0ed8991SXin LI sysctlnametomib("vfs.ffs.adjnffree", adjnffree, &size) < 0 || 157c0ed8991SXin LI sysctlnametomib("vfs.ffs.adjnumclusters", adjnumclusters, &size) < 0) { 158c0ed8991SXin LI bkgrdsumadj = 0; 159c0ed8991SXin LI pwarn("kernel lacks runtime superblock summary adjustment support"); 160c0ed8991SXin LI } 1617578c6abSKirk McKusick cmd.version = FFS_CMD_VERSION; 1627578c6abSKirk McKusick cmd.handle = fsreadfd; 1637578c6abSKirk McKusick fswritefd = -1; 1647578c6abSKirk McKusick } 1658fae3551SRodney W. Grimes if (preen == 0) 1668fae3551SRodney W. Grimes printf("** %s", dev); 1677578c6abSKirk McKusick if (bkgrdflag == 0 && 1687578c6abSKirk McKusick (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) { 1698fae3551SRodney W. Grimes fswritefd = -1; 1708fae3551SRodney W. Grimes if (preen) 1718fae3551SRodney W. Grimes pfatal("NO WRITE ACCESS"); 1728fae3551SRodney W. Grimes printf(" (NO WRITE)"); 1738fae3551SRodney W. Grimes } 1748fae3551SRodney W. Grimes if (preen == 0) 1758fae3551SRodney W. Grimes printf("\n"); 1768fae3551SRodney W. Grimes /* 1778fae3551SRodney W. Grimes * Read in the superblock, looking for alternates if necessary 1788fae3551SRodney W. Grimes */ 1798fae3551SRodney W. Grimes if (readsb(1) == 0) { 180780a5c1eSPeter Wemm skipclean = 0; 1818fae3551SRodney W. Grimes if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) 1828fae3551SRodney W. Grimes return(0); 1838fae3551SRodney W. Grimes if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) 1848fae3551SRodney W. Grimes return (0); 1858fae3551SRodney W. Grimes for (cg = 0; cg < proto.fs_ncg; cg++) { 1868fae3551SRodney W. Grimes bflag = fsbtodb(&proto, cgsblock(&proto, cg)); 1878fae3551SRodney W. Grimes if (readsb(0) != 0) 1888fae3551SRodney W. Grimes break; 1898fae3551SRodney W. Grimes } 1908fae3551SRodney W. Grimes if (cg >= proto.fs_ncg) { 1918fae3551SRodney W. Grimes printf("%s %s\n%s %s\n%s %s\n", 1928fae3551SRodney W. Grimes "SEARCH FOR ALTERNATE SUPER-BLOCK", 1938fae3551SRodney W. Grimes "FAILED. YOU MUST USE THE", 1948fae3551SRodney W. Grimes "-b OPTION TO FSCK TO SPECIFY THE", 1958fae3551SRodney W. Grimes "LOCATION OF AN ALTERNATE", 1968fae3551SRodney W. Grimes "SUPER-BLOCK TO SUPPLY NEEDED", 1978fae3551SRodney W. Grimes "INFORMATION; SEE fsck(8)."); 1981e30185aSBruce Evans bflag = 0; 1998fae3551SRodney W. Grimes return(0); 2008fae3551SRodney W. Grimes } 2018fae3551SRodney W. Grimes pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); 2021e30185aSBruce Evans bflag = 0; 2038fae3551SRodney W. Grimes } 20438375c40SKirk McKusick if (skipclean && preen && sblock.fs_clean) { 205d33e92f9SJulian Elischer pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); 206d33e92f9SJulian Elischer return (-1); 207d33e92f9SJulian Elischer } 2088fae3551SRodney W. Grimes maxfsblock = sblock.fs_size; 2098fae3551SRodney W. Grimes maxino = sblock.fs_ncg * sblock.fs_ipg; 2108fae3551SRodney W. Grimes /* 2118fae3551SRodney W. Grimes * Check and potentially fix certain fields in the super block. 2128fae3551SRodney W. Grimes */ 2138fae3551SRodney W. Grimes if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { 2148fae3551SRodney W. Grimes pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); 2158fae3551SRodney W. Grimes if (reply("SET TO DEFAULT") == 1) { 2168fae3551SRodney W. Grimes sblock.fs_optim = FS_OPTTIME; 2178fae3551SRodney W. Grimes sbdirty(); 2188fae3551SRodney W. Grimes } 2198fae3551SRodney W. Grimes } 2208fae3551SRodney W. Grimes if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { 2218fae3551SRodney W. Grimes pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 2228fae3551SRodney W. Grimes sblock.fs_minfree); 2238fae3551SRodney W. Grimes if (reply("SET TO DEFAULT") == 1) { 2248fae3551SRodney W. Grimes sblock.fs_minfree = 10; 2258fae3551SRodney W. Grimes sbdirty(); 2268fae3551SRodney W. Grimes } 2278fae3551SRodney W. Grimes } 2281c85e6a3SKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC && 2291c85e6a3SKirk McKusick sblock.fs_old_inodefmt < FS_44INODEFMT) { 230381ee4c2SPoul-Henning Kamp pwarn("Format of file system is too old.\n"); 231381ee4c2SPoul-Henning Kamp pwarn("Must update to modern format using a version of fsck\n"); 232381ee4c2SPoul-Henning Kamp pfatal("from before 2002 with the command ``fsck -c 2''\n"); 233381ee4c2SPoul-Henning Kamp exit(EEXIT); 2348fae3551SRodney W. Grimes } 235780a5c1eSPeter Wemm if (asblk.b_dirty && !bflag) { 236780a5c1eSPeter Wemm memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize); 2378fae3551SRodney W. Grimes flush(fswritefd, &asblk); 2388fae3551SRodney W. Grimes } 2398fae3551SRodney W. Grimes /* 2408fae3551SRodney W. Grimes * read in the summary info. 2418fae3551SRodney W. Grimes */ 2428fae3551SRodney W. Grimes asked = 0; 243f55ff3f3SIan Dowse sblock.fs_csp = calloc(1, sblock.fs_cssize); 24496e3efc0SColin Percival if (sblock.fs_csp == NULL) { 24596e3efc0SColin Percival printf("cannot alloc %u bytes for cg summary info\n", 24696e3efc0SColin Percival (unsigned)sblock.fs_cssize); 24796e3efc0SColin Percival goto badsb; 24896e3efc0SColin Percival } 2498fae3551SRodney W. Grimes for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 2508fae3551SRodney W. Grimes size = sblock.fs_cssize - i < sblock.fs_bsize ? 2518fae3551SRodney W. Grimes sblock.fs_cssize - i : sblock.fs_bsize; 252f55ff3f3SIan Dowse if (bread(fsreadfd, (char *)sblock.fs_csp + i, 2538fae3551SRodney W. Grimes fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 2548fae3551SRodney W. Grimes size) != 0 && !asked) { 2558fae3551SRodney W. Grimes pfatal("BAD SUMMARY INFORMATION"); 256b1897c19SJulian Elischer if (reply("CONTINUE") == 0) { 257b1897c19SJulian Elischer ckfini(0); 258780a5c1eSPeter Wemm exit(EEXIT); 259b1897c19SJulian Elischer } 2608fae3551SRodney W. Grimes asked++; 2618fae3551SRodney W. Grimes } 2628fae3551SRodney W. Grimes } 2638fae3551SRodney W. Grimes /* 2648fae3551SRodney W. Grimes * allocate and initialize the necessary maps 2658fae3551SRodney W. Grimes */ 26689fdc4e1SMike Barcroft bmapsize = roundup(howmany(maxfsblock, CHAR_BIT), sizeof(short)); 2678fae3551SRodney W. Grimes blockmap = calloc((unsigned)bmapsize, sizeof (char)); 2688fae3551SRodney W. Grimes if (blockmap == NULL) { 2698fae3551SRodney W. Grimes printf("cannot alloc %u bytes for blockmap\n", 2708fae3551SRodney W. Grimes (unsigned)bmapsize); 2718fae3551SRodney W. Grimes goto badsb; 2728fae3551SRodney W. Grimes } 273d33e92f9SJulian Elischer inostathead = calloc((unsigned)(sblock.fs_ncg), 274d33e92f9SJulian Elischer sizeof(struct inostatlist)); 275d33e92f9SJulian Elischer if (inostathead == NULL) { 276d33e92f9SJulian Elischer printf("cannot alloc %u bytes for inostathead\n", 277d33e92f9SJulian Elischer (unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg))); 2788fae3551SRodney W. Grimes goto badsb; 2798fae3551SRodney W. Grimes } 280f033309fSKirk McKusick numdirs = MAX(sblock.fs_cstotal.cs_ndir, 128); 281e50342e6SKirk McKusick dirhash = numdirs; 2828fae3551SRodney W. Grimes inplast = 0; 2838fae3551SRodney W. Grimes listmax = numdirs + 10; 2848fae3551SRodney W. Grimes inpsort = (struct inoinfo **)calloc((unsigned)listmax, 2858fae3551SRodney W. Grimes sizeof(struct inoinfo *)); 2868fae3551SRodney W. Grimes inphead = (struct inoinfo **)calloc((unsigned)numdirs, 2878fae3551SRodney W. Grimes sizeof(struct inoinfo *)); 2888fae3551SRodney W. Grimes if (inpsort == NULL || inphead == NULL) { 28984fc0d7eSMaxime Henrion printf("cannot alloc %ju bytes for inphead\n", 29084fc0d7eSMaxime Henrion (uintmax_t)numdirs * sizeof(struct inoinfo *)); 2918fae3551SRodney W. Grimes goto badsb; 2928fae3551SRodney W. Grimes } 2938fae3551SRodney W. Grimes bufinit(); 294b1897c19SJulian Elischer if (sblock.fs_flags & FS_DOSOFTDEP) 295b1897c19SJulian Elischer usedsoftdep = 1; 296b1897c19SJulian Elischer else 297b1897c19SJulian Elischer usedsoftdep = 0; 2988fae3551SRodney W. Grimes return (1); 2998fae3551SRodney W. Grimes 3008fae3551SRodney W. Grimes badsb: 301780a5c1eSPeter Wemm ckfini(0); 3028fae3551SRodney W. Grimes return (0); 3038fae3551SRodney W. Grimes } 3048fae3551SRodney W. Grimes 3058fae3551SRodney W. Grimes /* 3061c85e6a3SKirk McKusick * Possible superblock locations ordered from most to least likely. 3071c85e6a3SKirk McKusick */ 3081c85e6a3SKirk McKusick static int sblock_try[] = SBLOCKSEARCH; 3091c85e6a3SKirk McKusick 3103b7e1bf6SWes Peters #define BAD_MAGIC_MSG \ 3113b7e1bf6SWes Peters "The previous newfs operation on this volume did not complete.\n" \ 3123b7e1bf6SWes Peters "You must complete newfs before mounting this volume.\n" 3133b7e1bf6SWes Peters 3141c85e6a3SKirk McKusick /* 3158fae3551SRodney W. Grimes * Read in the super block and its summary info. 3168fae3551SRodney W. Grimes */ 31738375c40SKirk McKusick int 318b70cd7eeSWarner Losh readsb(int listerr) 3198fae3551SRodney W. Grimes { 3201c85e6a3SKirk McKusick ufs2_daddr_t super; 3211c85e6a3SKirk McKusick int i; 3228fae3551SRodney W. Grimes 3231c85e6a3SKirk McKusick if (bflag) { 3241c85e6a3SKirk McKusick super = bflag; 3251c85e6a3SKirk McKusick if ((bread(fsreadfd, (char *)&sblock, super, (long)SBLOCKSIZE))) 3268fae3551SRodney W. Grimes return (0); 327b72ea57fSJohn Baldwin if (sblock.fs_magic == FS_BAD_MAGIC) { 3283b7e1bf6SWes Peters fprintf(stderr, BAD_MAGIC_MSG); 3293b7e1bf6SWes Peters exit(11); 3303b7e1bf6SWes Peters } 331f033309fSKirk McKusick if (sblock.fs_magic != FS_UFS1_MAGIC && 332f033309fSKirk McKusick sblock.fs_magic != FS_UFS2_MAGIC) { 333f033309fSKirk McKusick fprintf(stderr, "%d is not a file system superblock\n", 334f033309fSKirk McKusick bflag); 335f033309fSKirk McKusick return (0); 336f033309fSKirk McKusick } 3371c85e6a3SKirk McKusick } else { 3381c85e6a3SKirk McKusick for (i = 0; sblock_try[i] != -1; i++) { 3391c85e6a3SKirk McKusick super = sblock_try[i] / dev_bsize; 3401c85e6a3SKirk McKusick if ((bread(fsreadfd, (char *)&sblock, super, 3411c85e6a3SKirk McKusick (long)SBLOCKSIZE))) 3421c85e6a3SKirk McKusick return (0); 343b72ea57fSJohn Baldwin if (sblock.fs_magic == FS_BAD_MAGIC) { 3443b7e1bf6SWes Peters fprintf(stderr, BAD_MAGIC_MSG); 3453b7e1bf6SWes Peters exit(11); 3463b7e1bf6SWes Peters } 3471c85e6a3SKirk McKusick if ((sblock.fs_magic == FS_UFS1_MAGIC || 3481c85e6a3SKirk McKusick (sblock.fs_magic == FS_UFS2_MAGIC && 349ada981b2SKirk McKusick sblock.fs_sblockloc == sblock_try[i])) && 3501c85e6a3SKirk McKusick sblock.fs_ncg >= 1 && 3511546eccdSKirk McKusick sblock.fs_bsize >= MINBSIZE && 3521c85e6a3SKirk McKusick sblock.fs_bsize >= sizeof(struct fs)) 3531c85e6a3SKirk McKusick break; 3541c85e6a3SKirk McKusick } 3551c85e6a3SKirk McKusick if (sblock_try[i] == -1) { 3561c85e6a3SKirk McKusick fprintf(stderr, "Cannot find file system superblock\n"); 3571c85e6a3SKirk McKusick return (0); 3581c85e6a3SKirk McKusick } 3591c85e6a3SKirk McKusick } 3608fae3551SRodney W. Grimes /* 3618fae3551SRodney W. Grimes * Compute block size that the file system is based on, 3628fae3551SRodney W. Grimes * according to fsbtodb, and adjust superblock block number 3638fae3551SRodney W. Grimes * so we can tell if this is an alternate later. 3648fae3551SRodney W. Grimes */ 3658fae3551SRodney W. Grimes super *= dev_bsize; 3668fae3551SRodney W. Grimes dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 3678fae3551SRodney W. Grimes sblk.b_bno = super / dev_bsize; 3681c85e6a3SKirk McKusick sblk.b_size = SBLOCKSIZE; 369f033309fSKirk McKusick if (bflag) 370f033309fSKirk McKusick goto out; 3718fae3551SRodney W. Grimes /* 372cdd5d266SKirk McKusick * Compare all fields that should not differ in alternate super block. 3738fae3551SRodney W. Grimes * When an alternate super-block is specified this check is skipped. 3748fae3551SRodney W. Grimes */ 3758fae3551SRodney W. Grimes getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize); 3768fae3551SRodney W. Grimes if (asblk.b_errs) 3778fae3551SRodney W. Grimes return (0); 378cdd5d266SKirk McKusick if (altsblock.fs_sblkno != sblock.fs_sblkno || 379cdd5d266SKirk McKusick altsblock.fs_cblkno != sblock.fs_cblkno || 380cdd5d266SKirk McKusick altsblock.fs_iblkno != sblock.fs_iblkno || 381cdd5d266SKirk McKusick altsblock.fs_dblkno != sblock.fs_dblkno || 382cdd5d266SKirk McKusick altsblock.fs_ncg != sblock.fs_ncg || 383cdd5d266SKirk McKusick altsblock.fs_bsize != sblock.fs_bsize || 384cdd5d266SKirk McKusick altsblock.fs_fsize != sblock.fs_fsize || 385cdd5d266SKirk McKusick altsblock.fs_frag != sblock.fs_frag || 386cdd5d266SKirk McKusick altsblock.fs_bmask != sblock.fs_bmask || 387cdd5d266SKirk McKusick altsblock.fs_fmask != sblock.fs_fmask || 388cdd5d266SKirk McKusick altsblock.fs_bshift != sblock.fs_bshift || 389cdd5d266SKirk McKusick altsblock.fs_fshift != sblock.fs_fshift || 390cdd5d266SKirk McKusick altsblock.fs_fragshift != sblock.fs_fragshift || 391cdd5d266SKirk McKusick altsblock.fs_fsbtodb != sblock.fs_fsbtodb || 392cdd5d266SKirk McKusick altsblock.fs_sbsize != sblock.fs_sbsize || 393cdd5d266SKirk McKusick altsblock.fs_nindir != sblock.fs_nindir || 394cdd5d266SKirk McKusick altsblock.fs_inopb != sblock.fs_inopb || 395cdd5d266SKirk McKusick altsblock.fs_cssize != sblock.fs_cssize || 396cdd5d266SKirk McKusick altsblock.fs_ipg != sblock.fs_ipg || 397cdd5d266SKirk McKusick altsblock.fs_fpg != sblock.fs_fpg || 398cdd5d266SKirk McKusick altsblock.fs_magic != sblock.fs_magic) { 3998fae3551SRodney W. Grimes badsb(listerr, 4008fae3551SRodney W. Grimes "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE"); 4018fae3551SRodney W. Grimes return (0); 4028fae3551SRodney W. Grimes } 403f033309fSKirk McKusick out: 4041c85e6a3SKirk McKusick /* 4051c85e6a3SKirk McKusick * If not yet done, update UFS1 superblock with new wider fields. 4061c85e6a3SKirk McKusick */ 4071c85e6a3SKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC && 4081c85e6a3SKirk McKusick sblock.fs_maxbsize != sblock.fs_bsize) { 4091c85e6a3SKirk McKusick sblock.fs_maxbsize = sblock.fs_bsize; 4101c85e6a3SKirk McKusick sblock.fs_time = sblock.fs_old_time; 4111c85e6a3SKirk McKusick sblock.fs_size = sblock.fs_old_size; 4121c85e6a3SKirk McKusick sblock.fs_dsize = sblock.fs_old_dsize; 4131c85e6a3SKirk McKusick sblock.fs_csaddr = sblock.fs_old_csaddr; 4141c85e6a3SKirk McKusick sblock.fs_cstotal.cs_ndir = sblock.fs_old_cstotal.cs_ndir; 4151c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nbfree = sblock.fs_old_cstotal.cs_nbfree; 4161c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nifree = sblock.fs_old_cstotal.cs_nifree; 4171c85e6a3SKirk McKusick sblock.fs_cstotal.cs_nffree = sblock.fs_old_cstotal.cs_nffree; 4181c85e6a3SKirk McKusick } 4198fae3551SRodney W. Grimes havesb = 1; 4208fae3551SRodney W. Grimes return (1); 4218fae3551SRodney W. Grimes } 4228fae3551SRodney W. Grimes 42331f4ab50SBruce Evans static void 424599304a4SPoul-Henning Kamp badsb(int listerr, const char *s) 4258fae3551SRodney W. Grimes { 4268fae3551SRodney W. Grimes 4278fae3551SRodney W. Grimes if (!listerr) 4288fae3551SRodney W. Grimes return; 4298fae3551SRodney W. Grimes if (preen) 4308fae3551SRodney W. Grimes printf("%s: ", cdevname); 4318fae3551SRodney W. Grimes pfatal("BAD SUPER BLOCK: %s\n", s); 4328fae3551SRodney W. Grimes } 4338fae3551SRodney W. Grimes 434d164d805SIan Dowse void 435b70cd7eeSWarner Losh sblock_init(void) 43638375c40SKirk McKusick { 43738375c40SKirk McKusick struct disklabel *lp; 43838375c40SKirk McKusick 43938375c40SKirk McKusick fswritefd = -1; 44038375c40SKirk McKusick fsmodified = 0; 44138375c40SKirk McKusick lfdir = 0; 44238375c40SKirk McKusick initbarea(&sblk); 44338375c40SKirk McKusick initbarea(&asblk); 4441c85e6a3SKirk McKusick sblk.b_un.b_buf = malloc(SBLOCKSIZE); 4451c85e6a3SKirk McKusick asblk.b_un.b_buf = malloc(SBLOCKSIZE); 44638375c40SKirk McKusick if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) 44738375c40SKirk McKusick errx(EEXIT, "cannot allocate space for superblock"); 44838375c40SKirk McKusick if ((lp = getdisklabel(NULL, fsreadfd))) 44938375c40SKirk McKusick dev_bsize = secsize = lp->d_secsize; 45038375c40SKirk McKusick else 45138375c40SKirk McKusick dev_bsize = secsize = DEV_BSIZE; 45238375c40SKirk McKusick } 45338375c40SKirk McKusick 4548fae3551SRodney W. Grimes /* 4558fae3551SRodney W. Grimes * Calculate a prototype superblock based on information in the disk label. 4568fae3551SRodney W. Grimes * When done the cgsblock macro can be calculated and the fs_ncg field 4578fae3551SRodney W. Grimes * can be used. Do NOT attempt to use other macros without verifying that 4588fae3551SRodney W. Grimes * their needed information is available! 4598fae3551SRodney W. Grimes */ 460780a5c1eSPeter Wemm static int 461b70cd7eeSWarner Losh calcsb(char *dev, int devfd, struct fs *fs) 4628fae3551SRodney W. Grimes { 4633d438ad6SDavid E. O'Brien struct disklabel *lp; 4643d438ad6SDavid E. O'Brien struct partition *pp; 4653d438ad6SDavid E. O'Brien char *cp; 4661c85e6a3SKirk McKusick int i, nspf; 4678fae3551SRodney W. Grimes 468780a5c1eSPeter Wemm cp = strchr(dev, '\0') - 1; 46931f4ab50SBruce Evans if (cp == (char *)-1 || ((*cp < 'a' || *cp > 'h') && !isdigit(*cp))) { 4708fae3551SRodney W. Grimes pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); 4718fae3551SRodney W. Grimes return (0); 4728fae3551SRodney W. Grimes } 4738fae3551SRodney W. Grimes lp = getdisklabel(dev, devfd); 4748fae3551SRodney W. Grimes if (isdigit(*cp)) 4758fae3551SRodney W. Grimes pp = &lp->d_partitions[0]; 4768fae3551SRodney W. Grimes else 4778fae3551SRodney W. Grimes pp = &lp->d_partitions[*cp - 'a']; 4788fae3551SRodney W. Grimes if (pp->p_fstype != FS_BSDFFS) { 4798fae3551SRodney W. Grimes pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n", 4808fae3551SRodney W. Grimes dev, pp->p_fstype < FSMAXTYPES ? 4818fae3551SRodney W. Grimes fstypenames[pp->p_fstype] : "unknown"); 4828fae3551SRodney W. Grimes return (0); 4838fae3551SRodney W. Grimes } 484d33e92f9SJulian Elischer if (pp->p_fsize == 0 || pp->p_frag == 0 || 485d33e92f9SJulian Elischer pp->p_cpg == 0 || pp->p_size == 0) { 486d33e92f9SJulian Elischer pfatal("%s: %s: type %s fsize %d, frag %d, cpg %d, size %d\n", 487d33e92f9SJulian Elischer dev, "INCOMPLETE LABEL", fstypenames[pp->p_fstype], 488d33e92f9SJulian Elischer pp->p_fsize, pp->p_frag, pp->p_cpg, pp->p_size); 489cc52d04fSBruce Evans return (0); 490cc52d04fSBruce Evans } 491780a5c1eSPeter Wemm memset(fs, 0, sizeof(struct fs)); 4928fae3551SRodney W. Grimes fs->fs_fsize = pp->p_fsize; 4938fae3551SRodney W. Grimes fs->fs_frag = pp->p_frag; 4948fae3551SRodney W. Grimes fs->fs_size = pp->p_size; 4951c85e6a3SKirk McKusick fs->fs_sblkno = roundup( 4961c85e6a3SKirk McKusick howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize), 4971c85e6a3SKirk McKusick fs->fs_frag); 4981c85e6a3SKirk McKusick nspf = fs->fs_fsize / lp->d_secsize; 4991c85e6a3SKirk McKusick for (fs->fs_fsbtodb = 0, i = nspf; i > 1; i >>= 1) 5008fae3551SRodney W. Grimes fs->fs_fsbtodb++; 5018fae3551SRodney W. Grimes dev_bsize = lp->d_secsize; 5021c85e6a3SKirk McKusick if (fs->fs_magic == FS_UFS2_MAGIC) { 5031c85e6a3SKirk McKusick fs->fs_fpg = pp->p_cpg; 5041c85e6a3SKirk McKusick fs->fs_ncg = howmany(fs->fs_size, fs->fs_fpg); 5051c85e6a3SKirk McKusick } else /* if (fs->fs_magic == FS_UFS1_MAGIC) */ { 5061c85e6a3SKirk McKusick fs->fs_old_cpg = pp->p_cpg; 5071c85e6a3SKirk McKusick fs->fs_old_cgmask = 0xffffffff; 5081c85e6a3SKirk McKusick for (i = lp->d_ntracks; i > 1; i >>= 1) 5091c85e6a3SKirk McKusick fs->fs_old_cgmask <<= 1; 5101c85e6a3SKirk McKusick if (!POWEROF2(lp->d_ntracks)) 5111c85e6a3SKirk McKusick fs->fs_old_cgmask <<= 1; 5121c85e6a3SKirk McKusick fs->fs_old_cgoffset = roundup(howmany(lp->d_nsectors, nspf), 5131c85e6a3SKirk McKusick fs->fs_frag); 5141c85e6a3SKirk McKusick fs->fs_fpg = (fs->fs_old_cpg * lp->d_secpercyl) / nspf; 5151c85e6a3SKirk McKusick fs->fs_ncg = howmany(fs->fs_size / lp->d_secpercyl, 5161c85e6a3SKirk McKusick fs->fs_old_cpg); 5171c85e6a3SKirk McKusick } 5188fae3551SRodney W. Grimes return (1); 5198fae3551SRodney W. Grimes } 5208fae3551SRodney W. Grimes 521780a5c1eSPeter Wemm static struct disklabel * 522b70cd7eeSWarner Losh getdisklabel(char *s, int fd) 5238fae3551SRodney W. Grimes { 5248fae3551SRodney W. Grimes static struct disklabel lab; 5258fae3551SRodney W. Grimes 5268fae3551SRodney W. Grimes if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { 5278fae3551SRodney W. Grimes if (s == NULL) 5288fae3551SRodney W. Grimes return ((struct disklabel *)NULL); 5298fae3551SRodney W. Grimes pwarn("ioctl (GCINFO): %s\n", strerror(errno)); 530780a5c1eSPeter Wemm errx(EEXIT, "%s: can't read disk label", s); 5318fae3551SRodney W. Grimes } 5328fae3551SRodney W. Grimes return (&lab); 5338fae3551SRodney W. Grimes } 534