GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/fsck_msdos/boot.c Lines: 0 205 0.0 %
Date: 2017-11-07 Branches: 0 129 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: boot.c,v 1.24 2016/10/10 00:34:50 bluhm Exp $	*/
2
/*	$NetBSD: boot.c,v 1.5 1997/10/17 11:19:23 ws Exp $	*/
3
4
/*
5
 * Copyright (C) 1995, 1997 Wolfgang Solfrank
6
 * Copyright (c) 1995 Martin Husemann
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
29
#include <sys/param.h>	/* DEV_BSIZE powerof2 */
30
#include <sys/disklabel.h>
31
32
#include <stdlib.h>
33
#include <string.h>
34
#include <ctype.h>
35
#include <stdio.h>
36
#include <unistd.h>
37
38
#include "ext.h"
39
40
int
41
readboot(int dosfs, struct bootblock *boot)
42
{
43
	u_char *block = NULL;
44
	u_char *fsinfo = NULL;
45
	u_char *backup = NULL;
46
	int ret = FSOK, secsize = lab.d_secsize, fsinfosz;
47
	off_t o;
48
	ssize_t n;
49
50
	if (secsize < DOSBOOTBLOCKSIZE) {
51
		xperror("sector size < DOSBOOTBLOCKSIZE");
52
		goto fail;
53
	}
54
	if (DOSBOOTBLOCKSIZE != DEV_BSIZE) {
55
		xperror("DOSBOOTBLOCKSIZE != DEV_BSIZE");
56
		goto fail;
57
	}
58
59
	block = malloc(secsize);
60
	if (block == NULL) {
61
		xperror("could not malloc boot block");
62
		goto fail;
63
	}
64
65
	if ((o = lseek(dosfs, 0, SEEK_SET)) == -1) {
66
		xperror("could not seek boot block");
67
		goto fail;
68
	}
69
70
	n = read(dosfs, block, secsize);
71
	if (n == -1 || n != secsize) {
72
		xperror("could not read boot block");
73
		goto fail;
74
	}
75
76
	if (block[510] != 0x55 || block[511] != 0xaa) {
77
		pfatal("Invalid signature in boot block: %02x%02x\n",
78
		    block[511], block[510]);
79
	}
80
81
	memset(boot, 0, sizeof *boot);
82
	boot->ValidFat = -1;
83
84
	/* decode bios parameter block */
85
	boot->BytesPerSec = block[11] + (block[12] << 8);
86
	if (boot->BytesPerSec == 0 || boot->BytesPerSec != secsize) {
87
		pfatal("Invalid sector size: %u\n", boot->BytesPerSec);
88
		goto fail;
89
	}
90
	boot->SecPerClust = block[13];
91
	if (boot->SecPerClust == 0 || !powerof2(boot->SecPerClust)) {
92
		pfatal("Invalid cluster size: %u\n", boot->SecPerClust);
93
		goto fail;
94
	}
95
	boot->ResSectors = block[14] + (block[15] << 8);
96
	boot->FATs = block[16];
97
	if (boot->FATs == 0) {
98
		pfatal("Invalid number of FATs: %u\n", boot->FATs);
99
		goto fail;
100
	}
101
	boot->RootDirEnts = block[17] + (block[18] << 8);
102
	boot->Sectors = block[19] + (block[20] << 8);
103
	boot->Media = block[21];
104
	boot->FATsmall = block[22] + (block[23] << 8);
105
	boot->SecPerTrack = block[24] + (block[25] << 8);
106
	boot->Heads = block[26] + (block[27] << 8);
107
	boot->HiddenSecs = block[28] + (block[29] << 8) + (block[30] << 16) + (block[31] << 24);
108
	boot->HugeSectors = block[32] + (block[33] << 8) + (block[34] << 16) + (block[35] << 24);
109
110
	boot->FATsecs = boot->FATsmall;
111
112
	if (!boot->RootDirEnts) {
113
		boot->flags |= FAT32;
114
		boot->FATsecs = block[36] + (block[37] << 8)
115
				+ (block[38] << 16) + (block[39] << 24);
116
		if (block[40] & 0x80)
117
			boot->ValidFat = block[40] & 0x0f;
118
119
		/* check version number: */
120
		if (block[42] || block[43]) {
121
			/* Correct?				XXX */
122
			pfatal("Unknown filesystem version: %x.%x\n",
123
			       block[43], block[42]);
124
			goto fail;
125
		}
126
		boot->RootCl = block[44] + (block[45] << 8)
127
			       + (block[46] << 16) + (block[47] << 24);
128
		boot->FSInfo = block[48] + (block[49] << 8);
129
		boot->Backup = block[50] + (block[51] << 8);
130
131
		o = lseek(dosfs, boot->FSInfo * secsize, SEEK_SET);
132
		if (o == -1 || o != boot->FSInfo * secsize) {
133
			xperror("could not seek fsinfo block");
134
			goto fail;
135
		}
136
137
		if ((2 * DOSBOOTBLOCKSIZE) < secsize)
138
			fsinfosz = secsize;
139
		else
140
			fsinfosz = 2 * secsize;
141
		fsinfo = malloc(fsinfosz);
142
		if (fsinfo == NULL) {
143
			xperror("could not malloc fsinfo");
144
			goto fail;
145
		}
146
		n = read(dosfs, fsinfo, fsinfosz);
147
		if (n == -1 || n != fsinfosz) {
148
			xperror("could not read fsinfo block");
149
			goto fail;
150
		}
151
152
		if (memcmp(fsinfo, "RRaA", 4)
153
		    || memcmp(fsinfo + 0x1e4, "rrAa", 4)
154
		    || fsinfo[0x1fc]
155
		    || fsinfo[0x1fd]
156
		    || fsinfo[0x1fe] != 0x55
157
		    || fsinfo[0x1ff] != 0xaa
158
		    || fsinfo[0x3fc]
159
		    || fsinfo[0x3fd]
160
		    || fsinfo[0x3fe] != 0x55
161
		    || fsinfo[0x3ff] != 0xaa) {
162
			pwarn("Invalid signature in fsinfo block\n");
163
			if (ask(0, "fix")) {
164
				memcpy(fsinfo, "RRaA", 4);
165
				memcpy(fsinfo + 0x1e4, "rrAa", 4);
166
				fsinfo[0x1fc] = fsinfo[0x1fd] = 0;
167
				fsinfo[0x1fe] = 0x55;
168
				fsinfo[0x1ff] = 0xaa;
169
				fsinfo[0x3fc] = fsinfo[0x3fd] = 0;
170
				fsinfo[0x3fe] = 0x55;
171
				fsinfo[0x3ff] = 0xaa;
172
173
				o = lseek(dosfs, boot->FSInfo * secsize,
174
				    SEEK_SET);
175
				if (o == -1 || o != boot->FSInfo * secsize) {
176
					xperror("Unable to seek FSInfo");
177
					goto fail;
178
				}
179
				n = write(dosfs, fsinfo, fsinfosz);
180
				if (n == -1 || n != fsinfosz) {
181
					xperror("Unable to write FSInfo");
182
					goto fail;
183
				}
184
				ret = FSBOOTMOD;
185
			} else
186
				boot->FSInfo = 0;
187
		}
188
		if (boot->FSInfo) {
189
			boot->FSFree = fsinfo[0x1e8] + (fsinfo[0x1e9] << 8)
190
				       + (fsinfo[0x1ea] << 16)
191
				       + (fsinfo[0x1eb] << 24);
192
			boot->FSNext = fsinfo[0x1ec] + (fsinfo[0x1ed] << 8)
193
				       + (fsinfo[0x1ee] << 16)
194
				       + (fsinfo[0x1ef] << 24);
195
		}
196
197
		o = lseek(dosfs, boot->Backup * secsize, SEEK_SET);
198
		if (o == -1 || o != boot->Backup * secsize) {
199
			xperror("could not seek backup bootblock");
200
			goto fail;
201
		}
202
		backup = malloc(2 * secsize); /* In case we check fsinfo. */
203
		if (backup == NULL) {
204
			xperror("could not malloc backup boot block");
205
			goto fail;
206
		}
207
		n = read(dosfs, backup, secsize);
208
		if (n == -1 || n != secsize) {
209
			xperror("could not read backup bootblock");
210
			goto fail;
211
		}
212
213
		/*
214
		 * Check that the backup boot block matches the primary one.
215
		 * We don't check every byte, since some vendor utilities
216
		 * seem to overwrite the boot code when they feel like it,
217
		 * without changing the backup block.  Specifically, we check
218
		 * the two-byte signature at the end, the BIOS parameter
219
		 * block (which starts after the 3-byte JMP and the 8-byte
220
		 * OEM name/version) and the filesystem information that
221
		 * follows the BPB (bsBPB[53] and bsExt[26] for FAT32, so we
222
		 * check 79 bytes).
223
		 */
224
		if (backup[510] != 0x55 || backup[511] != 0xaa) {
225
			pfatal("Invalid signature in backup boot block: %02x%02x\n", backup[511], backup[510]);
226
		}
227
		if (memcmp(block + 11, backup + 11, 79)) {
228
			pfatal("backup doesn't compare to primary bootblock\n");
229
			goto fail;
230
		}
231
		/* Check backup FSInfo?					XXX */
232
	}
233
234
	if (boot->FATsecs == 0) {
235
		pfatal("Invalid number of FAT sectors: %u\n", boot->FATsecs);
236
		goto fail;
237
	}
238
239
	boot->ClusterOffset = (boot->RootDirEnts * 32 + secsize - 1)
240
	    / secsize
241
	    + boot->ResSectors
242
	    + boot->FATs * boot->FATsecs
243
	    - CLUST_FIRST * boot->SecPerClust;
244
245
	if (boot->Sectors) {
246
		boot->HugeSectors = 0;
247
		boot->NumSectors = boot->Sectors;
248
	} else
249
		boot->NumSectors = boot->HugeSectors;
250
251
	if (boot->ClusterOffset > boot->NumSectors) {
252
		pfatal("Cluster offset too large (%u clusters)\n",
253
		    boot->ClusterOffset);
254
		goto fail;
255
	}
256
	boot->NumClusters = (boot->NumSectors - boot->ClusterOffset) / boot->SecPerClust;
257
258
	if (boot->flags&FAT32)
259
		boot->ClustMask = CLUST32_MASK;
260
	else if (boot->NumClusters < (CLUST_RSRVD&CLUST12_MASK))
261
		boot->ClustMask = CLUST12_MASK;
262
	else if (boot->NumClusters < (CLUST_RSRVD&CLUST16_MASK))
263
		boot->ClustMask = CLUST16_MASK;
264
	else {
265
		pfatal("Filesystem too big (%u clusters) for non-FAT32 partition\n",
266
		       boot->NumClusters);
267
		goto fail;
268
	}
269
270
	switch (boot->ClustMask) {
271
	case CLUST32_MASK:
272
		boot->NumFatEntries = (boot->FATsecs * secsize) / 4;
273
		break;
274
	case CLUST16_MASK:
275
		boot->NumFatEntries = (boot->FATsecs * secsize) / 2;
276
		break;
277
	default:
278
		boot->NumFatEntries = (boot->FATsecs * secsize * 2) / 3;
279
		break;
280
	}
281
282
	if (boot->NumFatEntries < boot->NumClusters) {
283
		pfatal("FAT size too small, %u entries won't fit into %u sectors\n",
284
		       boot->NumClusters, boot->FATsecs);
285
		goto fail;
286
	}
287
	boot->ClusterSize = boot->SecPerClust * secsize;
288
289
	boot->NumFiles = 1;
290
	boot->NumFree = 0;
291
292
	free(backup);
293
	free(block);
294
	free(fsinfo);
295
	return ret;
296
fail:
297
	free(backup);
298
	free(block);
299
	free(fsinfo);
300
	return FSFATAL;
301
}
302
303
int
304
writefsinfo(int dosfs, struct bootblock *boot)
305
{
306
	u_char *fsinfo = NULL;
307
	int secsize = lab.d_secsize, fsinfosz;
308
	off_t o;
309
	ssize_t n;
310
311
	if ((2 * DOSBOOTBLOCKSIZE) < secsize)
312
		fsinfosz = secsize;
313
	else
314
		fsinfosz = 2 * secsize;
315
316
	fsinfo = malloc(fsinfosz);
317
	if (fsinfo == NULL) {
318
		xperror("could not malloc fsinfo block");
319
		goto fail;
320
	}
321
322
	o = lseek(dosfs, boot->FSInfo * secsize, SEEK_SET);
323
	if (o == -1 || o != boot->FSInfo * secsize) {
324
		xperror("could not seek fsinfo block");
325
		goto fail;
326
	}
327
328
	n = read(dosfs, fsinfo, fsinfosz);
329
	if (n == -1 || n != fsinfosz) {
330
		xperror("could not read fsinfo block");
331
		goto fail;
332
	}
333
334
	fsinfo[0x1e8] = (u_char)boot->FSFree;
335
	fsinfo[0x1e9] = (u_char)(boot->FSFree >> 8);
336
	fsinfo[0x1ea] = (u_char)(boot->FSFree >> 16);
337
	fsinfo[0x1eb] = (u_char)(boot->FSFree >> 24);
338
	fsinfo[0x1ec] = (u_char)boot->FSNext;
339
	fsinfo[0x1ed] = (u_char)(boot->FSNext >> 8);
340
	fsinfo[0x1ee] = (u_char)(boot->FSNext >> 16);
341
	fsinfo[0x1ef] = (u_char)(boot->FSNext >> 24);
342
343
	o = lseek(dosfs, o, SEEK_SET);
344
	if (o == -1 || o != boot->FSInfo * boot->BytesPerSec) {
345
		xperror("Unable to seek FSInfo");
346
		goto fail;
347
	}
348
	n = write(dosfs, fsinfo, fsinfosz);
349
	if (n == -1 || n != fsinfosz) {
350
		xperror("Unable to write FSInfo");
351
		goto fail;
352
	}
353
354
	free(fsinfo);
355
356
	/*
357
	 * Technically, we should return FSBOOTMOD here.
358
	 *
359
	 * However, since Win95 OSR2 (the first M$ OS that has
360
	 * support for FAT32) doesn't maintain the FSINFO block
361
	 * correctly, it has to be fixed pretty often.
362
	 *
363
	 * Therefore, we handle the FSINFO block only informally,
364
	 * fixing it if necessary, but otherwise ignoring the
365
	 * fact that it was incorrect.
366
	 */
367
	return 0;
368
fail:
369
	free(fsinfo);
370
	return FSFATAL;
371
}