fdisk.c revision 1.12 1 1.12 thorpej /* $NetBSD: fdisk.c,v 1.12 1997/03/29 20:46:17 thorpej Exp $ */
2 1.10 cgd
3 1.4 mycroft /*
4 1.1 cgd * Mach Operating System
5 1.1 cgd * Copyright (c) 1992 Carnegie Mellon University
6 1.1 cgd * All Rights Reserved.
7 1.4 mycroft *
8 1.1 cgd * Permission to use, copy, modify and distribute this software and its
9 1.1 cgd * documentation is hereby granted, provided that both the copyright
10 1.1 cgd * notice and this permission notice appear in all copies of the
11 1.1 cgd * software, derivative works or modified versions, and any portions
12 1.1 cgd * thereof, and that both notices appear in supporting documentation.
13 1.4 mycroft *
14 1.1 cgd * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 1.1 cgd * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 1.1 cgd * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 1.4 mycroft *
18 1.1 cgd * Carnegie Mellon requests users of this software to return to
19 1.4 mycroft *
20 1.1 cgd * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
21 1.1 cgd * School of Computer Science
22 1.1 cgd * Carnegie Mellon University
23 1.1 cgd * Pittsburgh PA 15213-3890
24 1.4 mycroft *
25 1.1 cgd * any improvements or extensions that they make and grant Carnegie Mellon
26 1.1 cgd * the rights to redistribute these changes.
27 1.1 cgd */
28 1.1 cgd
29 1.2 mycroft #ifndef lint
30 1.12 thorpej static char rcsid[] = "$NetBSD: fdisk.c,v 1.12 1997/03/29 20:46:17 thorpej Exp $";
31 1.2 mycroft #endif /* not lint */
32 1.2 mycroft
33 1.1 cgd #include <sys/types.h>
34 1.1 cgd #include <sys/disklabel.h>
35 1.4 mycroft #include <sys/ioctl.h>
36 1.1 cgd #include <sys/stat.h>
37 1.4 mycroft
38 1.8 cgd #include <ctype.h>
39 1.4 mycroft #include <err.h>
40 1.1 cgd #include <fcntl.h>
41 1.4 mycroft #include <stdio.h>
42 1.4 mycroft #include <stdlib.h>
43 1.8 cgd #include <string.h>
44 1.8 cgd #include <unistd.h>
45 1.1 cgd
46 1.1 cgd #define LBUF 100
47 1.1 cgd static char lbuf[LBUF];
48 1.1 cgd
49 1.1 cgd /*
50 1.1 cgd * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University
51 1.1 cgd * Copyright (c) 1989 Robert. V. Baron
52 1.1 cgd * Created.
53 1.1 cgd */
54 1.1 cgd
55 1.1 cgd char *disk = "/dev/rwd0d";
56 1.1 cgd
57 1.1 cgd struct disklabel disklabel; /* disk parameters */
58 1.1 cgd
59 1.5 mycroft int cylinders, sectors, heads, cylindersectors, disksectors;
60 1.1 cgd
61 1.4 mycroft struct mboot {
62 1.1 cgd unsigned char padding[2]; /* force the longs to be long alligned */
63 1.1 cgd unsigned char bootinst[DOSPARTOFF];
64 1.1 cgd struct dos_partition parts[4];
65 1.1 cgd unsigned short int signature;
66 1.1 cgd };
67 1.1 cgd struct mboot mboot;
68 1.1 cgd
69 1.1 cgd #define ACTIVE 0x80
70 1.1 cgd #define BOOT_MAGIC 0xAA55
71 1.1 cgd
72 1.5 mycroft int dos_cylinders;
73 1.1 cgd int dos_heads;
74 1.1 cgd int dos_sectors;
75 1.5 mycroft int dos_cylindersectors;
76 1.1 cgd
77 1.4 mycroft #define DOSSECT(s,c) (((s) & 0x3f) | (((c) >> 2) & 0xc0))
78 1.4 mycroft #define DOSCYL(c) ((c) & 0xff)
79 1.4 mycroft int partition = -1;
80 1.4 mycroft
81 1.4 mycroft int a_flag; /* set active partition */
82 1.4 mycroft int i_flag; /* replace partition data */
83 1.4 mycroft int u_flag; /* update partition data */
84 1.4 mycroft
85 1.4 mycroft unsigned char bootcode[] = {
86 1.4 mycroft 0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf,
87 1.4 mycroft 0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe,
88 1.4 mycroft 0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd,
89 1.4 mycroft 0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74,
90 1.4 mycroft 0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00,
91 1.4 mycroft 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe,
92 1.4 mycroft 0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00,
93 1.4 mycroft 0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10,
94 1.1 cgd 0xeb, 0xf4, 0xfb, 0xeb, 0xfe,
95 1.1 cgd 'M', 'i', 's', 's', 'i', 'n', 'g', ' ',
96 1.1 cgd 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
97 1.4 mycroft 'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ',
98 1.1 cgd 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
99 1.1 cgd 'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ',
100 1.1 cgd 'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0,
101 1.1 cgd 'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ',
102 1.4 mycroft 'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0,
103 1.1 cgd
104 1.4 mycroft 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105 1.4 mycroft 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
106 1.4 mycroft 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107 1.4 mycroft 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108 1.4 mycroft 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
109 1.4 mycroft 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
110 1.4 mycroft 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
111 1.4 mycroft 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112 1.4 mycroft 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113 1.4 mycroft 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
114 1.4 mycroft 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115 1.4 mycroft 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
116 1.4 mycroft 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
117 1.1 cgd };
118 1.1 cgd
119 1.4 mycroft struct part_type {
121 1.4 mycroft int type;
122 1.4 mycroft char *name;
123 1.4 mycroft } part_types[] = {
124 1.4 mycroft {0x00, "unused"},
125 1.4 mycroft {0x01, "Primary DOS with 12 bit FAT"},
126 1.4 mycroft {0x02, "XENIX / filesystem"},
127 1.4 mycroft {0x03, "XENIX /usr filesystem"},
128 1.4 mycroft {0x04, "Primary DOS with 16 bit FAT"},
129 1.4 mycroft {0x05, "Extended DOS"},
130 1.4 mycroft {0x06, "Primary 'big' DOS (> 32MB)"},
131 1.4 mycroft {0x07, "OS/2 HPFS, QNX or Advanced UNIX"},
132 1.4 mycroft {0x08, "AIX filesystem"},
133 1.4 mycroft {0x09, "AIX boot partition or Coherent"},
134 1.4 mycroft {0x0A, "OS/2 Boot Manager or OPUS"},
135 1.4 mycroft {0x10, "OPUS"},
136 1.4 mycroft {0x40, "VENIX 286"},
137 1.4 mycroft {0x50, "DM"},
138 1.4 mycroft {0x51, "DM"},
139 1.4 mycroft {0x52, "CP/M or Microport SysV/AT"},
140 1.4 mycroft {0x56, "GB"},
141 1.4 mycroft {0x61, "Speed"},
142 1.4 mycroft {0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"},
143 1.4 mycroft {0x64, "Novell Netware 2.xx"},
144 1.4 mycroft {0x65, "Novell Netware 3.xx"},
145 1.4 mycroft {0x75, "PCIX"},
146 1.4 mycroft {0x80, "Minix 1.1 ... 1.4a"},
147 1.9 mycroft {0x81, "Minix 1.4b ... 1.5.10"},
148 1.9 mycroft {0x82, "Linux swap"},
149 1.4 mycroft {0x83, "Linux filesystem"},
150 1.4 mycroft {0x93, "Amoeba filesystem"},
151 1.9 mycroft {0x94, "Amoeba bad block table"},
152 1.4 mycroft {0xA5, "NetBSD or 386BSD"},
153 1.4 mycroft {0xB7, "BSDI BSD/386 filesystem"},
154 1.4 mycroft {0xB8, "BSDI BSD/386 swap"},
155 1.4 mycroft {0xDB, "Concurrent CPM or C.DOS or CTOS"},
156 1.4 mycroft {0xE1, "Speed"},
157 1.4 mycroft {0xE3, "Speed"},
158 1.4 mycroft {0xE4, "Speed"},
159 1.4 mycroft {0xF1, "Speed"},
160 1.4 mycroft {0xF2, "DOS 3.3+ Secondary"},
161 1.4 mycroft {0xF4, "Speed"},
162 1.1 cgd {0xFF, "BBT (Bad Blocks Table)"},
163 1.1 cgd };
164 1.4 mycroft
165 1.4 mycroft void usage __P((void));
166 1.4 mycroft void print_s0 __P((int));
167 1.4 mycroft void print_part __P((int));
168 1.11 ghudson void init_sector0 __P((int));
169 1.11 ghudson void intuit_translated_geometry __P((void));
170 1.11 ghudson int try_heads __P((quad_t, quad_t, quad_t, quad_t, quad_t, quad_t, quad_t,
171 1.11 ghudson quad_t));
172 1.4 mycroft int try_sectors __P((quad_t, quad_t, quad_t, quad_t, quad_t));
173 1.4 mycroft void change_part __P((int));
174 1.4 mycroft void print_params __P((void));
175 1.4 mycroft void change_active __P((int));
176 1.4 mycroft void get_params_to_use __P((void));
177 1.4 mycroft void dos __P((int, unsigned char *, unsigned char *, unsigned char *));
178 1.4 mycroft int open_disk __P((int));
179 1.4 mycroft int read_disk __P((int, void *));
180 1.4 mycroft int write_disk __P((int, void *));
181 1.4 mycroft int get_params __P((void));
182 1.4 mycroft int read_s0 __P((void));
183 1.4 mycroft int write_s0 __P((void));
184 1.5 mycroft int yesno __P((char *));
185 1.4 mycroft void decimal __P((char *, int *));
186 1.4 mycroft int type_match __P((const void *, const void *));
187 1.1 cgd char *get_type __P((int));
188 1.4 mycroft
189 1.1 cgd int
190 1.4 mycroft main(argc, argv)
191 1.4 mycroft int argc;
192 1.1 cgd char *argv[];
193 1.4 mycroft {
194 1.4 mycroft int ch;
195 1.1 cgd int part;
196 1.4 mycroft
197 1.4 mycroft a_flag = i_flag = u_flag = 0;
198 1.4 mycroft while ((ch = getopt(argc, argv, "0123aiu")) != -1)
199 1.4 mycroft switch (ch) {
200 1.4 mycroft case '0':
201 1.4 mycroft partition = 0;
202 1.4 mycroft break;
203 1.4 mycroft case '1':
204 1.4 mycroft partition = 1;
205 1.4 mycroft break;
206 1.4 mycroft case '2':
207 1.4 mycroft partition = 2;
208 1.4 mycroft break;
209 1.4 mycroft case '3':
210 1.4 mycroft partition = 3;
211 1.4 mycroft break;
212 1.4 mycroft case 'a':
213 1.4 mycroft a_flag = 1;
214 1.4 mycroft break;
215 1.4 mycroft case 'i':
216 1.4 mycroft i_flag = 1;
217 1.4 mycroft case 'u':
218 1.1 cgd u_flag = 1;
219 1.4 mycroft break;
220 1.4 mycroft default:
221 1.1 cgd usage();
222 1.4 mycroft }
223 1.4 mycroft argc -= optind;
224 1.1 cgd argv += optind;
225 1.1 cgd
226 1.1 cgd if (argc > 0)
227 1.4 mycroft disk = argv[0];
228 1.4 mycroft
229 1.1 cgd if (open_disk(a_flag || i_flag || u_flag) < 0)
230 1.1 cgd exit(1);
231 1.11 ghudson
232 1.11 ghudson if (read_s0())
233 1.11 ghudson init_sector0(1);
234 1.11 ghudson
235 1.11 ghudson intuit_translated_geometry();
236 1.4 mycroft
237 1.4 mycroft printf("******* Working on device %s *******\n", disk);
238 1.1 cgd if (u_flag)
239 1.1 cgd get_params_to_use();
240 1.1 cgd else
241 1.1 cgd print_params();
242 1.1 cgd
243 1.1 cgd printf("Warning: BIOS sector numbering starts with sector 1\n");
244 1.4 mycroft printf("Information from DOS bootblock is:\n");
245 1.4 mycroft if (partition == -1) {
246 1.4 mycroft for (part = 0; part < NDOSPART; part++)
247 1.4 mycroft change_part(part);
248 1.1 cgd } else
249 1.1 cgd change_part(partition);
250 1.1 cgd
251 1.1 cgd if (u_flag || a_flag)
252 1.1 cgd change_active(partition);
253 1.1 cgd
254 1.1 cgd if (u_flag || a_flag) {
255 1.1 cgd printf("\nWe haven't changed the partition table yet. ");
256 1.1 cgd printf("This is your last chance.\n");
257 1.4 mycroft print_s0(-1);
258 1.1 cgd if (yesno("Should we write new partition table?"))
259 1.1 cgd write_s0();
260 1.1 cgd }
261 1.1 cgd
262 1.4 mycroft exit(0);
263 1.1 cgd }
264 1.4 mycroft
265 1.4 mycroft void
266 1.4 mycroft usage()
267 1.4 mycroft {
268 1.4 mycroft
269 1.4 mycroft (void)fprintf(stderr, "usage: fdisk [-aiu] [-0|-1|-2|-3] [device]\n");
270 1.1 cgd exit(1);
271 1.1 cgd }
272 1.4 mycroft
273 1.1 cgd void
274 1.4 mycroft print_s0(which)
275 1.1 cgd int which;
276 1.4 mycroft {
277 1.1 cgd int part;
278 1.1 cgd
279 1.1 cgd print_params();
280 1.4 mycroft printf("Information from DOS bootblock is:\n");
281 1.4 mycroft if (which == -1) {
282 1.4 mycroft for (part = 0; part < NDOSPART; part++)
283 1.4 mycroft printf("%d: ", part), print_part(part);
284 1.1 cgd } else
285 1.1 cgd print_part(which);
286 1.1 cgd }
287 1.1 cgd
288 1.1 cgd static struct dos_partition mtpart = { 0 };
289 1.12 thorpej
290 1.12 thorpej static inline unsigned short
291 1.12 thorpej getshort(p)
292 1.12 thorpej void *p;
293 1.12 thorpej {
294 1.12 thorpej unsigned char *cp = p;
295 1.12 thorpej
296 1.12 thorpej return cp[0] | (cp[1] << 8);
297 1.12 thorpej }
298 1.12 thorpej
299 1.12 thorpej static inline void
300 1.12 thorpej putshort(p, l)
301 1.12 thorpej void *p;
302 1.12 thorpej unsigned short l;
303 1.12 thorpej {
304 1.12 thorpej unsigned char *cp = p;
305 1.12 thorpej
306 1.12 thorpej *cp++ = l;
307 1.12 thorpej *cp++ = l >> 8;
308 1.12 thorpej }
309 1.12 thorpej
310 1.12 thorpej static inline unsigned long
311 1.12 thorpej getlong(p)
312 1.12 thorpej void *p;
313 1.12 thorpej {
314 1.12 thorpej unsigned char *cp = p;
315 1.12 thorpej
316 1.12 thorpej return cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24);
317 1.12 thorpej }
318 1.12 thorpej
319 1.12 thorpej static inline void
320 1.12 thorpej putlong(p, l)
321 1.12 thorpej void *p;
322 1.12 thorpej unsigned long l;
323 1.12 thorpej {
324 1.12 thorpej unsigned char *cp = p;
325 1.12 thorpej
326 1.12 thorpej *cp++ = l;
327 1.12 thorpej *cp++ = l >> 8;
328 1.12 thorpej *cp++ = l >> 16;
329 1.12 thorpej *cp++ = l >> 24;
330 1.12 thorpej }
331 1.4 mycroft
332 1.4 mycroft void
333 1.4 mycroft print_part(part)
334 1.1 cgd int part;
335 1.4 mycroft {
336 1.1 cgd struct dos_partition *partp;
337 1.4 mycroft
338 1.6 mycroft partp = &mboot.parts[part];
339 1.1 cgd if (!memcmp(partp, &mtpart, sizeof(struct dos_partition))) {
340 1.1 cgd printf("<UNUSED>\n");
341 1.1 cgd return;
342 1.5 mycroft }
343 1.4 mycroft printf("sysid %d (%s)\n", partp->dp_typ, get_type(partp->dp_typ));
344 1.12 thorpej printf(" start %d, size %d (%d MB), flag %x\n",
345 1.12 thorpej getlong(&partp->dp_start), getlong(&partp->dp_size),
346 1.5 mycroft getlong(&partp->dp_size) * 512 / (1024 * 1024), partp->dp_flag);
347 1.5 mycroft printf("\tbeg: cylinder %4d, head %3d, sector %2d\n",
348 1.5 mycroft DPCYL(partp->dp_scyl, partp->dp_ssect),
349 1.5 mycroft partp->dp_shd, DPSECT(partp->dp_ssect));
350 1.5 mycroft printf("\tend: cylinder %4d, head %3d, sector %2d\n",
351 1.5 mycroft DPCYL(partp->dp_ecyl, partp->dp_esect),
352 1.1 cgd partp->dp_ehd, DPSECT(partp->dp_esect));
353 1.1 cgd }
354 1.4 mycroft
355 1.1 cgd void
356 1.4 mycroft init_sector0(start)
357 1.1 cgd int start;
358 1.4 mycroft {
359 1.1 cgd struct dos_partition *partp;
360 1.4 mycroft
361 1.12 thorpej memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
362 1.1 cgd putshort(&mboot.signature, BOOT_MAGIC);
363 1.4 mycroft
364 1.1 cgd partp = &mboot.parts[3];
365 1.1 cgd partp->dp_typ = DOSPTYP_386BSD;
366 1.12 thorpej partp->dp_flag = ACTIVE;
367 1.12 thorpej putlong(&partp->dp_start, start);
368 1.1 cgd putlong(&partp->dp_size, disksectors - start);
369 1.12 thorpej
370 1.4 mycroft dos(getlong(&partp->dp_start),
371 1.12 thorpej &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
372 1.4 mycroft dos(getlong(&partp->dp_start) + getlong(&partp->dp_size) - 1,
373 1.11 ghudson &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
374 1.11 ghudson }
375 1.11 ghudson
376 1.11 ghudson /* Prerequisite: the disklabel parameters and master boot record must
377 1.11 ghudson * have been read (i.e. dos_* and mboot are meaningful).
378 1.11 ghudson * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and
379 1.11 ghudson * dos_cylindersectors to be consistent with what the
380 1.11 ghudson * partition table is using, if we can find a geometry
381 1.11 ghudson * which is consistent with all partition table entries.
382 1.11 ghudson * We may get the number of cylinders slightly wrong (in
383 1.11 ghudson * the conservative direction). The idea is to be able
384 1.11 ghudson * to create a NetBSD partition on a disk we don't know
385 1.11 ghudson * the translated geometry of.
386 1.11 ghudson * This whole routine should be replaced with a kernel interface to get
387 1.11 ghudson * the BIOS geometry (which in turn requires modifications to the i386
388 1.11 ghudson * boot loader to pass in the BIOS geometry for each disk). */
389 1.11 ghudson void
390 1.11 ghudson intuit_translated_geometry()
391 1.11 ghudson {
392 1.11 ghudson int cylinders = -1, heads = -1, sectors = -1, i, j;
393 1.11 ghudson int c1, h1, s1, c2, h2, s2;
394 1.11 ghudson long a1, a2;
395 1.11 ghudson quad_t num, denom;
396 1.11 ghudson
397 1.11 ghudson /* Try to deduce the number of heads from two different mappings. */
398 1.11 ghudson for (i = 0; i < NDOSPART * 2; i++) {
399 1.11 ghudson if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
400 1.11 ghudson continue;
401 1.11 ghudson for (j = 0; j < 8; j++) {
402 1.11 ghudson if (get_mapping(j, &c2, &h2, &s2, &a2) < 0)
403 1.11 ghudson continue;
404 1.11 ghudson num = (quad_t)h1*(a2-s2) - h2*(a1-s1);
405 1.11 ghudson denom = (quad_t)c2*(a1-s1) - c1*(a2-s2);
406 1.11 ghudson if (denom != 0 && num % denom == 0) {
407 1.11 ghudson heads = num / denom;
408 1.11 ghudson break;
409 1.11 ghudson }
410 1.11 ghudson }
411 1.11 ghudson if (heads != -1)
412 1.11 ghudson break;
413 1.11 ghudson }
414 1.11 ghudson
415 1.11 ghudson if (heads == -1)
416 1.11 ghudson return;
417 1.11 ghudson
418 1.11 ghudson /* Now figure out the number of sectors from a single mapping. */
419 1.11 ghudson for (i = 0; i < NDOSPART * 2; i++) {
420 1.11 ghudson if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
421 1.11 ghudson continue;
422 1.11 ghudson num = a1 - s1;
423 1.11 ghudson denom = c1 * heads + h1;
424 1.11 ghudson if (denom != 0 && num % denom == 0) {
425 1.11 ghudson sectors = num / denom;
426 1.11 ghudson break;
427 1.11 ghudson }
428 1.11 ghudson }
429 1.11 ghudson
430 1.11 ghudson if (sectors == -1)
431 1.11 ghudson return;
432 1.11 ghudson
433 1.11 ghudson /* Estimate the number of cylinders. */
434 1.11 ghudson cylinders = dos_cylinders * dos_cylindersectors / heads / sectors;
435 1.11 ghudson
436 1.11 ghudson /* Now verify consistency with each of the partition table entries.
437 1.11 ghudson * Be willing to shove cylinders up a little bit to make things work,
438 1.11 ghudson * but translation mismatches are fatal. */
439 1.11 ghudson for (i = 0; i < NDOSPART * 2; i++) {
440 1.11 ghudson if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
441 1.11 ghudson continue;
442 1.11 ghudson if (sectors * (c1 * heads + h1) + s1 != a1)
443 1.11 ghudson return;
444 1.11 ghudson if (c1 >= cylinders)
445 1.11 ghudson cylinders = c1 + 1;
446 1.11 ghudson }
447 1.11 ghudson
448 1.11 ghudson /* Everything checks out. Reset the geometry to use for further
449 1.11 ghudson * calculations. */
450 1.11 ghudson dos_cylinders = cylinders;
451 1.11 ghudson dos_heads = heads;
452 1.11 ghudson dos_sectors = sectors;
453 1.11 ghudson dos_cylindersectors = heads * sectors;
454 1.11 ghudson }
455 1.11 ghudson
456 1.11 ghudson /* For the purposes of intuit_translated_geometry(), treat the partition
457 1.11 ghudson * table as a list of eight mapping between (cylinder, head, sector)
458 1.11 ghudson * triplets and absolute sectors. Get the relevant geometry triplet and
459 1.11 ghudson * absolute sectors for a given entry, or return -1 if it isn't present.
460 1.11 ghudson * Note: for simplicity, the returned sector is 0-based. */
461 1.11 ghudson int
462 1.11 ghudson get_mapping(i, cylinder, head, sector, absolute)
463 1.11 ghudson int i, *cylinder, *head, *sector;
464 1.11 ghudson long *absolute;
465 1.11 ghudson {
466 1.11 ghudson struct dos_partition *part = &mboot.parts[i / 2];
467 1.11 ghudson
468 1.11 ghudson if (part->dp_typ == 0)
469 1.11 ghudson return -1;
470 1.11 ghudson if (i % 2 == 0) {
471 1.11 ghudson *cylinder = DPCYL(part->dp_scyl, part->dp_ssect);
472 1.11 ghudson *head = part->dp_shd;
473 1.12 thorpej *sector = DPSECT(part->dp_ssect) - 1;
474 1.11 ghudson *absolute = getlong(&part->dp_start);
475 1.11 ghudson } else {
476 1.11 ghudson *cylinder = DPCYL(part->dp_ecyl, part->dp_esect);
477 1.11 ghudson *head = part->dp_ehd;
478 1.12 thorpej *sector = DPSECT(part->dp_esect) - 1;
479 1.12 thorpej *absolute = getlong(&part->dp_start)
480 1.11 ghudson + getlong(&part->dp_size) - 1;
481 1.11 ghudson }
482 1.1 cgd return 0;
483 1.1 cgd }
484 1.4 mycroft
485 1.4 mycroft void
486 1.4 mycroft change_part(part)
487 1.1 cgd int part;
488 1.4 mycroft {
489 1.1 cgd struct dos_partition *partp;
490 1.4 mycroft
491 1.1 cgd partp = &mboot.parts[part];
492 1.4 mycroft
493 1.4 mycroft printf("The data for partition %d is:\n", part);
494 1.4 mycroft print_part(part);
495 1.4 mycroft
496 1.4 mycroft if (!u_flag || !yesno("Do you want to change it?"))
497 1.1 cgd return;
498 1.1 cgd
499 1.7 mycroft if (i_flag) {
500 1.4 mycroft memset(partp, 0, sizeof(*partp));
501 1.1 cgd if (part == 3) {
502 1.1 cgd init_sector0(1);
503 1.4 mycroft printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
504 1.1 cgd print_part(part);
505 1.1 cgd }
506 1.1 cgd }
507 1.1 cgd
508 1.5 mycroft do {
509 1.5 mycroft {
510 1.5 mycroft int sysid, start, size;
511 1.5 mycroft
512 1.12 thorpej sysid = partp->dp_typ,
513 1.12 thorpej start = getlong(&partp->dp_start),
514 1.5 mycroft size = getlong(&partp->dp_size);
515 1.5 mycroft decimal("sysid", &sysid);
516 1.5 mycroft decimal("start", &start);
517 1.5 mycroft decimal("size", &size);
518 1.12 thorpej partp->dp_typ = sysid;
519 1.12 thorpej putlong(&partp->dp_start, start);
520 1.5 mycroft putlong(&partp->dp_size, size);
521 1.1 cgd }
522 1.7 mycroft
523 1.5 mycroft if (yesno("Explicitly specify beg/end address?")) {
524 1.4 mycroft int tsector, tcylinder, thead;
525 1.5 mycroft
526 1.5 mycroft tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect);
527 1.5 mycroft thead = partp->dp_shd;
528 1.5 mycroft tsector = DPSECT(partp->dp_ssect);
529 1.5 mycroft decimal("beginning cylinder", &tcylinder);
530 1.5 mycroft decimal("beginning head", &thead);
531 1.5 mycroft decimal("beginning sector", &tsector);
532 1.5 mycroft partp->dp_scyl = DOSCYL(tcylinder);
533 1.5 mycroft partp->dp_shd = thead;
534 1.5 mycroft partp->dp_ssect = DOSSECT(tsector, tcylinder);
535 1.5 mycroft
536 1.5 mycroft tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect);
537 1.5 mycroft thead = partp->dp_ehd;
538 1.5 mycroft tsector = DPSECT(partp->dp_esect);
539 1.5 mycroft decimal("ending cylinder", &tcylinder);
540 1.5 mycroft decimal("ending head", &thead);
541 1.5 mycroft decimal("ending sector", &tsector);
542 1.5 mycroft partp->dp_ecyl = DOSCYL(tcylinder);
543 1.5 mycroft partp->dp_ehd = thead;
544 1.1 cgd partp->dp_esect = DOSSECT(tsector, tcylinder);
545 1.12 thorpej } else {
546 1.4 mycroft dos(getlong(&partp->dp_start),
547 1.12 thorpej &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
548 1.12 thorpej dos(getlong(&partp->dp_start)
549 1.4 mycroft + getlong(&partp->dp_size) - 1,
550 1.1 cgd &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
551 1.4 mycroft }
552 1.4 mycroft
553 1.7 mycroft print_part(part);
554 1.1 cgd } while (!yesno("Is this entry okay?"));
555 1.1 cgd }
556 1.4 mycroft
557 1.1 cgd void
558 1.1 cgd print_params()
559 1.4 mycroft {
560 1.1 cgd
561 1.5 mycroft printf("parameters extracted from in-core disklabel are:\n");
562 1.5 mycroft printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
563 1.5 mycroft cylinders, heads, sectors, cylindersectors);
564 1.5 mycroft if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255)
565 1.1 cgd printf("Figures below won't work with BIOS for partitions not in cylinder 1\n");
566 1.5 mycroft printf("parameters to be used for BIOS calculations are:\n");
567 1.5 mycroft printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
568 1.1 cgd dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors);
569 1.1 cgd }
570 1.4 mycroft
571 1.1 cgd void
572 1.4 mycroft change_active(which)
573 1.1 cgd int which;
574 1.4 mycroft {
575 1.4 mycroft struct dos_partition *partp;
576 1.5 mycroft int part;
577 1.4 mycroft int active = 3;
578 1.4 mycroft
579 1.1 cgd partp = &mboot.parts[0];
580 1.1 cgd
581 1.1 cgd if (a_flag && which != -1)
582 1.4 mycroft active = which;
583 1.4 mycroft else {
584 1.4 mycroft for (part = 0; part < NDOSPART; part++)
585 1.4 mycroft if (partp[part].dp_flag & ACTIVE)
586 1.4 mycroft active = part;
587 1.4 mycroft }
588 1.4 mycroft if (yesno("Do you want to change the active partition?")) {
589 1.5 mycroft do {
590 1.4 mycroft decimal("active partition", &active);
591 1.1 cgd } while (!yesno("Are you happy with this choice?"));
592 1.4 mycroft }
593 1.4 mycroft for (part = 0; part < NDOSPART; part++)
594 1.4 mycroft partp[part].dp_flag &= ~ACTIVE;
595 1.1 cgd partp[active].dp_flag |= ACTIVE;
596 1.1 cgd }
597 1.4 mycroft
598 1.1 cgd void
599 1.1 cgd get_params_to_use()
600 1.4 mycroft {
601 1.1 cgd
602 1.4 mycroft print_params();
603 1.4 mycroft if (yesno("Do you want to change our idea of what BIOS thinks?")) {
604 1.5 mycroft do {
605 1.5 mycroft decimal("BIOS's idea of #cylinders", &dos_cylinders);
606 1.5 mycroft decimal("BIOS's idea of #heads", &dos_heads);
607 1.5 mycroft decimal("BIOS's idea of #sectors", &dos_sectors);
608 1.1 cgd dos_cylindersectors = dos_heads * dos_sectors;
609 1.4 mycroft print_params();
610 1.1 cgd } while (!yesno("Are you happy with this choice?"));
611 1.1 cgd }
612 1.1 cgd }
613 1.1 cgd
614 1.1 cgd /***********************************************\
615 1.1 cgd * Change real numbers into strange dos numbers *
616 1.4 mycroft \***********************************************/
617 1.5 mycroft void
618 1.5 mycroft dos(sector, cylinderp, headp, sectorp)
619 1.5 mycroft int sector;
620 1.4 mycroft unsigned char *cylinderp, *headp, *sectorp;
621 1.5 mycroft {
622 1.4 mycroft int cylinder, head;
623 1.5 mycroft
624 1.5 mycroft cylinder = sector / dos_cylindersectors;
625 1.4 mycroft sector -= cylinder * dos_cylindersectors;
626 1.5 mycroft
627 1.5 mycroft head = sector / dos_sectors;
628 1.4 mycroft sector -= head * dos_sectors;
629 1.5 mycroft
630 1.5 mycroft *cylinderp = DOSCYL(cylinder);
631 1.5 mycroft *headp = head;
632 1.1 cgd *sectorp = DOSSECT(sector + 1, cylinder);
633 1.1 cgd }
634 1.1 cgd
635 1.1 cgd int fd;
636 1.4 mycroft
637 1.1 cgd int
638 1.4 mycroft open_disk(u_flag)
639 1.1 cgd int u_flag;
640 1.4 mycroft {
641 1.1 cgd struct stat st;
642 1.4 mycroft
643 1.4 mycroft if ((fd = open(disk, u_flag ? O_RDWR : O_RDONLY)) == -1) {
644 1.4 mycroft warn("%s", disk);
645 1.4 mycroft return (-1);
646 1.4 mycroft }
647 1.4 mycroft if (fstat(fd, &st) == -1) {
648 1.4 mycroft close(fd);
649 1.4 mycroft warn("%s", disk);
650 1.1 cgd return (-1);
651 1.7 mycroft }
652 1.4 mycroft if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
653 1.7 mycroft close(fd);
654 1.4 mycroft warnx("%s is not a character device or regular file", disk);
655 1.1 cgd return (-1);
656 1.4 mycroft }
657 1.4 mycroft if (get_params() == -1) {
658 1.4 mycroft close(fd);
659 1.1 cgd return (-1);
660 1.4 mycroft }
661 1.1 cgd return (0);
662 1.1 cgd }
663 1.4 mycroft
664 1.1 cgd int
665 1.4 mycroft read_disk(sector, buf)
666 1.4 mycroft int sector;
667 1.1 cgd void *buf;
668 1.4 mycroft {
669 1.4 mycroft
670 1.4 mycroft if (lseek(fd, (off_t)(sector * 512), 0) == -1)
671 1.4 mycroft return (-1);
672 1.1 cgd return (read(fd, buf, 512));
673 1.1 cgd }
674 1.4 mycroft
675 1.1 cgd int
676 1.4 mycroft write_disk(sector, buf)
677 1.4 mycroft int sector;
678 1.1 cgd void *buf;
679 1.4 mycroft {
680 1.4 mycroft
681 1.4 mycroft if (lseek(fd, (off_t)(sector * 512), 0) == -1)
682 1.4 mycroft return (-1);
683 1.1 cgd return (write(fd, buf, 512));
684 1.1 cgd }
685 1.4 mycroft
686 1.4 mycroft int
687 1.1 cgd get_params()
688 1.1 cgd {
689 1.4 mycroft
690 1.4 mycroft if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
691 1.4 mycroft warn("DIOCGDINFO");
692 1.4 mycroft return (-1);
693 1.1 cgd }
694 1.5 mycroft
695 1.4 mycroft dos_cylinders = cylinders = disklabel.d_ncylinders;
696 1.4 mycroft dos_heads = heads = disklabel.d_ntracks;
697 1.5 mycroft dos_sectors = sectors = disklabel.d_nsectors;
698 1.5 mycroft dos_cylindersectors = cylindersectors = heads * sectors;
699 1.1 cgd disksectors = cylinders * heads * sectors;
700 1.4 mycroft
701 1.1 cgd return (0);
702 1.1 cgd }
703 1.4 mycroft
704 1.1 cgd int
705 1.1 cgd read_s0()
706 1.4 mycroft {
707 1.4 mycroft
708 1.4 mycroft if (read_disk(0, mboot.bootinst) == -1) {
709 1.4 mycroft warn("can't read fdisk partition table");
710 1.1 cgd return (-1);
711 1.12 thorpej }
712 1.12 thorpej if (getshort(&mboot.signature) != BOOT_MAGIC) {
713 1.4 mycroft warnx("invalid fdisk partition table found");
714 1.4 mycroft /* So should we initialize things? */
715 1.1 cgd return (-1);
716 1.4 mycroft }
717 1.1 cgd return (0);
718 1.1 cgd }
719 1.4 mycroft
720 1.1 cgd int
721 1.1 cgd write_s0()
722 1.4 mycroft {
723 1.4 mycroft int flag;
724 1.1 cgd
725 1.1 cgd /*
726 1.1 cgd * write enable label sector before write (if necessary),
727 1.1 cgd * disable after writing.
728 1.1 cgd * needed if the disklabel protected area also protects
729 1.1 cgd * sector 0. (e.g. empty disk)
730 1.1 cgd */
731 1.1 cgd flag = 1;
732 1.4 mycroft if (ioctl(fd, DIOCWLABEL, &flag) < 0)
733 1.4 mycroft warn("DIOCWLABEL");
734 1.4 mycroft if (write_disk(0, mboot.bootinst) == -1) {
735 1.1 cgd warn("can't write fdisk partition table");
736 1.4 mycroft return -1;
737 1.1 cgd }
738 1.4 mycroft flag = 0;
739 1.4 mycroft if (ioctl(fd, DIOCWLABEL, &flag) < 0)
740 1.1 cgd warn("DIOCWLABEL");
741 1.1 cgd }
742 1.4 mycroft
743 1.4 mycroft int
744 1.4 mycroft yesno(str)
745 1.4 mycroft char *str;
746 1.4 mycroft {
747 1.1 cgd int ch, first;
748 1.1 cgd
749 1.1 cgd printf("%s [n] ", str);
750 1.4 mycroft
751 1.4 mycroft first = ch = getchar();
752 1.4 mycroft while (ch != '\n' && ch != EOF)
753 1.4 mycroft ch = getchar();
754 1.1 cgd return (first == 'y' || first == 'Y');
755 1.1 cgd }
756 1.5 mycroft
757 1.5 mycroft void
758 1.4 mycroft decimal(str, num)
759 1.5 mycroft char *str;
760 1.1 cgd int *num;
761 1.8 cgd {
762 1.4 mycroft int acc = 0;
763 1.1 cgd char *cp;
764 1.5 mycroft
765 1.5 mycroft for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
766 1.1 cgd printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
767 1.1 cgd
768 1.7 mycroft fgets(lbuf, LBUF, stdin);
769 1.7 mycroft lbuf[strlen(lbuf)-1] = '\0';
770 1.7 mycroft cp = lbuf;
771 1.7 mycroft
772 1.7 mycroft cp += strspn(cp, " \t");
773 1.5 mycroft if (*cp == '\0')
774 1.1 cgd return;
775 1.7 mycroft
776 1.7 mycroft if (!isdigit(*cp))
777 1.5 mycroft continue;
778 1.7 mycroft acc = strtol(lbuf, &cp, 10);
779 1.5 mycroft
780 1.5 mycroft cp += strspn(cp, " \t");
781 1.5 mycroft if (*cp != '\0')
782 1.1 cgd continue;
783 1.5 mycroft
784 1.5 mycroft *num = acc;
785 1.1 cgd return;
786 1.1 cgd }
787 1.1 cgd
788 1.1 cgd }
789 1.4 mycroft
790 1.4 mycroft int
791 1.4 mycroft type_match(key, item)
792 1.4 mycroft const void *key, *item;
793 1.4 mycroft {
794 1.4 mycroft const int *typep = key;
795 1.4 mycroft const struct part_type *ptr = item;
796 1.4 mycroft
797 1.4 mycroft if (*typep < ptr->type)
798 1.4 mycroft return (-1);
799 1.4 mycroft if (*typep > ptr->type)
800 1.4 mycroft return (1);
801 1.4 mycroft return (0);
802 1.4 mycroft }
803 1.4 mycroft
804 1.4 mycroft char *
805 1.4 mycroft get_type(type)
806 1.4 mycroft int type;
807 1.4 mycroft {
808 1.4 mycroft struct part_type *ptr;
809 1.4 mycroft
810 1.4 mycroft ptr = bsearch(&type, part_types,
811 1.4 mycroft sizeof(part_types) / sizeof(struct part_type),
812 1.4 mycroft sizeof(struct part_type), type_match);
813 1.4 mycroft if (ptr == 0)
814 1.4 mycroft return ("unknown");
815 1.4 mycroft else
816 1.1 cgd return (ptr->name);
817 }
818