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