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