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.4 (Berkeley) 01/15/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 != SBLOCK) { 146 sblk.b_bno = SBLOCK; 147 sbdirty(); 148 flush(&dfile, &sblk); 149 } 150 flush(&dfile, &inoblk); 151 flush(&dfile, &cgblk); 152 (void)close(dfile.rfdes); 153 (void)close(dfile.wfdes); 154 } 155 156 bread(fcp, buf, blk, size) 157 register struct filecntl *fcp; 158 char *buf; 159 daddr_t blk; 160 long size; 161 { 162 char *cp; 163 int i, errs; 164 165 if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0) 166 rwerr("SEEK", blk); 167 else if (read(fcp->rfdes, buf, (int)size) == size) 168 return (0); 169 rwerr("READ", blk); 170 if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0) 171 rwerr("SEEK", blk); 172 errs = 0; 173 bzero(cp, size); 174 pfatal("THE FOLLOWING SECTORS COULD NOT BE READ:"); 175 for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE) { 176 if (read(fcp->rfdes, cp, DEV_BSIZE) < 0) { 177 lseek(fcp->rfdes, (long)dbtob(blk) + i + DEV_BSIZE, 0); 178 printf(" %d,", blk + i / DEV_BSIZE); 179 errs++; 180 } 181 } 182 printf("\n"); 183 return (errs); 184 } 185 186 bwrite(fcp, buf, blk, size) 187 register struct filecntl *fcp; 188 char *buf; 189 daddr_t blk; 190 long size; 191 { 192 int i; 193 char *cp; 194 195 if (fcp->wfdes < 0) 196 return; 197 if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0) 198 rwerr("SEEK", blk); 199 else if (write(fcp->wfdes, buf, (int)size) == size) { 200 fcp->mod = 1; 201 return; 202 } 203 rwerr("WRITE", blk); 204 if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0) 205 rwerr("SEEK", blk); 206 pfatal("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 207 for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE) 208 if (write(fcp->wfdes, cp, DEV_BSIZE) < 0) { 209 lseek(fcp->rfdes, (long)dbtob(blk) + i + DEV_BSIZE, 0); 210 printf(" %d,", blk + i / DEV_BSIZE); 211 } 212 printf("\n"); 213 return; 214 } 215 216 /* 217 * allocate a data block with the specified number of fragments 218 */ 219 allocblk(frags) 220 int frags; 221 { 222 register int i, j, k; 223 224 if (frags <= 0 || frags > sblock.fs_frag) 225 return (0); 226 for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) { 227 for (j = 0; j <= sblock.fs_frag - frags; j++) { 228 if (getbmap(i + j)) 229 continue; 230 for (k = 1; k < frags; k++) 231 if (getbmap(i + j + k)) 232 break; 233 if (k < frags) { 234 j += k; 235 continue; 236 } 237 for (k = 0; k < frags; k++) 238 setbmap(i + j + k); 239 n_blks += frags; 240 return (i + j); 241 } 242 } 243 return (0); 244 } 245 246 /* 247 * Free a previously allocated block 248 */ 249 freeblk(blkno, frags) 250 daddr_t blkno; 251 int frags; 252 { 253 struct inodesc idesc; 254 255 idesc.id_blkno = blkno; 256 idesc.id_numfrags = frags; 257 pass4check(&idesc); 258 } 259 260 /* 261 * Find a pathname 262 */ 263 getpathname(namebuf, curdir, ino) 264 char *namebuf; 265 ino_t curdir, ino; 266 { 267 int len; 268 register char *cp; 269 struct inodesc idesc; 270 extern int findname(); 271 272 if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) { 273 strcpy(namebuf, "?"); 274 return; 275 } 276 bzero(&idesc, sizeof(struct inodesc)); 277 idesc.id_type = DATA; 278 cp = &namebuf[BUFSIZ - 1]; 279 *cp = '\0'; 280 if (curdir != ino) { 281 idesc.id_parent = curdir; 282 goto namelookup; 283 } 284 while (ino != ROOTINO) { 285 idesc.id_number = ino; 286 idesc.id_func = findino; 287 idesc.id_name = ".."; 288 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 289 break; 290 namelookup: 291 idesc.id_number = idesc.id_parent; 292 idesc.id_parent = ino; 293 idesc.id_func = findname; 294 idesc.id_name = namebuf; 295 if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0) 296 break; 297 len = strlen(namebuf); 298 cp -= len; 299 if (cp < &namebuf[MAXNAMLEN]) 300 break; 301 bcopy(namebuf, cp, len); 302 *--cp = '/'; 303 ino = idesc.id_number; 304 } 305 if (ino != ROOTINO) { 306 strcpy(namebuf, "?"); 307 return; 308 } 309 bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp); 310 } 311 312 catch() 313 { 314 315 ckfini(); 316 exit(12); 317 } 318 319 /* 320 * When preening, allow a single quit to signal 321 * a special exit after filesystem checks complete 322 * so that reboot sequence may be interrupted. 323 */ 324 catchquit() 325 { 326 extern returntosingle; 327 328 printf("returning to single-user after filesystem check\n"); 329 returntosingle = 1; 330 (void)signal(SIGQUIT, SIG_DFL); 331 } 332 333 /* 334 * Ignore a single quit signal; wait and flush just in case. 335 * Used by child processes in preen. 336 */ 337 voidquit() 338 { 339 340 sleep(1); 341 (void)signal(SIGQUIT, SIG_IGN); 342 (void)signal(SIGQUIT, SIG_DFL); 343 } 344 345 /* 346 * determine whether an inode should be fixed. 347 */ 348 dofix(idesc, msg) 349 register struct inodesc *idesc; 350 char *msg; 351 { 352 353 switch (idesc->id_fix) { 354 355 case DONTKNOW: 356 if (idesc->id_type == DATA) 357 direrr(idesc->id_number, msg); 358 else 359 pwarn(msg); 360 if (preen) { 361 printf(" (SALVAGED)\n"); 362 idesc->id_fix = FIX; 363 return (ALTERED); 364 } 365 if (reply("SALVAGE") == 0) { 366 idesc->id_fix = NOFIX; 367 return (0); 368 } 369 idesc->id_fix = FIX; 370 return (ALTERED); 371 372 case FIX: 373 return (ALTERED); 374 375 case NOFIX: 376 return (0); 377 378 default: 379 errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 380 } 381 /* NOTREACHED */ 382 } 383 384 /* VARARGS1 */ 385 errexit(s1, s2, s3, s4) 386 char *s1; 387 { 388 printf(s1, s2, s3, s4); 389 exit(8); 390 } 391 392 /* 393 * An inconsistency occured which shouldn't during normal operations. 394 * Die if preening, otherwise just printf. 395 */ 396 /* VARARGS1 */ 397 pfatal(s, a1, a2, a3) 398 char *s; 399 { 400 401 if (preen) { 402 printf("%s: ", devname); 403 printf(s, a1, a2, a3); 404 printf("\n"); 405 printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 406 devname); 407 exit(8); 408 } 409 printf(s, a1, a2, a3); 410 } 411 412 /* 413 * Pwarn is like printf when not preening, 414 * or a warning (preceded by filename) when preening. 415 */ 416 /* VARARGS1 */ 417 pwarn(s, a1, a2, a3, a4, a5, a6) 418 char *s; 419 { 420 421 if (preen) 422 printf("%s: ", devname); 423 printf(s, a1, a2, a3, a4, a5, a6); 424 } 425 426 #ifndef lint 427 /* 428 * Stub for routines from kernel. 429 */ 430 panic(s) 431 char *s; 432 { 433 434 pfatal("INTERNAL INCONSISTENCY:"); 435 errexit(s); 436 } 437 #endif 438