1/*
2 * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25/*
26 * Copyright (c) 1997 Tobias Weingartner
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 *    notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 *    notice, this list of conditions and the following disclaimer in the
36 *    documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 *    must display the following acknowledgement:
39 *    This product includes software developed by Tobias Weingartner.
40 * 4. The name of the author may not be used to endorse or promote products
41 *    derived from this software without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
44 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
45 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
46 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
47 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
48 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
52 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 */
54
55#include <stdio.h>
56#include <ctype.h>
57#include <memory.h>
58#include <stdlib.h>
59#include <unistd.h>
60#include <signal.h>
61#include <sys/fcntl.h>
62#include "disk.h"
63#include "misc.h"
64#include "user.h"
65#include "part.h"
66#include "cmd.h"
67#include "auto.h"
68#define MAX(a, b) ((a) >= (b) ? (a) : (b))
69
70int
71Xerase(cmd, disk, mbr, tt, offset)
72	cmd_t *cmd;
73	disk_t *disk;
74	mbr_t *mbr;
75	mbr_t *tt;
76	int offset;
77{
78        bzero(mbr->part, sizeof(mbr->part));
79	mbr->signature = MBR_SIGNATURE;
80	return (CMD_DIRTY);
81}
82
83int
84Xreinit(cmd, disk, mbr, tt, offset)
85	cmd_t *cmd;
86	disk_t *disk;
87	mbr_t *mbr;
88	mbr_t *tt;
89	int offset;
90{
91	/* Copy template MBR */
92	MBR_make(tt);
93	MBR_parse(disk, offset, 0, mbr);
94
95	MBR_init(disk, mbr);
96
97	/* Tell em we did something */
98	printf("In memory copy is initialized to:\n");
99	printf("Offset: %d\t", offset);
100	MBR_print(mbr);
101	printf("Use 'write' to update disk.\n");
102
103	return (CMD_DIRTY);
104}
105
106int
107Xauto(cmd, disk, mbr, tt, offset)
108	cmd_t *cmd;
109	disk_t *disk;
110	mbr_t *mbr;
111	mbr_t *tt;
112	int offset;
113{
114	if (cmd->args[0] == '\0') {
115	    printf("usage: auto <style>\n");
116	    printf("  where style is one of:\n");
117	    AUTO_print_styles(stdout);
118	    return (CMD_CONT);
119	}
120
121        if (AUTO_init(disk, cmd->args, mbr) != AUTO_OK) {
122	    return (CMD_CONT);
123	}
124	MBR_make(mbr);
125	return (CMD_DIRTY);
126}
127
128int
129Xdisk(cmd, disk, mbr, tt, offset)
130	cmd_t *cmd;
131	disk_t *disk;
132	mbr_t *mbr;
133	mbr_t *tt;
134	int offset;
135{
136	int maxcyl  = 1024;
137	int maxhead = 256;
138	int maxsec  = 63;
139
140	/* Print out disk info */
141	DISK_printmetrics(disk);
142
143#if defined (__powerpc__) || defined (__mips__)
144	maxcyl  = 9999999;
145	maxhead = 9999999;
146	maxsec  = 9999999;
147#endif
148
149	/* Ask for new info */
150	if (ask_yn("Change disk geometry?", 0)) {
151		disk->real->cylinders = ask_num("BIOS Cylinders", ASK_DEC,
152		    disk->real->cylinders, 1, maxcyl, NULL);
153		disk->real->heads = ask_num("BIOS Heads", ASK_DEC,
154		    disk->real->heads, 1, maxhead, NULL);
155		disk->real->sectors = ask_num("BIOS Sectors", ASK_DEC,
156		    disk->real->sectors, 1, maxsec, NULL);
157
158		disk->real->size = disk->real->cylinders * disk->real->heads
159			* disk->real->sectors;
160	}
161
162	return (CMD_CONT);
163}
164
165int
166Xedit(cmd, disk, mbr, tt, offset)
167	cmd_t *cmd;
168	disk_t *disk;
169	mbr_t *mbr;
170	mbr_t *tt;
171	int offset;
172{
173	int pn, num, ret;
174	prt_t *pp;
175
176	ret = CMD_CONT;
177
178	if (!isdigit(cmd->args[0])) {
179		printf("Invalid argument: %s <partition number>\n", cmd->cmd);
180		return (ret);
181	}
182	pn = atoi(cmd->args) - 1;
183
184	if (pn < 0 || pn > 3) {
185		printf("Invalid partition number.\n");
186		return (ret);
187	}
188
189	/* Print out current table entry */
190	pp = &mbr->part[pn];
191	PRT_print(0, NULL);
192	PRT_print(pn, pp);
193
194#define	EDIT(p, f, v, n, m, h)				\
195	if ((num = ask_num(p, f, v, n, m, h)) != v)	\
196		ret = CMD_DIRTY;			\
197	v = num;
198
199	/* Ask for partition type */
200	EDIT("Partition id ('0' to disable) ", ASK_HEX, pp->id, 0, 0xFF, PRT_printall);
201
202	/* Unused, so just zero out */
203	if (pp->id == DOSPTYP_UNUSED) {
204		memset(pp, 0, sizeof(*pp));
205		printf("Partition %d is disabled.\n", pn + 1);
206		return (ret);
207	}
208
209	/* Change table entry */
210	if (ask_yn("Do you wish to edit in CHS mode?", 0)) {
211		int maxcyl, maxhead, maxsect;
212
213		/* Shorter */
214		maxcyl = disk->real->cylinders - 1;
215		maxhead = disk->real->heads - 1;
216		maxsect = disk->real->sectors;
217
218		/* Get data */
219		EDIT("BIOS Starting cylinder", ASK_DEC, pp->scyl,  0, maxcyl, NULL);
220		EDIT("BIOS Starting head",     ASK_DEC, pp->shead, 0, maxhead, NULL);
221		EDIT("BIOS Starting sector",   ASK_DEC, pp->ssect, 1, maxsect, NULL);
222		EDIT("BIOS Ending cylinder",   ASK_DEC, pp->ecyl,  0, maxcyl, NULL);
223		EDIT("BIOS Ending head",       ASK_DEC, pp->ehead, 0, maxhead, NULL);
224		EDIT("BIOS Ending sector",     ASK_DEC, pp->esect, 1, maxsect, NULL);
225		/* Fix up off/size values */
226		PRT_fix_BN(disk, pp, pn);
227		/* Fix up CHS values for LBA */
228		PRT_fix_CHS(disk, pp, pn);
229	} else {
230		u_int m;
231
232		if (pn == 0) {
233			pp->bs = 63 + offset;
234		} else {
235			if (mbr->part[pn-1].id != 0) {
236				pp->bs = mbr->part[pn-1].bs + mbr->part[pn-1].ns;
237			}
238		}
239		/* Get data */
240		EDIT("Partition offset", ASK_DEC, pp->bs, 0,
241		    disk->real->size, NULL);
242		m = MAX(pp->ns, disk->real->size - pp->bs);
243		if ( m > disk->real->size - pp->bs) {
244			/* dont have default value extend beyond end of disk */
245			m = disk->real->size - pp->bs;
246		}
247		pp->ns = m;
248		EDIT("Partition size", ASK_DEC, pp->ns, 1,
249		    m, NULL);
250
251		/* Fix up CHS values */
252		PRT_fix_CHS(disk, pp, pn);
253	}
254#undef EDIT
255	return (ret);
256}
257
258int
259Xsetpid(cmd, disk, mbr, tt, offset)
260	cmd_t *cmd;
261	disk_t *disk;
262	mbr_t *mbr;
263	mbr_t *tt;
264	int offset;
265{
266	int pn, num, ret;
267	prt_t *pp;
268
269	ret = CMD_CONT;
270
271	if (!isdigit(cmd->args[0])) {
272		printf("Invalid argument: %s <partition number>\n", cmd->cmd);
273		return (ret);
274	}
275	pn = atoi(cmd->args) - 1;
276
277	if (pn < 0 || pn > 3) {
278		printf("Invalid partition number.\n");
279		return (ret);
280	}
281
282	/* Print out current table entry */
283	pp = &mbr->part[pn];
284	PRT_print(0, NULL);
285	PRT_print(pn, pp);
286
287#define	EDIT(p, f, v, n, m, h)				\
288	if ((num = ask_num(p, f, v, n, m, h)) != v)	\
289		ret = CMD_DIRTY;			\
290	v = num;
291
292	/* Ask for partition type */
293	EDIT("Partition id ('0' to disable) ", ASK_HEX, pp->id, 0, 0xFF, PRT_printall);
294
295#undef EDIT
296	return (ret);
297}
298int
299Xselect(cmd, disk, mbr, tt, offset)
300	cmd_t *cmd;
301	disk_t *disk;
302	mbr_t *mbr;
303	mbr_t *tt;
304	int offset;
305{
306	static int firstoff = 0;
307	int off;
308	int pn;
309
310	if (!isdigit(cmd->args[0])) {
311		printf("Invalid argument: %s <partition number>\n", cmd->cmd);
312		return (CMD_CONT);
313	}
314
315	pn = atoi(cmd->args) - 1;
316	if (pn < 0 || pn > 3) {
317		printf("Invalid partition number.\n");
318		return (CMD_CONT);
319	}
320
321	off = mbr->part[pn].bs;
322
323	/* Sanity checks */
324	if ((mbr->part[pn].id != DOSPTYP_EXTEND) &&
325	    (mbr->part[pn].id != DOSPTYP_EXTENDL)) {
326		printf("Partition %d is not an extended partition.\n", pn + 1);
327		return (CMD_CONT);
328	}
329
330	if (firstoff == 0)
331		firstoff = off;
332
333	if (!off) {
334		printf("Loop to offset 0!  Not selected.\n");
335		return (CMD_CONT);
336	} else {
337		printf("Selected extended partition %d\n", pn + 1);
338		printf("New MBR at offset %d.\n", off);
339	}
340
341	/* Recursion is beautifull! */
342	USER_modify(disk, tt, off, firstoff);
343	return (CMD_CONT);
344}
345
346int
347Xprint(cmd, disk, mbr, tt, offset)
348	cmd_t *cmd;
349	disk_t *disk;
350	mbr_t *mbr;
351	mbr_t *tt;
352	int offset;
353{
354
355	DISK_printmetrics(disk);
356	printf("Offset: %d\t", offset);
357	MBR_print(mbr);
358
359	return (CMD_CONT);
360}
361
362int
363Xwrite(cmd, disk, mbr, tt, offset)
364	cmd_t *cmd;
365	disk_t *disk;
366	mbr_t *mbr;
367	mbr_t *tt;
368	int offset;
369{
370	int fd;
371	int shared = 0;
372
373	fd = DISK_openshared(disk->name, O_RDWR, &shared);
374	if(shared) {
375	  if(!ask_yn("Device could not be accessed exclusively.\nA reboot will be needed for changes to take effect. OK?", 0)) {
376	    close(fd);
377	    printf("MBR unchanged\n");
378	    return (CMD_CONT);
379	  }
380	}
381
382	printf("Writing MBR at offset %d.\n", offset);
383
384	MBR_make(mbr);
385	MBR_write(disk, fd, mbr);
386	close(fd);
387	return (CMD_CLEAN);
388}
389
390int
391Xquit(cmd, disk, r, tt, offset)
392	cmd_t *cmd;
393	disk_t *disk;
394	mbr_t *r;
395	mbr_t *tt;
396	int offset;
397{
398
399	/* Nothing to do here */
400	return (CMD_SAVE);
401}
402
403int
404Xabort(cmd, disk, mbr, tt, offset)
405	cmd_t *cmd;
406	disk_t *disk;
407	mbr_t *mbr;
408	mbr_t *tt;
409	int offset;
410{
411	exit(0);
412
413	/* NOTREACHED */
414	return (CMD_CONT);
415}
416
417
418int
419Xexit(cmd, disk, mbr, tt, offset)
420	cmd_t *cmd;
421	disk_t *disk;
422	mbr_t *mbr;
423	mbr_t *tt;
424	int offset;
425{
426
427	/* Nothing to do here */
428	return (CMD_EXIT);
429}
430
431int
432Xhelp(cmd, disk, mbr, tt, offset)
433	cmd_t *cmd;
434	disk_t *disk;
435	mbr_t *mbr;
436	mbr_t *tt;
437	int offset;
438{
439	cmd_table_t *cmd_table = cmd->table;
440	int i;
441
442	/* Hmm, print out cmd_table here... */
443	for (i = 0; cmd_table[i].cmd != NULL; i++)
444		printf("\t%s\t\t%s\n", cmd_table[i].cmd, cmd_table[i].help);
445	return (CMD_CONT);
446}
447
448int
449Xupdate(cmd, disk, mbr, tt, offset)
450	cmd_t *cmd;
451	disk_t *disk;
452	mbr_t *mbr;
453	mbr_t *tt;
454	int offset;
455{
456	extern char *mbr_binary;
457	/* Update code */
458	memcpy(mbr->code, mbr_binary, MBR_CODE_SIZE);
459	printf("Machine code updated.\n");
460	return (CMD_DIRTY);
461}
462
463int
464Xflag(cmd, disk, mbr, tt, offset)
465	cmd_t *cmd;
466	disk_t *disk;
467	mbr_t *mbr;
468	mbr_t *tt;
469	int offset;
470{
471	int i, pn = -1;
472
473	/* Parse partition table entry number */
474	if (!isdigit(cmd->args[0])) {
475		printf("Invalid argument: %s <partition number>\n", cmd->cmd);
476		return (CMD_CONT);
477	}
478	pn = atoi(cmd->args) - 1;
479
480	if (pn < 0 || pn > 3) {
481		printf("Invalid partition number.\n");
482		return (CMD_CONT);
483	}
484
485	/* Set active flag */
486	for (i = 0; i < 4; i++) {
487		if (i == pn)
488			mbr->part[i].flag = DOSACTIVE;
489		else
490			mbr->part[i].flag = 0x00;
491	}
492
493	printf("Partition %d marked active.\n", pn + 1);
494	return (CMD_DIRTY);
495}
496
497int
498Xmanual(cmd, disk, mbr, tt, offset)
499	cmd_t *cmd;
500	disk_t *disk;
501	mbr_t *mbr;
502	mbr_t *tt;
503	int offset;
504{
505	system("man 8 fdisk");
506	return (CMD_CONT);
507}
508