1 /** $MirOS: src/sbin/fdisk/cmd.c,v 1.7 2010/09/21 21:24:16 tg Exp $ */
2 /* $OpenBSD: cmd.c,v 1.42 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/param.h>
30 #include <sys/fcntl.h>
31 #include <sys/disklabel.h>
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <memory.h>
35 #include <stdbool.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <signal.h>
39 #include "disk.h"
40 #include "misc.h"
41 #include "user.h"
42 #include "part.h"
43 #include "cmd.h"
44
45 __RCSID("$MirOS: src/sbin/fdisk/cmd.c,v 1.7 2010/09/21 21:24:16 tg Exp $");
46
47 int
Xreinit(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)48 Xreinit(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
49 {
50 char buf[DEV_BSIZE];
51
52 /* Copy template MBR */
53 MBR_make(tt, buf);
54 MBR_parse(disk, buf, mbr->offset, mbr->reloffset, mbr);
55
56 MBR_init(disk, mbr);
57
58 /* Tell em we did something */
59 printf("In memory copy is initialized to:\n");
60 printf("Offset: %d\t", offset);
61 MBR_print(mbr, cmd->args);
62 printf("Use 'write' to update disk.\n");
63
64 return (CMD_DIRTY);
65 }
66
67 /* ARGSUSED */
68 int
Xdisk(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)69 Xdisk(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
70 {
71 int maxcyl = 1024;
72 int maxhead = 256;
73 int maxsec = 63;
74
75 /* Print out disk info */
76 DISK_printmetrics(disk, cmd->args);
77
78 #if defined (__powerpc__) || defined (__mips__)
79 maxcyl = 9999999;
80 maxhead = 9999999;
81 maxsec = 9999999;
82 #endif
83
84 /* Ask for new info */
85 if (ask_yn("Change disk geometry?")) {
86 disk->real->cylinders = ask_num("BIOS Cylinders", ASK_DEC,
87 disk->real->cylinders, 1, maxcyl, NULL);
88 disk->real->heads = ask_num("BIOS Heads", ASK_DEC,
89 disk->real->heads, 1, maxhead, NULL);
90 disk->real->sectors = ask_num("BIOS Sectors", ASK_DEC,
91 disk->real->sectors, 1, maxsec, NULL);
92
93 disk->real->size = disk->real->cylinders * disk->real->heads
94 * disk->real->sectors;
95 }
96 return (CMD_CONT);
97 }
98
99 /* ARGSUSED */
100 int
Xswap(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)101 Xswap(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
102 {
103 int pf, pt, ret;
104 prt_t pp;
105
106 ret = CMD_CONT;
107
108 if (!isdigit(cmd->args[0])) {
109 printf("Invalid argument: %s <from partition number>\n",
110 cmd->cmd);
111 return (ret);
112 }
113
114 pf = atoi(cmd->args);
115 if (pf < 0 || pf > 3) {
116 printf("Invalid partition number %d.\n", pf);
117 return (ret);
118 }
119
120 pt = ask_num("Swap with what partition?", ASK_DEC,
121 -1, 0, 3, NULL);
122 if (pt < 0 || pt > 3) {
123 printf("Invalid partition number %d.\n", pt);
124 return (ret);
125 }
126
127 if (pt == pf) {
128 printf("%d same partition as %d, doing nothing.\n", pt, pf);
129 return (ret);
130 }
131
132 pp = mbr->part[pt];
133 mbr->part[pt] = mbr->part[pf];
134 mbr->part[pf] = pp;
135
136 ret = CMD_DIRTY;
137 return (ret);
138 }
139
140
141 /* ARGSUSED */
142 int
Xedit(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)143 Xedit(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
144 {
145 int pn, num, ret;
146 prt_t *pp;
147
148 ret = CMD_CONT;
149
150 if (!isdigit(cmd->args[0])) {
151 printf("Invalid argument: %s <partition number>\n", cmd->cmd);
152 return (ret);
153 }
154 pn = atoi(cmd->args);
155
156 if (pn < 0 || pn > 3) {
157 printf("Invalid partition number.\n");
158 return (ret);
159 }
160 /* Print out current table entry */
161 pp = &mbr->part[pn];
162 PRT_print(0, NULL, NULL, 0);
163 PRT_print(pn, pp, NULL, mbr->code[MBR_FORCE_DEFPART]);
164
165 #define EDIT(p, f, v, n, m, h) \
166 if ((num = ask_num(p, f, v, n, m, h)) != v) \
167 ret = CMD_DIRTY; \
168 v = num;
169
170 /* Ask for partition type */
171 EDIT("Partition id ('0' to disable) ", ASK_HEX, pp->id, 0, 0xFF, PRT_printall);
172
173 /* Unused, so just zero out */
174 if (pp->id == DOSPTYP_UNUSED) {
175 memset(pp, 0, sizeof(*pp));
176 printf("Partition %d is disabled.\n", pn);
177 return (ret);
178 }
179 /* Change table entry */
180 if (ask_yn("Do you wish to edit in CHS mode?")) {
181 int maxcyl, maxhead, maxsect;
182
183 /* Shorter */
184 maxcyl = disk->real->cylinders - 1;
185 maxhead = disk->real->heads - 1;
186 maxsect = disk->real->sectors;
187
188 /* Get data */
189 EDIT("BIOS Starting cylinder", ASK_DEC, pp->scyl, 0, maxcyl, NULL);
190 EDIT("BIOS Starting head", ASK_DEC, pp->shead, 0, maxhead, NULL);
191 EDIT("BIOS Starting sector", ASK_DEC, pp->ssect, 1, maxsect, NULL);
192 EDIT("BIOS Ending cylinder", ASK_DEC, pp->ecyl, 0, maxcyl, NULL);
193 EDIT("BIOS Ending head", ASK_DEC, pp->ehead, 0, maxhead, NULL);
194 EDIT("BIOS Ending sector", ASK_DEC, pp->esect, 1, maxsect, NULL);
195 /* Fix up off/size values */
196 PRT_fix_BN(disk, pp, pn);
197 /* Fix up CHS values for LBA */
198 PRT_fix_CHS(disk, pp);
199 } else {
200 u_int m;
201
202 /* Get data */
203 pp->bs = getuint(disk, "offset",
204 "Starting sector for this partition.", pp->bs,
205 disk->real->size, 0, DO_CONVERSIONS |
206 (pp->id == FS_BSDFFS ? DO_ROUNDING : 0));
207
208 m = MAX(pp->ns, disk->real->size - pp->bs);
209 if (m > disk->real->size - pp->bs) {
210 /* dont have default value extend beyond end of disk */
211 m = disk->real->size - pp->bs;
212 }
213 pp->ns = getuint(disk, "size", "Size of the partition.",
214 pp->ns, m, pp->bs, DO_CONVERSIONS |
215 ((pp->id == FS_BSDFFS || pp->id == FS_SWAP) ?
216 DO_ROUNDING : 0));
217
218 /* Fix up CHS values */
219 PRT_fix_CHS(disk, pp);
220 }
221 #undef EDIT
222 return (ret);
223 }
224
225 /* ARGSUSED */
226 int
Xsetpid(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)227 Xsetpid(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
228 {
229 int pn, num, ret;
230 prt_t *pp;
231
232 ret = CMD_CONT;
233
234 if (!isdigit(cmd->args[0])) {
235 printf("Invalid argument: %s <partition number>\n", cmd->cmd);
236 return (ret);
237 }
238 pn = atoi(cmd->args);
239
240 if (pn < 0 || pn > 3) {
241 printf("Invalid partition number.\n");
242 return (ret);
243 }
244 /* Print out current table entry */
245 pp = &mbr->part[pn];
246 PRT_print(0, NULL, NULL, 0);
247 PRT_print(pn, pp, NULL, mbr->code[MBR_FORCE_DEFPART]);
248
249 #define EDIT(p, f, v, n, m, h) \
250 if ((num = ask_num(p, f, v, n, m, h)) != v) \
251 ret = CMD_DIRTY; \
252 v = num;
253
254 /* Ask for partition type */
255 EDIT("Partition id ('0' to disable) ", ASK_HEX, pp->id, 0, 0xFF, PRT_printall);
256
257 #undef EDIT
258 return (ret);
259 }
260
261 /* ARGSUSED */
262 int
Xselect(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)263 Xselect(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
264 {
265 static int firstoff = 0;
266 int off;
267 int pn;
268
269 if (!isdigit(cmd->args[0])) {
270 printf("Invalid argument: %s <partition number>\n", cmd->cmd);
271 return (CMD_CONT);
272 }
273 pn = atoi(cmd->args);
274 off = mbr->part[pn].bs;
275
276 /* Sanity checks */
277 if ((mbr->part[pn].id != DOSPTYP_EXTEND) &&
278 (mbr->part[pn].id != DOSPTYP_EXTENDL) &&
279 (mbr->part[pn].id != DOSPTYP_EXTENDLX)) {
280 printf("Partition %d is not an extended partition.\n", pn);
281 return (CMD_CONT);
282 }
283 if (firstoff == 0)
284 firstoff = off;
285
286 if (!off) {
287 printf("Loop to offset 0! Not selected.\n");
288 return (CMD_CONT);
289 } else {
290 printf("Selected extended partition %d\n", pn);
291 printf("New MBR at offset %d.\n", off);
292 }
293
294 /* Recursion is beautifull! */
295 USER_modify(disk, tt, off, firstoff);
296 return (CMD_CONT);
297 }
298
299 /* ARGSUSED */
300 int
Xprint(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)301 Xprint(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
302 {
303
304 DISK_printmetrics(disk, cmd->args);
305 printf("Offset: %d\t", offset);
306 MBR_print(mbr, cmd->args);
307
308 return (CMD_CONT);
309 }
310
311 /* ARGSUSED */
312 int
Xwrite(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)313 Xwrite(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
314 {
315 char mbr_buf[DEV_BSIZE];
316 int fd, ret;
317
318 ret = CMD_CONT;
319
320 printf("Writing MBR at offset %d.\n", offset);
321
322 fd = DISK_open(disk->name, O_RDWR);
323 MBR_make(mbr, mbr_buf);
324 if (MBR_write(fd, offset, mbr_buf) != -1)
325 ret = CMD_CLEAN;
326 close(fd);
327 return (ret);
328 }
329
330 /* ARGSUSED */
331 int
Xquit(cmd_t * cmd,disk_t * disk,mbr_t * r,mbr_t * tt,int offset)332 Xquit(cmd_t *cmd, disk_t *disk, mbr_t *r, mbr_t *tt, int offset)
333 {
334 /* Nothing to do here */
335 return (CMD_SAVE);
336 }
337
338 /* ARGSUSED */
339 int
Xabort(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)340 Xabort(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
341 {
342 exit(0);
343
344 /* NOTREACHED */
345 return (CMD_CONT);
346 }
347
348
349 /* ARGSUSED */
350 int
Xexit(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)351 Xexit(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
352 {
353
354 /* Nothing to do here */
355 return (CMD_EXIT);
356 }
357
358 /* ARGSUSED */
359 int
Xhelp(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)360 Xhelp(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
361 {
362 cmd_table_t *cmd_table = cmd->table;
363 int i;
364
365 /* Hmm, print out cmd_table here... */
366 for (i = 0; cmd_table[i].cmd != NULL; i++)
367 printf("\t%s\t\t%s\n", cmd_table[i].cmd, cmd_table[i].help);
368 return (CMD_CONT);
369 }
370
371 /* ARGSUSED */
372 int
Xupdate(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)373 Xupdate(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
374 {
375 bool disksig_r = false;
376 uint32_t disksig_val;
377
378 if ((tt->code[MBR_FORCE_DEFPART] == 0xFF) &&
379 (tt->code[MBR_DISKSIG_OFF + 0] == 0x00) &&
380 (tt->code[MBR_DISKSIG_OFF + 1] == 0x00) &&
381 (tt->code[MBR_DISKSIG_OFF + 2] == 0x00) &&
382 (tt->code[MBR_DISKSIG_OFF + 3] == 0x00)) {
383 disksig_r = true;
384 arc4random_pushb_fast(mbr, sizeof(mbr_t));
385 disksig_val = arc4random();
386 }
387 /* Update code */
388 memcpy(mbr->code, tt->code, MBR_CODE_SIZE);
389 mbr->signature = DOSMBR_SIGNATURE;
390 printf("Full machine boot code updated.\n");
391 if (disksig_r) {
392 memcpy(&mbr->code[MBR_DISKSIG_OFF], &disksig_val, 4);
393 printf("Disk Signature randomised.\n");
394 } else
395 printf("Disk Signature possibly touched.\n");
396 return (CMD_DIRTY);
397 }
398
399 int
Xumin(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)400 Xumin(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
401 {
402 /* Update code */
403 memcpy(mbr->code, tt->code, MBR_SMALLCODE_SIZE);
404 mbr->signature = DOSMBR_SIGNATURE;
405 printf("First portion of machine boot code updated.\n");
406 return (CMD_DIRTY);
407 }
408
409 int
Xfdef(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)410 Xfdef(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
411 {
412 int pn = -1;
413
414 /* Parse partition table entry number */
415 if (!isdigit(cmd->args[0])) {
416 printf("Invalid argument: %s <partition number>\n", cmd->cmd);
417 printf("To disable, use %s 9\n", cmd->cmd);
418 return (CMD_CONT);
419 }
420 pn = atoi(cmd->args);
421
422 if ((pn < 0 || pn > 3) && (pn != 9)) {
423 printf("Invalid partition number.\n");
424 return (CMD_CONT);
425 }
426 mbr->code[MBR_FORCE_DEFPART] = pn;
427
428 if (pn == 9)
429 printf("Forced default partition disabled.\n");
430 else
431 printf("Forcing partition %d default.\n", pn);
432 return (CMD_DIRTY);
433 }
434
435 /* ARGSUSED */
436 int
Xflag(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)437 Xflag(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
438 {
439 int i, pn = -1, val = -1;
440 char *p;
441
442 /* Parse partition table entry number */
443 if (!isdigit(cmd->args[0])) {
444 printf("Invalid argument: %s <partition number> [value]\n",
445 cmd->cmd);
446 return (CMD_CONT);
447 }
448 pn = atoi(cmd->args);
449 p = strchr(cmd->args, ' ');
450 if (p != NULL)
451 val = strtol(p + 1, NULL, 0) & 0xff;
452
453 if (pn < 0 || pn > 3) {
454 printf("Invalid partition number.\n");
455 return (CMD_CONT);
456 }
457
458 if (val == -1) {
459 /* Set active flag */
460 for (i = 0; i < 4; i++) {
461 if (i == pn)
462 mbr->part[i].flag = 0x80;
463 else
464 mbr->part[i].flag = 0x00;
465 }
466 printf("Partition %d marked active.\n", pn);
467 } else {
468 mbr->part[pn].flag = val;
469 printf("Partition %d flag value set to 0x%x.\n", pn, val);
470 }
471 return (CMD_DIRTY);
472 }
473
474 /* ARGSUSED */
475 int
Xmanual(cmd_t * cmd,disk_t * disk,mbr_t * mbr,mbr_t * tt,int offset)476 Xmanual(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
477 {
478 const char *pager = "/usr/bin/less";
479 char *p;
480 sig_t opipe;
481 extern const unsigned char manpage[];
482 FILE *f;
483
484 opipe = signal(SIGPIPE, SIG_IGN);
485 if ((p = getenv("PAGER")) != NULL && (*p != '\0'))
486 pager = p;
487 f = popen(pager, "w");
488 if (f) {
489 fwrite(manpage, strlen(manpage), 1, f);
490 pclose(f);
491 }
492 signal(SIGPIPE, opipe);
493 return (CMD_CONT);
494 }
495