test_sbitotal now fills ictable
[fsck.sofs09.git] / fsck.c
blob714606e1ec85bfe7ef8bdb2f8fa085c6e89c3a75
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <stdbool.h>
6 #include <assert.h>
8 #include "sofs09.h"
9 #include "fsck_helper.h"
11 /* usefull macro and function */
12 static void printError (int errcode, char *cmd_name)
14 fprintf(stderr, "%s: error #%d: %s\n", cmd_name, errcode,\
15 strerror(errcode));
18 #define ABORT(err) \
20 printError(-(err), argv[0]);\
21 exit(EXIT_FAILURE);\
24 #define FABORT(err, fname) \
26 printError(-(err), fname);\
27 exit(EXIT_FAILURE);\
30 /* type definitions */
31 typedef enum {corrupt, weird, nice} testresult_t;
32 typedef testresult_t (*testfunction_t)(void);
34 struct test_s {
35 testfunction_t function;
36 char *name;
38 typedef struct test_s test_t;
40 /* test functions */
42 testresult_t test_sbmagic (void)
44 testresult_t ret;
45 SOSuperBlock *sb;
47 fetch_superblock(&sb);
49 if (sb->magic == MAGIC_NUMBER) {
50 ret = nice;
51 } else {
52 ret = corrupt;
53 printf("This is not a valid SOFS09 filesystem.\n");
56 return ret;
59 testresult_t test_sbzones (void)
61 testresult_t ret;
62 int r, s;
63 int nzones;
64 SOSuperBlock *sb;
66 fetch_superblock(&sb);
68 /* current position inside the disc, in blocks */
69 uint32_t cpos;
71 struct zone_s {
72 /* start position, in blocks, of this zone */
73 uint32_t start;
74 /* size, in blocks, of this zone */
75 uint32_t size;
76 /* zone name */
77 char *name;
79 struct zone_s zone[] = {
80 {sb->fctable_start, sb->fctable_size, "FCT"},
81 {sb->ciutable_start, sb->ciutable_size, "CIUT"},
82 {sb->itable_start, sb->itable_size, "IT"},
83 {sb->dzone_start, sb->dzone_size*BLOCKS_PER_CLUSTER, "DATA"},
85 struct zone_s tempzone;
87 ret = nice;
89 /* sort zones by start position (bouble sort) */
90 nzones = sizeof(zone)/sizeof(struct zone_s);
91 for (r = 0; r < nzones-1; ++r) {
92 for (s = r; s < nzones-1-r; ++s) {
93 if (zone[r].start > zone[r+1].start) {
94 tempzone = zone[r];
95 zone[r] = zone[r+1];
96 zone[r+1] = tempzone;
101 cpos = 0;
103 /* advance superblock */
104 cpos++;
106 for (r = 0; (r < nzones) && (ret != corrupt); ++r) {
107 if (cpos > zone[r].start) {
108 printf("Zones overlap.\n");
109 ret = corrupt;
110 } else {
111 if (cpos != zone[r].start) {
112 printf("Zones are not contiguous.\n");
113 cpos = zone[r].start;
114 ret = weird;
116 cpos += zone[r].size;
117 if (cpos > sb->ntotal) {
118 printf("Zones exceed disc size.\n");
119 ret = corrupt;
124 printf("Detected structure: ZONE_NAME (start,end)\n");
125 printf("0: SB (0,1) : ");
126 for (r = 0; r < nzones; ++r) {
127 printf("%s (%d,%d): ", zone[r].name, zone[r].start,
128 zone[r].start + zone[r].size);
130 printf("%d\n", sb->ntotal);
132 return ret;
135 testresult_t test_sbfctablesize (void)
137 testresult_t ret;
138 SOSuperBlock *sb;
140 fetch_superblock(&sb);
142 /* ceil(a/b) = (a + b - 1)/b */
144 ret = nice;
145 if (sb->fctable_size < ((sb->dzone_size-1)+RPB-1)/RPB) {
146 printf("FCT too small to hold references to all clusters (even"
147 "considering that the root directory block will never be"
148 "there.\n");
149 ret = corrupt;
152 if (sb->fctable_size < (sb->dzone_size+RPB-1)/RPB) {
153 printf("FCT too big.\n");
154 ret = weird;
157 return ret;
160 testresult_t test_sbciutablesize (void)
162 testresult_t ret;
163 SOSuperBlock *sb;
165 fetch_superblock(&sb);
167 /* ceil(a/b) = (a + b - 1)/b */
169 ret = nice;
170 if (sb->ciutable_size < (sb->dzone_size+RPB-1)/RPB) {
171 printf("Cluster inode usage table too small.\n");
172 ret = corrupt;
175 if (sb->ciutable_size < (sb->dzone_size+RPB-1)/RPB) {
176 printf("Cluster inode usage table too big.\n");
177 ret = weird;
180 return ret;
183 testresult_t test_sbitotal (void)
185 testresult_t ret;
186 SOSuperBlock *sb;
188 fetch_superblock(&sb);
190 /* ceil(a/b) = (a + b - 1)/b */
192 ret = nice;
193 if (sb->itable_size < (sb->itotal+IPB-1)/IPB) {
194 printf("Inode table too small.\n");
195 ret = corrupt;
197 if (sb->itable_size > (sb->itotal+IPB-1)/IPB) {
198 printf("Inode table too big.\n");
199 ret = weird;
202 return ret;
205 testresult_t test_sbifree (void)
207 testresult_t ret;
208 uint32_t fret;
209 SOSuperBlock *sb;
211 fetch_superblock(&sb);
213 /* number of free inodes found in the free inode list */
214 uint32_t ifree;
216 /* current inode */
217 SOInode inode;
219 /* index of the current inode */
220 uint32_t inodeidx;
222 /* inode status from ictable */
223 ic_t icstat;
225 ret = nice;
226 ifree = 0;
227 inodeidx = sb->ihead;
228 while ((inodeidx != NULL_INODE) && (ret != corrupt)) {
229 if (inodeidx < sb->itotal) {
230 ictable_get(inodeidx, &icstat);
231 if (icstat == bah) {
232 ictable_set(inodeidx, idle);
233 fret = soReadInode(&inode, inodeidx);
234 if (fret < 0) {
235 perror("soReadInode:");
236 exit(EXIT_FAILURE);
238 ifree++;
239 } else {
240 printf("Free inode list is corrupted.\n");
241 ret = corrupt;
243 } else {
244 printf("Free inode list is corrupted.\n");
245 ret = corrupt;
247 inodeidx = inode.next;
250 if ((ret != corrupt) && (ifree != sb->ifree)) {
251 printf("ifree is incorrect.\n");
252 ret = corrupt;
255 return ret;
258 testresult_t test_sbfreeclusters (void)
260 testresult_t ret;
261 uint32_t freeclusters;
262 SOSuperBlock *sb;
264 fetch_superblock(&sb);
266 ret = nice;
268 if ((sb->fctable_head >= sb->fctable_size*RPB) || (sb->fctable_tail >= sb->fctable_size*RPB)) {
269 printf("fctable head or tail out of bounds.\n");
270 ret = corrupt;
271 } else {
272 if (sb->fctable_tail < sb->fctable_head) {
273 freeclusters = (sb->fctable_tail + sb->fctable_size*RPB) - sb->fctable_head;
274 } else {
275 freeclusters = sb->fctable_tail - sb->fctable_head;
277 freeclusters += sb->dzone_head.cache_cnt;
278 freeclusters += sb->dzone_tail.cache_cnt;
280 if (freeclusters != sb->dzone_free) {
281 printf("donze_free is not correct.\n");
282 ret = corrupt;
286 return ret;
289 void main (int argc, char *argv[])
291 int ret;
292 char *disc_path;
293 testresult_t testres;
294 int r;
295 int nfuncs;
297 /* functions containing the tests to be made */
298 test_t test[] =
300 {test_sbmagic, "sbmagic"},
301 {test_sbzones, "sbzones"},
302 {test_sbfctablesize, "sbfctablesize"},
303 {test_sbciutablesize, "sbciutablesize"},
304 {test_sbitotal, "sbitotal"},
305 {test_sbifree, "sbifree"},
306 {test_sbfreeclusters, "sbfreeclusters"},
309 if (argc != 2) ABORT(-EINVAL);
310 nfuncs = sizeof(test)/sizeof(test_t);
311 disc_path = argv[1];
313 printf("Opening file %s as disc.\n", disc_path);
314 ret = soOpenDevice(disc_path);
315 if (ret < 0) ABORT(ret);
316 atexit((void *)soCloseDevice);
318 for (r = 0; r < nfuncs; ++r) {
319 testres = test[r].function();
320 switch (testres) {
321 case corrupt:
322 printf("System file corrupted.\n");
323 exit(EXIT_FAILURE);
324 break;
325 case weird:
326 printf("System file is weird.\n");
327 break;
328 case nice:
329 printf("Test %s passed with success.\n", test[r].name);
330 break;
331 default:
332 printf("BUM!\n");
333 exit(EXIT_FAILURE);
334 break;
338 exit(EXIT_SUCCESS);