1 #ifndef lint 2 static char version[] = "@(#)utilities.c 3.5 (Berkeley) 02/18/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 if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) { 94 bp->b_bno = dblk; 95 bp->b_size = size; 96 return (bp); 97 } 98 bp->b_bno = (daddr_t)-1; 99 return (NULL); 100 } 101 102 flush(fcp, bp) 103 struct filecntl *fcp; 104 register BUFAREA *bp; 105 { 106 register int i, j; 107 108 if (!bp->b_dirty) 109 return; 110 bp->b_dirty = 0; 111 (void)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 (void)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 if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0) 157 rwerr("SEEK", blk); 158 else if (read(fcp->rfdes, buf, (int)size) == size) 159 return (1); 160 rwerr("READ", blk); 161 return (0); 162 } 163 164 bwrite(fcp, buf, blk, size) 165 register struct filecntl *fcp; 166 char *buf; 167 daddr_t blk; 168 long size; 169 { 170 171 if (fcp->wfdes < 0) 172 return (0); 173 if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0) 174 rwerr("SEEK", blk); 175 else if (write(fcp->wfdes, buf, (int)size) == size) { 176 fcp->mod = 1; 177 return (1); 178 } 179 rwerr("WRITE", blk); 180 return (0); 181 } 182 183 /* 184 * allocate a data block with the specified number of fragments 185 */ 186 allocblk(frags) 187 int frags; 188 { 189 register int i, j, k; 190 191 if (frags <= 0 || frags > sblock.fs_frag) 192 return (0); 193 for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) { 194 for (j = 0; j <= sblock.fs_frag - frags; j++) { 195 if (getbmap(i + j)) 196 continue; 197 for (k = 1; k < frags; k++) 198 if (getbmap(i + j + k)) 199 break; 200 if (k < frags) { 201 j += k; 202 continue; 203 } 204 for (k = 0; k < frags; k++) 205 setbmap(i + j + k); 206 n_blks += frags; 207 return (i + j); 208 } 209 } 210 return (0); 211 } 212 213 /* 214 * Free a previously allocated block 215 */ 216 freeblk(blkno, frags) 217 daddr_t blkno; 218 int frags; 219 { 220 struct inodesc idesc; 221 222 idesc.id_blkno = blkno; 223 idesc.id_numfrags = frags; 224 pass4check(&idesc); 225 } 226 227 /* 228 * Find a pathname 229 */ 230 getpathname(namebuf, curdir, ino) 231 char *namebuf; 232 ino_t curdir, ino; 233 { 234 int len; 235 register char *cp; 236 struct inodesc idesc; 237 extern int findname(); 238 239 if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) { 240 strcpy(namebuf, "?"); 241 return; 242 } 243 bzero(&idesc, sizeof(struct inodesc)); 244 idesc.id_type = DATA; 245 cp = &namebuf[BUFSIZ - 1]; 246 *cp-- = '\0'; 247 if (curdir != ino) { 248 idesc.id_parent = curdir; 249 goto namelookup; 250 } 251 while (ino != ROOTINO) { 252 idesc.id_number = ino; 253 idesc.id_func = findino; 254 idesc.id_name = ".."; 255 if ((ckinode(ginode(ino), &idesc) & STOP) == 0) 256 break; 257 namelookup: 258 idesc.id_number = idesc.id_parent; 259 idesc.id_parent = ino; 260 idesc.id_func = findname; 261 idesc.id_name = namebuf; 262 if ((ckinode(ginode(idesc.id_number), &idesc) & STOP) == 0) 263 break; 264 len = strlen(namebuf); 265 cp -= len; 266 if (cp < &namebuf[MAXNAMLEN]) 267 break; 268 bcopy(namebuf, cp, len); 269 *--cp = '/'; 270 ino = idesc.id_number; 271 } 272 if (ino != ROOTINO) { 273 strcpy(namebuf, "?"); 274 return; 275 } 276 bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp); 277 } 278 279 catch() 280 { 281 282 ckfini(); 283 exit(12); 284 } 285 286 /* 287 * determine whether an inode should be fixed. 288 */ 289 dofix(idesc, msg) 290 register struct inodesc *idesc; 291 char *msg; 292 { 293 294 switch (idesc->id_fix) { 295 296 case DONTKNOW: 297 if (idesc->id_type == DATA) 298 direrr(idesc->id_number, msg); 299 else 300 pwarn(msg); 301 if (preen) { 302 printf(" (SALVAGED)\n"); 303 idesc->id_fix = FIX; 304 return (ALTERED); 305 } 306 if (reply("SALVAGE") == 0) { 307 idesc->id_fix = NOFIX; 308 return (0); 309 } 310 idesc->id_fix = FIX; 311 return (ALTERED); 312 313 case FIX: 314 return (ALTERED); 315 316 case NOFIX: 317 return (0); 318 319 default: 320 errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 321 } 322 /* NOTREACHED */ 323 } 324 325 /* VARARGS1 */ 326 errexit(s1, s2, s3, s4) 327 char *s1; 328 { 329 printf(s1, s2, s3, s4); 330 exit(8); 331 } 332 333 /* 334 * An inconsistency occured which shouldn't during normal operations. 335 * Die if preening, otherwise just printf. 336 */ 337 /* VARARGS1 */ 338 pfatal(s, a1, a2, a3) 339 char *s; 340 { 341 342 if (preen) { 343 printf("%s: ", devname); 344 printf(s, a1, a2, a3); 345 printf("\n"); 346 printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 347 devname); 348 exit(8); 349 } 350 printf(s, a1, a2, a3); 351 } 352 353 /* 354 * Pwarn is like printf when not preening, 355 * or a warning (preceded by filename) when preening. 356 */ 357 /* VARARGS1 */ 358 pwarn(s, a1, a2, a3, a4, a5, a6) 359 char *s; 360 { 361 362 if (preen) 363 printf("%s: ", devname); 364 printf(s, a1, a2, a3, a4, a5, a6); 365 } 366 367 #ifndef lint 368 /* 369 * Stub for routines from kernel. 370 */ 371 panic(s) 372 char *s; 373 { 374 375 pfatal("INTERNAL INCONSISTENCY:"); 376 errexit(s); 377 } 378 #endif 379