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