dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fs.d / pcfs / fsck / fsck.c
blob200576d4ddad401623e228d2122949b4a5d221a6
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
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.
33 #include <stdio.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <strings.h>
40 #include <libintl.h>
41 #include <locale.h>
42 #include <sys/fcntl.h>
43 #include <sys/dktp/fdisk.h>
44 #include "pcfs_common.h"
45 #include "fsck_pcfs.h"
46 #include "pcfs_bpb.h"
48 int32_t BytesPerCluster;
49 int32_t TotalClusters;
50 int32_t LastCluster;
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.
70 static int Quick = 1;
72 int ReadOnly = 0;
73 int IsFAT32 = 0;
74 int Verbose = 0;
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
84 static void
85 passOne(int fd)
87 if (!Quick)
88 findBadClusters(fd);
89 scanAndFixMetadata(fd);
92 static void
93 writeBackChanges(int fd)
95 writeFATMods(fd);
96 if (!IsFAT32)
97 writeRootDirMods(fd);
98 writeClusterMods(fd);
101 static void
102 tryOpen(int *fd, char *openMe, int oflag, int exitOnFailure)
104 int saveError;
106 if ((*fd = open(openMe, oflag)) < 0) {
107 if (exitOnFailure == RETURN_ON_OPEN_FAILURE)
108 return;
109 saveError = errno;
110 mountSanityCheckFails();
111 (void) fprintf(stderr, "%s: ", openMe);
112 (void) fprintf(stderr, strerror(saveError));
113 (void) fprintf(stderr, "\n");
114 exit(1);
118 static void
119 doOpen(int *inFD, int *outFD, char *name, char *outName)
121 if (ReadOnly) {
122 tryOpen(inFD, name, O_RDONLY, EXIT_ON_OPEN_FAILURE);
123 *outFD = -1;
124 } else {
125 tryOpen(inFD, name, O_RDWR, RETURN_ON_OPEN_FAILURE);
126 if (*inFD < 0) {
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");
134 exit(2);
135 } else {
136 tryOpen(inFD, name, O_RDONLY,
137 EXIT_ON_OPEN_FAILURE);
138 AlwaysYes = 0;
139 AlwaysNo = 1;
140 ReadOnly = 1;
141 *outFD = -1;
143 } else {
144 *outFD = *inFD;
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)") : "");
157 static void
158 openFS(char *special, int *inFD, int *outFD)
160 struct stat dinfo;
161 char *actualDisk = NULL;
162 char *suffix = NULL;
164 if (Verbose)
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);
177 exit(2);
179 } else {
180 actualDisk = InputImage;
182 doOpen(inFD, outFD, actualDisk, OutputImage);
183 if (suffix) {
184 if ((PartitionOffset =
185 findPartitionOffset(*inFD, suffix)) < 0) {
186 mountSanityCheckFails();
187 (void) fprintf(stderr,
188 gettext("Unable to find logical drive %s\n"),
189 suffix);
190 exit(2);
191 } else if (Verbose) {
192 (void) fprintf(stderr,
193 gettext("Partition starts at offset %lld\n"),
194 PartitionOffset);
196 } else {
197 PartitionOffset = 0;
201 void
202 usage()
204 (void) fprintf(stderr,
205 gettext("pcfs Usage: fsck -F pcfs [-o v|p|w] special-file\n"));
206 exit(1);
209 static
210 char *LegalOpts[] = {
211 #define VFLAG 0
212 "v",
213 #define PFLAG 1
214 "p",
215 #define WFLAG 2
216 "w",
217 #define DFLAG 3
218 "d",
219 #define IFLAG 4
220 "i",
221 #define OFLAG 5
222 "o",
223 NULL
226 static void
227 parseSubOptions(char *optsstr)
229 char *value;
230 int c;
232 while (*optsstr != '\0') {
233 switch (c = getsubopt(&optsstr, LegalOpts, &value)) {
234 case VFLAG:
235 Quick = 0;
236 break;
237 case PFLAG:
238 Preen++;
239 break;
240 case WFLAG:
241 WritableOnly++;
242 break;
243 case DFLAG:
244 Verbose++;
245 break;
246 case IFLAG:
247 if (value == NULL) {
248 missing_arg(LegalOpts[c]);
249 } else {
250 InputImage = value;
252 break;
253 case OFLAG:
254 if (value == NULL) {
255 missing_arg(LegalOpts[c]);
256 } else {
257 OutputImage = value;
259 break;
260 default:
261 bad_arg(value);
262 break;
267 static void
268 sanityCheckOpts(void)
270 if (WritableOnly && ReadOnly) {
271 (void) fprintf(stderr,
272 gettext("-w option may not be used with the -n "
273 "or -m options\n"));
274 exit(4);
278 static void
279 confirmMountable(char *special, int fd)
281 char *printName;
282 int okayToMount = 1;
284 printName = InputImage ? InputImage : special;
286 if (!IsFAT32) {
287 /* make sure we can at least read the root directory */
288 getRootDirectory(fd);
289 if (TheRootDir.bytes == NULL)
290 okayToMount = 0;
291 } else {
292 /* check the bit designed into FAT32 for this purpose */
293 okayToMount = checkFAT32CleanBit(fd);
295 if (okayToMount) {
296 (void) fprintf(stderr,
297 gettext("pcfs fsck: sanity check: %s okay\n"), printName);
298 exit(0);
299 } else {
300 (void) fprintf(stderr,
301 gettext("pcfs fsck: sanity check: %s needs checking\n"),
302 printName);
303 exit(32);
307 void
308 mountSanityCheckFails(void)
310 if (Mflag) {
311 (void) fprintf(stderr,
312 gettext("pcfs fsck: sanity check failed: "));
317 * preenBail
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.
323 void
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.
331 if (Preen) {
332 if (outString)
333 (void) printf("%s", outString);
334 (void) printf(gettext("FILE SYSTEM FIX REQUIRES USER "
335 "INTERVENTION; RUN fsck MANUALLY.\n"));
336 exit(36);
341 main(int argc, char *argv[])
343 char *string;
344 int ifd, ofd;
345 int c;
347 (void) setlocale(LC_ALL, "");
349 #if !defined(TEXT_DOMAIN)
350 #define TEXT_DOMAIN "SYS_TEST"
351 #endif
352 (void) textdomain(TEXT_DOMAIN);
354 if (argc < 2)
355 usage();
357 while ((c = getopt(argc, argv, "F:VYNynmo:")) != EOF) {
358 switch (c) {
359 case 'F':
360 string = optarg;
361 if (strcmp(string, "pcfs") != 0)
362 usage();
363 break;
364 case 'V': {
365 char *opt_text;
366 int opt_count;
368 (void) printf(gettext("fsck -F pcfs "));
369 for (opt_count = 1; opt_count < argc;
370 opt_count++) {
371 opt_text = argv[opt_count];
372 if (opt_text)
373 (void) printf(" %s ",
374 opt_text);
376 (void) printf("\n");
377 exit(0);
379 break;
380 case 'N':
381 case 'n':
382 AlwaysYes = 0;
383 AlwaysNo = 1;
384 ReadOnly = 1;
385 break;
386 case 'Y':
387 case 'y':
388 AlwaysYes = 1;
389 AlwaysNo = 0;
390 break;
391 case 'm':
392 Mflag++;
393 ReadOnly = 1;
394 break;
395 case 'o':
396 string = optarg;
397 parseSubOptions(string);
398 break;
402 sanityCheckOpts();
403 if (InputImage == NULL && (optind < 0 || optind >= argc))
404 usage();
406 openFS(argv[optind], &ifd, &ofd);
407 readBPB(ifd);
410 * -m mountable fs check. This call will not return.
412 if (Mflag)
413 confirmMountable(argv[optind], ifd);
416 * Pass 1: Find any bad clusters and adjust the FAT and directory
417 * entries accordingly
419 passOne(ifd);
422 * XXX - future passes?
423 * Ideas:
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);
434 return (0);