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