1/*
2 * Copyright (c) 2002 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 <err.h>
56#include <util.h>
57#include <stdio.h>
58#include <unistd.h>
59#include <string.h>
60#include <sys/fcntl.h>
61#include <sys/types.h>
62#include <sys/stat.h>
63#include <machine/param.h>
64#include "user.h"
65#include "disk.h"
66#include "misc.h"
67#include "mbr.h"
68#include "cmd.h"
69
70
71/* Our command table */
72static cmd_table_t cmd_table[] = {
73	{"help",   Xhelp,	"Command help list"},
74	{"manual", Xmanual,	"Show entire man page for fdisk"},
75	{"reinit", Xreinit,	"Re-initialize loaded MBR (to defaults)"},
76	{"auto",   Xauto,       "Auto-partition the disk with a partition style"},
77	{"setpid", Xsetpid,	"Set the identifier of a given table entry"},
78	{"disk",   Xdisk,	"Edit current drive stats"},
79	{"edit",   Xedit,	"Edit given table entry"},
80	{"erase",  Xerase,      "Erase current MBR"},
81	{"flag",   Xflag,	"Flag given table entry as bootable"},
82	{"update", Xupdate,	"Update machine code in loaded MBR"},
83	{"select", Xselect,	"Select extended partition table entry MBR"},
84	{"print",  Xprint,	"Print loaded MBR partition table"},
85	{"write",  Xwrite,	"Write loaded MBR to disk"},
86	{"exit",   Xexit,	"Exit edit of current MBR, without saving changes"},
87	{"quit",   Xquit,	"Quit edit of current MBR, saving current changes"},
88	{"abort",  Xabort,	"Abort program without saving current changes"},
89	{NULL,     NULL,	NULL}
90};
91
92
93int
94USER_write(disk, tt, preserve, force)
95	disk_t *disk;
96	mbr_t *tt;     /* Template MBR to write */
97	int preserve;  /* Preserve partition table and just write boot code */
98	int force;     /* Don't ask any questions */
99{
100	int fd, yn;
101	char *msgp = "\nDo you wish to write new MBR?";
102	char *msgk = "\nDo you wish to write new MBR and partition table?";
103
104	/* Write sector 0 */
105	if (force) {
106	  yn = 1;
107	} else {
108	  printf("\a\n"
109		 "\t-----------------------------------------------------\n"
110		 "\t------ ATTENTION - UPDATING MASTER BOOT RECORD ------\n"
111		 "\t-----------------------------------------------------\n");
112	  if (preserve)
113	    yn = ask_yn(msgp, 0);
114	  else
115	    yn = ask_yn(msgk, 0);
116	}
117
118	if (yn) {
119	  if (preserve) {
120	    int shared;
121	    /* Only write the first one, if there's more than one in an extended partition chain */
122	    /* Since we're updating boot code, we don't require exclusive access */
123	    fd = DISK_openshared(disk->name, O_RDWR, &shared);
124	    MBR_make(tt);
125	    MBR_write(disk, fd, tt);
126	    DISK_close(fd);
127	  } else {
128	    MBR_write_all(disk, tt);
129	  }
130	} else {
131	  printf("MBR is unchanged\n");
132	}
133
134	return (0);
135}
136
137
138int
139USER_modify(disk, tt, offset, reloff)
140	disk_t *disk;
141	mbr_t *tt;
142	off_t offset;
143	off_t reloff;
144{
145	static int editlevel;
146	mbr_t *mbr;
147	cmd_t cmd;
148	int i, st, fd;
149	int modified = 0;
150
151	/* One level deeper */
152	editlevel += 1;
153
154	/* Set up command table pointer */
155	cmd.table = cmd_table;
156
157	/* Read MBR & partition */
158	mbr = MBR_alloc(NULL);
159	fd = DISK_open(disk->name, O_RDONLY);
160	MBR_read(disk, fd, offset, mbr);
161	DISK_close(fd);
162
163	/* Parse the sucker */
164	MBR_parse(disk, offset, reloff, mbr);
165
166	if (mbr->signature != MBR_SIGNATURE) {
167	    int yn = ask_yn("The signature for this MBR is invalid.\nWould you like to initialize the partition table?", 1);
168	    if (yn) {
169	      strcpy(cmd.cmd, "erase");
170	      cmd.args[0] = '\0';
171	      st = Xerase(&cmd, disk, mbr, tt, offset);
172	      modified = 1;
173	    }
174	}
175
176	printf("Enter 'help' for information\n");
177
178	/* Edit cycle */
179	do {
180again:
181		printf("fdisk:%c%d> ", (modified)?'*':' ', editlevel);
182		fflush(stdout);
183		ask_cmd(&cmd);
184
185		if (cmd.cmd[0] == '\0')
186			goto again;
187		for (i = 0; cmd_table[i].cmd != NULL; i++)
188			if (strstr(cmd_table[i].cmd, cmd.cmd)==cmd_table[i].cmd)
189				break;
190
191		/* Quick hack to put in '?' == 'help' */
192		if (!strcmp(cmd.cmd, "?"))
193			i = 0;
194
195		/* Check for valid command */
196		if (cmd_table[i].cmd == NULL) {
197			printf("Invalid command '%s'.  Try 'help'.\n", cmd.cmd);
198			continue;
199		} else
200			strcpy(cmd.cmd, cmd_table[i].cmd);
201
202		/* Call function */
203		st = cmd_table[i].fcn(&cmd, disk, mbr, tt, offset);
204
205		/* Update status */
206		if (st == CMD_EXIT)
207			break;
208		if (st == CMD_SAVE)
209			break;
210		if (st == CMD_CLEAN)
211			modified = 0;
212		if (st == CMD_DIRTY)
213			modified = 1;
214	} while (1);
215
216	/* Write out MBR */
217	if (modified) {
218		if (st == CMD_SAVE) {
219		  	int shared = 0;
220			printf("Writing current MBR to disk.\n");
221			fd = DISK_openshared(disk->name, O_RDWR, &shared);
222			if(shared) {
223       			  if(!ask_yn("Device could not be accessed exclusively.\nA reboot will be needed for changes to take effect. OK?", 0)) {
224			    close(fd);
225			    goto again;
226			  }
227			}
228
229			MBR_make(mbr);
230			MBR_write(disk, fd, mbr);
231			close(fd);
232		} else {
233	                int yn = ask_yn("MBR was modified; really quit without saving?", 0);
234			if (yn) {
235				printf("Aborting changes to current MBR.\n");
236			} else {
237				goto again;
238			}
239		}
240	}
241
242	/* One level less */
243	editlevel -= 1;
244
245	MBR_free(mbr);
246
247	return (0);
248}
249
250int
251USER_print_disk(disk, do_dump)
252	disk_t *disk;
253	int do_dump;
254{
255	int fd, offset, firstoff;
256	mbr_t *mbr;
257
258	fd = DISK_open(disk->name, O_RDONLY);
259	offset = firstoff = 0;
260
261	if (!do_dump)
262	  DISK_printmetrics(disk);
263
264	mbr = MBR_read_all(disk);
265	if (do_dump)
266	  MBR_dump_all(mbr);
267	else
268	  MBR_print_all(mbr);
269	MBR_free(mbr);
270
271	return (DISK_close(fd));
272}
273
274
275
276