1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
5 * Copyright (c) 1995 Martin Husemann
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28
29 #include <sys/cdefs.h>
30 #ifndef lint
31 __RCSID("$NetBSD: check.c,v 1.14 2006/06/05 16:51:18 christos Exp $");
32 #endif /* not lint */
33
34 #ifdef HAVE_LIBUTIL_H
35 #include <libutil.h>
36 #endif
37 #include <stdlib.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42
43 #include "ext.h"
44 #include "fsutil.h"
45
46 int
checkfilesys(const char * fname)47 checkfilesys(const char *fname)
48 {
49 int dosfs;
50 struct bootblock boot;
51 struct fat_descriptor *fat = NULL;
52 int finish_dosdirsection=0;
53 int mod = 0;
54 int ret = 8;
55 int64_t freebytes;
56 int64_t badbytes;
57
58 rdonly = alwaysno;
59 if (!preen)
60 printf("** %s", fname);
61
62 dosfs = open(fname, rdonly ? O_RDONLY : O_RDWR, 0);
63 if (dosfs < 0 && !rdonly) {
64 dosfs = open(fname, O_RDONLY, 0);
65 if (dosfs >= 0)
66 pwarn(" (NO WRITE)\n");
67 else if (!preen)
68 printf("\n");
69 rdonly = 1;
70 } else if (!preen)
71 printf("\n");
72
73 if (dosfs < 0) {
74 perr("Can't open `%s'", fname);
75 printf("\n");
76 return 8;
77 }
78
79 if (readboot(dosfs, &boot) == FSFATAL) {
80 close(dosfs);
81 printf("\n");
82 return 8;
83 }
84
85 if (skipclean && preen && checkdirty(dosfs, &boot)) {
86 printf("%s: ", fname);
87 printf("FILESYSTEM CLEAN; SKIPPING CHECKS\n");
88 ret = 0;
89 goto out;
90 }
91
92 if (!preen) {
93 printf("** Phase 1 - Read FAT and checking connectivity\n");
94 }
95
96 mod |= readfat(dosfs, &boot, &fat);
97 if (mod & FSFATAL) {
98 close(dosfs);
99 return 8;
100 }
101
102 if (!preen)
103 printf("** Phase 2 - Checking Directories\n");
104
105 mod |= resetDosDirSection(fat);
106 finish_dosdirsection = 1;
107 if (mod & FSFATAL)
108 goto out;
109 /* delay writing FATs */
110
111 mod |= handleDirTree(fat);
112 if (mod & FSFATAL)
113 goto out;
114
115 if (!preen)
116 printf("** Phase 3 - Checking for Lost Files\n");
117
118 mod |= checklost(fat);
119 if (mod & FSFATAL)
120 goto out;
121
122 /* now write the FATs */
123 if (mod & FSFATMOD) {
124 if (ask(1, "Update FATs")) {
125 mod |= writefat(fat);
126 if (mod & FSFATAL)
127 goto out;
128 } else
129 mod |= FSERROR;
130 }
131
132 freebytes = (int64_t)boot.NumFree * boot.ClusterSize;
133 badbytes = (int64_t)boot.NumBad * boot.ClusterSize;
134
135 #ifdef HAVE_LIBUTIL_H
136 char freestr[7], badstr[7];
137
138 humanize_number(freestr, sizeof(freestr), freebytes, "",
139 HN_AUTOSCALE, HN_DECIMAL | HN_IEC_PREFIXES);
140 if (boot.NumBad) {
141 humanize_number(badstr, sizeof(badstr), badbytes, "",
142 HN_AUTOSCALE, HN_B | HN_DECIMAL | HN_IEC_PREFIXES);
143
144 pwarn("%d files, %sB free (%d clusters), %sB bad (%d clusters)\n",
145 boot.NumFiles, freestr, boot.NumFree,
146 badstr, boot.NumBad);
147 } else {
148 pwarn("%d files, %sB free (%d clusters)\n",
149 boot.NumFiles, freestr, boot.NumFree);
150 }
151 #else
152 if (boot.NumBad)
153 pwarn("%d files, %jd KiB free (%d clusters), %jd KiB bad (%d clusters)\n",
154 boot.NumFiles, (intmax_t)freebytes / 1024, boot.NumFree,
155 (intmax_t)badbytes / 1024, boot.NumBad);
156 else
157 pwarn("%d files, %jd KiB free (%d clusters)\n",
158 boot.NumFiles, (intmax_t)freebytes / 1024, boot.NumFree);
159 #endif
160
161 if (mod && (mod & FSERROR) == 0) {
162 if (mod & FSDIRTY) {
163 if (ask(1, "MARK FILE SYSTEM CLEAN") == 0)
164 mod &= ~FSDIRTY;
165
166 if (mod & FSDIRTY) {
167 pwarn("MARKING FILE SYSTEM CLEAN\n");
168 mod |= cleardirty(fat);
169 } else {
170 pwarn("\n***** FILE SYSTEM IS LEFT MARKED AS DIRTY *****\n");
171 mod |= FSERROR; /* file system not clean */
172 }
173 }
174 }
175
176 if (mod & (FSFATAL | FSERROR))
177 goto out;
178
179 ret = 0;
180
181 out:
182 if (finish_dosdirsection)
183 finishDosDirSection();
184 free(fat);
185 close(dosfs);
186
187 if (mod & (FSFATMOD|FSDIRMOD))
188 pwarn("\n***** FILE SYSTEM WAS MODIFIED *****\n");
189
190 return ret;
191 }
192