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