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