1*dfd61507Ssthen /* $OpenBSD: setup.c,v 1.35 2024/12/18 10:36:05 sthen Exp $ */ 25ff4e0c8Sdownsj /* $NetBSD: setup.c,v 1.1 1997/06/11 11:22:01 bouyer Exp $ */ 38c424e8eSdownsj 48c424e8eSdownsj /* 55ff4e0c8Sdownsj * Copyright (c) 1997 Manuel Bouyer. 68c424e8eSdownsj * Copyright (c) 1980, 1986, 1993 78c424e8eSdownsj * The Regents of the University of California. All rights reserved. 88c424e8eSdownsj * 98c424e8eSdownsj * Redistribution and use in source and binary forms, with or without 108c424e8eSdownsj * modification, are permitted provided that the following conditions 118c424e8eSdownsj * are met: 128c424e8eSdownsj * 1. Redistributions of source code must retain the above copyright 138c424e8eSdownsj * notice, this list of conditions and the following disclaimer. 148c424e8eSdownsj * 2. Redistributions in binary form must reproduce the above copyright 158c424e8eSdownsj * notice, this list of conditions and the following disclaimer in the 168c424e8eSdownsj * documentation and/or other materials provided with the distribution. 171ef0d710Smillert * 3. Neither the name of the University nor the names of its contributors 188c424e8eSdownsj * may be used to endorse or promote products derived from this software 198c424e8eSdownsj * without specific prior written permission. 208c424e8eSdownsj * 218c424e8eSdownsj * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 228c424e8eSdownsj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 238c424e8eSdownsj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 248c424e8eSdownsj * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 258c424e8eSdownsj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 268c424e8eSdownsj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 278c424e8eSdownsj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 288c424e8eSdownsj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 298c424e8eSdownsj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 308c424e8eSdownsj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 318c424e8eSdownsj * SUCH DAMAGE. 328c424e8eSdownsj */ 338c424e8eSdownsj 348c424e8eSdownsj #define DKTYPENAMES 35b9fc9a72Sderaadt #include <sys/param.h> /* DEV_BSIZE roundup */ 368c424e8eSdownsj #include <sys/time.h> 378c424e8eSdownsj #include <ufs/ext2fs/ext2fs_dinode.h> 388c424e8eSdownsj #include <ufs/ext2fs/ext2fs.h> 398c424e8eSdownsj #include <sys/stat.h> 408c424e8eSdownsj #include <sys/ioctl.h> 4191f4f7d8Sdlg #include <sys/dkio.h> 428c424e8eSdownsj #include <sys/disklabel.h> 438c424e8eSdownsj 448c424e8eSdownsj #include <errno.h> 4501a83688Smillert #include <fcntl.h> 468c424e8eSdownsj #include <stdio.h> 478c424e8eSdownsj #include <stdlib.h> 48c0c611b7Sderaadt #include <unistd.h> 49*dfd61507Ssthen #include <util.h> 508c424e8eSdownsj #include <string.h> 518c424e8eSdownsj #include <ctype.h> 52c0c611b7Sderaadt #include <err.h> 538c424e8eSdownsj 548c424e8eSdownsj #include "fsck.h" 558c424e8eSdownsj #include "extern.h" 568c424e8eSdownsj #include "fsutil.h" 578c424e8eSdownsj 588c424e8eSdownsj #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 598c424e8eSdownsj 60c72b5b24Smillert void badsb(int, char *); 61c0c611b7Sderaadt int calcsb(char *, int, struct m_ext2fs *, struct disklabel *); 62c72b5b24Smillert static struct disklabel *getdisklabel(char *, int); 63c72b5b24Smillert static int readsb(int); 64*dfd61507Ssthen static char rdevname[PATH_MAX]; 658c424e8eSdownsj 668c424e8eSdownsj int 678809fabbSderaadt setup(char *dev) 688c424e8eSdownsj { 6965348f21Sjasoni long cg, asked, i; 708c424e8eSdownsj long bmapsize; 718c424e8eSdownsj struct disklabel *lp; 728c424e8eSdownsj off_t sizepb; 738c424e8eSdownsj struct stat statb; 748c424e8eSdownsj struct m_ext2fs proto; 75*dfd61507Ssthen char *realdev; 768c424e8eSdownsj int doskipclean; 778c424e8eSdownsj u_int64_t maxfilesize; 788c424e8eSdownsj 798c424e8eSdownsj havesb = 0; 808c424e8eSdownsj fswritefd = -1; 818c424e8eSdownsj doskipclean = skipclean; 82*dfd61507Ssthen if ((fsreadfd = opendev(dev, O_RDONLY, 0, &realdev)) == -1) { 838c424e8eSdownsj printf("Can't open %s: %s\n", dev, strerror(errno)); 848c424e8eSdownsj return (0); 858c424e8eSdownsj } 86*dfd61507Ssthen if (strncmp(dev, realdev, PATH_MAX) != 0) { 87*dfd61507Ssthen blockcheck(unrawname(realdev)); 88*dfd61507Ssthen strlcpy(rdevname, realdev, sizeof(rdevname)); 89*dfd61507Ssthen setcdevname(rdevname, dev, preen); 90*dfd61507Ssthen } 91*dfd61507Ssthen if (fstat(fsreadfd, &statb) == -1) { 92*dfd61507Ssthen printf("Can't stat %s: %s\n", realdev, strerror(errno)); 93*dfd61507Ssthen return (0); 94*dfd61507Ssthen } 95*dfd61507Ssthen if (!S_ISCHR(statb.st_mode)) { 96*dfd61507Ssthen pfatal("%s is not a character device", realdev); 97*dfd61507Ssthen if (reply("CONTINUE") == 0) { 98*dfd61507Ssthen close(fsreadfd); 99*dfd61507Ssthen return (0); 100*dfd61507Ssthen } 101*dfd61507Ssthen } 1028c424e8eSdownsj if (preen == 0) 103*dfd61507Ssthen printf("** %s", realdev); 104*dfd61507Ssthen if (nflag || (fswritefd = opendev(dev, O_WRONLY, 0, NULL)) == -1) { 1058c424e8eSdownsj fswritefd = -1; 1068c424e8eSdownsj if (preen) 1078c424e8eSdownsj pfatal("NO WRITE ACCESS"); 1088c424e8eSdownsj printf(" (NO WRITE)"); 1098c424e8eSdownsj } 1108c424e8eSdownsj if (preen == 0) 1118c424e8eSdownsj printf("\n"); 1128c424e8eSdownsj fsmodified = 0; 1138c424e8eSdownsj lfdir = 0; 1148c424e8eSdownsj initbarea(&sblk); 1158c424e8eSdownsj initbarea(&asblk); 11665348f21Sjasoni sblk.b_un.b_buf = malloc(SBSIZE); 11765348f21Sjasoni asblk.b_un.b_buf = malloc(SBSIZE); 1188c424e8eSdownsj if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) 1198c424e8eSdownsj errexit("cannot allocate space for superblock\n"); 120c0c611b7Sderaadt if ((lp = getdisklabel(NULL, fsreadfd)) != NULL) 1219e7daf04Skrw secsize = lp->d_secsize; 1228c424e8eSdownsj else 1239e7daf04Skrw secsize = DEV_BSIZE; 124c0c611b7Sderaadt 125c0c611b7Sderaadt if (!hotroot()) { 126f0426f3aSsemarie #ifndef SMALL 127f0426f3aSsemarie if (pledge("stdio getpw", NULL) == -1) 128f0426f3aSsemarie err(1, "pledge"); 129f0426f3aSsemarie #else 130c0c611b7Sderaadt if (pledge("stdio", NULL) == -1) 131c0c611b7Sderaadt err(1, "pledge"); 132f0426f3aSsemarie #endif 133c0c611b7Sderaadt } 134c0c611b7Sderaadt 1358c424e8eSdownsj /* 1368c424e8eSdownsj * Read in the superblock, looking for alternates if necessary 1378c424e8eSdownsj */ 1388c424e8eSdownsj if (readsb(1) == 0) { 139*dfd61507Ssthen if (bflag || preen || calcsb(realdev, fsreadfd, &proto, lp) == 0) 1408c424e8eSdownsj return(0); 1418c424e8eSdownsj if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) 1428c424e8eSdownsj return (0); 1438c424e8eSdownsj for (cg = 1; cg < proto.e2fs_ncg; cg++) { 1448c424e8eSdownsj bflag = fsbtodb(&proto, 1458c424e8eSdownsj cg * proto.e2fs.e2fs_bpg + proto.e2fs.e2fs_first_dblock); 1468c424e8eSdownsj if (readsb(0) != 0) 1478c424e8eSdownsj break; 1488c424e8eSdownsj } 1498c424e8eSdownsj if (cg >= proto.e2fs_ncg) { 1508c424e8eSdownsj printf("%s %s\n%s %s\n%s %s\n", 1518c424e8eSdownsj "SEARCH FOR ALTERNATE SUPER-BLOCK", 1528c424e8eSdownsj "FAILED. YOU MUST USE THE", 1538c424e8eSdownsj "-b OPTION TO FSCK_FFS TO SPECIFY THE", 1548c424e8eSdownsj "LOCATION OF AN ALTERNATE", 1558c424e8eSdownsj "SUPER-BLOCK TO SUPPLY NEEDED", 1568c424e8eSdownsj "INFORMATION; SEE fsck_ext2fs(8)."); 1578c424e8eSdownsj return(0); 1588c424e8eSdownsj } 1598c424e8eSdownsj doskipclean = 0; 1608c424e8eSdownsj pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); 1618c424e8eSdownsj } 1628c424e8eSdownsj if (debug) 1638c424e8eSdownsj printf("state = %d\n", sblock.e2fs.e2fs_state); 1648c424e8eSdownsj if (sblock.e2fs.e2fs_state == E2FS_ISCLEAN) { 1658c424e8eSdownsj if (doskipclean) { 1668c424e8eSdownsj pwarn("%sile system is clean; not checking\n", 1678c424e8eSdownsj preen ? "f" : "** F"); 1688c424e8eSdownsj return (-1); 1698c424e8eSdownsj } 1708c424e8eSdownsj if (!preen) 1718c424e8eSdownsj pwarn("** File system is already clean\n"); 1728c424e8eSdownsj } 1738c424e8eSdownsj maxfsblock = sblock.e2fs.e2fs_bcount; 1748c424e8eSdownsj maxino = sblock.e2fs_ncg * sblock.e2fs.e2fs_ipg; 1758c424e8eSdownsj sizepb = sblock.e2fs_bsize; 1768c424e8eSdownsj maxfilesize = sblock.e2fs_bsize * NDADDR - 1; 1778c424e8eSdownsj for (i = 0; i < NIADDR; i++) { 1788c424e8eSdownsj sizepb *= NINDIR(&sblock); 1798c424e8eSdownsj maxfilesize += sizepb; 1808c424e8eSdownsj } 1818c424e8eSdownsj /* 1828c424e8eSdownsj * Check and potentially fix certain fields in the super block. 1838c424e8eSdownsj */ 1845814667eSotto if (/* (sblock.e2fs.e2fs_rbcount < 0) || */ 1858c424e8eSdownsj (sblock.e2fs.e2fs_rbcount > sblock.e2fs.e2fs_bcount)) { 1868c424e8eSdownsj pfatal("IMPOSSIBLE RESERVED BLOCK COUNT=%d IN SUPERBLOCK", 1878c424e8eSdownsj sblock.e2fs.e2fs_rbcount); 1888c424e8eSdownsj if (reply("SET TO DEFAULT") == 1) { 1898c424e8eSdownsj sblock.e2fs.e2fs_rbcount = sblock.e2fs.e2fs_bcount * 0.1; 1908c424e8eSdownsj sbdirty(); 19165348f21Sjasoni dirty(&asblk); 1928c424e8eSdownsj } 1938c424e8eSdownsj } 1948c424e8eSdownsj if (sblock.e2fs.e2fs_bpg != sblock.e2fs.e2fs_fpg) { 1958c424e8eSdownsj pfatal("WRONG FPG=%d (BPG=%d) IN SUPERBLOCK", 1968c424e8eSdownsj sblock.e2fs.e2fs_fpg, sblock.e2fs.e2fs_bpg); 1978c424e8eSdownsj return 0; 1988c424e8eSdownsj } 1998c424e8eSdownsj if (asblk.b_dirty && !bflag) { 20065348f21Sjasoni copyback_sb(&asblk); 2018c424e8eSdownsj flush(fswritefd, &asblk); 2028c424e8eSdownsj } 2038c424e8eSdownsj /* 2048c424e8eSdownsj * read in the summary info. 2058c424e8eSdownsj */ 2068c424e8eSdownsj 2071ed98fdfSderaadt sblock.e2fs_gd = calloc(sblock.e2fs_ngdb, sblock.e2fs_bsize); 20865348f21Sjasoni if (sblock.e2fs_gd == NULL) 20965348f21Sjasoni errexit("out of memory\n"); 2108c424e8eSdownsj asked = 0; 2118c424e8eSdownsj for (i=0; i < sblock.e2fs_ngdb; i++) { 2128c424e8eSdownsj if (bread(fsreadfd,(char *) 2138c424e8eSdownsj &sblock.e2fs_gd[i* sblock.e2fs_bsize / sizeof(struct ext2_gd)], 2148c424e8eSdownsj fsbtodb(&sblock, ((sblock.e2fs_bsize>1024)?0:1)+i+1), 2158c424e8eSdownsj sblock.e2fs_bsize) != 0 && !asked) { 2168c424e8eSdownsj pfatal("BAD SUMMARY INFORMATION"); 2178c424e8eSdownsj if (reply("CONTINUE") == 0) 2188c424e8eSdownsj errexit("%s\n", ""); 2198c424e8eSdownsj asked++; 2208c424e8eSdownsj } 2218c424e8eSdownsj } 2228c424e8eSdownsj /* 2238c424e8eSdownsj * allocate and initialize the necessary maps 2248c424e8eSdownsj */ 2258c424e8eSdownsj bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); 2268c424e8eSdownsj blockmap = calloc((unsigned)bmapsize, sizeof (char)); 2278c424e8eSdownsj if (blockmap == NULL) { 2288c424e8eSdownsj printf("cannot alloc %u bytes for blockmap\n", 2298c424e8eSdownsj (unsigned)bmapsize); 2308c424e8eSdownsj goto badsblabel; 2318c424e8eSdownsj } 2328c424e8eSdownsj statemap = calloc((unsigned)(maxino + 2), sizeof(char)); 2338c424e8eSdownsj if (statemap == NULL) { 2348c424e8eSdownsj printf("cannot alloc %u bytes for statemap\n", 2358c424e8eSdownsj (unsigned)(maxino + 1)); 2368c424e8eSdownsj goto badsblabel; 2378c424e8eSdownsj } 23828704fc2Sderaadt typemap = calloc((unsigned)(maxino + 1), sizeof(u_char)); 23965348f21Sjasoni if (typemap == NULL) { 24065348f21Sjasoni printf("cannot alloc %u bytes for typemap\n", 24165348f21Sjasoni (unsigned)(maxino + 1)); 24265348f21Sjasoni goto badsblabel; 24365348f21Sjasoni } 2445ae94ef8Sderaadt lncntp = calloc((unsigned)(maxino + 1), sizeof(int16_t)); 2458c424e8eSdownsj if (lncntp == NULL) { 2468c424e8eSdownsj printf("cannot alloc %u bytes for lncntp\n", 24765348f21Sjasoni (unsigned)((maxino + 1) * sizeof(int16_t))); 2488c424e8eSdownsj goto badsblabel; 2498c424e8eSdownsj } 2508c424e8eSdownsj for (numdirs = 0, cg = 0; cg < sblock.e2fs_ncg; cg++) { 25160a51e06Spelikan numdirs += letoh16(sblock.e2fs_gd[cg].ext2bgd_ndirs); 2528c424e8eSdownsj } 2538c424e8eSdownsj inplast = 0; 2548c424e8eSdownsj listmax = numdirs + 10; 2555ae94ef8Sderaadt inpsort = calloc((unsigned)listmax, sizeof(struct inoinfo *)); 2565ae94ef8Sderaadt inphead = calloc((unsigned)numdirs, sizeof(struct inoinfo *)); 2578c424e8eSdownsj if (inpsort == NULL || inphead == NULL) { 2588c424e8eSdownsj printf("cannot alloc %u bytes for inphead\n", 25965348f21Sjasoni (unsigned)(numdirs * sizeof(struct inoinfo *))); 2608c424e8eSdownsj goto badsblabel; 2618c424e8eSdownsj } 2628c424e8eSdownsj bufinit(); 2638c424e8eSdownsj return (1); 2648c424e8eSdownsj 2658c424e8eSdownsj badsblabel: 2668c424e8eSdownsj ckfini(0); 2678c424e8eSdownsj return (0); 2688c424e8eSdownsj } 2698c424e8eSdownsj 2708c424e8eSdownsj /* 2718c424e8eSdownsj * Read in the super block and its summary info. 2728c424e8eSdownsj */ 2738c424e8eSdownsj static int 2748809fabbSderaadt readsb(int listerr) 2758c424e8eSdownsj { 2769e7daf04Skrw daddr32_t super = bflag ? bflag : SBOFF / DEV_BSIZE; 2778c424e8eSdownsj 27865348f21Sjasoni if (bread(fsreadfd, (char *)sblk.b_un.b_fs, super, (long)SBSIZE) != 0) 2798c424e8eSdownsj return (0); 2808c424e8eSdownsj sblk.b_bno = super; 2818c424e8eSdownsj sblk.b_size = SBSIZE; 28265348f21Sjasoni 28365348f21Sjasoni /* Copy the superblock in memory */ 28465348f21Sjasoni e2fs_sbload(sblk.b_un.b_fs, &sblock.e2fs); 28565348f21Sjasoni 2868c424e8eSdownsj /* 2878c424e8eSdownsj * run a few consistency checks of the super block 2888c424e8eSdownsj */ 2898c424e8eSdownsj if (sblock.e2fs.e2fs_magic != E2FS_MAGIC) { 2908c424e8eSdownsj badsb(listerr, "MAGIC NUMBER WRONG"); return (0); 2918c424e8eSdownsj } 2928c424e8eSdownsj if (sblock.e2fs.e2fs_log_bsize > 2) { 2938c424e8eSdownsj badsb(listerr, "BAD LOG_BSIZE"); return (0); 2948c424e8eSdownsj } 2953917ca2dStobias if (sblock.e2fs.e2fs_bpg == 0) { 2963917ca2dStobias badsb(listerr, "BAD BLOCKS PER GROUP"); return (0); 2973917ca2dStobias } 2988c424e8eSdownsj 2998c424e8eSdownsj /* compute the dynamic fields of the in-memory sb */ 3008c424e8eSdownsj /* compute dynamic sb infos */ 3018c424e8eSdownsj sblock.e2fs_ncg = 3028c424e8eSdownsj howmany(sblock.e2fs.e2fs_bcount - sblock.e2fs.e2fs_first_dblock, 3038c424e8eSdownsj sblock.e2fs.e2fs_bpg); 3048c424e8eSdownsj /* XXX assume hw bsize = 512 */ 3058c424e8eSdownsj sblock.e2fs_fsbtodb = sblock.e2fs.e2fs_log_bsize + 1; 3068c424e8eSdownsj sblock.e2fs_bsize = 1024 << sblock.e2fs.e2fs_log_bsize; 3078c424e8eSdownsj sblock.e2fs_bshift = LOG_MINBSIZE + sblock.e2fs.e2fs_log_bsize; 3088c424e8eSdownsj sblock.e2fs_qbmask = sblock.e2fs_bsize - 1; 3098c424e8eSdownsj sblock.e2fs_bmask = ~sblock.e2fs_qbmask; 3108c424e8eSdownsj sblock.e2fs_ngdb = howmany(sblock.e2fs_ncg, 3118c424e8eSdownsj sblock.e2fs_bsize / sizeof(struct ext2_gd)); 31250e48d67Skrw sblock.e2fs_ipb = sblock.e2fs_bsize / EXT2_DINODE_SIZE(&sblock); 3138c424e8eSdownsj sblock.e2fs_itpg = sblock.e2fs.e2fs_ipg/sblock.e2fs_ipb; 3148c424e8eSdownsj 3158c424e8eSdownsj /* 3168c424e8eSdownsj * Compute block size that the filesystem is based on, 3178c424e8eSdownsj * according to fsbtodb, and adjust superblock block number 3188c424e8eSdownsj * so we can tell if this is an alternate later. 3198c424e8eSdownsj */ 3209e7daf04Skrw sblk.b_bno = super / DEV_BSIZE; 32165348f21Sjasoni 3223c4b0c78Sotto if (sblock.e2fs_ncg == 1) { 3233c4b0c78Sotto /* no alternate superblock; assume it's okey */ 3243c4b0c78Sotto havesb = 1; 3253c4b0c78Sotto return 1; 3263c4b0c78Sotto } 3273c4b0c78Sotto 32865348f21Sjasoni getblk(&asblk, 1 * sblock.e2fs.e2fs_bpg + sblock.e2fs.e2fs_first_dblock, 32965348f21Sjasoni (long)SBSIZE); 33065348f21Sjasoni if (asblk.b_errs) 33165348f21Sjasoni return (0); 3328c424e8eSdownsj if (bflag) { 3338c424e8eSdownsj havesb = 1; 3348c424e8eSdownsj return (1); 3358c424e8eSdownsj } 3368c424e8eSdownsj 3378c424e8eSdownsj /* 3388c424e8eSdownsj * Set all possible fields that could differ, then do check 3398c424e8eSdownsj * of whole super block against an alternate super block. 3408c424e8eSdownsj * When an alternate super-block is specified this check is skipped. 3418c424e8eSdownsj */ 34265348f21Sjasoni asblk.b_un.b_fs->e2fs_rbcount = sblk.b_un.b_fs->e2fs_rbcount; 34365348f21Sjasoni asblk.b_un.b_fs->e2fs_fbcount = sblk.b_un.b_fs->e2fs_fbcount; 34465348f21Sjasoni asblk.b_un.b_fs->e2fs_ficount = sblk.b_un.b_fs->e2fs_ficount; 34565348f21Sjasoni asblk.b_un.b_fs->e2fs_mtime = sblk.b_un.b_fs->e2fs_mtime; 34665348f21Sjasoni asblk.b_un.b_fs->e2fs_wtime = sblk.b_un.b_fs->e2fs_wtime; 34765348f21Sjasoni asblk.b_un.b_fs->e2fs_mnt_count = sblk.b_un.b_fs->e2fs_mnt_count; 34865348f21Sjasoni asblk.b_un.b_fs->e2fs_max_mnt_count = sblk.b_un.b_fs->e2fs_max_mnt_count; 34965348f21Sjasoni asblk.b_un.b_fs->e2fs_state = sblk.b_un.b_fs->e2fs_state; 35065348f21Sjasoni asblk.b_un.b_fs->e2fs_beh = sblk.b_un.b_fs->e2fs_beh; 35165348f21Sjasoni asblk.b_un.b_fs->e2fs_lastfsck = sblk.b_un.b_fs->e2fs_lastfsck; 35265348f21Sjasoni asblk.b_un.b_fs->e2fs_fsckintv = sblk.b_un.b_fs->e2fs_fsckintv; 35365348f21Sjasoni asblk.b_un.b_fs->e2fs_ruid = sblk.b_un.b_fs->e2fs_ruid; 35465348f21Sjasoni asblk.b_un.b_fs->e2fs_rgid = sblk.b_un.b_fs->e2fs_rgid; 35565348f21Sjasoni asblk.b_un.b_fs->e2fs_block_group_nr = 35665348f21Sjasoni sblk.b_un.b_fs->e2fs_block_group_nr; 357bf2afe82Skevlo asblk.b_un.b_fs->e2fs_features_rocompat &= ~EXT2F_ROCOMPAT_LARGE_FILE; 358935730fbSniallo asblk.b_un.b_fs->e2fs_features_rocompat |= 359bf2afe82Skevlo sblk.b_un.b_fs->e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGE_FILE; 3600025a967Smartijn memcpy(asblk.b_un.b_fs->e2fs_fsmnt, sblk.b_un.b_fs->e2fs_fsmnt, 3610025a967Smartijn sizeof(sblk.b_un.b_fs->e2fs_fsmnt)); 3620025a967Smartijn asblk.b_un.b_fs->e2fs_kbytes_written = sblk.b_un.b_fs->e2fs_kbytes_written; 3630025a967Smartijn 36465348f21Sjasoni if (sblock.e2fs.e2fs_rev > E2FS_REV0 && 36565348f21Sjasoni ((sblock.e2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP) || 36665348f21Sjasoni (sblock.e2fs.e2fs_features_rocompat & ~EXT2F_ROCOMPAT_SUPP))) { 3678c424e8eSdownsj if (debug) { 36865348f21Sjasoni printf("compat 0x%08x, incompat 0x%08x, compat_ro " 36965348f21Sjasoni "0x%08x\n", 37065348f21Sjasoni sblock.e2fs.e2fs_features_compat, 37165348f21Sjasoni sblock.e2fs.e2fs_features_incompat, 37265348f21Sjasoni sblock.e2fs.e2fs_features_rocompat); 37365348f21Sjasoni } 37465348f21Sjasoni badsb(listerr,"INCOMPATIBLE FEATURE BITS IN SUPER BLOCK"); 37565348f21Sjasoni return 0; 37665348f21Sjasoni } 37765348f21Sjasoni if (memcmp(sblk.b_un.b_fs, asblk.b_un.b_fs, SBSIZE)) { 37865348f21Sjasoni if (debug) { 37965348f21Sjasoni u_int32_t *nlp, *olp, *endlp; 3808c424e8eSdownsj 3818c424e8eSdownsj printf("superblock mismatches\n"); 38265348f21Sjasoni nlp = (u_int32_t *)asblk.b_un.b_fs; 38365348f21Sjasoni olp = (u_int32_t *)sblk.b_un.b_fs; 3848c424e8eSdownsj endlp = olp + (SBSIZE / sizeof *olp); 3858c424e8eSdownsj for ( ; olp < endlp; olp++, nlp++) { 3868c424e8eSdownsj if (*olp == *nlp) 3878c424e8eSdownsj continue; 38865348f21Sjasoni printf("offset %ld, original %ld, alternate %ld\n", 38965348f21Sjasoni (long)(olp - (u_int32_t *)sblk.b_un.b_fs), 39060a51e06Spelikan (long)letoh32(*olp), 39160a51e06Spelikan (long)letoh32(*nlp)); 3928c424e8eSdownsj } 3938c424e8eSdownsj } 3948c424e8eSdownsj badsb(listerr, 3958c424e8eSdownsj "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE"); 3968c424e8eSdownsj return (0); 3978c424e8eSdownsj } 3988c424e8eSdownsj havesb = 1; 3998c424e8eSdownsj return (1); 4008c424e8eSdownsj } 4018c424e8eSdownsj 4028c424e8eSdownsj void 4038809fabbSderaadt copyback_sb(struct bufarea *bp) 40465348f21Sjasoni { 40565348f21Sjasoni /* Copy the in-memory superblock back to buffer */ 40660a51e06Spelikan bp->b_un.b_fs->e2fs_icount = letoh32(sblock.e2fs.e2fs_icount); 40760a51e06Spelikan bp->b_un.b_fs->e2fs_bcount = letoh32(sblock.e2fs.e2fs_bcount); 40860a51e06Spelikan bp->b_un.b_fs->e2fs_rbcount = letoh32(sblock.e2fs.e2fs_rbcount); 40960a51e06Spelikan bp->b_un.b_fs->e2fs_fbcount = letoh32(sblock.e2fs.e2fs_fbcount); 41060a51e06Spelikan bp->b_un.b_fs->e2fs_ficount = letoh32(sblock.e2fs.e2fs_ficount); 41165348f21Sjasoni bp->b_un.b_fs->e2fs_first_dblock = 41260a51e06Spelikan letoh32(sblock.e2fs.e2fs_first_dblock); 41360a51e06Spelikan bp->b_un.b_fs->e2fs_log_bsize = letoh32(sblock.e2fs.e2fs_log_bsize); 41460a51e06Spelikan bp->b_un.b_fs->e2fs_log_fsize = letoh32(sblock.e2fs.e2fs_log_fsize); 41560a51e06Spelikan bp->b_un.b_fs->e2fs_bpg = letoh32(sblock.e2fs.e2fs_bpg); 41660a51e06Spelikan bp->b_un.b_fs->e2fs_fpg = letoh32(sblock.e2fs.e2fs_fpg); 41760a51e06Spelikan bp->b_un.b_fs->e2fs_ipg = letoh32(sblock.e2fs.e2fs_ipg); 41860a51e06Spelikan bp->b_un.b_fs->e2fs_mtime = letoh32(sblock.e2fs.e2fs_mtime); 41960a51e06Spelikan bp->b_un.b_fs->e2fs_wtime = letoh32(sblock.e2fs.e2fs_wtime); 42060a51e06Spelikan bp->b_un.b_fs->e2fs_lastfsck = letoh32(sblock.e2fs.e2fs_lastfsck); 42160a51e06Spelikan bp->b_un.b_fs->e2fs_fsckintv = letoh32(sblock.e2fs.e2fs_fsckintv); 42260a51e06Spelikan bp->b_un.b_fs->e2fs_creator = letoh32(sblock.e2fs.e2fs_creator); 42360a51e06Spelikan bp->b_un.b_fs->e2fs_rev = letoh32(sblock.e2fs.e2fs_rev); 42460a51e06Spelikan bp->b_un.b_fs->e2fs_mnt_count = letoh16(sblock.e2fs.e2fs_mnt_count); 42565348f21Sjasoni bp->b_un.b_fs->e2fs_max_mnt_count = 42660a51e06Spelikan letoh16(sblock.e2fs.e2fs_max_mnt_count); 42760a51e06Spelikan bp->b_un.b_fs->e2fs_magic = letoh16(sblock.e2fs.e2fs_magic); 42860a51e06Spelikan bp->b_un.b_fs->e2fs_state = letoh16(sblock.e2fs.e2fs_state); 42960a51e06Spelikan bp->b_un.b_fs->e2fs_beh = letoh16(sblock.e2fs.e2fs_beh); 43060a51e06Spelikan bp->b_un.b_fs->e2fs_ruid = letoh16(sblock.e2fs.e2fs_ruid); 43160a51e06Spelikan bp->b_un.b_fs->e2fs_rgid = letoh16(sblock.e2fs.e2fs_rgid); 43265348f21Sjasoni } 43365348f21Sjasoni 43465348f21Sjasoni void 4358809fabbSderaadt badsb(int listerr, char *s) 4368c424e8eSdownsj { 4378c424e8eSdownsj 4388c424e8eSdownsj if (!listerr) 4398c424e8eSdownsj return; 4408c424e8eSdownsj if (preen) 4418c424e8eSdownsj printf("%s: ", cdevname()); 4428c424e8eSdownsj pfatal("BAD SUPER BLOCK: %s\n", s); 4438c424e8eSdownsj } 4448c424e8eSdownsj 4458c424e8eSdownsj /* 4468c424e8eSdownsj * Calculate a prototype superblock based on information in the disk label. 4478c424e8eSdownsj * When done the cgsblock macro can be calculated and the fs_ncg field 4488c424e8eSdownsj * can be used. Do NOT attempt to use other macros without verifying that 4498c424e8eSdownsj * their needed information is available! 4508c424e8eSdownsj */ 4518c424e8eSdownsj int 452c0c611b7Sderaadt calcsb(char *dev, int devfd, struct m_ext2fs *fs, struct disklabel *lp) 4538c424e8eSdownsj { 4540190393fSart struct partition *pp; 4550190393fSart char *cp; 4568c424e8eSdownsj 457e45111b0Sguenther cp = strchr(dev, '\0'); 458e45111b0Sguenther if ((cp == NULL || (cp[-1] < 'a' || cp[-1] >= 'a' + MAXPARTITIONS)) && 459e45111b0Sguenther !isdigit((unsigned char)cp[-1])) { 4608c424e8eSdownsj pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); 4618c424e8eSdownsj return (0); 4628c424e8eSdownsj } 463e45111b0Sguenther cp--; 464c0c611b7Sderaadt if (lp == NULL) 465c0c611b7Sderaadt pfatal("%s: CANNOT READ DISKLABEL\n", dev); 466e45111b0Sguenther if (isdigit((unsigned char)*cp)) 4678c424e8eSdownsj pp = &lp->d_partitions[0]; 4688c424e8eSdownsj else 4698c424e8eSdownsj pp = &lp->d_partitions[*cp - 'a']; 47065348f21Sjasoni if (pp->p_fstype != FS_EXT2FS) { 47165348f21Sjasoni pfatal("%s: NOT LABELED AS A EXT2 FILE SYSTEM (%s)\n", 4728c424e8eSdownsj dev, pp->p_fstype < FSMAXTYPES ? 4738c424e8eSdownsj fstypenames[pp->p_fstype] : "unknown"); 4748c424e8eSdownsj return (0); 4758c424e8eSdownsj } 4768c424e8eSdownsj memset(fs, 0, sizeof(struct m_ext2fs)); 477ddfcbf38Sotto fs->e2fs_bsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); /* XXX */ 47828704fc2Sderaadt if (fs->e2fs_bsize == 0) { 47928704fc2Sderaadt pfatal("%s: BLOCK SIZE DETERMINED TO BE ZERO\n", dev); 48028704fc2Sderaadt return (0); 48128704fc2Sderaadt } 482ddfcbf38Sotto fs->e2fs.e2fs_log_bsize = fs->e2fs_bsize / 1024; 4838c424e8eSdownsj fs->e2fs.e2fs_bcount = (pp->p_size * DEV_BSIZE) / fs->e2fs_bsize; 48465348f21Sjasoni fs->e2fs.e2fs_first_dblock = (fs->e2fs.e2fs_log_bsize == 0) ? 1 : 0; 4858c424e8eSdownsj fs->e2fs.e2fs_bpg = fs->e2fs_bsize * NBBY; 4868c424e8eSdownsj fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize; 4878c424e8eSdownsj fs->e2fs_qbmask = fs->e2fs_bsize - 1; 4888c424e8eSdownsj fs->e2fs_bmask = ~fs->e2fs_qbmask; 4898c424e8eSdownsj fs->e2fs_ncg = 4908c424e8eSdownsj howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock, 4918c424e8eSdownsj fs->e2fs.e2fs_bpg); 4928c424e8eSdownsj fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1; 4938c424e8eSdownsj fs->e2fs_ngdb = howmany(fs->e2fs_ncg, 4948c424e8eSdownsj fs->e2fs_bsize / sizeof(struct ext2_gd)); 4958c424e8eSdownsj 4968c424e8eSdownsj return (1); 4978c424e8eSdownsj } 4988c424e8eSdownsj 4998c424e8eSdownsj static struct disklabel * 5008809fabbSderaadt getdisklabel(char *s, int fd) 5018c424e8eSdownsj { 5028c424e8eSdownsj static struct disklabel lab; 5038c424e8eSdownsj 504df69c215Sderaadt if (ioctl(fd, DIOCGDINFO, (char *)&lab) == -1) { 5058c424e8eSdownsj if (s == NULL) 506c0c611b7Sderaadt return (NULL); 5078c424e8eSdownsj pwarn("ioctl (GCINFO): %s\n", strerror(errno)); 5088c424e8eSdownsj errexit("%s: can't read disk label\n", s); 5098c424e8eSdownsj } 5108c424e8eSdownsj return (&lab); 5118c424e8eSdownsj } 51265348f21Sjasoni 513b6d2e2d5Sderaadt daddr32_t 5148809fabbSderaadt cgoverhead(int c) 51565348f21Sjasoni { 51665348f21Sjasoni int overh; 51765348f21Sjasoni overh = 1 /* block bitmap */ + 51865348f21Sjasoni 1 /* inode bitmap */ + 51965348f21Sjasoni sblock.e2fs_itpg; 52065348f21Sjasoni if (sblock.e2fs.e2fs_rev > E2FS_REV0 && 521bf2afe82Skevlo sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_SPARSE_SUPER) { 52265348f21Sjasoni if (cg_has_sb(c) == 0) 52365348f21Sjasoni return overh; 52465348f21Sjasoni } 52565348f21Sjasoni overh += 1 + sblock.e2fs_ngdb; 52665348f21Sjasoni return overh; 52765348f21Sjasoni } 528