summaryrefslogtreecommitdiff
path: root/Bootinst.c
blob: fa6cbb22cdf1ec2517a05f103bc128279306adc6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/*
 * Boot installator.
 * Author: Serge Vakulenko, <vak@kiae.su>
 */

#include <stdio.h>
#include <fcntl.h>
#include <dos.h>

#define BOOTFILE	"boot.bin"
#define SAVEFILE	"bootsav.bin"
#define SAVE2FILE	"boot2sav.bin"

#define PartAddr        0x1be	/* Offset to partition table */
#define ValidationAddr  0x1fe	/* Offset to validation bytes */
#define MAGIC		0xaa55	/* Validation tag */

#define DISK1		0
#define DISK2		1
#define READ		0
#define WRITE		1

typedef struct PartitionEntry {
	unsigned char	bootIndicator;
	unsigned char	beginHead;
	unsigned char	beginSector;
	unsigned char	beginCyl;
	unsigned char	systemId;
	unsigned char	endHead;
	unsigned char	endSector;
	unsigned char	endCyl;
	unsigned short	relSectorLow;
	unsigned short	relSectorHigh;
	unsigned short	numSectorsLow;
	unsigned short	numSectorsHigh;
} PartitionEntry;

unsigned char bootRecord [512];
unsigned char bootProg [512];

char head1 [] =	"ÚÄÂÄÄÄÄÄÄÄÄÄÂÄÄÄÄÂÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄ¿\n";
char head2 [] =	"³ ³Partition³Can ³Boot³   Beginning   ³    Ending     ³ Relative³Number of³\n";
char head3 [] =	"³N³  Type   ³Boot³Part³Head  Cyl  Sect³Head  Cyl  Sect³ Sectors ³ Sectors ³\n";
char head4 [] =	"ÃÄÅÄÄÄÄÄÄÄÄÄÅÄÄÄÄÅÄÄÄÄÅÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÅÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÅÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄ´\n";
char mid1 []  = "³%d³%-9.9s³%-4.4s³%-4.4s³%3u ³%4u ³%3u ³%3u ³%4u ³%3u ³%8lu ³%8lu ³\n";
char mid2 []  =	"ÃÄÅÄÄÄÄÄÄÄÄÄÅÄÄÄÄÅÄÄÄÄÅÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÅÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÅÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄ´\n";
char foot []  =	"ÀÄÁÄÄÄÄÄÄÄÄÄÁÄÄÄÄÁÄÄÄÄÁÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÁÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÁÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÙ\n";

void printtable (disk)
{
	PartitionEntry *part = (PartitionEntry *) (bootRecord + PartAddr);
	int i, cb;
	long relSectors;
	long numSectors;
	char *typeString, block [512];

	printf ("\n");
	printf (head1);
	printf (head2);
	printf (head3);
	printf (head4);

	for (i=0; i<4; ++i) {
		switch (part->systemId) {
		default:	typeString = "  ?????";   cb = 1; break;
		case 0:		typeString = "  empty";   cb = 0; break;
		case 1:		typeString = "  dos-12";  cb = 1; break;
		case 2:		typeString = "  xenix";   cb = 1; break;
		case 3:		typeString = "xenix usr"; cb = 0; break;
		case 4:		typeString = "  dos-16";  cb = 1; break;
		case 5:		typeString = "  extend";  cb = 0; break;
		case 6:		typeString = "  bigdos";  cb = 1; break;
		case 7:
		case 0x0B:
		case 0x0C:
		case 0x87:	typeString = "windows";   cb = 1; break;
		case 0x75:	typeString = "  pcix";    cb = 1; break;
		case 0xdb:	typeString = "  cp/m";    cb = 1; break;
		case 0xff:	typeString = "  bbt";     cb = 0; break;
		case 0x08:	typeString = "  aix";     cb = 0; break;
		case 0x09:	typeString = " coherent"; cb = 1; break;
		case 0x0A:	typeString = "  os/2";    cb = 1; break;
		case 0x10:	typeString = "  opus";    cb = 1; break;
		case 0x40:	typeString = "venix 286"; cb = 1; break;
		case 0x50:
		case 0x51:	typeString = "  dm";      cb = 1; break;
		case 0x52:	typeString = "microport"; cb = 1; break;
		case 0x56:	typeString = "  gb";      cb = 1; break;
		case 0x61:
		case 0xE1:
		case 0xE3:
		case 0xE4:
		case 0xF1:
		case 0xF4:	typeString = "  speed";   cb = 1; break;
		case 0x63:	typeString = "  unix";    cb = 1; break;
		case 0x64:	typeString = "novell286"; cb = 1; break;
		case 0x65:	typeString = "novell386"; cb = 1; break;
		case 0x80:	typeString = "old minix"; cb = 1; break;
		case 0x81:	typeString = "  minix";   cb = 1; break;
		case 0x82:	typeString = "  linux";   cb = 1; break;
		case 0x93:	typeString = "  amoeba";  cb = 1; break;
		case 0x94:	typeString = "amoebaBBT"; cb = 0; break;
		case 0xA5:	typeString = " freebsd";  cb = 1; break;
		case 0xA6:	typeString = " openbsd";  cb = 1; break;
		case 0xA9:	typeString = "  netbsd";  cb = 1; break;
		case 0x9f:
		case 0xB7:	typeString = "  bsdi";    cb = 1; break;
		case 0xB8:	typeString = "bsdi swap"; cb = 0; break;
		case 0xF2:	typeString = " dos sec";  cb = 1; break;
		}
		relSectors = part->relSectorLow |
			(unsigned long) part->relSectorHigh<<16;
		numSectors = part->numSectorsLow |
			(unsigned long) part->numSectorsHigh<<16;

		if (cb && (bootio (disk, READ, part->beginHead, part->beginCyl,
		    part->beginSector, block) != 0 ||
		    *(short *) &block [ValidationAddr] != (short) MAGIC))
			cb = 0;

		printf (mid1, i+1, typeString, cb ? " yes" : " no",
			(part->bootIndicator & 0x80) ? " yes" : " no",
			part->beginHead, part->beginCyl |
			part->beginSector<<2 & 0x300,
			part->beginSector & 077, part->endHead,
			part->endCyl | part->endSector<<2 & 0x300,
			part->endSector & 077, relSectors, numSectors);
		if (i < 3)
			printf (mid2);
		++part;
	}
	printf (foot);
}

