home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sbin / fsck / setup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  14.5 KB  |  485 lines

  1. /*
  2.  * Copyright (c) 1980, 1986 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)setup.c    5.33 (Berkeley) 2/22/91";
  36. #endif /* not lint */
  37.  
  38. #define DKTYPENAMES
  39. #include <sys/param.h>
  40. #include <ufs/dinode.h>
  41. #include <ufs/fs.h>
  42. #include <sys/stat.h>
  43. #include <sys/ioctl.h>
  44. #include <sys/disklabel.h>
  45. #include <sys/file.h>
  46. #include <errno.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include <ctype.h>
  50. #include "fsck.h"
  51.  
  52. struct bufarea asblk;
  53. #define altsblock (*asblk.b_un.b_fs)
  54. #define POWEROF2(num)    (((num) & ((num) - 1)) == 0)
  55.  
  56. /*
  57.  * The size of a cylinder group is calculated by CGSIZE. The maximum size
  58.  * is limited by the fact that cylinder groups are at most one block.
  59.  * Its size is derived from the size of the maps maintained in the 
  60.  * cylinder group and the (struct cg) size.
  61.  */
  62. #define CGSIZE(fs) \
  63.     /* base cg */    (sizeof(struct cg) + \
  64.     /* blktot size */    (fs)->fs_cpg * sizeof(long) + \
  65.     /* blks size */    (fs)->fs_cpg * (fs)->fs_nrpos * sizeof(short) + \
  66.     /* inode map */    howmany((fs)->fs_ipg, NBBY) + \
  67.     /* block map */    howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY))
  68.  
  69. char    *index();
  70. struct    disklabel *getdisklabel();
  71.  
  72. setup(dev)
  73.     char *dev;
  74. {
  75.     long cg, size, asked, i, j;
  76.     long bmapsize;
  77.     struct disklabel *lp;
  78.     struct stat statb;
  79.     struct fs proto;
  80.  
  81.     havesb = 0;
  82.     if (stat(dev, &statb) < 0) {
  83.         printf("Can't stat %s: %s\n", dev, strerror(errno));
  84.         return (0);
  85.     }
  86.     if ((statb.st_mode & S_IFMT) != S_IFCHR) {
  87.         pfatal("%s is not a character device", dev);
  88.         if (reply("CONTINUE") == 0)
  89.             return (0);
  90.     }
  91.     if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
  92.         printf("Can't open %s: %s\n", dev, strerror(errno));
  93.         return (0);
  94.     }
  95.     if (preen == 0)
  96.         printf("** %s", dev);
  97.     if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) {
  98.         fswritefd = -1;
  99.         if (preen)
  100.             pfatal("NO WRITE ACCESS");
  101.         printf(" (NO WRITE)");
  102.     }
  103.     if (preen == 0)
  104.         printf("\n");
  105.     fsmodified = 0;
  106.     lfdir = 0;
  107.     initbarea(&sblk);
  108.     initbarea(&asblk);
  109.     sblk.b_un.b_buf = malloc(SBSIZE);
  110.     asblk.b_un.b_buf = malloc(SBSIZE);
  111.     if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
  112.         errexit("cannot allocate space for superblock\n");
  113.     if (lp = getdisklabel((char *)NULL, fsreadfd))
  114.         dev_bsize = secsize = lp->d_secsize;
  115.     else
  116.         dev_bsize = secsize = DEV_BSIZE;
  117. #ifdef tahoe
  118.     /*
  119.      * On the tahoe, the disk label and the disk driver disagree.
  120.      * The label knows that sectors are 512 bytes, but the disk
  121.      * drivers will only transfer in 1024 sized pieces.
  122.      */
  123.     secsize = 1024;
  124. #endif
  125.     /*
  126.      * Read in the superblock, looking for alternates if necessary
  127.      */
  128.     if (readsb(1) == 0) {
  129.         if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
  130.             return(0);
  131.         if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
  132.             return (0);
  133.         for (cg = 0; cg < proto.fs_ncg; cg++) {
  134.             bflag = fsbtodb(&proto, cgsblock(&proto, cg));
  135.             if (readsb(0) != 0)
  136.                 break;
  137.         }
  138.         if (cg >= proto.fs_ncg) {
  139.             printf("%s %s\n%s %s\n%s %s\n",
  140.                 "SEARCH FOR ALTERNATE SUPER-BLOCK",
  141.                 "FAILED. YOU MUST USE THE",
  142.                 "-b OPTION TO FSCK TO SPECIFY THE",
  143.                 "LOCATION OF AN ALTERNATE",
  144.                 "SUPER-BLOCK TO SUPPLY NEEDED",
  145.                 "INFORMATION; SEE fsck(8).");
  146.             return(0);
  147.         }
  148.         pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
  149.     }
  150.     maxfsblock = sblock.fs_size;
  151.     maxino = sblock.fs_ncg * sblock.fs_ipg;
  152.     /*
  153.      * Check and potentially fix certain fields in the super block.
  154.      */
  155.     if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
  156.         pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
  157.         if (reply("SET TO DEFAULT") == 1) {
  158.             sblock.fs_optim = FS_OPTTIME;
  159.             sbdirty();
  160.         }
  161.     }
  162.     if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
  163.         pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
  164.             sblock.fs_minfree);
  165.         if (reply("SET TO DEFAULT") == 1) {
  166.             sblock.fs_minfree = 10;
  167.             sbdirty();
  168.         }
  169.     }
  170.     if (sblock.fs_interleave < 1 || 
  171.         sblock.fs_interleave > sblock.fs_nsect) {
  172.         pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK",
  173.             sblock.fs_interleave);
  174.         sblock.fs_interleave = 1;
  175.         if (preen)
  176.             printf(" (FIXED)\n");
  177.         if (preen || reply("SET TO DEFAULT") == 1) {
  178.             sbdirty();
  179.             dirty(&asblk);
  180.         }
  181.     }
  182.     if (sblock.fs_npsect < sblock.fs_nsect || 
  183.         sblock.fs_npsect > sblock.fs_nsect*2) {
  184.         pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
  185.             sblock.fs_npsect);
  186.         sblock.fs_npsect = sblock.fs_nsect;
  187.         if (preen)
  188.             printf(" (FIXED)\n");
  189.         if (preen || reply("SET TO DEFAULT") == 1) {
  190.             sbdirty();
  191.             dirty(&asblk);
  192.         }
  193.     }
  194.     if (cvtflag) {
  195.         if (sblock.fs_postblformat == FS_42POSTBLFMT) {
  196.             /*
  197.              * Requested to convert from old format to new format
  198.              */
  199.             if (preen)
  200.                 pwarn("CONVERTING TO NEW FILE SYSTEM FORMAT\n");
  201.             else if (!reply("CONVERT TO NEW FILE SYSTEM FORMAT"))
  202.                 return(0);
  203.             sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
  204.             sblock.fs_nrpos = 8;
  205.             sblock.fs_postbloff =
  206.                 (char *)(&sblock.fs_opostbl[0][0]) -
  207.                 (char *)(&sblock.fs_link);
  208.             sblock.fs_rotbloff = &sblock.fs_space[0] -
  209.                 (u_char *)(&sblock.fs_link);
  210.             sblock.fs_cgsize =
  211.                 fragroundup(&sblock, CGSIZE(&sblock));
  212.             /*
  213.              * Planning now for future expansion.
  214.              */
  215. #            if (BYTE_ORDER == BIG_ENDIAN)
  216.                 sblock.fs_qbmask.val[0] = 0;
  217.                 sblock.fs_qbmask.val[1] = ~sblock.fs_bmask;
  218.                 sblock.fs_qfmask.val[0] = 0;
  219.                 sblock.fs_qfmask.val[1] = ~sblock.fs_fmask;
  220. #            endif /* BIG_ENDIAN */
  221. #            if (BYTE_ORDER == LITTLE_ENDIAN)
  222.                 sblock.fs_qbmask.val[0] = ~sblock.fs_bmask;
  223.                 sblock.fs_qbmask.val[1] = 0;
  224.                 sblock.fs_qfmask.val[0] = ~sblock.fs_fmask;
  225.                 sblock.fs_qfmask.val[1] = 0;
  226. #            endif /* LITTLE_ENDIAN */
  227.             sbdirty();
  228.             dirty(&asblk);
  229.         } else if (sblock.fs_postblformat == FS_DYNAMICPOSTBLFMT) {
  230.             /*
  231.              * Requested to convert from new format to old format
  232.              */
  233.             if (sblock.fs_nrpos != 8 || sblock.fs_ipg > 2048 ||
  234.                 sblock.fs_cpg > 32 || sblock.fs_cpc > 16) {
  235.                 printf(
  236.                 "PARAMETERS OF CURRENT FILE SYSTEM DO NOT\n\t");
  237.                 errexit(
  238.                 "ALLOW CONVERSION TO OLD FILE SYSTEM FORMAT\n");
  239.             }
  240.             if (preen)
  241.                 pwarn("CONVERTING TO OLD FILE SYSTEM FORMAT\n");
  242.             else if (!reply("CONVERT TO OLD FILE SYSTEM FORMAT"))
  243.                 return(0);
  244.             sblock.fs_postblformat = FS_42POSTBLFMT;
  245.             sblock.fs_cgsize = fragroundup(&sblock,
  246.                 sizeof(struct ocg) + howmany(sblock.fs_fpg, NBBY));
  247.             sbdirty();
  248.             dirty(&asblk);
  249.         } else {
  250.             errexit("UNKNOWN FILE SYSTEM FORMAT\n");
  251.         }
  252.     }
  253.     if (asblk.b_dirty) {
  254.         bcopy((char *)&sblock, (char *)&altsblock,
  255.             (size_t)sblock.fs_sbsize);
  256.         flush(fswritefd, &asblk);
  257.     }
  258.     /*
  259.      * read in the summary info.
  260.      */
  261.     asked = 0;
  262.     for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
  263.         size = sblock.fs_cssize - i < sblock.fs_bsize ?
  264.             sblock.fs_cssize - i : sblock.fs_bsize;
  265.         sblock.fs_csp[j] = (struct csum *)calloc(1, (unsigned)size);
  266.         if (bread(fsreadfd, (char *)sblock.fs_csp[j],
  267.             fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
  268.             size) != 0 && !asked) {
  269.             pfatal("BAD SUMMARY INFORMATION");
  270.             if (reply("CONTINUE") == 0)
  271.                 errexit("");
  272.             asked++;
  273.         }
  274.     }
  275.     /*
  276.      * allocate and initialize the necessary maps
  277.      */
  278.     bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(short));
  279.     blockmap = calloc((unsigned)bmapsize, sizeof (char));
  280.     if (blockmap == NULL) {
  281.         printf("cannot alloc %u bytes for blockmap\n",
  282.             (unsigned)bmapsize);
  283.         goto badsb;
  284.     }
  285.     statemap = calloc((unsigned)(maxino + 1), sizeof(char));
  286.     if (statemap == NULL) {
  287.         printf("cannot alloc %u bytes for statemap\n",
  288.             (unsigned)(maxino + 1));
  289.         goto badsb;
  290.     }
  291.     lncntp = (short *)calloc((unsigned)(maxino + 1), sizeof(short));
  292.     if (lncntp == NULL) {
  293.         printf("cannot alloc %u bytes for lncntp\n", 
  294.             (unsigned)(maxino + 1) * sizeof(short));
  295.         goto badsb;
  296.     }
  297.     numdirs = sblock.fs_cstotal.cs_ndir;
  298.     inplast = 0;
  299.     listmax = numdirs + 10;
  300.     inpsort = (struct inoinfo **)calloc((unsigned)listmax,
  301.         sizeof(struct inoinfo *));
  302.     inphead = (struct inoinfo **)calloc((unsigned)numdirs,
  303.         sizeof(struct inoinfo *));
  304.     if (inpsort == NULL || inphead == NULL) {
  305.         printf("cannot alloc %u bytes for inphead\n", 
  306.             (unsigned)numdirs * sizeof(struct inoinfo *));
  307.         goto badsb;
  308.     }
  309.     bufinit();
  310.     return (1);
  311.  
  312. badsb:
  313.     ckfini();
  314.     return (0);
  315. }
  316.  
  317. /*
  318.  * Read in the super block and its summary info.
  319.  */
  320. readsb(listerr)
  321.     int listerr;
  322. {
  323.     daddr_t super = bflag ? bflag : SBOFF / dev_bsize;
  324.  
  325.     if (bread(fsreadfd, (char *)&sblock, super, (long)SBSIZE) != 0)
  326.         return (0);
  327.     sblk.b_bno = super;
  328.     sblk.b_size = SBSIZE;
  329.     /*
  330.      * run a few consistency checks of the super block
  331.      */
  332.     if (sblock.fs_magic != FS_MAGIC)
  333.         { badsb(listerr, "MAGIC NUMBER WRONG"); return (0); }
  334.     if (sblock.fs_ncg < 1)
  335.         { badsb(listerr, "NCG OUT OF RANGE"); return (0); }
  336.     if (sblock.fs_cpg < 1)
  337.         { badsb(listerr, "CPG OUT OF RANGE"); return (0); }
  338.     if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
  339.         (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
  340.         { badsb(listerr, "NCYL LESS THAN NCG*CPG"); return (0); }
  341.     if (sblock.fs_sbsize > SBSIZE)
  342.         { badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
  343.     /*
  344.      * Compute block size that the filesystem is based on,
  345.      * according to fsbtodb, and adjust superblock block number
  346.      * so we can tell if this is an alternate later.
  347.      */
  348.     super *= dev_bsize;
  349.     dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
  350.     sblk.b_bno = super / dev_bsize;
  351.     /*
  352.      * Set all possible fields that could differ, then do check
  353.      * of whole super block against an alternate super block.
  354.      * When an alternate super-block is specified this check is skipped.
  355.      */
  356.     getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
  357.     if (asblk.b_errs)
  358.         return (0);
  359.     if (bflag) {
  360.         havesb = 1;
  361.         return (1);
  362.     }
  363.     altsblock.fs_link = sblock.fs_link;
  364.     altsblock.fs_rlink = sblock.fs_rlink;
  365.     altsblock.fs_time = sblock.fs_time;
  366.     altsblock.fs_cstotal = sblock.fs_cstotal;
  367.     altsblock.fs_cgrotor = sblock.fs_cgrotor;
  368.     altsblock.fs_fmod = sblock.fs_fmod;
  369.     altsblock.fs_clean = sblock.fs_clean;
  370.     altsblock.fs_ronly = sblock.fs_ronly;
  371.     altsblock.fs_flags = sblock.fs_flags;
  372.     altsblock.fs_maxcontig = sblock.fs_maxcontig;
  373.     altsblock.fs_minfree = sblock.fs_minfree;
  374.     altsblock.fs_optim = sblock.fs_optim;
  375.     altsblock.fs_rotdelay = sblock.fs_rotdelay;
  376.     altsblock.fs_maxbpg = sblock.fs_maxbpg;
  377.     bcopy((char *)sblock.fs_csp, (char *)altsblock.fs_csp,
  378.         sizeof sblock.fs_csp);
  379.     bcopy((char *)sblock.fs_fsmnt, (char *)altsblock.fs_fsmnt,
  380.         sizeof sblock.fs_fsmnt);
  381.     bcopy((char *)sblock.fs_sparecon, (char *)altsblock.fs_sparecon,
  382.         sizeof sblock.fs_sparecon);
  383.     /*
  384.      * The following should not have to be copied.
  385.      */
  386.     altsblock.fs_fsbtodb = sblock.fs_fsbtodb;
  387.     altsblock.fs_interleave = sblock.fs_interleave;
  388.     altsblock.fs_npsect = sblock.fs_npsect;
  389.     altsblock.fs_nrpos = sblock.fs_nrpos;
  390.     if (bcmp((char *)&sblock, (char *)&altsblock, (int)sblock.fs_sbsize)) {
  391.         badsb(listerr,
  392.         "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
  393.         return (0);
  394.     }
  395.     havesb = 1;
  396.     return (1);
  397. }
  398.  
  399. badsb(listerr, s)
  400.     int listerr;
  401.     char *s;
  402. {
  403.  
  404.     if (!listerr)
  405.         return;
  406.     if (preen)
  407.         printf("%s: ", devname);
  408.     pfatal("BAD SUPER BLOCK: %s\n", s);
  409. }
  410.  
  411. /*
  412.  * Calculate a prototype superblock based on information in the disk label.
  413.  * When done the cgsblock macro can be calculated and the fs_ncg field
  414.  * can be used. Do NOT attempt to use other macros without verifying that
  415.  * their needed information is available!
  416.  */
  417. calcsb(dev, devfd, fs)
  418.     char *dev;
  419.     int devfd;
  420.     register struct fs *fs;
  421. {
  422.     register struct disklabel *lp;
  423.     register struct partition *pp;
  424.     register char *cp;
  425.     int i;
  426.  
  427.     cp = index(dev, '\0') - 1;
  428.     if (cp == (char *)-1 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)) {
  429.         pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
  430.         return (0);
  431.     }
  432.     lp = getdisklabel(dev, devfd);
  433.     if (isdigit(*cp))
  434.         pp = &lp->d_partitions[0];
  435.     else
  436.         pp = &lp->d_partitions[*cp - 'a'];
  437.     if (pp->p_fstype != FS_BSDFFS) {
  438.         pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n",
  439.             dev, pp->p_fstype < FSMAXTYPES ?
  440.             fstypenames[pp->p_fstype] : "unknown");
  441.         return (0);
  442.     }
  443.     bzero((char *)fs, sizeof(struct fs));
  444.     fs->fs_fsize = pp->p_fsize;
  445.     fs->fs_frag = pp->p_frag;
  446.     fs->fs_cpg = pp->p_cpg;
  447.     fs->fs_size = pp->p_size;
  448.     fs->fs_ntrak = lp->d_ntracks;
  449.     fs->fs_nsect = lp->d_nsectors;
  450.     fs->fs_spc = lp->d_secpercyl;
  451.     fs->fs_nspf = fs->fs_fsize / lp->d_secsize;
  452.     fs->fs_sblkno = roundup(
  453.         howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize),
  454.         fs->fs_frag);
  455.     fs->fs_cgmask = 0xffffffff;
  456.     for (i = fs->fs_ntrak; i > 1; i >>= 1)
  457.         fs->fs_cgmask <<= 1;
  458.     if (!POWEROF2(fs->fs_ntrak))
  459.         fs->fs_cgmask <<= 1;
  460.     fs->fs_cgoffset = roundup(
  461.         howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag);
  462.     fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs);
  463.     fs->fs_ncg = howmany(fs->fs_size / fs->fs_spc, fs->fs_cpg);
  464.     for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1)
  465.         fs->fs_fsbtodb++;
  466.     dev_bsize = lp->d_secsize;
  467.     return (1);
  468. }
  469.  
  470. struct disklabel *
  471. getdisklabel(s, fd)
  472.     char *s;
  473.     int    fd;
  474. {
  475.     static struct disklabel lab;
  476.  
  477.     if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
  478.         if (s == NULL)
  479.             return ((struct disklabel *)NULL);
  480.         pwarn("ioctl (GCINFO): %s\n", strerror(errno));
  481.         errexit("%s: can't read disk label\n", s);
  482.     }
  483.     return (&lab);
  484. }
  485.