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.6 (Berkeley) 02/26/87"; 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 perror("/"); 266 printf("Can't stat root\n"); 267 return (0); 268 } 269 retry: 270 if (stat(name, &stblock) < 0){ 271 perror(name); 272 printf("Can't stat %s\n", name); 273 return (0); 274 } 275 if ((stblock.st_mode & S_IFMT) == S_IFBLK) { 276 if (stslash.st_dev == stblock.st_rdev) { 277 hotroot++; 278 return (name); 279 } 280 raw = rawname(name); 281 if (stat(raw, &stchar) < 0){ 282 perror(raw); 283 printf("Can't stat %s\n", raw); 284 return (name); 285 } 286 if ((stchar.st_mode & S_IFMT) == S_IFCHR) 287 return (raw); 288 else { 289 printf("%s is not a character device\n", raw); 290 return (name); 291 } 292 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR) { 293 if (looped) { 294 printf("Can't make sense out of name %s\n", name); 295 return (0); 296 } 297 name = unrawname(name); 298 looped++; 299 goto retry; 300 } 301 printf("Can't make sense out of name %s\n", name); 302 return (0); 303 } 304 305 char * 306 unrawname(cp) 307 char *cp; 308 { 309 char *dp = rindex(cp, '/'); 310 struct stat stb; 311 312 if (dp == 0) 313 return (cp); 314 if (stat(cp, &stb) < 0) 315 return (cp); 316 if ((stb.st_mode&S_IFMT) != S_IFCHR) 317 return (cp); 318 if (*(dp+1) != 'r') 319 return (cp); 320 (void)strcpy(dp+1, dp+2); 321 return (cp); 322 } 323 324 char * 325 rawname(cp) 326 char *cp; 327 { 328 static char rawbuf[32]; 329 char *dp = rindex(cp, '/'); 330 331 if (dp == 0) 332 return (0); 333 *dp = 0; 334 (void)strcpy(rawbuf, cp); 335 *dp = '/'; 336 (void)strcat(rawbuf, "/r"); 337 (void)strcat(rawbuf, dp+1); 338 return (rawbuf); 339 } 340