xref: /illumos-gate/usr/src/cmd/fs.d/pcfs/fsck/fsck_main.c (revision fdc43e978a96b43e8b78e80d9bc6f39c99a8ca83)
1*fdc43e97SToomas Soome /*
2*fdc43e97SToomas Soome  * CDDL HEADER START
3*fdc43e97SToomas Soome  *
4*fdc43e97SToomas Soome  * The contents of this file are subject to the terms of the
5*fdc43e97SToomas Soome  * Common Development and Distribution License, Version 1.0 only
6*fdc43e97SToomas Soome  * (the "License").  You may not use this file except in compliance
7*fdc43e97SToomas Soome  * with the License.
8*fdc43e97SToomas Soome  *
9*fdc43e97SToomas Soome  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*fdc43e97SToomas Soome  * or http://www.opensolaris.org/os/licensing.
11*fdc43e97SToomas Soome  * See the License for the specific language governing permissions
12*fdc43e97SToomas Soome  * and limitations under the License.
13*fdc43e97SToomas Soome  *
14*fdc43e97SToomas Soome  * When distributing Covered Code, include this CDDL HEADER in each
15*fdc43e97SToomas Soome  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*fdc43e97SToomas Soome  * If applicable, add the following below this CDDL HEADER, with the
17*fdc43e97SToomas Soome  * fields enclosed by brackets "[]" replaced with your own identifying
18*fdc43e97SToomas Soome  * information: Portions Copyright [yyyy] [name of copyright owner]
19*fdc43e97SToomas Soome  *
20*fdc43e97SToomas Soome  * CDDL HEADER END
21*fdc43e97SToomas Soome  */
22*fdc43e97SToomas Soome /*
23*fdc43e97SToomas Soome  * Copyright (c) 1999,2001 by Sun Microsystems, Inc.
24*fdc43e97SToomas Soome  * All rights reserved.
25*fdc43e97SToomas Soome  * Copyright 2024 MNX Cloud, Inc.
26*fdc43e97SToomas Soome  */
27*fdc43e97SToomas Soome 
28*fdc43e97SToomas Soome /*
29*fdc43e97SToomas Soome  * fsck_pcfs -- main routines.
30*fdc43e97SToomas Soome  */
31*fdc43e97SToomas Soome 
32*fdc43e97SToomas Soome #include <stdio.h>
33*fdc43e97SToomas Soome #include <errno.h>
34*fdc43e97SToomas Soome #include <err.h>
35*fdc43e97SToomas Soome #include <stdlib.h>
36*fdc43e97SToomas Soome #include <sys/types.h>
37*fdc43e97SToomas Soome #include <sys/stat.h>
38*fdc43e97SToomas Soome #include <fcntl.h>
39*fdc43e97SToomas Soome #include <strings.h>
40*fdc43e97SToomas Soome #include <libintl.h>
41*fdc43e97SToomas Soome #include <locale.h>
42*fdc43e97SToomas Soome #include <unistd.h>
43*fdc43e97SToomas Soome #include <stropts.h>
44*fdc43e97SToomas Soome #include <sys/fcntl.h>
45*fdc43e97SToomas Soome #include <sys/dktp/fdisk.h>
46*fdc43e97SToomas Soome #include "getresponse.h"
47*fdc43e97SToomas Soome #include "pcfs_common.h"
48*fdc43e97SToomas Soome #include "fsck_pcfs.h"
49*fdc43e97SToomas Soome #include "pcfs_bpb.h"
50*fdc43e97SToomas Soome 
51*fdc43e97SToomas Soome size_t bpsec = MINBPS;
52*fdc43e97SToomas Soome int32_t BytesPerCluster;
53*fdc43e97SToomas Soome int32_t TotalClusters;
54*fdc43e97SToomas Soome int32_t LastCluster;
55*fdc43e97SToomas Soome off64_t	FirstClusterOffset;
56*fdc43e97SToomas Soome off64_t	PartitionOffset;
57*fdc43e97SToomas Soome bpb_t	TheBIOSParameterBlock;
58*fdc43e97SToomas Soome 
59*fdc43e97SToomas Soome /*
60*fdc43e97SToomas Soome  * {Output,Input}Image are the file names where we should write the
61*fdc43e97SToomas Soome  * checked fs image and from which we should read the initial fs.
62*fdc43e97SToomas Soome  * The image capability is designed for debugging purposes.
63*fdc43e97SToomas Soome  */
64*fdc43e97SToomas Soome static char	*OutputImage = NULL;
65*fdc43e97SToomas Soome static char	*InputImage = NULL;
66*fdc43e97SToomas Soome static int	WritableOnly = 0; /* -o w, check writable fs' only */
67*fdc43e97SToomas Soome static int	Mflag = 0;	  /* -m, sanity check if fs is mountable */
68*fdc43e97SToomas Soome static int	Preen = 0;	  /* -o p, preen; non-interactive */
69*fdc43e97SToomas Soome /*
70*fdc43e97SToomas Soome  * By default be quick; skip verify reads.
71*fdc43e97SToomas Soome  * If the user wants more exhaustive checking,
72*fdc43e97SToomas Soome  * they should run with the -o v option.
73*fdc43e97SToomas Soome  */
74*fdc43e97SToomas Soome static int	Quick = 1;
75*fdc43e97SToomas Soome 
76*fdc43e97SToomas Soome int	ReadOnly = 0;
77*fdc43e97SToomas Soome int	IsFAT32 = 0;
78*fdc43e97SToomas Soome int	Verbose = 0;
79*fdc43e97SToomas Soome 
80*fdc43e97SToomas Soome bool	AlwaysYes = false; /* -y or -Y, assume a yes answer to all questions */
81*fdc43e97SToomas Soome bool	AlwaysNo = false; /* -n or -N, assume a no answer to all questions */
82*fdc43e97SToomas Soome 
83*fdc43e97SToomas Soome extern	ClusterContents	TheRootDir;
84*fdc43e97SToomas Soome 
85*fdc43e97SToomas Soome /*
86*fdc43e97SToomas Soome  * Function definitions
87*fdc43e97SToomas Soome  */
88*fdc43e97SToomas Soome 
89*fdc43e97SToomas Soome static void
passOne(int fd)90*fdc43e97SToomas Soome passOne(int fd)
91*fdc43e97SToomas Soome {
92*fdc43e97SToomas Soome 	if (!Quick)
93*fdc43e97SToomas Soome 		findBadClusters(fd);
94*fdc43e97SToomas Soome 	scanAndFixMetadata(fd);
95*fdc43e97SToomas Soome }
96*fdc43e97SToomas Soome 
97*fdc43e97SToomas Soome static void
writeBackChanges(int fd)98*fdc43e97SToomas Soome writeBackChanges(int fd)
99*fdc43e97SToomas Soome {
100*fdc43e97SToomas Soome 	writeFATMods(fd);
101*fdc43e97SToomas Soome 	if (!IsFAT32)
102*fdc43e97SToomas Soome 		writeRootDirMods(fd);
103*fdc43e97SToomas Soome 	writeClusterMods(fd);
104*fdc43e97SToomas Soome }
105*fdc43e97SToomas Soome 
106*fdc43e97SToomas Soome static void
tryOpen(int * fd,char * openMe,int oflag,int exitOnFailure)107*fdc43e97SToomas Soome tryOpen(int *fd, char *openMe, int oflag, int exitOnFailure)
108*fdc43e97SToomas Soome {
109*fdc43e97SToomas Soome 	int saveError;
110*fdc43e97SToomas Soome 
111*fdc43e97SToomas Soome 	if ((*fd = open(openMe, oflag)) < 0) {
112*fdc43e97SToomas Soome 		if (exitOnFailure == RETURN_ON_OPEN_FAILURE)
113*fdc43e97SToomas Soome 			return;
114*fdc43e97SToomas Soome 		saveError = errno;
115*fdc43e97SToomas Soome 		mountSanityCheckFails();
116*fdc43e97SToomas Soome 		(void) fprintf(stderr, "%s: ", openMe);
117*fdc43e97SToomas Soome 		(void) fprintf(stderr, strerror(saveError));
118*fdc43e97SToomas Soome 		(void) fprintf(stderr, "\n");
119*fdc43e97SToomas Soome 		exit(1);
120*fdc43e97SToomas Soome 	}
121*fdc43e97SToomas Soome }
122*fdc43e97SToomas Soome 
123*fdc43e97SToomas Soome static void
doOpen(int * inFD,int * outFD,char * name,char * outName)124*fdc43e97SToomas Soome doOpen(int *inFD, int *outFD, char *name, char *outName)
125*fdc43e97SToomas Soome {
126*fdc43e97SToomas Soome 	if (ReadOnly) {
127*fdc43e97SToomas Soome 		tryOpen(inFD, name, O_RDONLY, EXIT_ON_OPEN_FAILURE);
128*fdc43e97SToomas Soome 		*outFD = -1;
129*fdc43e97SToomas Soome 	} else {
130*fdc43e97SToomas Soome 		tryOpen(inFD, name, O_RDWR, RETURN_ON_OPEN_FAILURE);
131*fdc43e97SToomas Soome 		if (*inFD < 0) {
132*fdc43e97SToomas Soome 			if (errno != EACCES || WritableOnly) {
133*fdc43e97SToomas Soome 				int saveError = errno;
134*fdc43e97SToomas Soome 				mountSanityCheckFails();
135*fdc43e97SToomas Soome 				(void) fprintf(stderr,
136*fdc43e97SToomas Soome 				    gettext("%s: "), name);
137*fdc43e97SToomas Soome 				(void) fprintf(stderr, strerror(saveError));
138*fdc43e97SToomas Soome 				(void) fprintf(stderr, "\n");
139*fdc43e97SToomas Soome 				exit(2);
140*fdc43e97SToomas Soome 			} else {
141*fdc43e97SToomas Soome 				tryOpen(inFD, name, O_RDONLY,
142*fdc43e97SToomas Soome 				    EXIT_ON_OPEN_FAILURE);
143*fdc43e97SToomas Soome 				AlwaysYes = false;
144*fdc43e97SToomas Soome 				AlwaysNo = true;
145*fdc43e97SToomas Soome 				ReadOnly = 1;
146*fdc43e97SToomas Soome 				*outFD = -1;
147*fdc43e97SToomas Soome 			}
148*fdc43e97SToomas Soome 		} else {
149*fdc43e97SToomas Soome 			*outFD = *inFD;
150*fdc43e97SToomas Soome 		}
151*fdc43e97SToomas Soome 	}
152*fdc43e97SToomas Soome 
153*fdc43e97SToomas Soome 	if (outName != NULL) {
154*fdc43e97SToomas Soome 		tryOpen(outFD, outName, (O_RDWR | O_CREAT),
155*fdc43e97SToomas Soome 		    EXIT_ON_OPEN_FAILURE);
156*fdc43e97SToomas Soome 	}
157*fdc43e97SToomas Soome 
158*fdc43e97SToomas Soome 	(void) printf("** %s %s\n", name,
159*fdc43e97SToomas Soome 	    ReadOnly ? gettext("(NO WRITE)") : "");
160*fdc43e97SToomas Soome }
161*fdc43e97SToomas Soome 
162*fdc43e97SToomas Soome static void
openFS(char * special,int * inFD,int * outFD)163*fdc43e97SToomas Soome openFS(char *special, int *inFD, int *outFD)
164*fdc43e97SToomas Soome {
165*fdc43e97SToomas Soome 	struct stat dinfo;
166*fdc43e97SToomas Soome 	char *actualDisk = NULL;
167*fdc43e97SToomas Soome 	char *suffix = NULL;
168*fdc43e97SToomas Soome 	int rv;
169*fdc43e97SToomas Soome 
170*fdc43e97SToomas Soome 	if (Verbose)
171*fdc43e97SToomas Soome 		(void) fprintf(stderr, gettext("Opening file system.\n"));
172*fdc43e97SToomas Soome 
173*fdc43e97SToomas Soome 	if (InputImage == NULL) {
174*fdc43e97SToomas Soome 		actualDisk = stat_actual_disk(special, &dinfo, &suffix);
175*fdc43e97SToomas Soome 		/*
176*fdc43e97SToomas Soome 		 *  Destination exists, now find more about it.
177*fdc43e97SToomas Soome 		 */
178*fdc43e97SToomas Soome 		if (!(S_ISCHR(dinfo.st_mode))) {
179*fdc43e97SToomas Soome 			mountSanityCheckFails();
180*fdc43e97SToomas Soome 			(void) fprintf(stderr,
181*fdc43e97SToomas Soome 			    gettext("\n%s: device name must be a "
182*fdc43e97SToomas Soome 			    "character special device.\n"), actualDisk);
183*fdc43e97SToomas Soome 			exit(2);
184*fdc43e97SToomas Soome 		}
185*fdc43e97SToomas Soome 	} else {
186*fdc43e97SToomas Soome 		actualDisk = InputImage;
187*fdc43e97SToomas Soome 	}
188*fdc43e97SToomas Soome 	doOpen(inFD, outFD, actualDisk, OutputImage);
189*fdc43e97SToomas Soome 	rv = get_media_sector_size(*inFD, &bpsec);
190*fdc43e97SToomas Soome 	if (rv != 0) {
191*fdc43e97SToomas Soome 		(void) fprintf(stderr,
192*fdc43e97SToomas Soome 		    gettext("error detecting device sector size: %s\n"),
193*fdc43e97SToomas Soome 		    strerror(rv));
194*fdc43e97SToomas Soome 		exit(2);
195*fdc43e97SToomas Soome 	}
196*fdc43e97SToomas Soome 	if (!is_sector_size_valid(bpsec)) {
197*fdc43e97SToomas Soome 		(void) fprintf(stderr,
198*fdc43e97SToomas Soome 		    gettext("unsupported sector size: %zu\n"), bpsec);
199*fdc43e97SToomas Soome 		exit(2);
200*fdc43e97SToomas Soome 	}
201*fdc43e97SToomas Soome 
202*fdc43e97SToomas Soome 	if (suffix) {
203*fdc43e97SToomas Soome 		if ((PartitionOffset =
204*fdc43e97SToomas Soome 		    findPartitionOffset(*inFD, bpsec, suffix)) < 0) {
205*fdc43e97SToomas Soome 			mountSanityCheckFails();
206*fdc43e97SToomas Soome 			(void) fprintf(stderr,
207*fdc43e97SToomas Soome 			    gettext("Unable to find logical drive %s\n"),
208*fdc43e97SToomas Soome 			    suffix);
209*fdc43e97SToomas Soome 			exit(2);
210*fdc43e97SToomas Soome 		} else if (Verbose) {
211*fdc43e97SToomas Soome 			(void) fprintf(stderr,
212*fdc43e97SToomas Soome 			    gettext("Partition starts at offset %lld\n"),
213*fdc43e97SToomas Soome 			    PartitionOffset);
214*fdc43e97SToomas Soome 		}
215*fdc43e97SToomas Soome 	} else {
216*fdc43e97SToomas Soome 		PartitionOffset = 0;
217*fdc43e97SToomas Soome 	}
218*fdc43e97SToomas Soome }
219*fdc43e97SToomas Soome 
220*fdc43e97SToomas Soome void
usage(void)221*fdc43e97SToomas Soome usage(void)
222*fdc43e97SToomas Soome {
223*fdc43e97SToomas Soome 	(void) fprintf(stderr,
224*fdc43e97SToomas Soome 	    gettext("pcfs Usage: fsck -F pcfs [-o v|p|w] special-file\n"));
225*fdc43e97SToomas Soome 	exit(1);
226*fdc43e97SToomas Soome }
227*fdc43e97SToomas Soome 
228*fdc43e97SToomas Soome static
229*fdc43e97SToomas Soome char *LegalOpts[] = {
230*fdc43e97SToomas Soome #define	VFLAG 0
231*fdc43e97SToomas Soome 	"v",
232*fdc43e97SToomas Soome #define	PFLAG 1
233*fdc43e97SToomas Soome 	"p",
234*fdc43e97SToomas Soome #define	WFLAG 2
235*fdc43e97SToomas Soome 	"w",
236*fdc43e97SToomas Soome #define	DFLAG 3
237*fdc43e97SToomas Soome 	"d",
238*fdc43e97SToomas Soome #define	IFLAG 4
239*fdc43e97SToomas Soome 	"i",
240*fdc43e97SToomas Soome #define	OFLAG 5
241*fdc43e97SToomas Soome 	"o",
242*fdc43e97SToomas Soome 	NULL
243*fdc43e97SToomas Soome };
244*fdc43e97SToomas Soome 
245*fdc43e97SToomas Soome static void
parseSubOptions(char * optsstr)246*fdc43e97SToomas Soome parseSubOptions(char *optsstr)
247*fdc43e97SToomas Soome {
248*fdc43e97SToomas Soome 	char *value;
249*fdc43e97SToomas Soome 	int c;
250*fdc43e97SToomas Soome 
251*fdc43e97SToomas Soome 	while (*optsstr != '\0') {
252*fdc43e97SToomas Soome 		switch (c = getsubopt(&optsstr, LegalOpts, &value)) {
253*fdc43e97SToomas Soome 		case VFLAG:
254*fdc43e97SToomas Soome 			Quick = 0;
255*fdc43e97SToomas Soome 			break;
256*fdc43e97SToomas Soome 		case PFLAG:
257*fdc43e97SToomas Soome 			Preen++;
258*fdc43e97SToomas Soome 			break;
259*fdc43e97SToomas Soome 		case WFLAG:
260*fdc43e97SToomas Soome 			WritableOnly++;
261*fdc43e97SToomas Soome 			break;
262*fdc43e97SToomas Soome 		case DFLAG:
263*fdc43e97SToomas Soome 			Verbose++;
264*fdc43e97SToomas Soome 			break;
265*fdc43e97SToomas Soome 		case IFLAG:
266*fdc43e97SToomas Soome 			if (value == NULL) {
267*fdc43e97SToomas Soome 				missing_arg(LegalOpts[c]);
268*fdc43e97SToomas Soome 			} else {
269*fdc43e97SToomas Soome 				InputImage = value;
270*fdc43e97SToomas Soome 			}
271*fdc43e97SToomas Soome 			break;
272*fdc43e97SToomas Soome 		case OFLAG:
273*fdc43e97SToomas Soome 			if (value == NULL) {
274*fdc43e97SToomas Soome 				missing_arg(LegalOpts[c]);
275*fdc43e97SToomas Soome 			} else {
276*fdc43e97SToomas Soome 				OutputImage = value;
277*fdc43e97SToomas Soome 			}
278*fdc43e97SToomas Soome 			break;
279*fdc43e97SToomas Soome 		default:
280*fdc43e97SToomas Soome 			bad_arg(value);
281*fdc43e97SToomas Soome 			break;
282*fdc43e97SToomas Soome 		}
283*fdc43e97SToomas Soome 	}
284*fdc43e97SToomas Soome }
285*fdc43e97SToomas Soome 
286*fdc43e97SToomas Soome static void
sanityCheckOpts(void)287*fdc43e97SToomas Soome sanityCheckOpts(void)
288*fdc43e97SToomas Soome {
289*fdc43e97SToomas Soome 	if (WritableOnly && ReadOnly) {
290*fdc43e97SToomas Soome 		(void) fprintf(stderr,
291*fdc43e97SToomas Soome 		    gettext("-w option may not be used with the -n "
292*fdc43e97SToomas Soome 		    "or -m options\n"));
293*fdc43e97SToomas Soome 		exit(4);
294*fdc43e97SToomas Soome 	}
295*fdc43e97SToomas Soome }
296*fdc43e97SToomas Soome 
297*fdc43e97SToomas Soome static void
confirmMountable(char * special,int fd)298*fdc43e97SToomas Soome confirmMountable(char *special, int fd)
299*fdc43e97SToomas Soome {
300*fdc43e97SToomas Soome 	char *printName;
301*fdc43e97SToomas Soome 	int okayToMount = 1;
302*fdc43e97SToomas Soome 
303*fdc43e97SToomas Soome 	printName = InputImage ? InputImage : special;
304*fdc43e97SToomas Soome 
305*fdc43e97SToomas Soome 	if (!IsFAT32) {
306*fdc43e97SToomas Soome 		/* make sure we can at least read the root directory */
307*fdc43e97SToomas Soome 		getRootDirectory(fd);
308*fdc43e97SToomas Soome 		if (TheRootDir.bytes == NULL)
309*fdc43e97SToomas Soome 			okayToMount = 0;
310*fdc43e97SToomas Soome 	} else {
311*fdc43e97SToomas Soome 		/* check the bit designed into FAT32 for this purpose */
312*fdc43e97SToomas Soome 		okayToMount = checkFAT32CleanBit(fd);
313*fdc43e97SToomas Soome 	}
314*fdc43e97SToomas Soome 	if (okayToMount) {
315*fdc43e97SToomas Soome 		(void) fprintf(stderr,
316*fdc43e97SToomas Soome 		    gettext("pcfs fsck: sanity check: %s okay\n"), printName);
317*fdc43e97SToomas Soome 		exit(0);
318*fdc43e97SToomas Soome 	} else {
319*fdc43e97SToomas Soome 		(void) fprintf(stderr,
320*fdc43e97SToomas Soome 		    gettext("pcfs fsck: sanity check: %s needs checking\n"),
321*fdc43e97SToomas Soome 		    printName);
322*fdc43e97SToomas Soome 		exit(32);
323*fdc43e97SToomas Soome 	}
324*fdc43e97SToomas Soome }
325*fdc43e97SToomas Soome 
326*fdc43e97SToomas Soome void
mountSanityCheckFails(void)327*fdc43e97SToomas Soome mountSanityCheckFails(void)
328*fdc43e97SToomas Soome {
329*fdc43e97SToomas Soome 	if (Mflag) {
330*fdc43e97SToomas Soome 		(void) fprintf(stderr,
331*fdc43e97SToomas Soome 		    gettext("pcfs fsck: sanity check failed: "));
332*fdc43e97SToomas Soome 	}
333*fdc43e97SToomas Soome }
334*fdc43e97SToomas Soome 
335*fdc43e97SToomas Soome /*
336*fdc43e97SToomas Soome  * preenBail
337*fdc43e97SToomas Soome  *	Routine that other routines can call if they would go into a
338*fdc43e97SToomas Soome  *	state where they need user input.  They can send an optional
339*fdc43e97SToomas Soome  *	message string to be printed before the exit.  Caller should
340*fdc43e97SToomas Soome  *	send a NULL string if they don't have an exit message.
341*fdc43e97SToomas Soome  */
342*fdc43e97SToomas Soome void
preenBail(char * outString)343*fdc43e97SToomas Soome preenBail(char *outString)
344*fdc43e97SToomas Soome {
345*fdc43e97SToomas Soome 	/*
346*fdc43e97SToomas Soome 	 *  If we are running in the 'preen' mode, we got here because
347*fdc43e97SToomas Soome 	 *  we reached a situation that would require user intervention.
348*fdc43e97SToomas Soome 	 *  We have no choice but to bail at this point.
349*fdc43e97SToomas Soome 	 */
350*fdc43e97SToomas Soome 	if (Preen) {
351*fdc43e97SToomas Soome 		if (outString)
352*fdc43e97SToomas Soome 			(void) printf("%s", outString);
353*fdc43e97SToomas Soome 		(void) printf(gettext("FILE SYSTEM FIX REQUIRES USER "
354*fdc43e97SToomas Soome 		    "INTERVENTION; RUN fsck MANUALLY.\n"));
355*fdc43e97SToomas Soome 		exit(36);
356*fdc43e97SToomas Soome 	}
357*fdc43e97SToomas Soome }
358*fdc43e97SToomas Soome 
359*fdc43e97SToomas Soome int
main(int argc,char * argv[])360*fdc43e97SToomas Soome main(int argc, char *argv[])
361*fdc43e97SToomas Soome {
362*fdc43e97SToomas Soome 	char *string;
363*fdc43e97SToomas Soome 	int  ifd, ofd;
364*fdc43e97SToomas Soome 	int  c;
365*fdc43e97SToomas Soome 
366*fdc43e97SToomas Soome 	(void) setlocale(LC_ALL, "");
367*fdc43e97SToomas Soome 
368*fdc43e97SToomas Soome #if !defined(TEXT_DOMAIN)
369*fdc43e97SToomas Soome #define	TEXT_DOMAIN "SYS_TEST"
370*fdc43e97SToomas Soome #endif
371*fdc43e97SToomas Soome 	(void) textdomain(TEXT_DOMAIN);
372*fdc43e97SToomas Soome 	if (init_yes() < 0)
373*fdc43e97SToomas Soome 		errx(2, gettext(ERR_MSG_INIT_YES), strerror(errno));
374*fdc43e97SToomas Soome 
375*fdc43e97SToomas Soome 	if (argc < 2)
376*fdc43e97SToomas Soome 		usage();
377*fdc43e97SToomas Soome 
378*fdc43e97SToomas Soome 	while ((c = getopt(argc, argv, "F:VYNynmo:")) != EOF) {
379*fdc43e97SToomas Soome 		switch (c) {
380*fdc43e97SToomas Soome 		case 'F':
381*fdc43e97SToomas Soome 			string = optarg;
382*fdc43e97SToomas Soome 			if (strcmp(string, "pcfs") != 0)
383*fdc43e97SToomas Soome 				usage();
384*fdc43e97SToomas Soome 			break;
385*fdc43e97SToomas Soome 		case 'V': {
386*fdc43e97SToomas Soome 				char	*opt_text;
387*fdc43e97SToomas Soome 				int	opt_count;
388*fdc43e97SToomas Soome 
389*fdc43e97SToomas Soome 				(void) printf(gettext("fsck -F pcfs "));
390*fdc43e97SToomas Soome 				for (opt_count = 1; opt_count < argc;
391*fdc43e97SToomas Soome 				    opt_count++) {
392*fdc43e97SToomas Soome 					opt_text = argv[opt_count];
393*fdc43e97SToomas Soome 					if (opt_text)
394*fdc43e97SToomas Soome 						(void) printf(" %s ",
395*fdc43e97SToomas Soome 						    opt_text);
396*fdc43e97SToomas Soome 				}
397*fdc43e97SToomas Soome 				(void) printf("\n");
398*fdc43e97SToomas Soome 				fini_yes();
399*fdc43e97SToomas Soome 				exit(0);
400*fdc43e97SToomas Soome 			}
401*fdc43e97SToomas Soome 			break;
402*fdc43e97SToomas Soome 		case 'N':
403*fdc43e97SToomas Soome 		case 'n':
404*fdc43e97SToomas Soome 			AlwaysYes = false;
405*fdc43e97SToomas Soome 			AlwaysNo = true;
406*fdc43e97SToomas Soome 			ReadOnly = 1;
407*fdc43e97SToomas Soome 			break;
408*fdc43e97SToomas Soome 		case 'Y':
409*fdc43e97SToomas Soome 		case 'y':
410*fdc43e97SToomas Soome 			AlwaysYes = true;
411*fdc43e97SToomas Soome 			AlwaysNo = false;
412*fdc43e97SToomas Soome 			break;
413*fdc43e97SToomas Soome 		case 'm':
414*fdc43e97SToomas Soome 			Mflag++;
415*fdc43e97SToomas Soome 			ReadOnly = 1;
416*fdc43e97SToomas Soome 			break;
417*fdc43e97SToomas Soome 		case 'o':
418*fdc43e97SToomas Soome 			string = optarg;
419*fdc43e97SToomas Soome 			parseSubOptions(string);
420*fdc43e97SToomas Soome 			break;
421*fdc43e97SToomas Soome 		}
422*fdc43e97SToomas Soome 	}
423*fdc43e97SToomas Soome 
424*fdc43e97SToomas Soome 	sanityCheckOpts();
425*fdc43e97SToomas Soome 	if (InputImage == NULL && (optind < 0 || optind >= argc))
426*fdc43e97SToomas Soome 		usage();
427*fdc43e97SToomas Soome 
428*fdc43e97SToomas Soome 	openFS(argv[optind], &ifd, &ofd);
429*fdc43e97SToomas Soome 	readBPB(ifd);
430*fdc43e97SToomas Soome 
431*fdc43e97SToomas Soome 	/*
432*fdc43e97SToomas Soome 	 * -m mountable fs check.  This call will not return.
433*fdc43e97SToomas Soome 	 */
434*fdc43e97SToomas Soome 	if (Mflag)
435*fdc43e97SToomas Soome 		confirmMountable(argv[optind], ifd);
436*fdc43e97SToomas Soome 
437*fdc43e97SToomas Soome 	/*
438*fdc43e97SToomas Soome 	 *  Pass 1: Find any bad clusters and adjust the FAT and directory
439*fdc43e97SToomas Soome 	 *	entries accordingly
440*fdc43e97SToomas Soome 	 */
441*fdc43e97SToomas Soome 	passOne(ifd);
442*fdc43e97SToomas Soome 
443*fdc43e97SToomas Soome 	/*
444*fdc43e97SToomas Soome 	 *  XXX - future passes?
445*fdc43e97SToomas Soome 	 *	Ideas:
446*fdc43e97SToomas Soome 	 *	    Data relocation for bad clusters with partial read success?
447*fdc43e97SToomas Soome 	 *	    Syncing backup FAT copies with main copy?
448*fdc43e97SToomas Soome 	 *	    Syncing backup root sector for FAT32?
449*fdc43e97SToomas Soome 	 */
450*fdc43e97SToomas Soome 
451*fdc43e97SToomas Soome 	/*
452*fdc43e97SToomas Soome 	 *  No problems if we made it this far.
453*fdc43e97SToomas Soome 	 */
454*fdc43e97SToomas Soome 	printSummary(stdout);
455*fdc43e97SToomas Soome 	writeBackChanges(ofd);
456*fdc43e97SToomas Soome 	fini_yes();
457*fdc43e97SToomas Soome 	return (0);
458*fdc43e97SToomas Soome }
459