1330449Seadler/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
479455Sobrien * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
579455Sobrien * Copyright (c) 1995 Martin Husemann
679455Sobrien *
779455Sobrien * Redistribution and use in source and binary forms, with or without
879455Sobrien * modification, are permitted provided that the following conditions
979455Sobrien * are met:
1079455Sobrien * 1. Redistributions of source code must retain the above copyright
1179455Sobrien *    notice, this list of conditions and the following disclaimer.
1279455Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1379455Sobrien *    notice, this list of conditions and the following disclaimer in the
1479455Sobrien *    documentation and/or other materials provided with the distribution.
1579455Sobrien *
1679455Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1779455Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1879455Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1979455Sobrien * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2079455Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2179455Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2279455Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2379455Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2479455Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2579455Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2679455Sobrien */
2779455Sobrien
2879455Sobrien
2979455Sobrien#include <sys/cdefs.h>
3079455Sobrien#ifndef lint
31241806Suqs__RCSID("$NetBSD: check.c,v 1.14 2006/06/05 16:51:18 christos Exp $");
3279455Sobrienstatic const char rcsid[] =
3379455Sobrien  "$FreeBSD: stable/11/sbin/fsck_msdosfs/check.c 360490 2020-04-30 06:34:34Z delphij $";
3479455Sobrien#endif /* not lint */
3579455Sobrien
36360490Sdelphij#ifdef HAVE_LIBUTIL_H
37360490Sdelphij#include <libutil.h>
38360490Sdelphij#endif
3979455Sobrien#include <stdlib.h>
4079455Sobrien#include <string.h>
4179455Sobrien#include <stdio.h>
4279455Sobrien#include <unistd.h>
4379455Sobrien#include <fcntl.h>
4479455Sobrien
4579455Sobrien#include "ext.h"
4679455Sobrien#include "fsutil.h"
4779455Sobrien
4879455Sobrienint
49121726Strhodescheckfilesys(const char *fname)
5079455Sobrien{
5179455Sobrien	int dosfs;
5279455Sobrien	struct bootblock boot;
53360490Sdelphij	struct fat_descriptor *fat = NULL;
54203872Skib	int finish_dosdirsection=0;
5579455Sobrien	int mod = 0;
5679455Sobrien	int ret = 8;
57360490Sdelphij	int64_t freebytes;
58360490Sdelphij	int64_t badbytes;
5979455Sobrien
6079455Sobrien	rdonly = alwaysno;
6179455Sobrien	if (!preen)
6279455Sobrien		printf("** %s", fname);
6379455Sobrien
6479455Sobrien	dosfs = open(fname, rdonly ? O_RDONLY : O_RDWR, 0);
6579455Sobrien	if (dosfs < 0 && !rdonly) {
6679455Sobrien		dosfs = open(fname, O_RDONLY, 0);
6779455Sobrien		if (dosfs >= 0)
6879455Sobrien			pwarn(" (NO WRITE)\n");
6979455Sobrien		else if (!preen)
7079455Sobrien			printf("\n");
7179455Sobrien		rdonly = 1;
7279455Sobrien	} else if (!preen)
7379455Sobrien		printf("\n");
7479455Sobrien
7579455Sobrien	if (dosfs < 0) {
76241806Suqs		perr("Can't open `%s'", fname);
77242511Sjh		printf("\n");
7879455Sobrien		return 8;
7979455Sobrien	}
8079455Sobrien
81334605Sdelphij	if (readboot(dosfs, &boot) == FSFATAL) {
8279455Sobrien		close(dosfs);
8379455Sobrien		printf("\n");
8479455Sobrien		return 8;
8579455Sobrien	}
8679455Sobrien
87125486Sbde	if (skipclean && preen && checkdirty(dosfs, &boot)) {
88125486Sbde		printf("%s: ", fname);
89123873Strhodes		printf("FILESYSTEM CLEAN; SKIPPING CHECKS\n");
90123873Strhodes		ret = 0;
91123873Strhodes		goto out;
92123873Strhodes	}
93123873Strhodes
9479455Sobrien	if (!preen)  {
95360490Sdelphij		printf("** Phase 1 - Read FAT and checking connectivity\n");
9679455Sobrien	}
9779455Sobrien
98360490Sdelphij	mod |= readfat(dosfs, &boot, &fat);
9979455Sobrien	if (mod & FSFATAL) {
10079455Sobrien		close(dosfs);
10179455Sobrien		return 8;
10279455Sobrien	}
10379455Sobrien
10479455Sobrien	if (!preen)
105360490Sdelphij		printf("** Phase 2 - Checking Directories\n");
10679455Sobrien
107360490Sdelphij	mod |= resetDosDirSection(fat);
10879455Sobrien	finish_dosdirsection = 1;
10979455Sobrien	if (mod & FSFATAL)
11079455Sobrien		goto out;
11179455Sobrien	/* delay writing FATs */
11279455Sobrien
113360490Sdelphij	mod |= handleDirTree(fat);
11479455Sobrien	if (mod & FSFATAL)
11579455Sobrien		goto out;
11679455Sobrien
11779455Sobrien	if (!preen)
118360490Sdelphij		printf("** Phase 3 - Checking for Lost Files\n");
11979455Sobrien
120360490Sdelphij	mod |= checklost(fat);
12179455Sobrien	if (mod & FSFATAL)
12279455Sobrien		goto out;
12379455Sobrien
12479455Sobrien	/* now write the FATs */
125360490Sdelphij	if (mod & FSFATMOD) {
12679455Sobrien		if (ask(1, "Update FATs")) {
127360490Sdelphij			mod |= writefat(fat);
12879455Sobrien			if (mod & FSFATAL)
12979455Sobrien				goto out;
13079455Sobrien		} else
13179455Sobrien			mod |= FSERROR;
13279455Sobrien	}
13379455Sobrien
134360490Sdelphij	freebytes = (int64_t)boot.NumFree * boot.ClusterSize;
135360490Sdelphij	badbytes = (int64_t)boot.NumBad * boot.ClusterSize;
136360490Sdelphij
137360490Sdelphij#ifdef HAVE_LIBUTIL_H
138360490Sdelphij	char freestr[7], badstr[7];
139360490Sdelphij
140360490Sdelphij	humanize_number(freestr, sizeof(freestr), freebytes, "",
141360490Sdelphij	    HN_AUTOSCALE, HN_DECIMAL | HN_IEC_PREFIXES);
142360490Sdelphij	if (boot.NumBad) {
143360490Sdelphij		humanize_number(badstr, sizeof(badstr), badbytes, "",
144360490Sdelphij		    HN_AUTOSCALE, HN_B | HN_DECIMAL | HN_IEC_PREFIXES);
145360490Sdelphij
146360490Sdelphij		pwarn("%d files, %sB free (%d clusters), %sB bad (%d clusters)\n",
147360490Sdelphij		      boot.NumFiles, freestr, boot.NumFree,
148360490Sdelphij		      badstr, boot.NumBad);
149360490Sdelphij	} else {
150360490Sdelphij		pwarn("%d files, %sB free (%d clusters)\n",
151360490Sdelphij		      boot.NumFiles, freestr, boot.NumFree);
152360490Sdelphij	}
153360490Sdelphij#else
15479455Sobrien	if (boot.NumBad)
155360490Sdelphij		pwarn("%d files, %jd KiB free (%d clusters), %jd KiB bad (%d clusters)\n",
156360490Sdelphij		      boot.NumFiles, (intmax_t)freebytes / 1024, boot.NumFree,
157360490Sdelphij		      (intmax_t)badbytes / 1024, boot.NumBad);
15879455Sobrien	else
159360490Sdelphij		pwarn("%d files, %jd KiB free (%d clusters)\n",
160360490Sdelphij		      boot.NumFiles, (intmax_t)freebytes / 1024, boot.NumFree);
161360490Sdelphij#endif
16279455Sobrien
16379455Sobrien	if (mod && (mod & FSERROR) == 0) {
16479455Sobrien		if (mod & FSDIRTY) {
16579455Sobrien			if (ask(1, "MARK FILE SYSTEM CLEAN") == 0)
16679455Sobrien				mod &= ~FSDIRTY;
16779455Sobrien
16879455Sobrien			if (mod & FSDIRTY) {
16979455Sobrien				pwarn("MARKING FILE SYSTEM CLEAN\n");
170360490Sdelphij				mod |= cleardirty(fat);
17179455Sobrien			} else {
17279455Sobrien				pwarn("\n***** FILE SYSTEM IS LEFT MARKED AS DIRTY *****\n");
173102231Strhodes				mod |= FSERROR; /* file system not clean */
17479455Sobrien			}
17579455Sobrien		}
17679455Sobrien	}
17779455Sobrien
17879455Sobrien	if (mod & (FSFATAL | FSERROR))
17979455Sobrien		goto out;
18079455Sobrien
18179455Sobrien	ret = 0;
18279455Sobrien
18379455Sobrien    out:
18479455Sobrien	if (finish_dosdirsection)
18579455Sobrien		finishDosDirSection();
18679455Sobrien	free(fat);
18779455Sobrien	close(dosfs);
18879455Sobrien
18979455Sobrien	if (mod & (FSFATMOD|FSDIRMOD))
19079455Sobrien		pwarn("\n***** FILE SYSTEM WAS MODIFIED *****\n");
19179455Sobrien
19279455Sobrien	return ret;
19379455Sobrien}
194