1 /**	$MirOS: src/sbin/fdisk/user.c,v 1.4 2006/09/20 20:03:31 tg Exp $	*/
2 /*	$OpenBSD: user.c,v 1.23 2006/07/27 04:06:13 ray Exp $	*/
3 
4 /*
5  * Copyright (c) 1997 Tobias Weingartner
6  * All rights reserved.
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 AUTHOR ``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 AUTHOR 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/types.h>
30 #include <sys/fcntl.h>
31 #include <sys/stat.h>
32 #include <sys/disklabel.h>
33 #include <machine/param.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <util.h>
37 #include <stdio.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include "user.h"
41 #include "disk.h"
42 #include "misc.h"
43 #include "mbr.h"
44 #include "cmd.h"
45 
46 __RCSID("$MirOS: src/sbin/fdisk/user.c,v 1.4 2006/09/20 20:03:31 tg Exp $");
47 
48 /* Our command table */
49 static cmd_table_t cmd_table[] = {
50 	{"help",   Xhelp,	"Command help list"},
51 	{"manual", Xmanual,	"Show entire OpenBSD man page for fdisk"},
52 	{"reinit", Xreinit,	"Re-initialize loaded MBR (to defaults)"},
53 	{"setpid", Xsetpid,	"Set the identifier of a given table entry"},
54 	{"disk",   Xdisk,	"Edit current drive stats"},
55 	{"edit",   Xedit,	"Edit given table entry"},
56 	{"flag",   Xflag,	"Flag given table entry as active"},
57 	{"fdef",   Xfdef,	"Flag as default (dangerous)"},
58 	{"update", Xupdate,	"Update machine boot code in loaded MBR"},
59 	{"umin",   Xumin,	"Update small portion of boot code only"},
60 	{"select", Xselect,	"Select extended partition table entry MBR"},
61 	{"swap",   Xswap,	"Swap two partition entries"},
62 	{"print",  Xprint,	"Print loaded MBR partition table"},
63 	{"write",  Xwrite,	"Write loaded MBR to disk"},
64 	{"exit",   Xexit,	"Exit edit of current MBR, without saving changes"},
65 	{"quit",   Xquit,	"Quit edit of current MBR, saving current changes"},
66 	{"abort",  Xabort,	"Abort program without saving current changes"},
67 	{NULL,     NULL,	NULL}
68 };
69 
70 
71 int
USER_init(disk_t * disk,mbr_t * tt,int preserve)72 USER_init(disk_t *disk, mbr_t *tt, int preserve)
73 {
74 	int fd, yn;
75 	char mbr_buf[DEV_BSIZE];
76 	char *msgp = "\nDo you wish to write new MBR?";
77 	char *msgk = "\nDo you wish to write new MBR and partition table?";
78 
79 	if (preserve)
80 		MBR_pcopy(disk, tt);
81 	else
82 		MBR_init(disk, tt);
83 
84 	/* Write sector 0 */
85 	printf("\a\n"
86 	   "\t-----------------------------------------------------\n"
87 	   "\t------ ATTENTION - UPDATING MASTER BOOT RECORD ------\n"
88 	   "\t-----------------------------------------------------\n");
89 	if (preserve)
90 		yn = ask_yn(msgp);
91 	else
92 		yn = ask_yn(msgk);
93 
94 	if (yn) {
95 		fd = DISK_open(disk->name, O_RDWR);
96 		MBR_make(tt, mbr_buf);
97 		if (MBR_write(fd, 0, mbr_buf) == -1) {
98 			int saved_errno = errno;
99 			DISK_close(fd);
100 			errno = saved_errno;
101 			return (-1);
102 		}
103 		DISK_close(fd);
104 	} else
105 		printf("MBR is unchanged\n");
106 
107 	return (0);
108 }
109 
110 int modified;
111 
112 int
USER_modify(disk_t * disk,mbr_t * tt,off_t offset,off_t reloff)113 USER_modify(disk_t *disk, mbr_t *tt, off_t offset, off_t reloff)
114 {
115 	static int editlevel;
116 	char mbr_buf[DEV_BSIZE];
117 	mbr_t mbr;
118 	cmd_t cmd;
119 	int i, st, fd;
120 
121 	/* One level deeper */
122 	editlevel += 1;
123 
124 	/* Set up command table pointer */
125 	cmd.table = cmd_table;
126 
127 	/* Read MBR & partition */
128 	fd = DISK_open(disk->name, O_RDONLY);
129 	MBR_read(fd, offset, mbr_buf);
130 	DISK_close(fd);
131 
132 	/* Parse the sucker */
133 	MBR_parse(disk, mbr_buf, offset, reloff, &mbr);
134 
135 	printf("Enter 'help' for information\n");
136 
137 	/* Edit cycle */
138 	do {
139 again:
140 		printf("fdisk:%c%d> ", (modified)?'*':' ', editlevel);
141 		fflush(stdout);
142 		ask_cmd(&cmd);
143 
144 		if (cmd.cmd[0] == '\0')
145 			goto again;
146 		for (i = 0; cmd_table[i].cmd != NULL; i++)
147 			if (strstr(cmd_table[i].cmd, cmd.cmd)==cmd_table[i].cmd)
148 				break;
149 
150 		/* Quick hack to put in '?' == 'help' */
151 		if (!strcmp(cmd.cmd, "?"))
152 			i = 0;
153 
154 		/* Check for valid command */
155 		if (cmd_table[i].cmd == NULL) {
156 			printf("Invalid command '%s'.  Try 'help'.\n", cmd.cmd);
157 			continue;
158 		} else
159 			strlcpy(cmd.cmd, cmd_table[i].cmd, sizeof cmd.cmd);
160 
161 		/* Call function */
162 		st = cmd_table[i].fcn(&cmd, disk, &mbr, tt, offset);
163 
164 		/* Update status */
165 		if (st == CMD_EXIT)
166 			break;
167 		if (st == CMD_SAVE)
168 			break;
169 		if (st == CMD_CLEAN)
170 			modified = 0;
171 		if (st == CMD_DIRTY)
172 			modified = 1;
173 	} while (1);
174 
175 	/* Write out MBR */
176 	if (modified) {
177 		if (st == CMD_SAVE) {
178 			printf("Writing current MBR to disk.\n");
179 			fd = DISK_open(disk->name, O_RDWR);
180 			MBR_make(&mbr, mbr_buf);
181 			if (MBR_write(fd, offset, mbr_buf) == -1) {
182 				warn("error writing MBR");
183 				close(fd);
184 				goto again;
185 			}
186 			close(fd);
187 		} else
188 			printf("Aborting changes to current MBR.\n");
189 	}
190 
191 	/* One level less */
192 	editlevel -= 1;
193 
194 	return (0);
195 }
196 
197 int
USER_print_disk(disk_t * disk)198 USER_print_disk(disk_t *disk)
199 {
200 	int fd, offset, firstoff, i;
201 	char mbr_buf[DEV_BSIZE];
202 	mbr_t mbr;
203 
204 	fd = DISK_open(disk->name, O_RDONLY);
205 	offset = firstoff = 0;
206 
207 	DISK_printmetrics(disk, NULL);
208 
209 	do {
210 		MBR_read(fd, (off_t)offset, mbr_buf);
211 		MBR_parse(disk, mbr_buf, offset, firstoff, &mbr);
212 
213 		printf("Offset: %d\t", (int)offset);
214 		MBR_print(&mbr, NULL);
215 
216 		/* Print out extended partitions too */
217 		for (offset = i = 0; i < 4; i++)
218 			if (mbr.part[i].id == DOSPTYP_EXTEND ||
219 			    mbr.part[i].id == DOSPTYP_EXTENDL ||
220 			    mbr.part[i].id == DOSPTYP_EXTENDLX) {
221 				offset = mbr.part[i].bs;
222 				if (firstoff == 0)
223 					firstoff = offset;
224 			}
225 	} while (offset);
226 
227 	return (DISK_close(fd));
228 }
229