1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#define FOR_fsck
28#include "toys.h"
29#include <mntent.h>
30
31#define FLAG_WITHOUT_NO_PRFX 1
32#define FLAG_WITH_NO_PRFX 2
33#define FLAG_DONE 1
34
35GLOBALS(
36 int fd_num;
37 char *t_list;
38
39 struct double_list *devices;
40 char *arr_flag;
41 char **arr_type;
42 int negate;
43 int sum_status;
44 int nr_run;
45 int sig_num;
46 long max_nr_run;
47)
48
49struct f_sys_info {
50 char *device, *mountpt, *type, *opts;
51 int passno, flag;
52 struct f_sys_info *next;
53};
54
55struct child_list {
56 struct child_list *next;
57 pid_t pid;
58 char *prog_name, *dev_name;
59};
60
61static struct f_sys_info *filesys_info = NULL;
62static struct child_list *c_list = NULL;
63
64static void kill_all(void)
65{
66 struct child_list *child;
67
68 for (child = c_list; child; child = child->next)
69 kill(child->pid, SIGTERM);
70 _exit(0);
71}
72
73static long strtol_range(char *str, int min, int max)
74{
75 char *endptr = NULL;
76 errno = 0;
77 long ret_value = strtol(str, &endptr, 10);
78
79 if(errno) perror_exit("Invalid num %s", str);
80 else if(endptr && (*endptr != '\0' || endptr == str))
81 perror_exit("Not a valid num %s", str);
82 if(ret_value >= min && ret_value <= max) return ret_value;
83 else perror_exit("Number %s is not in valid [%d-%d] Range", str, min, max);
84}
85
86
87static struct f_sys_info* create_db(struct mntent *f_info)
88{
89 struct f_sys_info *temp = filesys_info;
90 if (temp) {
91 while (temp->next) temp = temp->next;
92 temp->next = xzalloc(sizeof(struct f_sys_info));
93 temp = temp->next;
94 } else filesys_info = temp = xzalloc(sizeof(struct f_sys_info));
95
96 temp->device = xstrdup(f_info->mnt_fsname);
97 temp->mountpt = xstrdup(f_info->mnt_dir);
98 if (strchr(f_info->mnt_type, ',')) temp->type = xstrdup("auto");
99 else temp->type = xstrdup(f_info->mnt_type);
100 temp->opts = xstrdup(f_info->mnt_opts);
101 temp->passno = f_info->mnt_passno;
102 return temp;
103}
104
105
106static int is_no_prefix(char **p)
107{
108 int no = 0;
109
110 if ((*p[0] == 'n' && *(*p + 1) == 'o')) no = 2;
111 else if (*p[0] == '!') no = 1;
112 *p += no;
113 return ((no) ? 1 :0);
114}
115
116static void fix_tlist(void)
117{
118 char *p, *s = TT.t_list;
119 int n = 1, no;
120
121 while ((s = strchr(s, ','))) {
122 s++;
123 n++;
124 }
125
126 TT.arr_flag = xzalloc(n + 1);
127 TT.arr_type = xzalloc((n + 1) * sizeof(char *));
128 s = TT.t_list;
129 n = 0;
130 while ((p = strsep(&s, ","))) {
131 no = is_no_prefix(&p);
132 if (!strcmp(p, "loop")) {
133 TT.arr_flag[n] = no ? FLAG_WITH_NO_PRFX :FLAG_WITHOUT_NO_PRFX;
134 TT.negate = no;
135 } else if (!strncmp(p, "opts=", 5)) {
136 p+=5;
137 TT.arr_flag[n] = is_no_prefix(&p) ?FLAG_WITH_NO_PRFX :FLAG_WITHOUT_NO_PRFX;
138 TT.negate = no;
139 } else {
140 if (!n) TT.negate = no;
141 if (n && TT.negate != no) error_exit("either all or none of the filesystem"
142 " types passed to -t must be prefixed with 'no' or '!'");
143 }
144 TT.arr_type[n++] = p;
145 }
146}
147
148
149static int ignore_type(char *type)
150{
151 int i = 0;
152 char *str;
153 char *ignored_types[] = {
154 "ignore","iso9660", "nfs","proc",
155 "sw","swap", "tmpfs","devpts",NULL
156 };
157 while ((str = ignored_types[i++])) {
158 if (!strcmp(str, type)) return 1;
159 }
160 return 0;
161}
162
163
164static int to_be_ignored(struct f_sys_info *finfo)
165{
166 int i, ret = 0, type_present = 0;
167
168 if (!finfo->passno) return 1;
169 if (TT.arr_type) {
170 for (i = 0; TT.arr_type[i]; i++) {
171 if (!TT.arr_flag[i]) {
172 type_present = 2;
173 if (!strcmp(TT.arr_type[i], finfo->type)) ret = 0;
174 else ret = 1;
175 } else if (TT.arr_flag[i] == FLAG_WITH_NO_PRFX) {
176 if (hasmntopt((const struct mntent *)finfo, TT.arr_type[i])) return 1;
177 } else {
178 if (!hasmntopt((const struct mntent *)finfo, TT.arr_type[i])) return 1;
179 }
180 }
181 }
182 if (ignore_type(finfo->type)) return 1;
183 if (TT.arr_type && type_present != 2) return 0;
184 return ((TT.negate) ? !ret : ret);
185}
186
187
188static void do_fsck(struct f_sys_info *finfo)
189{
190 struct child_list *child;
191 char **args;
192 char *type;
193 pid_t pid;
194 int i = 1, j = 0;
195
196 if (strcmp(finfo->type, "auto")) type = finfo->type;
197 else if (TT.t_list && (TT.t_list[0] != 'n' || TT.t_list[1] != 'o' || TT.t_list[0] != '!')
198 && strncmp(TT.t_list, "opts=", 5) && strncmp(TT.t_list , "loop", 4)
199 && !TT.arr_type[1]) type = TT.t_list;
200 else type = "auto";
201
202 args = xzalloc((toys.optc + 2 + 1 + 1) * sizeof(char*));
203 args[0] = xmprintf("fsck.%s", type);
204
205 if(toys.optflags & FLAG_C) args[i++] = xmprintf("%s %d","-C", TT.fd_num);
206 while(toys.optargs[j]) {
207 if(*toys.optargs[j]) args[i++] = xstrdup(toys.optargs[j]);
208 j++;
209 }
210 args[i] = finfo->device;
211
212 TT.nr_run++;
213 if ((toys.optflags & FLAG_V) || (toys.optflags & FLAG_N)) {
214 printf("[%s (%d) -- %s]", args[0], TT.nr_run,
215 finfo->mountpt ? finfo->mountpt : finfo->device);
216 for (i = 0; args[i]; i++) xprintf(" %s", args[i]);
217 xputc('\n');
218 }
219
220 if (toys.optflags & FLAG_N) {
221 for (j=0;j<i;j++) free(args[i]);
222 free(args);
223 return;
224 } else {
225 if ((pid = fork()) < 0) {
226 perror_msg(args[0]);
227 for (j=0;j<i;j++) free(args[i]);
228 free(args);
229 return;
230 }
231 if (!pid) xexec(args);
232 }
233
234 child = xzalloc(sizeof(struct child_list));
235 child->dev_name = xstrdup(finfo->device);
236 child->prog_name = args[0];
237 child->pid = pid;
238
239 if (c_list) {
240 child->next = c_list;
241 c_list = child;
242 } else {
243 c_list = child;
244 child->next =NULL;
245 }
246}
247
248
249
250static int wait_for(int for_all)
251{
252 pid_t pid;
253 int status = 0, child_exited;
254 struct child_list *prev, *temp;
255
256 errno = 0;
257 if (!c_list) return 0;
258 while ((pid = wait(&status))) {
259 temp = c_list;
260 prev = temp;
261 if (TT.sig_num) kill_all();
262 child_exited = 0;
263 if (pid < 0) {
264 if (errno == EINTR) continue;
265 else if (errno == ECHILD) break;
266 else perror_exit("option arg Invalid\n");
267 }
268 while (temp) {
269 if (temp->pid == pid) {
270 child_exited = 1;
271 break;
272 }
273 prev = temp;
274 temp = temp->next;
275 }
276 if (child_exited) {
277 if (WIFEXITED(status)) TT.sum_status |= WEXITSTATUS(status);
278 else if (WIFSIGNALED(status)) {
279 TT.sum_status |= 4;
280 if (WTERMSIG(status) != SIGINT)
281 perror_msg("child Term. by sig: %d\n",(WTERMSIG(status)));
282 TT.sum_status |= 8;
283 } else {
284 TT.sum_status |= 4;
285 perror_msg("%s %s: status is %x, should never happen\n",
286 temp->prog_name, temp->dev_name, status);
287 }
288 TT.nr_run--;
289 if (prev == temp) c_list = c_list->next;
290 else prev->next = temp->next;
291 free(temp->prog_name);
292 free(temp->dev_name);
293 free(temp);
294 if (!for_all) break;
295 }
296 }
297 return TT.sum_status;
298}
299
300
301static int scan_all(void)
302{
303 struct f_sys_info *finfo = filesys_info;
304 int ret = 0, passno;
305
306 if (toys.optflags & FLAG_V) xprintf("Checking all filesystem\n");
307 while (finfo) {
308 if (to_be_ignored(finfo)) finfo->flag |= FLAG_DONE;
309 finfo = finfo->next;
310 }
311 finfo = filesys_info;
312
313 if (!(toys.optflags & FLAG_P)) {
314 while (finfo) {
315 if (!strcmp(finfo->mountpt, "/")) {
316 if ((toys.optflags & FLAG_R) || to_be_ignored(finfo)) {
317 finfo->flag |= FLAG_DONE;
318 break;
319 } else {
320 do_fsck(finfo);
321 finfo->flag |= FLAG_DONE;
322 if (TT.sig_num) kill_all();
323 if ((ret |= wait_for(1)) > 4) return ret;
324 break;
325 }
326 }
327 finfo = finfo->next;
328 }
329 }
330 if (toys.optflags & FLAG_R) {
331 for (finfo = filesys_info; finfo; finfo = finfo->next) {
332 if(!strcmp(finfo->mountpt, "/")) finfo->flag |= FLAG_DONE;
333 }
334 }
335 passno = 1;
336 while (1) {
337 for (finfo = filesys_info; finfo; finfo = finfo->next)
338 if (!finfo->flag) break;
339 if (!finfo) break;
340
341 for (finfo = filesys_info; finfo; finfo = finfo->next) {
342 if (finfo->flag) continue;
343 if (finfo->passno == passno) {
344 do_fsck(finfo);
345 finfo->flag |= FLAG_DONE;
346 if ((toys.optflags & FLAG_s) || (TT.nr_run
347 && (TT.nr_run >= TT.max_nr_run))) ret |= wait_for(0);
348 }
349 }
350 if (TT.sig_num) kill_all();
351 ret |= wait_for(1);
352 passno++;
353 }
354 return ret;
355}
356
357void record_sig_num(int sig)
358{
359 TT.sig_num = sig;
360}
361
362void fsck_main(void)
363{
364 struct mntent mt;
365 struct double_list *dev;
366 struct f_sys_info *finfo;
367 FILE *fp;
368 char *tmp, **arg = toys.optargs;
369
370 sigatexit(record_sig_num);
371 while (*arg) {
372 if ((**arg == '/') || strchr(*arg, '=')) {
373 dlist_add(&TT.devices, xstrdup(*arg));
374 **arg = '\0';
375 }
376 arg++;
377 }
378 if (toys.optflags & FLAG_t) fix_tlist();
379 if (!(tmp = getenv("FSTAB_FILE"))) tmp = "/etc/fstab";
380 if (!(fp = setmntent(tmp, "r"))) perror_exit("setmntent failed:");
381 while (getmntent_r(fp, &mt, toybuf, 4096)) create_db(&mt);
382 endmntent(fp);
383
384 if (!(toys.optflags & FLAG_T)) xprintf("fsck ----- (Toybox)\n");
385
386 if ((tmp = getenv("FSCK_MAX_INST")))
387 TT.max_nr_run = strtol_range(tmp, 0, INT_MAX);
388 if (!TT.devices || (toys.optflags & FLAG_A)) {
389 toys.exitval = scan_all();
390 if (CFG_TOYBOX_FREE) goto free_all;
391 return;
392 }
393
394 dev = TT.devices;
395 dev->prev->next = NULL;
396 for (; dev; dev = dev->next) {
397 for (finfo = filesys_info; finfo; finfo = finfo->next)
398 if (!strcmp(finfo->device, dev->data)
399 || !strcmp(finfo->mountpt, dev->data)) break;
400 if (!finfo) {
401 mt.mnt_fsname = dev->data;
402 mt.mnt_dir = "";
403 mt.mnt_type = "auto";
404 mt.mnt_opts = "";
405 mt.mnt_passno = -1;
406 finfo = create_db(&mt);
407 }
408 do_fsck(finfo);
409 finfo->flag |= FLAG_DONE;
410 if ((toys.optflags & FLAG_s) || (TT.nr_run && (TT.nr_run >= TT.max_nr_run)))
411 toys.exitval |= wait_for(0);
412 }
413 if (TT.sig_num) kill_all();
414 toys.exitval |= wait_for(1);
415 finfo = filesys_info;
416
417free_all:
418 if (CFG_TOYBOX_FREE) {
419 struct f_sys_info *finfo, *temp;
420
421 llist_traverse(TT.devices, llist_free_double);
422 free(TT.arr_type);
423 free(TT.arr_flag);
424 for (finfo = filesys_info; finfo;) {
425 temp = finfo->next;
426 free(finfo->device);
427 free(finfo->mountpt);
428 free(finfo->type);
429 free(finfo->opts);
430 free(finfo);
431 finfo = temp;
432 }
433 }
434}
435