1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 static char sccsid[] = "@(#)utilities.c 5.10 (Berkeley) 04/07/87"; 9 #endif not lint 10 11 #include <stdio.h> 12 #include <ctype.h> 13 #include <sys/param.h> 14 #include <sys/inode.h> 15 #include <sys/fs.h> 16 #include <sys/dir.h> 17 #include "fsck.h" 18 19 long lseek(); 20 21 ftypeok(dp) 22 DINODE *dp; 23 { 24 switch (dp->di_mode & IFMT) { 25 26 case IFDIR: 27 case IFREG: 28 case IFBLK: 29 case IFCHR: 30 case IFLNK: 31 case IFSOCK: 32 return (1); 33 34 default: 35 if (debug) 36 printf("bad file type 0%o\n", dp->di_mode); 37 return (0); 38 } 39 } 40 41 reply(s) 42 char *s; 43 { 44 char line[80]; 45 int cont = (strcmp(s, "CONTINUE") == 0); 46 47 if (preen) 48 pfatal("INTERNAL ERROR: GOT TO reply()"); 49 printf("\n%s? ", s); 50 if (!cont && (nflag || dfile.wfdes < 0)) { 51 printf(" no\n\n"); 52 return (0); 53 } 54 if (yflag || (cont && nflag)) { 55 printf(" yes\n\n"); 56 return (1); 57 } 58 if (getline(stdin, line, sizeof(line)) == EOF) 59 errexit("\n"); 60 printf("\n"); 61 if (line[0] == 'y' || line[0] == 'Y') 62 return (1); 63 else 64 return (0); 65 } 66 67 getline(fp, loc, maxlen) 68 FILE *fp; 69 char *loc; 70 { 71 register n; 72 register char *p, *lastloc; 73 74 p = loc; 75 lastloc = &p[maxlen-1]; 76 while ((n = getc(fp)) != '\n') { 77 if (n == EOF) 78 return (EOF); 79 if (!isspace(n) && p < lastloc) 80 *p++ = n; 81 } 82 *p = 0; 83 return (p - loc); 84 } 85 86 BUFAREA * 87 getblk(bp, blk, size) 88 register BUFAREA *bp; 89 daddr_t blk; 90 long size; 91 { 92 register struct filecntl *fcp; 93 daddr_t dblk; 94 95 fcp = &dfile; 96 dblk = fsbtodb(&sblock, blk); 97 if (bp->b_bno == dblk) 98 return (bp); 99 flush(fcp, bp); 100 bp->b_errs = bread(fcp, bp->b_un.b_buf, dblk, size); 101 bp->b_bno = dblk; 102 bp->b_size = size; 103 return (bp); 104 } 105 106 flush(fcp, bp) 107 struct filecntl *fcp; 108 register BUFAREA *bp; 109 { 110 register int i, j; 111 112 if (!bp->b_dirty) 113 return; 114 if (bp->b_errs != 0) 115 pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", 116 (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 117 bp->b_bno); 118 bp->b_dirty = 0; 119 bp->b_errs = 0; 120 bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 121 if (bp != &sblk) 122 return; 123 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 124 bwrite(&dfile, (char *)sblock.fs_csp[j], 125 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 126 sblock.fs_cssize - i < sblock.fs_bsize ? 127 sblock.fs_cssize - i : sblock.fs_bsize); 128 } 129 } 130 131 rwerr(s, blk) 132 char *s; 133 daddr_t blk; 134 { 135 136 if (preen == 0) 137 printf("\n"); 138 pfatal("CANNOT %s: BLK %ld", s, blk); 139 if (reply("CONTINUE") == 0) 140 errexit("Program terminated\n"); 141 } 142 143 ckfini() 144 { 145 146 flush(&dfile, &fileblk); 147 flush(&dfile, &sblk); 148 if (havesb && sblk.b_bno != SBOFF / dev_bsize && 149 !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 150 sblk.b_bno = SBOFF / dev_bsize; 151 sbdirty(); 152 flush(&dfile, &sblk); 153 } 154 flush(&dfile, &inoblk); 155 flush(&dfile, &cgblk); 156 (void)close(dfile.rfdes); 157 (void)close(dfile.wfdes); 158 } 159 160 bread(fcp, buf, blk, size) 161 register struct filecntl *fcp; 162 char *buf; 163 daddr_t blk; 164 long size; 165 { 166 char *cp; 167 int i, errs; 168 169 if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0) 170 rwerr("SEEK", blk); 171 else if (read(fcp->rfdes, buf, (int)size) == size) 172 return (0); 173 rwerr("READ", blk); 174 if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0) 175 rwerr("SEEK", blk); 176 errs = 0; 177 bzero(buf, size); 178 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 179 for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 180 if (read(fcp->rfdes, cp, secsize) < 0) { 181 lseek(fcp->rfdes, blk * dev_bsize + i + secsize, 0); 182 if (secsize != dev_bsize && dev_bsize != 1) 183 printf(" %d (%d),", 184 (blk * dev_bsize + i) / secsize, 185 blk + i / dev_bsize); 186 else 187 printf(" %d,", blk + i / dev_bsize); 188 errs++; 189 } 190 } 191 printf("\n"); 192 return (errs); 193 } 194 195 bwrite(fcp, buf, blk, size) 196 register struct filecntl *fcp; 197 char *buf; 198 daddr_t blk; 199 long size; 200 { 201 int i; 202 char *cp; 203 204 if (fcp->wfdes < 0) 205 return; 206 if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0) 207 rwerr("SEEK", blk); 208 else if (write(fcp->wfdes, buf, (int)size) == size) { 209 fcp->mod = 1; 210 return; 211 } 212 rwerr("WRITE", blk); 213 if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0) 214 rwerr("SEEK", blk); 215 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 216 for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 217 if (write(fcp->wfdes, cp, dev_bsize) < 0) { 218 lseek(fcp->rfdes, blk * dev_bsize + i + dev_bsize, 0); 219 printf(" %d,", blk + i / dev_bsize); 220 } 221 printf("\n"); 222 return; 223 } 224 225 /* 226 * allocate a data block with the specified number of fragments 227 */ 228 allocblk(frags) 229 int frags; 230 { 231 register int i, j, k; 232 233 if (frags <= 0 || frags > sblock.fs_frag) 234 return (0); 235 for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) { 236 for (j = 0; j <= sblock.fs_frag - frags; j++) { 237 if (getbmap(i + j)) 238 continue; 239 for (k = 1; k < frags; k++) 240 if (getbmap(i + j + k)) 241 break; 242 if (k < frags) { 243 j += k; 244 continue; 245 } 246 for (k = 0; k < frags; k++) 247 setbmap(i + j + k); 248 n_blks += frags; 249 return (i + j); 250 } 251 } 252 return (0); 253 } 254 255 /* 256 * Free a previously allocated block 257 */ 258 freeblk(blkno, frags) 259 daddr_t blkno; 260 int frags; 261 { 262 struct inodesc idesc; 263 264 idesc.id_blkno = blkno; 265 idesc.id_numfrags = frags; 266 pass4check(&idesc); 267 } 268 269 /* 270 * Find a pathname 271 */ 272 getpathname(namebuf, curdir, ino) 273 char *namebuf; 274 ino_t curdir, ino; 275 { 276 int len; 277 register char *cp; 278 struct inodesc idesc; 279 extern int findname(); 280 281 if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) { 282 strcpy(namebuf, "?"); 283 return; 284 } 285 bzero(&idesc, sizeof(struct inodesc)); 286 idesc.id_type = DATA; 287 cp = &namebuf[BUFSIZ - 1]; 288 *cp = '\0'; 289 if (curdir != ino) { 290 idesc.id_parent = curdir; 291 goto namelookup; 292 } 293 while (ino != ROOTINO) { 294 idesc.id_number = ino; 295 idesc.id_func = findino; 296 idesc.id_name = ".."; 297 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 298 break; 299 namelookup: 300 idesc.id_number = idesc.id_parent; 301 idesc.id_parent = ino; 302 idesc.id_func = findname; 303 idesc.id_name = namebuf; 304 if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0) 305 break; 306 len = strlen(namebuf); 307 cp -= len; 308 if (cp < &namebuf[MAXNAMLEN]) 309 break; 310 bcopy(namebuf, cp, len); 311 *--cp = '/'; 312 ino = idesc.id_number; 313 } 314 if (ino != ROOTINO) { 315 strcpy(namebuf, "?"); 316 return; 317 } 318 bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp); 319 } 320 321 catch() 322 { 323 324 ckfini(); 325 exit(12); 326 } 327 328 /* 329 * When preening, allow a single quit to signal 330 * a special exit after filesystem checks complete 331 * so that reboot sequence may be interrupted. 332 */ 333 catchquit() 334 { 335 extern returntosingle; 336 337 printf("returning to single-user after filesystem check\n"); 338 returntosingle = 1; 339 (void)signal(SIGQUIT, SIG_DFL); 340 } 341 342 /* 343 * Ignore a single quit signal; wait and flush just in case. 344 * Used by child processes in preen. 345 */ 346 voidquit() 347 { 348 349 sleep(1); 350 (void)signal(SIGQUIT, SIG_IGN); 351 (void)signal(SIGQUIT, SIG_DFL); 352 } 353 354 /* 355 * determine whether an inode should be fixed. 356 */ 357 dofix(idesc, msg) 358 register struct inodesc *idesc; 359 char *msg; 360 { 361 362 switch (idesc->id_fix) { 363 364 case DONTKNOW: 365 if (idesc->id_type == DATA) 366 direrr(idesc->id_number, msg); 367 else 368 pwarn(msg); 369 if (preen) { 370 printf(" (SALVAGED)\n"); 371 idesc->id_fix = FIX; 372 return (ALTERED); 373 } 374 if (reply("SALVAGE") == 0) { 375 idesc->id_fix = NOFIX; 376 return (0); 377 } 378 idesc->id_fix = FIX; 379 return (ALTERED); 380 381 case FIX: 382 return (ALTERED); 383 384 case NOFIX: 385 return (0); 386 387 default: 388 errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 389 } 390 /* NOTREACHED */ 391 } 392 393 /* VARARGS1 */ 394 errexit(s1, s2, s3, s4) 395 char *s1; 396 { 397 printf(s1, s2, s3, s4); 398 exit(8); 399 } 400 401 /* 402 * An inconsistency occured which shouldn't during normal operations. 403 * Die if preening, otherwise just printf. 404 */ 405 /* VARARGS1 */ 406 pfatal(s, a1, a2, a3) 407 char *s; 408 { 409 410 if (preen) { 411 printf("%s: ", devname); 412 printf(s, a1, a2, a3); 413 printf("\n"); 414 printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 415 devname); 416 exit(8); 417 } 418 printf(s, a1, a2, a3); 419 } 420 421 /* 422 * Pwarn is like printf when not preening, 423 * or a warning (preceded by filename) when preening. 424 */ 425 /* VARARGS1 */ 426 pwarn(s, a1, a2, a3, a4, a5, a6) 427 char *s; 428 { 429 430 if (preen) 431 printf("%s: ", devname); 432 printf(s, a1, a2, a3, a4, a5, a6); 433 } 434 435 #ifndef lint 436 /* 437 * Stub for routines from kernel. 438 */ 439 panic(s) 440 char *s; 441 { 442 443 pfatal("INTERNAL INCONSISTENCY:"); 444 errexit(s); 445 } 446 #endif 447