home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sbin / fsck / pass2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  10.9 KB  |  393 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[] = "@(#)pass2.c    5.17 (Berkeley) 12/28/90";
  36. #endif /* not lint */
  37.  
  38. #include <sys/param.h>
  39. #include <ufs/dinode.h>
  40. #include <ufs/fs.h>
  41. #define KERNEL
  42. #include <ufs/dir.h>
  43. #undef KERNEL
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include "fsck.h"
  47.  
  48. #define MINDIRSIZE    (sizeof (struct dirtemplate))
  49.  
  50. int    pass2check(), blksort();
  51.  
  52. pass2()
  53. {
  54.     register struct dinode *dp;
  55.     register struct inoinfo **inpp, *inp;
  56.     struct inoinfo **inpend;
  57.     struct inodesc curino;
  58.     struct dinode dino;
  59.     char pathbuf[MAXPATHLEN + 1];
  60.  
  61.     switch (statemap[ROOTINO]) {
  62.  
  63.     case USTATE:
  64.         pfatal("ROOT INODE UNALLOCATED");
  65.         if (reply("ALLOCATE") == 0)
  66.             errexit("");
  67.         if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
  68.             errexit("CANNOT ALLOCATE ROOT INODE\n");
  69.         break;
  70.  
  71.     case DCLEAR:
  72.         pfatal("DUPS/BAD IN ROOT INODE");
  73.         if (reply("REALLOCATE")) {
  74.             freeino(ROOTINO);
  75.             if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
  76.                 errexit("CANNOT ALLOCATE ROOT INODE\n");
  77.             break;
  78.         }
  79.         if (reply("CONTINUE") == 0)
  80.             errexit("");
  81.         break;
  82.  
  83.     case FSTATE:
  84.     case FCLEAR:
  85.         pfatal("ROOT INODE NOT DIRECTORY");
  86.         if (reply("REALLOCATE")) {
  87.             freeino(ROOTINO);
  88.             if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
  89.                 errexit("CANNOT ALLOCATE ROOT INODE\n");
  90.             break;
  91.         }
  92.         if (reply("FIX") == 0)
  93.             errexit("");
  94.         dp = ginode(ROOTINO);
  95.         dp->di_mode &= ~IFMT;
  96.         dp->di_mode |= IFDIR;
  97.         inodirty();
  98.         break;
  99.  
  100.     case DSTATE:
  101.         break;
  102.  
  103.     default:
  104.         errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
  105.     }
  106.     statemap[ROOTINO] = DFOUND;
  107.     /*
  108.      * Sort the directory list into disk block order.
  109.      */
  110.     qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort);
  111.     /*
  112.      * Check the integrity of each directory.
  113.      */
  114.     bzero((char *)&curino, sizeof(struct inodesc));
  115.     curino.id_type = DATA;
  116.     curino.id_func = pass2check;
  117.     dino.di_mode = IFDIR;
  118.     dp = &dino;
  119.     inpend = &inpsort[inplast];
  120.     for (inpp = inpsort; inpp < inpend; inpp++) {
  121.         inp = *inpp;
  122.         if (inp->i_isize == 0)
  123.             continue;
  124.         if (inp->i_isize < MINDIRSIZE) {
  125.             direrror(inp->i_number, "DIRECTORY TOO SHORT");
  126.             inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ);
  127.             if (reply("FIX") == 1) {
  128.                 dp = ginode(inp->i_number);
  129.                 dp->di_size = inp->i_isize;
  130.                 inodirty();
  131.                 dp = &dino;
  132.             }
  133.         } else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) {
  134.             getpathname(pathbuf, inp->i_number, inp->i_number);
  135.             pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d",
  136.                 pathbuf, inp->i_isize, DIRBLKSIZ);
  137.             if (preen)
  138.                 printf(" (ADJUSTED)\n");
  139.             inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ);
  140.             if (preen || reply("ADJUST") == 1) {
  141.                 dp = ginode(inp->i_number);
  142.                 dp->di_size = roundup(inp->i_isize, DIRBLKSIZ);
  143.                 inodirty();
  144.                 dp = &dino;
  145.             }
  146.         }
  147.         dp->di_size = inp->i_isize;
  148.         bcopy((char *)&inp->i_blks[0], (char *)&dp->di_db[0],
  149.             (size_t)inp->i_numblks);
  150.         curino.id_number = inp->i_number;
  151.         curino.id_parent = inp->i_parent;
  152.         (void)ckinode(dp, &curino);
  153.     }
  154.     /*
  155.      * Now that the parents of all directories have been found,
  156.      * make another pass to verify the value of `..'
  157.      */
  158.     for (inpp = inpsort; inpp < inpend; inpp++) {
  159.         inp = *inpp;
  160.         if (inp->i_parent == 0 || inp->i_isize == 0)
  161.             continue;
  162.         if (statemap[inp->i_parent] == DFOUND &&
  163.             statemap[inp->i_number] == DSTATE)
  164.             statemap[inp->i_number] = DFOUND;
  165.         if (inp->i_dotdot == inp->i_parent ||
  166.             inp->i_dotdot == (ino_t)-1)
  167.             continue;
  168.         if (inp->i_dotdot == 0) {
  169.             inp->i_dotdot = inp->i_parent;
  170.             fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
  171.             if (reply("FIX") == 0)
  172.                 continue;
  173.             (void)makeentry(inp->i_number, inp->i_parent, "..");
  174.             lncntp[inp->i_parent]--;
  175.             continue;
  176.         }
  177.         fileerror(inp->i_parent, inp->i_number,
  178.             "BAD INODE NUMBER FOR '..'");
  179.         if (reply("FIX") == 0)
  180.             continue;
  181.         lncntp[inp->i_dotdot]++;
  182.         lncntp[inp->i_parent]--;
  183.         inp->i_dotdot = inp->i_parent;
  184.         (void)changeino(inp->i_number, "..", inp->i_parent);
  185.     }
  186.     /*
  187.      * Mark all the directories that can be found from the root.
  188.      */
  189.     propagate();
  190. }
  191.  
  192. pass2check(idesc)
  193.     struct inodesc *idesc;
  194. {
  195.     register struct direct *dirp = idesc->id_dirp;
  196.     register struct inoinfo *inp;
  197.     int n, entrysize, ret = 0;
  198.     struct dinode *dp;
  199.     char *errmsg;
  200.     struct direct proto;
  201.     char namebuf[MAXPATHLEN + 1];
  202.     char pathbuf[MAXPATHLEN + 1];
  203.  
  204.     /* 
  205.      * check for "."
  206.      */
  207.     if (idesc->id_entryno != 0)
  208.         goto chk1;
  209.     if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
  210.         if (dirp->d_ino != idesc->id_number) {
  211.             direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
  212.             dirp->d_ino = idesc->id_number;
  213.             if (reply("FIX") == 1)
  214.                 ret |= ALTERED;
  215.         }
  216.         goto chk1;
  217.     }
  218.     direrror(idesc->id_number, "MISSING '.'");
  219.     proto.d_ino = idesc->id_number;
  220.     proto.d_namlen = 1;
  221.     (void)strcpy(proto.d_name, ".");
  222.     entrysize = DIRSIZ(&proto);
  223.     if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
  224.         pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
  225.             dirp->d_name);
  226.     } else if (dirp->d_reclen < entrysize) {
  227.         pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
  228.     } else if (dirp->d_reclen < 2 * entrysize) {
  229.         proto.d_reclen = dirp->d_reclen;
  230.         bcopy((char *)&proto, (char *)dirp, (size_t)entrysize);
  231.         if (reply("FIX") == 1)
  232.             ret |= ALTERED;
  233.     } else {
  234.         n = dirp->d_reclen - entrysize;
  235.         proto.d_reclen = entrysize;
  236.         bcopy((char *)&proto, (char *)dirp, (size_t)entrysize);
  237.         idesc->id_entryno++;
  238.         lncntp[dirp->d_ino]--;
  239.         dirp = (struct direct *)((char *)(dirp) + entrysize);
  240.         bzero((char *)dirp, (size_t)n);
  241.         dirp->d_reclen = n;
  242.         if (reply("FIX") == 1)
  243.             ret |= ALTERED;
  244.     }
  245. chk1:
  246.     if (idesc->id_entryno > 1)
  247.         goto chk2;
  248.     inp = getinoinfo(idesc->id_number);
  249.     proto.d_ino = inp->i_parent;
  250.     proto.d_namlen = 2;
  251.     (void)strcpy(proto.d_name, "..");
  252.     entrysize = DIRSIZ(&proto);
  253.     if (idesc->id_entryno == 0) {
  254.         n = DIRSIZ(dirp);
  255.         if (dirp->d_reclen < n + entrysize)
  256.             goto chk2;
  257.         proto.d_reclen = dirp->d_reclen - n;
  258.         dirp->d_reclen = n;
  259.         idesc->id_entryno++;
  260.         lncntp[dirp->d_ino]--;
  261.         dirp = (struct direct *)((char *)(dirp) + n);
  262.         bzero((char *)dirp, (size_t)proto.d_reclen);
  263.         dirp->d_reclen = proto.d_reclen;
  264.     }
  265.     if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
  266.         inp->i_dotdot = dirp->d_ino;
  267.         goto chk2;
  268.     }
  269.     if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
  270.         fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
  271.         pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
  272.             dirp->d_name);
  273.         inp->i_dotdot = (ino_t)-1;
  274.     } else if (dirp->d_reclen < entrysize) {
  275.         fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
  276.         pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
  277.         inp->i_dotdot = (ino_t)-1;
  278.     } else if (inp->i_parent != 0) {
  279.         /*
  280.          * We know the parent, so fix now.
  281.          */
  282.         inp->i_dotdot = inp->i_parent;
  283.         fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
  284.         proto.d_reclen = dirp->d_reclen;
  285.         bcopy((char *)&proto, (char *)dirp, (size_t)entrysize);
  286.         if (reply("FIX") == 1)
  287.             ret |= ALTERED;
  288.     }
  289.     idesc->id_entryno++;
  290.     if (dirp->d_ino != 0)
  291.         lncntp[dirp->d_ino]--;
  292.     return (ret|KEEPON);
  293. chk2:
  294.     if (dirp->d_ino == 0)
  295.         return (ret|KEEPON);
  296.     if (dirp->d_namlen <= 2 &&
  297.         dirp->d_name[0] == '.' &&
  298.         idesc->id_entryno >= 2) {
  299.         if (dirp->d_namlen == 1) {
  300.             direrror(idesc->id_number, "EXTRA '.' ENTRY");
  301.             dirp->d_ino = 0;
  302.             if (reply("FIX") == 1)
  303.                 ret |= ALTERED;
  304.             return (KEEPON | ret);
  305.         }
  306.         if (dirp->d_name[1] == '.') {
  307.             direrror(idesc->id_number, "EXTRA '..' ENTRY");
  308.             dirp->d_ino = 0;
  309.             if (reply("FIX") == 1)
  310.                 ret |= ALTERED;
  311.             return (KEEPON | ret);
  312.         }
  313.     }
  314.     idesc->id_entryno++;
  315.     n = 0;
  316.     if (dirp->d_ino > maxino) {
  317.         fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
  318.         n = reply("REMOVE");
  319.     } else {
  320. again:
  321.         switch (statemap[dirp->d_ino]) {
  322.         case USTATE:
  323.             if (idesc->id_entryno <= 2)
  324.                 break;
  325.             fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED");
  326.             n = reply("REMOVE");
  327.             break;
  328.  
  329.         case DCLEAR:
  330.         case FCLEAR:
  331.             if (idesc->id_entryno <= 2)
  332.                 break;
  333.             if (statemap[dirp->d_ino] == DCLEAR)
  334.                 errmsg = "ZERO LENGTH DIRECTORY";
  335.             else
  336.                 errmsg = "DUP/BAD";
  337.             fileerror(idesc->id_number, dirp->d_ino, errmsg);
  338.             if ((n = reply("REMOVE")) == 1)
  339.                 break;
  340.             dp = ginode(dirp->d_ino);
  341.             statemap[dirp->d_ino] =
  342.                 (dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
  343.             lncntp[dirp->d_ino] = dp->di_nlink;
  344.             goto again;
  345.  
  346.         case DSTATE:
  347.             if (statemap[idesc->id_number] == DFOUND)
  348.                 statemap[dirp->d_ino] = DFOUND;
  349.             /* fall through */
  350.  
  351.         case DFOUND:
  352.             inp = getinoinfo(dirp->d_ino);
  353.             if (inp->i_parent != 0 && idesc->id_entryno > 2) {
  354.                 getpathname(pathbuf, idesc->id_number,
  355.                     idesc->id_number);
  356.                 getpathname(namebuf, dirp->d_ino, dirp->d_ino);
  357.                 pwarn("%s %s %s\n", pathbuf,
  358.                     "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
  359.                     namebuf);
  360.                 if (preen)
  361.                     printf(" (IGNORED)\n");
  362.                 else if ((n = reply("REMOVE")) == 1)
  363.                     break;
  364.             }
  365.             if (idesc->id_entryno > 2)
  366.                 inp->i_parent = idesc->id_number;
  367.             /* fall through */
  368.  
  369.         case FSTATE:
  370.             lncntp[dirp->d_ino]--;
  371.             break;
  372.  
  373.         default:
  374.             errexit("BAD STATE %d FOR INODE I=%d",
  375.                 statemap[dirp->d_ino], dirp->d_ino);
  376.         }
  377.     }
  378.     if (n == 0)
  379.         return (ret|KEEPON);
  380.     dirp->d_ino = 0;
  381.     return (ret|KEEPON|ALTERED);
  382. }
  383.  
  384. /*
  385.  * Routine to sort disk blocks.
  386.  */
  387. blksort(inpp1, inpp2)
  388.     struct inoinfo **inpp1, **inpp2;
  389. {
  390.  
  391.     return ((*inpp1)->i_blks[0] - (*inpp2)->i_blks[0]);
  392. }
  393.