1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms are permitted 14 * provided that: (1) source distributions retain this entire copyright 15 * notice and comment, and (2) distributions including binaries display 16 * the following acknowledgement: ``This product includes software 17 * developed by the University of California, Berkeley and its contributors'' 18 * in the documentation or other materials provided with the distribution 19 * and in all advertising materials mentioning features or use of this 20 * software. Neither the name of the University nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <sys/param.h> 33 #include <sys/types.h> 34 #include <sys/sysmacros.h> 35 #include <sys/mntent.h> 36 #include <sys/fs/ufs_fs.h> 37 #include <sys/vnode.h> 38 #include <sys/fs/ufs_inode.h> 39 #define _KERNEL 40 #include <sys/fs/ufs_fsdir.h> 41 #undef _KERNEL 42 #include <string.h> 43 #include "fsck.h" 44 45 #define MINDIRSIZE (sizeof (struct dirtemplate)) 46 47 static int blksort(const void *, const void *); 48 static int pass2check(struct inodesc *); 49 50 void 51 pass2(void) 52 { 53 struct dinode *dp, *dp2, *dpattr; 54 struct inoinfo **inpp, *inp; 55 struct inoinfo **inpend; 56 struct inodesc curino; 57 struct inodesc ldesc; 58 struct dinode dino; 59 char pathbuf[MAXPATHLEN + 1]; 60 int found; 61 int dirtype; 62 caddr_t errmsg; 63 struct shadowclientinfo *sci; 64 65 switch (statemap[UFSROOTINO] & ~INDELAYD) { 66 case USTATE: 67 pfatal("ROOT INODE UNALLOCATED"); 68 if (reply("ALLOCATE") == 0) { 69 errexit("Program terminated."); 70 } 71 if (allocdir(UFSROOTINO, UFSROOTINO, 0755, 0) != UFSROOTINO) 72 errexit("CANNOT ALLOCATE ROOT INODE\n"); 73 break; 74 75 case DCLEAR: 76 pfatal("DUPS/BAD IN ROOT INODE"); 77 if (reply("REALLOCATE") == 1) { 78 freeino(UFSROOTINO, TI_NOPARENT); 79 if (allocdir(UFSROOTINO, UFSROOTINO, 80 0755, 0) != UFSROOTINO) 81 errexit("CANNOT ALLOCATE ROOT INODE\n"); 82 break; 83 } 84 if (reply("CONTINUE") == 0) { 85 errexit("Program terminated."); 86 } 87 break; 88 89 case FSTATE: 90 case FCLEAR: 91 case FZLINK: 92 case SSTATE: 93 case SCLEAR: 94 pfatal("ROOT INODE NOT DIRECTORY"); 95 if (reply("REALLOCATE") == 1) { 96 freeino(UFSROOTINO, TI_NOPARENT); 97 if (allocdir(UFSROOTINO, UFSROOTINO, 0755, 0) != 98 UFSROOTINO) 99 errexit("CANNOT ALLOCATE ROOT INODE\n"); 100 break; 101 } 102 if (reply("FIX") == 0) { 103 ckfini(); 104 errexit("Program terminated."); 105 } 106 dp = ginode(UFSROOTINO); 107 dp->di_mode &= ~IFMT; 108 dp->di_mode |= IFDIR; 109 inodirty(); 110 break; 111 112 case DSTATE: 113 case DZLINK: 114 break; 115 116 default: 117 errexit("BAD STATE 0x%x FOR ROOT INODE\n", 118 statemap[UFSROOTINO]); 119 } 120 statemap[UFSROOTINO] = DFOUND; 121 122 /* 123 * Technically, we do know who the parent is. However, 124 * if this is set, then we'll get confused during the 125 * second-dir-entry-is-dotdot test for the root inode. 126 */ 127 inp = getinoinfo(UFSROOTINO); 128 if (inp != NULL && inp->i_dotdot != 0) 129 inp->i_dotdot = 0; 130 131 /* 132 * Sort the directory list into disk block order. There's no 133 * requirement to do this, but it may help improve our i/o times 134 * somewhat. 135 */ 136 qsort((void *)inpsort, (size_t)inplast, sizeof (*inpsort), blksort); 137 /* 138 * Check the integrity of each directory. In general, we treat 139 * attribute directories just like normal ones. Only the handling 140 * of .. is really different. 141 */ 142 (void) memset(&dino, 0, sizeof (struct dinode)); 143 dino.di_mode = IFDIR; 144 inpend = &inpsort[inplast]; 145 for (inpp = inpsort; inpp < inpend; inpp++) { 146 inp = *inpp; 147 148 if (inp->i_isize == 0) 149 continue; 150 151 /* != DSTATE also covers case of == USTATE */ 152 if (((statemap[inp->i_number] & STMASK) != DSTATE) || 153 ((statemap[inp->i_number] & INCLEAR) == INCLEAR)) 154 continue; 155 156 if (inp->i_isize < (offset_t)MINDIRSIZE) { 157 direrror(inp->i_number, "DIRECTORY TOO SHORT"); 158 inp->i_isize = (offset_t)roundup(MINDIRSIZE, DIRBLKSIZ); 159 if (reply("FIX") == 1) { 160 dp = ginode(inp->i_number); 161 dp->di_size = (u_offset_t)inp->i_isize; 162 inodirty(); 163 } else { 164 iscorrupt = 1; 165 } 166 } 167 if ((inp->i_isize & (offset_t)(DIRBLKSIZ - 1)) != 0) { 168 getpathname(pathbuf, inp->i_number, inp->i_number); 169 pwarn("DIRECTORY %s: LENGTH %lld NOT MULTIPLE OF %d", 170 pathbuf, (longlong_t)inp->i_isize, DIRBLKSIZ); 171 inp->i_isize = roundup(inp->i_isize, 172 (offset_t)DIRBLKSIZ); 173 if (preen || reply("ADJUST") == 1) { 174 dp = ginode(inp->i_number); 175 dp->di_size = 176 (u_offset_t)roundup(inp->i_isize, 177 (offset_t)DIRBLKSIZ); 178 inodirty(); 179 if (preen) 180 (void) printf(" (ADJUSTED)\n"); 181 } else { 182 iscorrupt = 1; 183 } 184 } 185 dp = ginode(inp->i_number); 186 if ((dp->di_mode & IFMT) == IFATTRDIR && 187 (dp->di_cflags & IXATTR) == 0) { 188 pwarn("ATTRIBUTE DIRECTORY I=%d MISSING IXATTR FLAG", 189 inp->i_number); 190 if (preen || reply("CORRECT") == 1) { 191 dp->di_cflags |= IXATTR; 192 inodirty(); 193 if (preen) 194 (void) printf(" (CORRECTED)\n"); 195 } 196 } 197 dp = &dino; 198 dp->di_size = (u_offset_t)inp->i_isize; 199 (void) memmove((void *)&dp->di_db[0], (void *)&inp->i_blks[0], 200 inp->i_blkssize); 201 init_inodesc(&curino); 202 curino.id_type = DATA; 203 curino.id_func = pass2check; 204 curino.id_number = inp->i_number; 205 curino.id_parent = inp->i_parent; 206 curino.id_fix = DONTKNOW; 207 (void) ckinode(dp, &curino, CKI_TRAVERSE); 208 209 /* 210 * Make sure we mark attrdirs as DFOUND, since they won't 211 * be located during normal scan of standard directories. 212 */ 213 if (curino.id_parent == 0) { 214 dpattr = ginode(inp->i_number); 215 if ((dpattr->di_mode & IFMT) == IFATTRDIR) { 216 for (sci = attrclientinfo; sci != NULL; 217 sci = sci->next) { 218 if (sci->shadow == inp->i_number) { 219 curino.id_parent = 220 sci->clients->client[0]; 221 statemap[inp->i_number] = 222 DFOUND; 223 inp->i_parent = 224 curino.id_parent; 225 } 226 } 227 } 228 } 229 } 230 /* 231 * Now that the parents of all directories have been found, 232 * make another pass to verify the value of .. 233 */ 234 for (inpp = inpsort; inpp < inpend; inpp++) { 235 inp = *inpp; 236 if (inp->i_parent == 0 || inp->i_isize == 0) 237 continue; 238 /* 239 * There are only directories in inpsort[], so only 240 * directory-related states need to be checked. There 241 * should never be any flags associated with USTATE. 242 */ 243 if ((statemap[inp->i_number] & STMASK) == DCLEAR || 244 statemap[inp->i_number] == USTATE) { 245 continue; 246 } 247 if (statemap[inp->i_parent] == DFOUND && 248 S_IS_DUNFOUND(statemap[inp->i_number])) { 249 statemap[inp->i_number] = DFOUND | 250 (statemap[inp->i_number] & INCLEAR); 251 } 252 if (inp->i_dotdot == inp->i_parent || 253 inp->i_dotdot == (fsck_ino_t)-1) { 254 continue; 255 } 256 if (inp->i_dotdot == 0) { 257 inp->i_dotdot = inp->i_parent; 258 fileerror(inp->i_parent, inp->i_number, 259 "MISSING '..'"); 260 if (reply("FIX") == 0) { 261 iscorrupt = 1; 262 continue; 263 } 264 dp = ginode(inp->i_number); 265 found = 0; 266 dirtype = (dp->di_mode & IFMT); 267 268 /* 269 * See if this is an attrdir that we located in pass1. 270 * i.e. it was on an i_oeftflag of some other inode. 271 * if it isn't found then we have an orphaned attrdir 272 * that needs to be tossed into lost+found. 273 */ 274 if (dirtype == IFATTRDIR) { 275 for (sci = attrclientinfo; 276 sci != NULL; 277 sci = sci->next) { 278 if (sci->shadow == inp->i_number) { 279 inp->i_parent = 280 sci->clients->client[0]; 281 found = 1; 282 } 283 } 284 } 285 286 /* 287 * We've already proven there's no "..", so this 288 * can't create a duplicate. 289 */ 290 if (makeentry(inp->i_number, inp->i_parent, "..")) { 291 292 /* 293 * is it an orphaned attrdir? 294 */ 295 if (dirtype == IFATTRDIR && found == 0) { 296 /* 297 * Throw it into lost+found 298 */ 299 if (linkup(inp->i_number, lfdir, 300 NULL) == 0) { 301 pwarn( 302 "Unable to move attrdir I=%d to lost+found\n", 303 inp->i_number); 304 iscorrupt = 1; 305 } 306 maybe_convert_attrdir_to_dir( 307 inp->i_number); 308 } 309 if (dirtype == IFDIR) { 310 LINK_RANGE(errmsg, 311 lncntp[inp->i_parent], -1); 312 if (errmsg != NULL) { 313 LINK_CLEAR(errmsg, 314 inp->i_parent, IFDIR, 315 &ldesc); 316 if (statemap[inp->i_parent] != 317 USTATE) { 318 /* 319 * iscorrupt is 320 * already set 321 */ 322 continue; 323 } 324 } 325 TRACK_LNCNTP(inp->i_parent, 326 lncntp[inp->i_parent]--); 327 } 328 329 continue; 330 } 331 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 332 iscorrupt = 1; 333 inp->i_dotdot = (fsck_ino_t)-1; 334 continue; 335 } 336 337 dp2 = ginode(inp->i_parent); 338 339 if ((dp2->di_mode & IFMT) == IFATTRDIR) { 340 continue; 341 } 342 fileerror(inp->i_parent, inp->i_number, 343 "BAD INODE NUMBER FOR '..'"); 344 if (reply("FIX") == 0) { 345 iscorrupt = 1; 346 continue; 347 } 348 349 LINK_RANGE(errmsg, lncntp[inp->i_dotdot], 1); 350 if (errmsg != NULL) { 351 LINK_CLEAR(errmsg, inp->i_dotdot, IFDIR, &ldesc); 352 if (statemap[inp->i_dotdot] != USTATE) { 353 /* iscorrupt is already set */ 354 continue; 355 } 356 } 357 TRACK_LNCNTP(inp->i_dotdot, lncntp[inp->i_dotdot]++); 358 359 LINK_RANGE(errmsg, lncntp[inp->i_parent], -1); 360 if (errmsg != NULL) { 361 LINK_CLEAR(errmsg, inp->i_parent, IFDIR, &ldesc); 362 if (statemap[inp->i_parent] != USTATE) { 363 /* iscorrupt is already set */ 364 continue; 365 } 366 } 367 TRACK_LNCNTP(inp->i_parent, lncntp[inp->i_parent]--); 368 369 inp->i_dotdot = inp->i_parent; 370 (void) changeino(inp->i_number, "..", inp->i_parent); 371 } 372 /* 373 * Mark all the directories that can be found from the root. 374 */ 375 propagate(); 376 } 377 378 /* 379 * Sanity-check a single directory entry. Which entry is being 380 * examined is tracked via idesc->id_entryno. There are two 381 * special ones, 0 (.) and 1 (..). Those have to exist in order 382 * in the first two locations in the directory, and have the usual 383 * properties. All other entries have to not be for either of 384 * the special two, and the inode they reference has to be 385 * reasonable. 386 * 387 * This is only called from dirscan(), which looks for the 388 * ALTERED flag after each invocation. If it finds it, the 389 * relevant buffer gets pushed out, so we don't have to worry 390 * about it here. 391 */ 392 #define PASS2B_PROMPT "REMOVE DIRECTORY ENTRY FROM I=%d" 393 394 static int 395 pass2check(struct inodesc *idesc) 396 { 397 struct direct *dirp = idesc->id_dirp; 398 struct inodesc ldesc; 399 struct inoinfo *inp; 400 short reclen, entrysize; 401 int ret = 0; 402 int act, update_lncntp; 403 struct dinode *dp, *pdirp, *attrdirp; 404 caddr_t errmsg; 405 struct direct proto; 406 char namebuf[MAXPATHLEN + 1]; 407 char pathbuf[MAXPATHLEN + 1]; 408 int isattr; 409 int pdirtype; 410 int breakout = 0; 411 int dontreconnect; 412 413 if (idesc->id_entryno != 0) 414 goto chk1; 415 /* 416 * check for "." 417 */ 418 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { 419 if (dirp->d_ino != idesc->id_number) { 420 direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'"); 421 dirp->d_ino = idesc->id_number; 422 if (reply("FIX") == 1) { 423 ret |= ALTERED; 424 } else { 425 iscorrupt = 1; 426 } 427 } 428 goto chk1; 429 } 430 /* 431 * Build up a new one, and make sure there's room to put 432 * it where it belongs. 433 */ 434 direrror(idesc->id_number, "MISSING '.'"); 435 proto.d_ino = idesc->id_number; 436 proto.d_namlen = 1; 437 (void) strcpy(proto.d_name, "."); 438 entrysize = DIRSIZ(&proto); 439 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { 440 pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", 441 dirp->d_name); 442 iscorrupt = 1; 443 } else if ((int)dirp->d_reclen < entrysize) { 444 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); 445 iscorrupt = 1; 446 } else if ((int)dirp->d_reclen < 2 * entrysize) { 447 /* 448 * No room for another entry after us ("." is the 449 * smallest entry you can have), so just put all 450 * of the old entry's space into the new entry. 451 * 452 * Because we don't touch id_entryno, we end up going 453 * through the chk2 tests as well. 454 */ 455 proto.d_reclen = dirp->d_reclen; 456 (void) memmove((void *)dirp, (void *)&proto, 457 (size_t)entrysize); 458 if (reply("FIX") == 1) { 459 ret |= ALTERED; 460 } else { 461 iscorrupt = 1; 462 } 463 } else { 464 /* 465 * There's enough room for an entire additional entry 466 * after this, so create the "." entry and follow it 467 * with an empty entry that covers the rest of the 468 * space. 469 * 470 * The increment of id_entryno means we'll skip the 471 * "." case of chk1, doing the ".." tests instead. 472 * Since we know that there's not a ".." where it 473 * should be (because we just created an empty entry 474 * there), that's the best way of getting it recreated 475 * as well. 476 */ 477 reclen = dirp->d_reclen - entrysize; 478 proto.d_reclen = entrysize; 479 (void) memmove((void *)dirp, (void *)&proto, 480 (size_t)entrysize); 481 idesc->id_entryno++; 482 /* 483 * Make sure the link count is in range before updating 484 * it. This makes the assumption that the link count 485 * for this inode included one for ".", even though 486 * there wasn't a "." entry. Even if that's not true, 487 * it's a reasonable working hypothesis, and the link 488 * count verification done in pass4 will fix it for 489 * us anyway. 490 */ 491 LINK_RANGE(errmsg, lncntp[dirp->d_ino], -1); 492 if (errmsg != NULL) { 493 LINK_CLEAR(errmsg, dirp->d_ino, IFDIR, &ldesc); 494 if (statemap[dirp->d_ino] == USTATE) { 495 /* 496 * The inode got zapped, so reset the 497 * directory entry. Extend it to also 498 * cover the space we were going to make 499 * into a new entry. 500 */ 501 dirp->d_ino = 0; 502 dirp->d_reclen += reclen; 503 ret |= ALTERED; 504 return (ret); 505 } 506 } 507 508 /* 509 * Create the new empty entry. 510 */ 511 /* LINTED pointer cast alignment (entrysize is valid) */ 512 dirp = (struct direct *)((char *)(dirp) + entrysize); 513 (void) memset((void *)dirp, 0, (size_t)reclen); 514 dirp->d_reclen = reclen; 515 516 /* 517 * Did the user want us to create a new "."? This 518 * query assumes that the direrror(MISSING) was the 519 * last thing printed, so if the LINK_RANGE() check 520 * fails, it can't pass through here. 521 */ 522 if (reply("FIX") == 1) { 523 TRACK_LNCNTP(idesc->id_number, 524 lncntp[idesc->id_number]--); 525 ret |= ALTERED; 526 } else { 527 iscorrupt = 1; 528 } 529 } 530 531 /* 532 * XXX The next few lines are needed whether we're processing "." 533 * or "..". However, there are some extra steps still needed 534 * for the former, hence the big block of code for 535 * id_entryno == 0. Alternatively, there could be a label just 536 * before this comment, and everything through the end of that 537 * block moved there. In some ways, that might make the 538 * control flow more logical (factoring out to separate functions 539 * would be even better). 540 */ 541 542 chk1: 543 if (idesc->id_entryno > 1) 544 goto chk2; 545 inp = getinoinfo(idesc->id_number); 546 if (inp == NULL) { 547 /* 548 * This is a can't-happen, since inodes get cached before 549 * we get called on them. 550 */ 551 errexit("pass2check got NULL from getinoinfo at chk1 I=%d\n", 552 idesc->id_number); 553 } 554 proto.d_ino = inp->i_parent; 555 proto.d_namlen = 2; 556 (void) strcpy(proto.d_name, ".."); 557 entrysize = DIRSIZ(&proto); 558 if (idesc->id_entryno == 0) { 559 /* 560 * We may not actually need to split things up, but if 561 * there's room to do so, we should, as that implies 562 * that the "." entry is larger than it is supposed 563 * to be, and therefore there's something wrong, albeit 564 * possibly harmlessly so. 565 */ 566 reclen = DIRSIZ(dirp); 567 if ((int)dirp->d_reclen < reclen + entrysize) { 568 /* 569 * Not enough room for inserting a ".." after 570 * the "." entry. 571 */ 572 goto chk2; 573 } 574 /* 575 * There's enough room for an entire additional entry 576 * after "."'s, so split it up. There's no reason "." 577 * should be bigger than the minimum, so shrink it to 578 * fit, too. Since by the time we're done with this 579 * part, dirp will be pointing at where ".." should be, 580 * update id_entryno to show that that's the entry 581 * we're on. 582 */ 583 proto.d_reclen = dirp->d_reclen - reclen; 584 dirp->d_reclen = reclen; 585 idesc->id_entryno++; 586 if (dirp->d_ino > 0 && dirp->d_ino <= maxino) { 587 /* 588 * Account for the link to ourselves. 589 */ 590 LINK_RANGE(errmsg, lncntp[dirp->d_ino], -1); 591 if (errmsg != NULL) { 592 LINK_CLEAR(errmsg, dirp->d_ino, IFDIR, &ldesc); 593 if (statemap[dirp->d_ino] == USTATE) { 594 /* 595 * We were going to split the entry 596 * up, but the link count overflowed. 597 * Since we got rid of the inode, 598 * we need to also zap the directory 599 * entry, and restoring the original 600 * state of things is the least-bad 601 * result. 602 */ 603 dirp->d_ino = 0; 604 dirp->d_reclen += proto.d_reclen; 605 ret |= ALTERED; 606 return (ret); 607 } 608 } 609 TRACK_LNCNTP(dirp->d_ino, lncntp[dirp->d_ino]--); 610 /* 611 * Make sure the new entry doesn't get interpreted 612 * as having actual content. 613 */ 614 /* LINTED pointer cast alignment (reclen is valid) */ 615 dirp = (struct direct *)((char *)(dirp) + reclen); 616 (void) memset((void *)dirp, 0, (size_t)proto.d_reclen); 617 dirp->d_reclen = proto.d_reclen; 618 } else { 619 /* 620 * Everything was fine, up until we realized that 621 * the indicated inode was impossible. By clearing 622 * d_ino here, we'll trigger the recreation of it 623 * down below, using i_parent. Unlike the other 624 * half of this if(), we're everything so it shows 625 * that we're still on the "." entry. 626 */ 627 fileerror(idesc->id_number, dirp->d_ino, 628 "I OUT OF RANGE"); 629 dirp->d_ino = 0; 630 if (reply("FIX") == 1) { 631 ret |= ALTERED; 632 } else { 633 iscorrupt = 1; 634 } 635 } 636 } 637 /* 638 * Record this ".." inode, but only if we haven't seen one before. 639 * If this isn't the first, it'll get cleared below, and so we 640 * want to remember the entry that'll still be around later. 641 */ 642 if (dirp->d_ino != 0 && inp->i_dotdot == 0 && 643 strcmp(dirp->d_name, "..") == 0) { 644 inp->i_dotdot = dirp->d_ino; 645 goto chk2; 646 } 647 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { 648 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 649 pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", 650 dirp->d_name); 651 iscorrupt = 1; 652 inp->i_dotdot = (fsck_ino_t)-1; 653 } else if ((int)dirp->d_reclen < entrysize) { 654 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 655 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 656 /* XXX Same consideration as immediately above. */ 657 iscorrupt = 1; 658 inp->i_dotdot = (fsck_ino_t)-1; 659 } else if (inp->i_parent != 0) { 660 /* 661 * We know the parent, so fix now. 662 */ 663 proto.d_ino = inp->i_dotdot = inp->i_parent; 664 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 665 /* 666 * Lint won't be quiet about d_reclen being set but not 667 * used. It apparently doesn't understand the implications 668 * of calling memmove(), and won't believe us that it's ok. 669 */ 670 proto.d_reclen = dirp->d_reclen; 671 (void) memmove((void *)dirp, (void *)&proto, 672 (size_t)entrysize); 673 if (reply("FIX") == 1) { 674 ret |= ALTERED; 675 } else { 676 iscorrupt = 1; 677 } 678 } else if (inp->i_number == UFSROOTINO) { 679 /* 680 * Always know parent of root inode, so fix now. 681 */ 682 proto.d_ino = inp->i_dotdot = inp->i_parent = UFSROOTINO; 683 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 684 /* 685 * Lint won't be quiet about d_reclen being set but not 686 * used. It apparently doesn't understand the implications 687 * of calling memmove(), and won't believe us that it's ok. 688 */ 689 proto.d_reclen = dirp->d_reclen; 690 (void) memmove((void *)dirp, (void *)&proto, (size_t)entrysize); 691 if (reply("FIX") == 1) { 692 ret |= ALTERED; 693 } else { 694 iscorrupt = 1; 695 } 696 } 697 idesc->id_entryno++; 698 if (dirp->d_ino != 0) { 699 LINK_RANGE(errmsg, lncntp[dirp->d_ino], -1); 700 if (errmsg != NULL) { 701 LINK_CLEAR(errmsg, dirp->d_ino, IFDIR, &ldesc); 702 if (statemap[dirp->d_ino] == USTATE) { 703 dirp->d_ino = 0; 704 ret |= ALTERED; 705 } 706 } 707 TRACK_LNCNTP(dirp->d_ino, lncntp[dirp->d_ino]--); 708 } 709 return (ret|KEEPON); 710 chk2: 711 if (dirp->d_ino == 0) 712 return (ret|KEEPON); 713 if (dirp->d_namlen <= 2 && 714 dirp->d_name[0] == '.' && 715 idesc->id_entryno >= 2) { 716 if (dirp->d_namlen == 1) { 717 direrror(idesc->id_number, "EXTRA '.' ENTRY"); 718 dirp->d_ino = 0; 719 if (reply("FIX") == 1) { 720 ret |= ALTERED; 721 } else { 722 iscorrupt = 1; 723 } 724 return (KEEPON | ret); 725 } 726 if (dirp->d_name[1] == '.') { 727 direrror(idesc->id_number, "EXTRA '..' ENTRY"); 728 dirp->d_ino = 0; 729 if (reply("FIX") == 1) { 730 ret |= ALTERED; 731 } else { 732 iscorrupt = 1; 733 } 734 return (KEEPON | ret); 735 } 736 } 737 /* 738 * Because of this increment, all tests for skipping . and .. 739 * below are ``> 2'', not ``> 1'' as would logically be expected. 740 */ 741 idesc->id_entryno++; 742 act = -1; 743 /* 744 * The obvious check would be for d_ino < UFSROOTINO. However, 745 * 1 is a valid inode number. Although it isn't currently used, 746 * as it was once the bad block list, there's nothing to prevent 747 * it from acquiring a new purpose in the future. So, don't 748 * arbitrarily disallow it. We don't test for <= zero, because 749 * d_ino is unsigned. 750 */ 751 update_lncntp = 0; 752 if (dirp->d_ino > maxino || dirp->d_ino == 0) { 753 fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE"); 754 act = (reply(PASS2B_PROMPT, idesc->id_number) == 1); 755 } else { 756 again: 757 update_lncntp = 0; 758 switch (statemap[dirp->d_ino] & ~(INDELAYD)) { 759 case USTATE: 760 if (idesc->id_entryno <= 2) 761 break; 762 fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED"); 763 act = (reply(PASS2B_PROMPT, idesc->id_number) == 1); 764 break; 765 766 case DCLEAR: 767 case FCLEAR: 768 case SCLEAR: 769 if (idesc->id_entryno <= 2) 770 break; 771 dp = ginode(dirp->d_ino); 772 if (statemap[dirp->d_ino] == DCLEAR) { 773 errmsg = ((dp->di_mode & IFMT) == IFATTRDIR) ? 774 "REFERENCE TO ZERO LENGTH ATTRIBUTE DIRECTORY" : 775 "REFERENCE TO ZERO LENGTH DIRECTORY"; 776 inp = getinoinfo(dirp->d_ino); 777 if (inp == NULL) { 778 /* 779 * The inode doesn't exist, as all 780 * should be cached by now. This 781 * gets caught by the range check 782 * above, and so it is a can't-happen 783 * at this point. 784 */ 785 errexit("pass2check found a zero-len " 786 "reference to bad I=%d\n", 787 dirp->d_ino); 788 } 789 if (inp->i_parent != 0) { 790 (void) printf( 791 "Multiple links to I=%d, link counts wrong, rerun fsck\n", 792 inp->i_number); 793 iscorrupt = 1; 794 } 795 } else if (statemap[dirp->d_ino] == SCLEAR) { 796 /* 797 * In theory, this is a can't-happen, 798 * because shadows don't appear in directory 799 * entries. However, an inode might've 800 * been reused without a stale directory 801 * entry having been cleared, so check 802 * for it just in case. We'll check for 803 * the no-dir-entry shadows in pass3b(). 804 */ 805 errmsg = "ZERO LENGTH SHADOW"; 806 } else { 807 errmsg = "DUP/BAD"; 808 } 809 fileerror(idesc->id_number, dirp->d_ino, errmsg); 810 if ((act = reply(PASS2B_PROMPT, idesc->id_number)) == 1) 811 break; 812 /* 813 * Not doing anything about it, so just try 814 * again as whatever the base type was. 815 * 816 * fileerror() invalidated dp. Lint thinks this 817 * is unnecessary, but we know better. 818 */ 819 dp = ginode(dirp->d_ino); 820 statemap[dirp->d_ino] &= STMASK; 821 TRACK_LNCNTP(dirp->d_ino, lncntp[dirp->d_ino] = 0); 822 goto again; 823 824 case DSTATE: 825 case DZLINK: 826 if (statemap[idesc->id_number] == DFOUND) { 827 statemap[dirp->d_ino] = DFOUND; 828 } 829 /* FALLTHROUGH */ 830 831 case DFOUND: 832 /* 833 * This is encouraging the best-practice of not 834 * hard-linking directories. It's legal (see POSIX), 835 * but not a good idea. So, don't consider it an 836 * instance of corruption, but offer to nuke it. 837 */ 838 inp = getinoinfo(dirp->d_ino); 839 if (inp == NULL) { 840 /* 841 * Same can't-happen argument as in the 842 * zero-len case above. 843 */ 844 errexit("pass2check found bad reference to " 845 "hard-linked directory I=%d\n", 846 dirp->d_ino); 847 } 848 dp = ginode(idesc->id_number); 849 if (inp->i_parent != 0 && idesc->id_entryno > 2 && 850 ((dp->di_mode & IFMT) != IFATTRDIR)) { 851 /* 852 * XXX For nested dirs, this can report 853 * the same name for both paths. 854 */ 855 getpathname(pathbuf, idesc->id_number, 856 dirp->d_ino); 857 getpathname(namebuf, dirp->d_ino, dirp->d_ino); 858 pwarn( 859 "%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s\n", 860 pathbuf, namebuf); 861 if (preen) 862 (void) printf(" (IGNORED)\n"); 863 else if ((act = reply(PASS2B_PROMPT, 864 idesc->id_number)) == 1) { 865 update_lncntp = 1; 866 broke_dir_link = 1; 867 break; 868 } 869 } 870 871 if ((idesc->id_entryno > 2) && 872 (inp->i_extattr != idesc->id_number)) { 873 inp->i_parent = idesc->id_number; 874 } 875 /* FALLTHROUGH */ 876 877 case FSTATE: 878 case FZLINK: 879 /* 880 * There's nothing to do for normal file-like 881 * things. Extended attributes come through 882 * here as well, though, and for them, .. may point 883 * to a file. In this situation we don't want 884 * to decrement link count as it was already 885 * decremented when the entry was seen in the 886 * directory it actually lives in. 887 */ 888 pdirp = ginode(idesc->id_number); 889 pdirtype = (pdirp->di_mode & IFMT); 890 dp = ginode(dirp->d_ino); 891 isattr = (dp->di_cflags & IXATTR); 892 act = -1; 893 if (pdirtype == IFATTRDIR && 894 (strcmp(dirp->d_name, "..") == 0)) { 895 dontreconnect = 0; 896 if (dp->di_oeftflag != 0) { 897 attrdirp = ginode(dp->di_oeftflag); 898 899 /* 900 * is it really an attrdir? 901 * if so, then don't do anything. 902 */ 903 904 if ((attrdirp->di_mode & IFMT) == 905 IFATTRDIR) 906 dontreconnect = 1; 907 dp = ginode(dirp->d_ino); 908 } 909 /* 910 * Rare corner case - the attrdir's .. 911 * points to the attrdir itself. 912 */ 913 if (dirp->d_ino == idesc->id_number) { 914 dontreconnect = 1; 915 TRACK_LNCNTP(idesc->id_number, 916 lncntp[idesc->id_number]--); 917 } 918 /* 919 * Lets see if we have an orphaned attrdir 920 * that thinks it belongs to this file. 921 * Only re-connect it if the current 922 * attrdir is 0 or not an attrdir. 923 */ 924 if ((dp->di_oeftflag != idesc->id_number) && 925 (dontreconnect == 0)) { 926 fileerror(idesc->id_number, 927 dirp->d_ino, 928 "Attribute directory I=%d not " 929 "attached to file I=%d\n", 930 idesc->id_number, dirp->d_ino); 931 if ((act = reply("FIX")) == 1) { 932 dp = ginode(dirp->d_ino); 933 if (debug) 934 (void) printf( 935 "debug: changing i=%d's oeft from %d ", 936 dirp->d_ino, 937 dp->di_oeftflag); 938 dp->di_oeftflag = 939 idesc->id_number; 940 if (debug) 941 (void) printf("to %d\n", 942 dp->di_oeftflag); 943 inodirty(); 944 registershadowclient( 945 idesc->id_number, 946 dirp->d_ino, 947 &attrclientinfo); 948 } 949 dp = ginode(dirp->d_ino); 950 } 951 952 /* 953 * This can only be true if we've modified 954 * an inode/xattr connection, and we 955 * don't keep track of those in the link 956 * counts. So, skipping the checks just 957 * after this is not a problem. 958 */ 959 if (act > 0) 960 return (KEEPON | ALTERED); 961 962 /* 963 * Don't screw up link counts for directories. 964 * If we aren't careful we can perform 965 * an extra decrement, since the .. of 966 * an attrdir could be either a file or a 967 * directory. If it's a file then its link 968 * should be correct after it is seen when the 969 * directory it lives in scanned. 970 */ 971 if ((pdirtype == IFATTRDIR) && 972 ((dp->di_mode & IFMT) == IFDIR)) 973 breakout = 1; 974 if ((dp->di_mode & IFMT) != IFDIR) 975 breakout = 1; 976 977 } else if ((pdirtype != IFATTRDIR) || 978 (strcmp(dirp->d_name, ".") != 0)) { 979 if ((pdirtype == IFDIR) && isattr) { 980 fileerror(idesc->id_number, 981 dirp->d_ino, 982 "File should NOT be marked as " 983 "extended attribute\n"); 984 if ((act = reply("FIX")) == 1) { 985 dp = ginode(dirp->d_ino); 986 if (debug) 987 (void) printf( 988 "changing i=%d's cflags from 0x%x to ", 989 dirp->d_ino, 990 dp->di_cflags); 991 992 dp->di_cflags &= ~IXATTR; 993 if (debug) 994 (void) printf("0x%x\n", 995 dp->di_cflags); 996 inodirty(); 997 if ((dp->di_mode & IFMT) == 998 IFATTRDIR) { 999 dp->di_mode &= 1000 ~IFATTRDIR; 1001 dp->di_mode |= IFDIR; 1002 inodirty(); 1003 pdirp = ginode( 1004 idesc->id_number); 1005 if (pdirp->di_oeftflag 1006 != 0) { 1007 pdirp->di_oeftflag = 0; 1008 inodirty(); 1009 } 1010 } 1011 } 1012 } else { 1013 if (pdirtype == IFATTRDIR && 1014 (isattr == 0)) { 1015 fileerror(idesc->id_number, 1016 dirp->d_ino, 1017 "File should BE marked as " 1018 "extended attribute\n"); 1019 if ((act = reply("FIX")) == 1) { 1020 dp = ginode( 1021 dirp->d_ino); 1022 dp->di_cflags |= IXATTR; 1023 /* 1024 * Make sure it's a file 1025 * while we're at it. 1026 */ 1027 dp->di_mode &= ~IFMT; 1028 dp->di_mode |= IFREG; 1029 inodirty(); 1030 } 1031 } 1032 } 1033 1034 } 1035 if (breakout == 0 || dontreconnect == 0) { 1036 TRACK_LNCNTP(dirp->d_ino, 1037 lncntp[dirp->d_ino]--); 1038 if (act > 0) 1039 return (KEEPON | ALTERED); 1040 } 1041 break; 1042 1043 case SSTATE: 1044 errmsg = "ACL IN DIRECTORY"; 1045 fileerror(idesc->id_number, dirp->d_ino, errmsg); 1046 act = (reply(PASS2B_PROMPT, idesc->id_number) == 1); 1047 break; 1048 1049 default: 1050 errexit("BAD STATE 0x%x FOR INODE I=%d", 1051 statemap[dirp->d_ino], dirp->d_ino); 1052 } 1053 } 1054 1055 if (act == 0) { 1056 iscorrupt = 1; 1057 } 1058 1059 if (act <= 0) 1060 return (ret|KEEPON); 1061 1062 if (update_lncntp) { 1063 LINK_RANGE(errmsg, lncntp[idesc->id_number], 1); 1064 if (errmsg != NULL) { 1065 LINK_CLEAR(errmsg, idesc->id_number, IFDIR, &ldesc); 1066 if (statemap[idesc->id_number] == USTATE) { 1067 idesc->id_number = 0; 1068 ret |= ALTERED; 1069 } 1070 } 1071 TRACK_LNCNTP(idesc->id_number, lncntp[idesc->id_number]++); 1072 } 1073 1074 dirp->d_ino = 0; 1075 1076 return (ret|KEEPON|ALTERED); 1077 } 1078 1079 #undef PASS2B_PROMPT 1080 1081 /* 1082 * Routine to sort disk blocks. 1083 */ 1084 static int 1085 blksort(const void *arg1, const void *arg2) 1086 { 1087 const struct inoinfo **inpp1 = (const struct inoinfo **)arg1; 1088 const struct inoinfo **inpp2 = (const struct inoinfo **)arg2; 1089 1090 return ((*inpp1)->i_blks[0] - (*inpp2)->i_blks[0]); 1091 } 1092