xref: /openbsd-src/sbin/fdisk/cmd.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: cmd.c,v 1.43 2009/02/08 18:03:18 krw Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 Tobias Weingartner
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <err.h>
29 #include <errno.h>
30 #include <stdio.h>
31 #include <ctype.h>
32 #include <memory.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <signal.h>
36 #include <sys/fcntl.h>
37 #include <sys/disklabel.h>
38 #include "disk.h"
39 #include "misc.h"
40 #include "user.h"
41 #include "part.h"
42 #include "cmd.h"
43 #define MAX(a, b) ((a) >= (b) ? (a) : (b))
44 
45 int
46 Xreinit(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
47 {
48 	char buf[DEV_BSIZE];
49 
50 	/* Copy template MBR */
51 	MBR_make(tt, buf);
52 	MBR_parse(disk, buf, mbr->offset, mbr->reloffset, mbr);
53 
54 	MBR_init(disk, mbr);
55 
56 	/* Tell em we did something */
57 	printf("In memory copy is initialized to:\n");
58 	printf("Offset: %d\t", offset);
59 	MBR_print(mbr, cmd->args);
60 	printf("Use 'write' to update disk.\n");
61 
62 	return (CMD_DIRTY);
63 }
64 
65 /* ARGSUSED */
66 int
67 Xdisk(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
68 {
69 	int maxcyl  = 1024;
70 	int maxhead = 256;
71 	int maxsec  = 63;
72 
73 	/* Print out disk info */
74 	DISK_printmetrics(disk, cmd->args);
75 
76 #if defined (__powerpc__) || defined (__mips__)
77 	maxcyl  = 9999999;
78 	maxhead = 9999999;
79 	maxsec  = 9999999;
80 #endif
81 
82 	/* Ask for new info */
83 	if (ask_yn("Change disk geometry?")) {
84 		disk->real->cylinders = ask_num("BIOS Cylinders", ASK_DEC,
85 		    disk->real->cylinders, 1, maxcyl, NULL);
86 		disk->real->heads = ask_num("BIOS Heads", ASK_DEC,
87 		    disk->real->heads, 1, maxhead, NULL);
88 		disk->real->sectors = ask_num("BIOS Sectors", ASK_DEC,
89 		    disk->real->sectors, 1, maxsec, NULL);
90 
91 		disk->real->size = disk->real->cylinders * disk->real->heads
92 			* disk->real->sectors;
93 	}
94 
95 	return (CMD_CONT);
96 }
97 
98 /* ARGSUSED */
99 int
100 Xswap(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
101 {
102 	int pf, pt, ret;
103 	prt_t pp;
104 
105 	ret = CMD_CONT;
106 
107 	if (!isdigit(cmd->args[0])) {
108 		printf("Invalid argument: %s <from partition number>\n",
109 		    cmd->cmd);
110 		return (ret);
111 	}
112 
113 	pf = atoi(cmd->args);
114 	if (pf < 0 || pf > 3) {
115 		printf("Invalid partition number %d.\n", pf);
116 		return (ret);
117 	}
118 
119 	pt = ask_num("Swap with what partition?", ASK_DEC,
120 	    -1, 0, 3, NULL);
121 	if (pt < 0 || pt > 3) {
122 		printf("Invalid partition number %d.\n", pt);
123 		return (ret);
124 	}
125 
126 	if (pt == pf) {
127 		printf("%d same partition as %d, doing nothing.\n", pt, pf);
128 		return (ret);
129 	}
130 
131 	pp = mbr->part[pt];
132 	mbr->part[pt] = mbr->part[pf];
133 	mbr->part[pf] = pp;
134 
135 	ret = CMD_DIRTY;
136 	return (ret);
137 }
138 
139 
140 /* ARGSUSED */
141 int
142 Xedit(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
143 {
144 	int pn, num, ret;
145 	prt_t *pp;
146 
147 	ret = CMD_CONT;
148 
149 	if (!isdigit(cmd->args[0])) {
150 		printf("Invalid argument: %s <partition number>\n", cmd->cmd);
151 		return (ret);
152 	}
153 	pn = atoi(cmd->args);
154 
155 	if (pn < 0 || pn > 3) {
156 		printf("Invalid partition number.\n");
157 		return (ret);
158 	}
159 
160 	/* Print out current table entry */
161 	pp = &mbr->part[pn];
162 	PRT_print(0, NULL, NULL);
163 	PRT_print(pn, pp, NULL);
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 
180 	/* Change table entry */
181 	if (ask_yn("Do you wish to edit in CHS mode?")) {
182 		int maxcyl, maxhead, maxsect;
183 
184 		/* Shorter */
185 		maxcyl = disk->real->cylinders - 1;
186 		maxhead = disk->real->heads - 1;
187 		maxsect = disk->real->sectors;
188 
189 		/* Get data */
190 		EDIT("BIOS Starting cylinder", ASK_DEC, pp->scyl,  0, maxcyl, NULL);
191 		EDIT("BIOS Starting head",     ASK_DEC, pp->shead, 0, maxhead, NULL);
192 		EDIT("BIOS Starting sector",   ASK_DEC, pp->ssect, 1, maxsect, NULL);
193 		EDIT("BIOS Ending cylinder",   ASK_DEC, pp->ecyl,  0, maxcyl, NULL);
194 		EDIT("BIOS Ending head",       ASK_DEC, pp->ehead, 0, maxhead, NULL);
195 		EDIT("BIOS Ending sector",     ASK_DEC, pp->esect, 1, maxsect, NULL);
196 		/* Fix up off/size values */
197 		PRT_fix_BN(disk, pp, pn);
198 		/* Fix up CHS values for LBA */
199 		PRT_fix_CHS(disk, pp);
200 	} else {
201 		u_int m;
202 
203 		/* Get data */
204 		pp->bs = getuint(disk, "offset",
205 		   "Starting sector for this partition.", pp->bs,
206 		   disk->real->size, 0, DO_CONVERSIONS |
207 		   (pp->id == FS_BSDFFS ? DO_ROUNDING : 0));
208 
209 		m = MAX(pp->ns, disk->real->size - pp->bs);
210 		if ( m > disk->real->size - pp->bs) {
211 			/* dont have default value extend beyond end of disk */
212 			m = disk->real->size - pp->bs;
213 		}
214 		pp->ns = getuint(disk, "size", "Size of the partition.",
215 		    pp->ns, m, pp->bs , DO_CONVERSIONS |
216 		    ((pp->id == FS_BSDFFS || pp->id == FS_SWAP) ?
217 		    DO_ROUNDING : 0));
218 
219 		/* Fix up CHS values */
220 		PRT_fix_CHS(disk, pp);
221 	}
222 #undef EDIT
223 	return (ret);
224 }
225 
226 /* ARGSUSED */
227 int
228 Xsetpid(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
229 {
230 	int pn, num, ret;
231 	prt_t *pp;
232 
233 	ret = CMD_CONT;
234 
235 	if (!isdigit(cmd->args[0])) {
236 		printf("Invalid argument: %s <partition number>\n", cmd->cmd);
237 		return (ret);
238 	}
239 	pn = atoi(cmd->args);
240 
241 	if (pn < 0 || pn > 3) {
242 		printf("Invalid partition number.\n");
243 		return (ret);
244 	}
245 
246 	/* Print out current table entry */
247 	pp = &mbr->part[pn];
248 	PRT_print(0, NULL, NULL);
249 	PRT_print(pn, pp, NULL);
250 
251 #define	EDIT(p, f, v, n, m, h)				\
252 	if ((num = ask_num(p, f, v, n, m, h)) != v)	\
253 		ret = CMD_DIRTY;			\
254 	v = num;
255 
256 	/* Ask for partition type */
257 	EDIT("Partition id ('0' to disable) ", ASK_HEX, pp->id, 0, 0xFF, PRT_printall);
258 
259 #undef EDIT
260 	return (ret);
261 }
262 
263 /* ARGSUSED */
264 int
265 Xselect(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
266 {
267 	static int firstoff = 0;
268 	int off;
269 	int pn;
270 
271 	if (!isdigit(cmd->args[0])) {
272 		printf("Invalid argument: %s <partition number>\n", cmd->cmd);
273 		return (CMD_CONT);
274 	}
275 
276 	pn = atoi(cmd->args);
277 	off = mbr->part[pn].bs;
278 
279 	/* Sanity checks */
280 	if ((mbr->part[pn].id != DOSPTYP_EXTEND) &&
281 	    (mbr->part[pn].id != DOSPTYP_EXTENDL)) {
282 		printf("Partition %d is not an extended partition.\n", pn);
283 		return (CMD_CONT);
284 	}
285 
286 	if (firstoff == 0)
287 		firstoff = off;
288 
289 	if (!off) {
290 		printf("Loop to offset 0!  Not selected.\n");
291 		return (CMD_CONT);
292 	} else {
293 		printf("Selected extended partition %d\n", pn);
294 		printf("New MBR at offset %d.\n", off);
295 	}
296 
297 	/* Recursion is beautifull! */
298 	USER_modify(disk, tt, off, firstoff);
299 	return (CMD_CONT);
300 }
301 
302 /* ARGSUSED */
303 int
304 Xprint(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
305 {
306 
307 	DISK_printmetrics(disk, cmd->args);
308 	printf("Offset: %d\t", offset);
309 	MBR_print(mbr, cmd->args);
310 
311 	return (CMD_CONT);
312 }
313 
314 /* ARGSUSED */
315 int
316 Xwrite(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
317 {
318 	char mbr_buf[DEV_BSIZE];
319 	int fd;
320 
321 	fd = DISK_open(disk->name, O_RDWR);
322 	MBR_make(mbr, mbr_buf);
323 
324 	printf("Writing MBR at offset %d.\n", offset);
325 	if (MBR_write(fd, offset, mbr_buf) == -1) {
326 		int saved_errno = errno;
327 		warn("error writing MBR");
328 		close(fd);
329 		errno = saved_errno;
330 		return (CMD_CONT);
331 	}
332 	close(fd);
333 
334 	return (CMD_CLEAN);
335 }
336 
337 /* ARGSUSED */
338 int
339 Xquit(cmd, disk, r, tt, offset)
340 	cmd_t *cmd;
341 	disk_t *disk;
342 	mbr_t *r;
343 	mbr_t *tt;
344 	int offset;
345 {
346 
347 	/* Nothing to do here */
348 	return (CMD_SAVE);
349 }
350 
351 /* ARGSUSED */
352 int
353 Xabort(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
354 {
355 	exit(0);
356 
357 	/* NOTREACHED */
358 	return (CMD_CONT);
359 }
360 
361 
362 /* ARGSUSED */
363 int
364 Xexit(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
365 {
366 
367 	/* Nothing to do here */
368 	return (CMD_EXIT);
369 }
370 
371 /* ARGSUSED */
372 int
373 Xhelp(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
374 {
375 	cmd_table_t *cmd_table = cmd->table;
376 	int i;
377 
378 	/* Hmm, print out cmd_table here... */
379 	for (i = 0; cmd_table[i].cmd != NULL; i++)
380 		printf("\t%s\t\t%s\n", cmd_table[i].cmd, cmd_table[i].help);
381 	return (CMD_CONT);
382 }
383 
384 /* ARGSUSED */
385 int
386 Xupdate(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
387 {
388 
389 	/* Update code */
390 	memcpy(mbr->code, tt->code, MBR_CODE_SIZE);
391 	mbr->signature = DOSMBR_SIGNATURE;
392 	printf("Machine code updated.\n");
393 	return (CMD_DIRTY);
394 }
395 
396 /* ARGSUSED */
397 int
398 Xflag(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
399 {
400 	int i, pn = -1, val = -1;
401 	char *p;
402 
403 	/* Parse partition table entry number */
404 	if (!isdigit(cmd->args[0])) {
405 		printf("Invalid argument: %s <partition number> [value]\n",
406 		    cmd->cmd);
407 		return (CMD_CONT);
408 	}
409 	pn = atoi(cmd->args);
410 	p = strchr(cmd->args, ' ');
411 	if (p != NULL)
412 		val = strtol(p + 1, NULL, 0) & 0xff;
413 
414 	if (pn < 0 || pn > 3) {
415 		printf("Invalid partition number.\n");
416 		return (CMD_CONT);
417 	}
418 
419 	if (val == -1) {
420 		/* Set active flag */
421 		for (i = 0; i < 4; i++) {
422 			if (i == pn)
423 				mbr->part[i].flag = DOSACTIVE;
424 			else
425 				mbr->part[i].flag = 0x00;
426 		}
427 		printf("Partition %d marked active.\n", pn);
428 	} else {
429 		mbr->part[pn].flag = val;
430 		printf("Partition %d flag value set to 0x%x.\n", pn, val);
431 	}
432 	return (CMD_DIRTY);
433 }
434 
435 /* ARGSUSED */
436 int
437 Xmanual(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
438 {
439 	char *pager = "/usr/bin/less";
440 	char *p;
441 	sig_t opipe;
442 	extern const unsigned char manpage[];
443 	extern const int manpage_sz;
444 	FILE *f;
445 
446 	opipe = signal(SIGPIPE, SIG_IGN);
447 	if ((p = getenv("PAGER")) != NULL && (*p != '\0'))
448 		pager = p;
449 	if (asprintf(&p, "gunzip -qc|%s", pager) != -1) {
450 		f = popen(p, "w");
451 		if (f) {
452 			(void) fwrite(manpage, manpage_sz, 1, f);
453 			pclose(f);
454 		}
455 		free(p);
456 	}
457 
458 	(void)signal(SIGPIPE, opipe);
459 	return (CMD_CONT);
460 }
461 
462