xref: /openbsd-src/sbin/fdisk/cmd.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: cmd.c,v 1.69 2014/03/20 13:18:21 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 <sys/types.h>
29 #include <sys/fcntl.h>
30 #include <sys/disklabel.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <stdio.h>
34 #include <memory.h>
35 #include <stdlib.h>
36 #include <signal.h>
37 #include <unistd.h>
38 
39 #include "disk.h"
40 #include "misc.h"
41 #include "part.h"
42 #include "mbr.h"
43 #include "user.h"
44 #include "cmd.h"
45 
46 int
47 Xreinit(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
48     int offset)
49 {
50 	struct dos_mbr dos_mbr;
51 
52 	/* Copy template MBR */
53 	MBR_make(tt, &dos_mbr);
54 	MBR_parse(disk, &dos_mbr, 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, args);
62 	printf("Use 'write' to update disk.\n");
63 
64 	return (CMD_DIRTY);
65 }
66 
67 int
68 Xdisk(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
69     int offset)
70 {
71 	int maxcyl  = 1024;
72 	int maxhead = 256;
73 	int maxsec  = 63;
74 
75 	/* Print out disk info */
76 	DISK_printgeometry(disk, 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->cylinders = ask_num("BIOS Cylinders",
87 		    disk->cylinders, 1, maxcyl);
88 		disk->heads = ask_num("BIOS Heads",
89 		    disk->heads, 1, maxhead);
90 		disk->sectors = ask_num("BIOS Sectors",
91 		    disk->sectors, 1, maxsec);
92 
93 		disk->size = disk->cylinders * disk->heads * disk->sectors;
94 	}
95 
96 	return (CMD_CONT);
97 }
98 
99 int
100 Xswap(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
101     int offset)
102 {
103 	const char *errstr;
104 	char *from, *to;
105 	int pf, pt, ret;
106 	struct prt pp;
107 
108 	ret = CMD_CONT;
109 
110 	to = 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 = strtonum(from, 0, 3, &errstr);
119 	if (errstr) {
120 		printf("partition number is %s: %s\n", errstr, from);
121 		return (ret);
122 	}
123 	pt = 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 int
144 Xedit(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
145     int offset)
146 {
147 	const char *errstr;
148 	int pn, num, ret;
149 	struct prt *pp;
150 
151 	pn = strtonum(args, 0, 3, &errstr);
152 	if (errstr) {
153 		printf("partition number is %s: %s\n", errstr, args);
154 		return (CMD_CONT);
155 	}
156 	pp = &mbr->part[pn];
157 
158 	/* Edit partition type */
159 	ret = Xsetpid(args, 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->cylinders - 1;
179 		maxhead = disk->heads - 1;
180 		maxsect = disk->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->size);
196 		pp->ns = getuint(disk, "Partition size", pp->ns,
197 		    disk->size - pp->bs);
198 		/* Fix up CHS values */
199 		PRT_fix_CHS(disk, pp);
200 	}
201 #undef EDIT
202 	return (ret);
203 }
204 
205 int
206 Xsetpid(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
207     int offset)
208 {
209 	const char *errstr;
210 	int pn, num, ret;
211 	struct prt *pp;
212 
213 	ret = CMD_CONT;
214 
215 	pn = strtonum(args, 0, 3, &errstr);
216 	if (errstr) {
217 		printf("partition number is %s: %s\n", errstr, 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 int
237 Xselect(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
238     int offset)
239 {
240 	const char *errstr;
241 	static int firstoff = 0;
242 	int off;
243 	int pn;
244 
245 	pn = strtonum(args, 0, 3, &errstr);
246 	if (errstr) {
247 		printf("partition number is %s: %s\n", errstr, 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 int
277 Xprint(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
278     int offset)
279 {
280 
281 	DISK_printgeometry(disk, args);
282 	printf("Offset: %d\t", offset);
283 	MBR_print(mbr, args);
284 
285 	return (CMD_CONT);
286 }
287 
288 int
289 Xwrite(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
290     int offset)
291 {
292 	struct dos_mbr dos_mbr;
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, &dos_mbr);
306 
307 	printf("Writing MBR at offset %d.\n", offset);
308 	if (MBR_write(fd, offset, &dos_mbr) == -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, &dos_mbr, mbr->offset, mbr->reloffset, mbr);
319 
320 	return (CMD_CLEAN);
321 }
322 
323 int
324 Xquit(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
325     int offset)
326 {
327 
328 	/* Nothing to do here */
329 	return (CMD_SAVE);
330 }
331 
332 int
333 Xabort(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
334     int offset)
335 {
336 	exit(0);
337 
338 	/* NOTREACHED */
339 	return (CMD_CONT);
340 }
341 
342 
343 int
344 Xexit(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
345     int offset)
346 {
347 
348 	/* Nothing to do here */
349 	return (CMD_EXIT);
350 }
351 
352 int
353 Xhelp(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
354     int offset)
355 {
356 	int i;
357 
358 	for (i = 0; cmd_table[i].cmd != NULL; i++)
359 		printf("\t%s\t\t%s\n", cmd_table[i].cmd, cmd_table[i].help);
360 	return (CMD_CONT);
361 }
362 
363 int
364 Xupdate(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
365     int offset)
366 {
367 	/* Update code */
368 	memcpy(mbr->code, tt->code, sizeof(mbr->code));
369 	mbr->signature = DOSMBR_SIGNATURE;
370 	printf("Machine code updated.\n");
371 	return (CMD_DIRTY);
372 }
373 
374 int
375 Xflag(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
376     int offset)
377 {
378 	const char *errstr;
379 	int i, pn = -1, val = -1;
380 	char *part, *flag;
381 
382 	flag = args;
383 	part = strsep(&flag, " \t");
384 
385 	pn = strtonum(part, 0, 3, &errstr);
386 	if (errstr) {
387 		printf("partition number is %s: %s.\n", errstr, part);
388 		return (CMD_CONT);
389 	}
390 
391 	if (flag != NULL) {
392 		val = (int)strtonum(flag, 0, 0xff, &errstr);
393 		if (errstr) {
394 			printf("flag value is %s: %s.\n", errstr, flag);
395 			return (CMD_CONT);
396 		}
397 	}
398 
399 	if (val == -1) {
400 		/* Set active flag */
401 		for (i = 0; i < 4; i++) {
402 			if (i == pn)
403 				mbr->part[i].flag = DOSACTIVE;
404 			else
405 				mbr->part[i].flag = 0x00;
406 		}
407 		printf("Partition %d marked active.\n", pn);
408 	} else {
409 		mbr->part[pn].flag = val;
410 		printf("Partition %d flag value set to 0x%x.\n", pn, val);
411 	}
412 	return (CMD_DIRTY);
413 }
414 
415 int
416 Xmanual(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
417     int offset)
418 {
419 	char *pager = "/usr/bin/less";
420 	char *p;
421 	sig_t opipe;
422 	extern const unsigned char manpage[];
423 	extern const int manpage_sz;
424 	FILE *f;
425 
426 	opipe = signal(SIGPIPE, SIG_IGN);
427 	if ((p = getenv("PAGER")) != NULL && (*p != '\0'))
428 		pager = p;
429 	if (asprintf(&p, "gunzip -qc|%s", pager) != -1) {
430 		f = popen(p, "w");
431 		if (f) {
432 			fwrite(manpage, manpage_sz, 1, f);
433 			pclose(f);
434 		}
435 		free(p);
436 	}
437 
438 	signal(SIGPIPE, opipe);
439 	return (CMD_CONT);
440 }
441 
442