int yes ()
{
	char reply [80];

	printf (" (yes/no) ");
	fgets (reply, sizeof (reply), stdin);
	return (!stricmp (reply, "y\n") || !stricmp (reply, "yes\n"));
}

int install (disk, file, savefile)
char *file, *savefile;
{
	int rc, fd;

	rc = bootio (disk, READ, 0, 0, 1, bootRecord);
	if (rc) {
		fprintf (stderr, "Error %d reading boot record from disk %d\n",
			rc, disk);
		return (-1);
	}
	if (*(short *) &bootRecord [ValidationAddr] != (short) MAGIC) {
		fprintf (stderr, "Bad master boot record on disk %d!\n",
			disk);
		return (-1);
	}

	printtable (disk);

	fd = open (file, O_RDONLY|O_BINARY);
	if (fd < 0) {
		fprintf (stderr, "Cannot read file %s\n", file);
		return (-1);
	}
	if (read (fd, bootProg, 512) != 512) {
		fprintf (stderr, "Error reading %s\n", file);
		return (-1);
	}
	close (fd);
	if (*(short *) &bootProg [ValidationAddr] != (short) MAGIC) {
		fprintf (stderr, "Bad boot image in file %s\n", file);
		return (-1);
	}

	printf ("\nAre you sure you want to install new boot on disk %d?",
		disk);
	if (! yes ())
		return (0);

	close (creat (savefile, 0664));
	fd = open (savefile, O_WRONLY|O_BINARY);
	if (fd < 0) {
		fprintf (stderr, "Cannot write to file %s\n", savefile);
		return (-1);
	}
	if (write (fd, bootRecord, 512) != 512) {
		fprintf (stderr, "Error writing to %s\n", savefile);
		return (-1);
	}
	close (fd);

	memcpy (bootRecord, bootProg, PartAddr);

	rc = bootio (disk, WRITE, 0, 0, 1, bootRecord);
	if (rc) {
		fprintf (stderr, "Error %d updating boot record on disk %d\n",
			rc, disk);
		return (-1);
	}
	printf ("New boot record successfully installed.\n");
	return (0);
}

bootio (disk, op, head, cyl, sect, buf)
char *buf;
{
	return (biosdisk (op==WRITE ? 3 : 2, disk==DISK1 ? 0x80 : 0x81,
		head, cyl, sect, 1, buf));
}

int main (argc, argv)
char **argv;
{
	char *bootfile;
	int disk2present;

	printf ("Boot installer, version 1.7, Copyright (C) Serge Vakulenko\n\n");

	printf ("This utility allows you to install new boot program on your\n");
	printf ("hard disk.  The usage is:\n\n");
	printf ("        bootinst [bootfile]\n\n");
	printf ("It installs boot block from bootfile (default boot.bin) to the first\n");
	printf ("drive and, if second drive is present, to the second drive.\n");
	printf ("Old boot sectors are saved to bootsav.bin and boot2sav.bin respectively.\n");
	printf ("\nYou can copy and distribute this software free of charge,\n");
	printf ("provided that sources are included.  No warranty, of course.\n\n");

	if (argc > 3)
		return (-1);

	bootfile = argc>1 ? argv[1] : BOOTFILE;
	if (access (bootfile, 4) < 0) {
		perror (bootfile);
		return (-1);
	}

	/*
	 * Is second disk present?  Try to read boot sector,
	 * check that it is bootable and has valid partition table.
	 */
	disk2present = (bootio (DISK2, READ, 0, 0, 1, bootRecord) == 0 &&
		*(short *) &bootRecord [ValidationAddr] == (short) MAGIC &&
		(bootRecord [PartAddr] == 0 || bootRecord [PartAddr] == 0x80) &&
		(bootRecord [PartAddr+16] == 0 || bootRecord [PartAddr+16] == 0x80) &&
		(bootRecord [PartAddr+32] == 0 || bootRecord [PartAddr+32] == 0x80) &&
		(bootRecord [PartAddr+48] == 0 || bootRecord [PartAddr+48] == 0x80));

	printf ("Continue with installation?");
	if (! yes ())
		return (0);

	install (DISK1, bootfile, SAVEFILE);

	if (disk2present)
		install (DISK2, bootfile, SAVE2FILE);

	return (0);
}