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