update for 4.3BSD version
[unix-history] / usr / src / sbin / fsck / main.c
CommitLineData
76797561
DF
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
8char copyright[] =
9"@(#) Copyright (c) 1980 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
fa95fc59 13#ifndef lint
1a02fd3a 14static char sccsid[] = "@(#)main.c 5.4 (Berkeley) %G%";
76797561 15#endif not lint
07670f7d 16
4d308541 17#include <sys/param.h>
4d308541 18#include <sys/inode.h>
f7635e39 19#include <sys/fs.h>
7718c0e6
KM
20#include <sys/stat.h>
21#include <sys/wait.h>
22#include <fstab.h>
23#include <strings.h>
f7635e39 24#include "fsck.h"
6e884967 25
7718c0e6 26char *rawname(), *unrawname(), *blockcheck();
3cfe4689
MK
27int catch(), catchquit(), voidquit();
28int returntosingle;
7718c0e6
KM
29int (*signal())();
30
31main(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);
3cfe4689
MK
79 if (preen)
80 (void)signal(SIGQUIT, catchquit);
7718c0e6
KM
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) {
3cfe4689 115 (void)signal(SIGQUIT, voidquit);
7718c0e6
KM
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();
3cfe4689
MK
134 if (returntosingle)
135 exit(2);
7718c0e6
KM
136 exit(0);
137}
138
d2c95d76
BJ
139checkfilesys(filesys)
140 char *filesys;
6e884967 141{
993a756c 142 daddr_t n_ffree, n_bfree;
d4233021 143 struct dups *dp;
1a02fd3a 144 struct zlncnt *zlnp;
6e884967 145
d2c95d76
BJ
146 devname = filesys;
147 if (setup(filesys) == 0) {
6e884967 148 if (preen)
d2c95d76 149 pfatal("CAN'T CHECK FILE SYSTEM.");
6e884967
KM
150 return;
151 }
993a756c
KM
152 /*
153 * 1: scan inodes tallying blocks used
154 */
690f77ba
KM
155 if (preen == 0) {
156 printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
6e884967
KM
157 if (hotroot)
158 printf("** Root file system\n");
159 printf("** Phase 1 - Check Blocks and Sizes\n");
160 }
d2c95d76
BJ
161 pass1();
162
993a756c
KM
163 /*
164 * 1b: locate first references to duplicates, if any
165 */
62e6c152 166 if (duplist) {
d2c95d76
BJ
167 if (preen)
168 pfatal("INTERNAL ERROR: dups with -p");
169 printf("** Phase 1b - Rescan For More DUPS\n");
170 pass1b();
171 }
172
993a756c
KM
173 /*
174 * 2: traverse directories from root to mark all connected directories
175 */
d2c95d76
BJ
176 if (preen == 0)
177 printf("** Phase 2 - Check Pathnames\n");
178 pass2();
179
993a756c
KM
180 /*
181 * 3: scan inodes looking for disconnected directories
182 */
d2c95d76
BJ
183 if (preen == 0)
184 printf("** Phase 3 - Check Connectivity\n");
185 pass3();
186
993a756c
KM
187 /*
188 * 4: scan inodes looking for disconnected files; check reference counts
189 */
d2c95d76
BJ
190 if (preen == 0)
191 printf("** Phase 4 - Check Reference Counts\n");
192 pass4();
193
993a756c
KM
194 /*
195 * 5: check and repair resource counts in cylinder groups
196 */
d2c95d76
BJ
197 if (preen == 0)
198 printf("** Phase 5 - Check Cyl groups\n");
199 pass5();
200
993a756c
KM
201 /*
202 * print out summary statistics
203 */
204 n_ffree = sblock.fs_cstotal.cs_nffree;
205 n_bfree = sblock.fs_cstotal.cs_nbfree;
8755a38b
KM
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);
993a756c
KM
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);
d4233021
KM
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 }
1a02fd3a
KM
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 }
d2c95d76 231 }
1a02fd3a
KM
232 zlnhead = (struct zlncnt *)0;
233 duplist = (struct dups *)0;
d2c95d76 234 if (dfile.mod) {
1a724405 235 (void)time(&sblock.fs_time);
d2c95d76
BJ
236 sbdirty();
237 }
238 ckfini();
239 free(blockmap);
d2c95d76 240 free(statemap);
1a724405 241 free((char *)lncntp);
addfa1aa
BJ
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);
f5971be7 252 }
f5971be7 253}
7718c0e6
KM
254
255char *
256blockcheck(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 }
268retry:
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
302char *
303unrawname(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
321char *
322rawname(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}