xref: /openbsd-src/sbin/fsck_msdos/check.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: check.c,v 1.18 2015/10/14 16:58:55 deraadt Exp $	*/
2 /*	$NetBSD: check.c,v 1.8 1997/10/17 11:19:29 ws Exp $	*/
3 
4 /*
5  * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
6  * Copyright (c) 1995 Martin Husemann
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/types.h>
30 #include <sys/ioctl.h>
31 #include <sys/dkio.h>
32 #include <sys/disklabel.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <limits.h>
39 #include <fcntl.h>
40 #include <util.h>
41 #include <err.h>
42 
43 #include "ext.h"
44 
45 struct disklabel lab;
46 
47 int
48 checkfilesys(const char *fname)
49 {
50 	int dosfs;
51 	struct bootblock boot;
52 	struct fatEntry *fat = NULL;
53 	char *realdev;
54 	int i;
55 	int mod = 0;
56 
57 	rdonly = alwaysno;
58 
59 	dosfs = opendev(fname, rdonly ? O_RDONLY : O_RDWR, 0, &realdev);
60 	if (dosfs < 0 && !rdonly) {
61 		dosfs = opendev(fname, O_RDONLY, 0, &realdev);
62 		rdonly = 1;
63 	}
64 	if (dosfs < 0) {
65 		xperror("Can't open");
66 		return (8);
67 	}
68 
69 	if (!preen) {
70 		printf("** %s", realdev);
71 		if (strncmp(fname, realdev, PATH_MAX) != 0)
72 			printf(" (%s)", fname);
73 		if (rdonly)
74 			printf(" (NO WRITE)");
75 		printf("\n");
76 	}
77 
78 	if (ioctl(dosfs, DIOCGDINFO, (char *)&lab) < 0)
79 		pfatal("can't read disk label for %s\n", fname);
80 
81 	if (pledge("stdio", NULL) == -1)
82 		err(1, "pledge");
83 
84 	if (readboot(dosfs, &boot) != FSOK) {
85 		(void)close(dosfs);
86 		return (8);
87 	}
88 
89 	if (!preen) {
90 		if (boot.ValidFat < 0)
91 			printf("** Phase 1 - Read and Compare FATs\n");
92 		else
93 			printf("** Phase 1 - Read FAT\n");
94 	}
95 
96 	mod |= readfat(dosfs, &boot, boot.ValidFat >= 0 ? boot.ValidFat : 0, &fat);
97 	if (mod & FSFATAL) {
98 		(void)close(dosfs);
99 		return 8;
100 	}
101 
102 	if (boot.ValidFat < 0)
103 		for (i = 1; i < boot.FATs; i++) {
104 			struct fatEntry *currentFat;
105 			mod |= readfat(dosfs, &boot, i, &currentFat);
106 
107 			if (mod & FSFATAL) {
108 				free(fat);
109 				(void)close(dosfs);
110 				return 8;
111 			}
112 
113 			mod |= comparefat(&boot, fat, currentFat, i);
114 			free(currentFat);
115 			if (mod & FSFATAL) {
116 				free(fat);
117 				(void)close(dosfs);
118 				return (8);
119 			}
120 		}
121 
122 	if (!preen)
123 		printf("** Phase 2 - Check Cluster Chains\n");
124 
125 	mod |= checkfat(&boot, fat);
126 	if (mod & FSFATAL) {
127 		free(fat);
128 		(void)close(dosfs);
129 		return (8);
130 	}
131 
132 	if (mod & FSFATMOD)
133 		mod |= writefat(dosfs, &boot, fat); /* delay writing fats?	XXX */
134 	if (mod & FSFATAL) {
135 		free(fat);
136 		(void)close(dosfs);
137 		return (8);
138 	}
139 
140 	if (!preen)
141 		printf("** Phase 3 - Check Directories\n");
142 
143 	mod |= resetDosDirSection(&boot, fat);
144 	if (mod & FSFATAL) {
145 		free(fat);
146 		close(dosfs);
147 		return 8;
148 	}
149 
150 	if (mod & FSFATMOD)
151 		mod |= writefat(dosfs, &boot, fat); /* delay writing fats?	XXX */
152 	if (mod & FSFATAL) {
153 		finishDosDirSection();
154 		free(fat);
155 		(void)close(dosfs);
156 		return (8);
157 	}
158 
159 	mod |= handleDirTree(dosfs, &boot, fat);
160 	if (mod & FSFATAL) {
161 		finishDosDirSection();
162 		free(fat);
163 		(void)close(dosfs);
164 		return (8);
165 	}
166 
167 	if (!preen)
168 		printf("** Phase 4 - Check for Lost Files\n");
169 
170 	mod |= checklost(dosfs, &boot, fat);
171 	if (mod & FSFATAL) {
172 		finishDosDirSection();
173 		free(fat);
174 		(void)close(dosfs);
175 		return 8;
176 	}
177 
178 	if (mod & FSFATMOD)
179 		mod |= writefat(dosfs, &boot, fat); /* delay writing fats?    XXX */
180 
181 	finishDosDirSection();
182 	free(fat);
183 	(void)close(dosfs);
184 	if (mod & FSFATAL)
185 		return 8;
186 
187 	if (boot.NumBad)
188 		pwarn("%d files, %d free (%d clusters), %d bad (%d clusters)\n",
189 		      boot.NumFiles,
190 		      boot.NumFree * boot.ClusterSize / 1024, boot.NumFree,
191 		      boot.NumBad * boot.ClusterSize / 1024, boot.NumBad);
192 	else
193 		pwarn("%d files, %d free (%d clusters)\n",
194 		      boot.NumFiles,
195 		      boot.NumFree * boot.ClusterSize / 1024, boot.NumFree);
196 
197 	if (mod & (FSFATAL | FSERROR))
198 		return (8);
199 	if (mod) {
200 		pwarn("\n***** FILE SYSTEM WAS MODIFIED *****\n");
201 		return (4);
202 	}
203 	return (0);
204 }
205