4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1999,2001 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * fsck_pcfs -- main routines.
36 #include <sys/types.h>
42 #include <sys/fcntl.h>
43 #include <sys/dktp/fdisk.h>
44 #include "pcfs_common.h"
45 #include "fsck_pcfs.h"
48 int32_t BytesPerCluster
;
49 int32_t TotalClusters
;
51 off64_t FirstClusterOffset
;
52 off64_t PartitionOffset
;
53 bpb_t TheBIOSParameterBlock
;
56 * {Output,Input}Image are the file names where we should write the
57 * checked fs image and from which we should read the initial fs.
58 * The image capability is designed for debugging purposes.
60 static char *OutputImage
= NULL
;
61 static char *InputImage
= NULL
;
62 static int WritableOnly
= 0; /* -o w, check writable fs' only */
63 static int Mflag
= 0; /* -m, sanity check if fs is mountable */
64 static int Preen
= 0; /* -o p, preen; non-interactive */
66 * By default be quick; skip verify reads.
67 * If the user wants more exhaustive checking,
68 * they should run with the -o v option.
76 int AlwaysYes
= 0; /* -y or -Y, assume a yes answer to all questions */
77 int AlwaysNo
= 0; /* -n or -N, assume a no answer to all questions */
79 extern ClusterContents TheRootDir
;
82 * Function definitions
89 scanAndFixMetadata(fd
);
93 writeBackChanges(int fd
)
102 tryOpen(int *fd
, char *openMe
, int oflag
, int exitOnFailure
)
106 if ((*fd
= open(openMe
, oflag
)) < 0) {
107 if (exitOnFailure
== RETURN_ON_OPEN_FAILURE
)
110 mountSanityCheckFails();
111 (void) fprintf(stderr
, "%s: ", openMe
);
112 (void) fprintf(stderr
, strerror(saveError
));
113 (void) fprintf(stderr
, "\n");
119 doOpen(int *inFD
, int *outFD
, char *name
, char *outName
)
122 tryOpen(inFD
, name
, O_RDONLY
, EXIT_ON_OPEN_FAILURE
);
125 tryOpen(inFD
, name
, O_RDWR
, RETURN_ON_OPEN_FAILURE
);
127 if (errno
!= EACCES
|| WritableOnly
) {
128 int saveError
= errno
;
129 mountSanityCheckFails();
130 (void) fprintf(stderr
,
131 gettext("%s: "), name
);
132 (void) fprintf(stderr
, strerror(saveError
));
133 (void) fprintf(stderr
, "\n");
136 tryOpen(inFD
, name
, O_RDONLY
,
137 EXIT_ON_OPEN_FAILURE
);
148 if (outName
!= NULL
) {
149 tryOpen(outFD
, outName
, (O_RDWR
| O_CREAT
),
150 EXIT_ON_OPEN_FAILURE
);
153 (void) printf("** %s %s\n", name
,
154 ReadOnly
? gettext("(NO WRITE)") : "");
158 openFS(char *special
, int *inFD
, int *outFD
)
161 char *actualDisk
= NULL
;
165 (void) fprintf(stderr
, gettext("Opening file system.\n"));
167 if (InputImage
== NULL
) {
168 actualDisk
= stat_actual_disk(special
, &dinfo
, &suffix
);
170 * Destination exists, now find more about it.
172 if (!(S_ISCHR(dinfo
.st_mode
))) {
173 mountSanityCheckFails();
174 (void) fprintf(stderr
,
175 gettext("\n%s: device name must be a "
176 "character special device.\n"), actualDisk
);
180 actualDisk
= InputImage
;
182 doOpen(inFD
, outFD
, actualDisk
, OutputImage
);
184 if ((PartitionOffset
=
185 findPartitionOffset(*inFD
, suffix
)) < 0) {
186 mountSanityCheckFails();
187 (void) fprintf(stderr
,
188 gettext("Unable to find logical drive %s\n"),
191 } else if (Verbose
) {
192 (void) fprintf(stderr
,
193 gettext("Partition starts at offset %lld\n"),
204 (void) fprintf(stderr
,
205 gettext("pcfs Usage: fsck -F pcfs [-o v|p|w] special-file\n"));
210 char *LegalOpts
[] = {
227 parseSubOptions(char *optsstr
)
232 while (*optsstr
!= '\0') {
233 switch (c
= getsubopt(&optsstr
, LegalOpts
, &value
)) {
248 missing_arg(LegalOpts
[c
]);
255 missing_arg(LegalOpts
[c
]);
268 sanityCheckOpts(void)
270 if (WritableOnly
&& ReadOnly
) {
271 (void) fprintf(stderr
,
272 gettext("-w option may not be used with the -n "
279 confirmMountable(char *special
, int fd
)
284 printName
= InputImage
? InputImage
: special
;
287 /* make sure we can at least read the root directory */
288 getRootDirectory(fd
);
289 if (TheRootDir
.bytes
== NULL
)
292 /* check the bit designed into FAT32 for this purpose */
293 okayToMount
= checkFAT32CleanBit(fd
);
296 (void) fprintf(stderr
,
297 gettext("pcfs fsck: sanity check: %s okay\n"), printName
);
300 (void) fprintf(stderr
,
301 gettext("pcfs fsck: sanity check: %s needs checking\n"),
308 mountSanityCheckFails(void)
311 (void) fprintf(stderr
,
312 gettext("pcfs fsck: sanity check failed: "));
318 * Routine that other routines can call if they would go into a
319 * state where they need user input. They can send an optional
320 * message string to be printed before the exit. Caller should
321 * send a NULL string if they don't have an exit message.
324 preenBail(char *outString
)
327 * If we are running in the 'preen' mode, we got here because
328 * we reached a situation that would require user intervention.
329 * We have no choice but to bail at this point.
333 (void) printf("%s", outString
);
334 (void) printf(gettext("FILE SYSTEM FIX REQUIRES USER "
335 "INTERVENTION; RUN fsck MANUALLY.\n"));
341 main(int argc
, char *argv
[])
347 (void) setlocale(LC_ALL
, "");
349 #if !defined(TEXT_DOMAIN)
350 #define TEXT_DOMAIN "SYS_TEST"
352 (void) textdomain(TEXT_DOMAIN
);
357 while ((c
= getopt(argc
, argv
, "F:VYNynmo:")) != EOF
) {
361 if (strcmp(string
, "pcfs") != 0)
368 (void) printf(gettext("fsck -F pcfs "));
369 for (opt_count
= 1; opt_count
< argc
;
371 opt_text
= argv
[opt_count
];
373 (void) printf(" %s ",
397 parseSubOptions(string
);
403 if (InputImage
== NULL
&& (optind
< 0 || optind
>= argc
))
406 openFS(argv
[optind
], &ifd
, &ofd
);
410 * -m mountable fs check. This call will not return.
413 confirmMountable(argv
[optind
], ifd
);
416 * Pass 1: Find any bad clusters and adjust the FAT and directory
417 * entries accordingly
422 * XXX - future passes?
424 * Data relocation for bad clusters with partial read success?
425 * Syncing backup FAT copies with main copy?
426 * Syncing backup root sector for FAT32?
430 * No problems if we made it this far.
432 printSummary(stdout
);
433 writeBackChanges(ofd
);