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 char copyright[] = 9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif not lint 12 13 #ifndef lint 14 static char sccsid[] = "@(#)main.c 5.4 (Berkeley) 03/05/86"; 15 #endif not lint 16 17 #include <sys/param.h> 18 #include <sys/inode.h> 19 #include <sys/fs.h> 20 #include <sys/stat.h> 21 #include <sys/wait.h> 22 #include <fstab.h> 23 #include <strings.h> 24 #include "fsck.h" 25 26 char *rawname(), *unrawname(), *blockcheck(); 27 int catch(), catchquit(), voidquit(); 28 int returntosingle; 29 int (*signal())(); 30 31 main(argc, argv) 32 int argc; 33 char *argv[]; 34 { 35 struct fstab *fsp; 36 int pid, passno, anygtr, sumstatus; 37 char *name; 38 39 sync(); 40 while (--argc > 0 && **++argv == '-') { 41 switch (*++*argv) { 42 43 case 'p': 44 preen++; 45 break; 46 47 case 'b': 48 if (argv[0][1] != '\0') { 49 bflag = atoi(argv[0]+1); 50 } else { 51 bflag = atoi(*++argv); 52 argc--; 53 } 54 printf("Alternate super block location: %d\n", bflag); 55 break; 56 57 case 'd': 58 debug++; 59 break; 60 61 case 'n': /* default no answer flag */ 62 case 'N': 63 nflag++; 64 yflag = 0; 65 break; 66 67 case 'y': /* default yes answer flag */ 68 case 'Y': 69 yflag++; 70 nflag = 0; 71 break; 72 73 default: 74 errexit("%c option?\n", **argv); 75 } 76 } 77 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 78 (void)signal(SIGINT, catch); 79 if (preen) 80 (void)signal(SIGQUIT, catchquit); 81 if (argc) { 82 while (argc-- > 0) { 83 hotroot = 0; 84 checkfilesys(*argv++); 85 } 86 exit(0); 87 } 88 sumstatus = 0; 89 passno = 1; 90 do { 91 anygtr = 0; 92 if (setfsent() == 0) 93 errexit("Can't open checklist file: %s\n", FSTAB); 94 while ((fsp = getfsent()) != 0) { 95 if (strcmp(fsp->fs_type, FSTAB_RW) && 96 strcmp(fsp->fs_type, FSTAB_RO) && 97 strcmp(fsp->fs_type, FSTAB_RQ)) 98 continue; 99 if (preen == 0 || 100 passno == 1 && fsp->fs_passno == passno) { 101 name = blockcheck(fsp->fs_spec); 102 if (name != NULL) 103 checkfilesys(name); 104 else if (preen) 105 exit(8); 106 } else if (fsp->fs_passno > passno) { 107 anygtr = 1; 108 } else if (fsp->fs_passno == passno) { 109 pid = fork(); 110 if (pid < 0) { 111 perror("fork"); 112 exit(8); 113 } 114 if (pid == 0) { 115 (void)signal(SIGQUIT, voidquit); 116 name = blockcheck(fsp->fs_spec); 117 if (name == NULL) 118 exit(8); 119 checkfilesys(name); 120 exit(0); 121 } 122 } 123 } 124 if (preen) { 125 union wait status; 126 while (wait(&status) != -1) 127 sumstatus |= status.w_retcode; 128 } 129 passno++; 130 } while (anygtr); 131 if (sumstatus) 132 exit(8); 133 (void)endfsent(); 134 if (returntosingle) 135 exit(2); 136 exit(0); 137 } 138 139 checkfilesys(filesys) 140 char *filesys; 141 { 142 daddr_t n_ffree, n_bfree; 143 struct dups *dp; 144 struct zlncnt *zlnp; 145 146 devname = filesys; 147 if (setup(filesys) == 0) { 148 if (preen) 149 pfatal("CAN'T CHECK FILE SYSTEM."); 150 return; 151 } 152 /* 153 * 1: scan inodes tallying blocks used 154 */ 155 if (preen == 0) { 156 printf("** Last Mounted on %s\n", sblock.fs_fsmnt); 157 if (hotroot) 158 printf("** Root file system\n"); 159 printf("** Phase 1 - Check Blocks and Sizes\n"); 160 } 161 pass1(); 162 163 /* 164 * 1b: locate first references to duplicates, if any 165 */ 166 if (duplist) { 167 if (preen) 168 pfatal("INTERNAL ERROR: dups with -p"); 169 printf("** Phase 1b - Rescan For More DUPS\n"); 170 pass1b(); 171 } 172 173 /* 174 * 2: traverse directories from root to mark all connected directories 175 */ 176 if (preen == 0) 177 printf("** Phase 2 - Check Pathnames\n"); 178 pass2(); 179 180 /* 181 * 3: scan inodes looking for disconnected directories 182 */ 183 if (preen == 0) 184 printf("** Phase 3 - Check Connectivity\n"); 185 pass3(); 186 187 /* 188 * 4: scan inodes looking for disconnected files; check reference counts 189 */ 190 if (preen == 0) 191 printf("** Phase 4 - Check Reference Counts\n"); 192 pass4(); 193 194 /* 195 * 5: check and repair resource counts in cylinder groups 196 */ 197 if (preen == 0) 198 printf("** Phase 5 - Check Cyl groups\n"); 199 pass5(); 200 201 /* 202 * print out summary statistics 203 */ 204 n_ffree = sblock.fs_cstotal.cs_nffree; 205 n_bfree = sblock.fs_cstotal.cs_nbfree; 206 pwarn("%d files, %d used, %d free ", 207 n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree); 208 printf("(%d frags, %d blocks, %.1f%% fragmentation)\n", 209 n_ffree, n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize); 210 if (debug && (n_files -= imax - ROOTINO - sblock.fs_cstotal.cs_nifree)) 211 printf("%d files missing\n", n_files); 212 if (debug) { 213 n_blks += sblock.fs_ncg * 214 (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); 215 n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); 216 n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); 217 if (n_blks -= fmax - (n_ffree + sblock.fs_frag * n_bfree)) 218 printf("%d blocks missing\n", n_blks); 219 if (duplist != NULL) { 220 printf("The following duplicate blocks remain:"); 221 for (dp = duplist; dp; dp = dp->next) 222 printf(" %d,", dp->dup); 223 printf("\n"); 224 } 225 if (zlnhead != NULL) { 226 printf("The following zero link count inodes remain:"); 227 for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) 228 printf(" %d,", zlnp->zlncnt); 229 printf("\n"); 230 } 231 } 232 zlnhead = (struct zlncnt *)0; 233 duplist = (struct dups *)0; 234 if (dfile.mod) { 235 (void)time(&sblock.fs_time); 236 sbdirty(); 237 } 238 ckfini(); 239 free(blockmap); 240 free(statemap); 241 free((char *)lncntp); 242 if (!dfile.mod) 243 return; 244 if (!preen) { 245 printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 246 if (hotroot) 247 printf("\n***** REBOOT UNIX *****\n"); 248 } 249 if (hotroot) { 250 sync(); 251 exit(4); 252 } 253 } 254 255 char * 256 blockcheck(name) 257 char *name; 258 { 259 struct stat stslash, stblock, stchar; 260 char *raw; 261 int looped = 0; 262 263 hotroot = 0; 264 if (stat("/", &stslash) < 0){ 265 printf("Can't stat root\n"); 266 return (0); 267 } 268 retry: 269 if (stat(name, &stblock) < 0){ 270 printf("Can't stat %s\n", name); 271 return (0); 272 } 273 if (stblock.st_mode & S_IFBLK) { 274 raw = rawname(name); 275 if (stat(raw, &stchar) < 0){ 276 printf("Can't stat %s\n", raw); 277 return (0); 278 } 279 if (stchar.st_mode & S_IFCHR) { 280 if (stslash.st_dev == stblock.st_rdev) { 281 hotroot++; 282 raw = unrawname(name); 283 } 284 return (raw); 285 } else { 286 printf("%s is not a character device\n", raw); 287 return (0); 288 } 289 } else if (stblock.st_mode & S_IFCHR) { 290 if (looped) { 291 printf("Can't make sense out of name %s\n", name); 292 return (0); 293 } 294 name = unrawname(name); 295 looped++; 296 goto retry; 297 } 298 printf("Can't make sense out of name %s\n", name); 299 return (0); 300 } 301 302 char * 303 unrawname(cp) 304 char *cp; 305 { 306 char *dp = rindex(cp, '/'); 307 struct stat stb; 308 309 if (dp == 0) 310 return (cp); 311 if (stat(cp, &stb) < 0) 312 return (cp); 313 if ((stb.st_mode&S_IFMT) != S_IFCHR) 314 return (cp); 315 if (*(dp+1) != 'r') 316 return (cp); 317 (void)strcpy(dp+1, dp+2); 318 return (cp); 319 } 320 321 char * 322 rawname(cp) 323 char *cp; 324 { 325 static char rawbuf[32]; 326 char *dp = rindex(cp, '/'); 327 328 if (dp == 0) 329 return (0); 330 *dp = 0; 331 (void)strcpy(rawbuf, cp); 332 *dp = '/'; 333 (void)strcat(rawbuf, "/r"); 334 (void)strcat(rawbuf, dp+1); 335 return (rawbuf); 336 } 337