xref: /openbsd-src/sbin/fdisk/cmd.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: cmd.c,v 1.71 2014/03/31 23:04:03 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;
106 	struct prt pp;
107 
108 	to = args;
109 	from = strsep(&to, " \t");
110 
111 	if (to == NULL) {
112 		printf("partition number is invalid:\n");
113 		return (CMD_CONT);
114 	}
115 
116 	pf = strtonum(from, 0, 3, &errstr);
117 	if (errstr) {
118 		printf("partition number is %s: %s\n", errstr, from);
119 		return (CMD_CONT);
120 	}
121 	pt = strtonum(to, 0, 3, &errstr);
122 	if (errstr) {
123 		printf("partition number is %s: %s\n", errstr, to);
124 		return (CMD_CONT);
125 	}
126 
127 	if (pt == pf) {
128 		printf("%d same partition as %d, doing nothing.\n", pt, pf);
129 		return (CMD_CONT);
130 	}
131 
132 	pp = mbr->part[pt];
133 	mbr->part[pt] = mbr->part[pf];
134 	mbr->part[pf] = pp;
135 
136 	return (CMD_DIRTY);
137 }
138 
139 int
140 Xedit(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
141     int offset)
142 {
143 	const char *errstr;
144 	int pn, num, ret;
145 	struct prt *pp;
146 
147 	pn = strtonum(args, 0, 3, &errstr);
148 	if (errstr) {
149 		printf("partition number is %s: %s\n", errstr, args);
150 		return (CMD_CONT);
151 	}
152 	pp = &mbr->part[pn];
153 
154 	/* Edit partition type */
155 	ret = Xsetpid(args, disk, mbr, tt, offset);
156 
157 #define	EDIT(p, v, n, m)					\
158 	if ((num = ask_num(p, v, n, m)) != v)	\
159 		ret = CMD_DIRTY;				\
160 	v = num;
161 
162 	/* Unused, so just zero out */
163 	if (pp->id == DOSPTYP_UNUSED) {
164 		memset(pp, 0, sizeof(*pp));
165 		printf("Partition %d is disabled.\n", pn);
166 		return (ret);
167 	}
168 
169 	/* Change table entry */
170 	if (ask_yn("Do you wish to edit in CHS mode?")) {
171 		int maxcyl, maxhead, maxsect;
172 
173 		/* Shorter */
174 		maxcyl = disk->cylinders - 1;
175 		maxhead = disk->heads - 1;
176 		maxsect = disk->sectors;
177 
178 		/* Get data */
179 		EDIT("BIOS Starting cylinder", pp->scyl,  0, maxcyl);
180 		EDIT("BIOS Starting head",     pp->shead, 0, maxhead);
181 		EDIT("BIOS Starting sector",   pp->ssect, 1, maxsect);
182 		EDIT("BIOS Ending cylinder",   pp->ecyl,  0, maxcyl);
183 		EDIT("BIOS Ending head",       pp->ehead, 0, maxhead);
184 		EDIT("BIOS Ending sector",     pp->esect, 1, maxsect);
185 		/* Fix up off/size values */
186 		PRT_fix_BN(disk, pp, pn);
187 		/* Fix up CHS values for LBA */
188 		PRT_fix_CHS(disk, pp);
189 	} else {
190 		pp->bs = getuint(disk, "Partition offset", pp->bs,
191 		    disk->size);
192 		pp->ns = getuint(disk, "Partition size", pp->ns,
193 		    disk->size - pp->bs);
194 		/* Fix up CHS values */
195 		PRT_fix_CHS(disk, pp);
196 	}
197 #undef EDIT
198 	return (ret);
199 }
200 
201 int
202 Xsetpid(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
203     int offset)
204 {
205 	const char *errstr;
206 	int pn, num;
207 	struct prt *pp;
208 
209 	pn = strtonum(args, 0, 3, &errstr);
210 	if (errstr) {
211 		printf("partition number is %s: %s\n", errstr, args);
212 		return (CMD_CONT);
213 	}
214 	pp = &mbr->part[pn];
215 
216 	/* Print out current table entry */
217 	PRT_print(0, NULL, NULL);
218 	PRT_print(pn, pp, NULL);
219 
220 	/* Ask for partition type */
221 	num = ask_pid(pp->id);
222 	if (num == pp->id)
223 		return (CMD_CONT);
224 
225 	pp->id = num;
226 	return (CMD_DIRTY);
227 }
228 
229 int
230 Xselect(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
231     int offset)
232 {
233 	const char *errstr;
234 	static int firstoff = 0;
235 	int off;
236 	int pn;
237 
238 	pn = strtonum(args, 0, 3, &errstr);
239 	if (errstr) {
240 		printf("partition number is %s: %s\n", errstr, args);
241 		return (CMD_CONT);
242 	}
243 
244 	off = mbr->part[pn].bs;
245 
246 	/* Sanity checks */
247 	if ((mbr->part[pn].id != DOSPTYP_EXTEND) &&
248 	    (mbr->part[pn].id != DOSPTYP_EXTENDL)) {
249 		printf("Partition %d is not an extended partition.\n", pn);
250 		return (CMD_CONT);
251 	}
252 
253 	if (firstoff == 0)
254 		firstoff = off;
255 
256 	if (!off) {
257 		printf("Loop to offset 0!  Not selected.\n");
258 		return (CMD_CONT);
259 	} else {
260 		printf("Selected extended partition %d\n", pn);
261 		printf("New MBR at offset %d.\n", off);
262 	}
263 
264 	/* Recursion is beautiful! */
265 	USER_modify(disk, tt, off, firstoff);
266 	return (CMD_CONT);
267 }
268 
269 int
270 Xprint(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
271     int offset)
272 {
273 
274 	DISK_printgeometry(disk, args);
275 	printf("Offset: %d\t", offset);
276 	MBR_print(mbr, args);
277 
278 	return (CMD_CONT);
279 }
280 
281 int
282 Xwrite(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
283     int offset)
284 {
285 	struct dos_mbr dos_mbr;
286 	int fd, i, n;
287 
288 	for (i = 0, n = 0; i < NDOSPART; i++)
289 		if (mbr->part[i].id == 0xA6)
290 			n++;
291 	if (n >= 2) {
292 		warnx("MBR contains more than one OpenBSD partition!");
293 		if (!ask_yn("Write MBR anyway?"))
294 			return (CMD_CONT);
295 	}
296 
297 	fd = DISK_open(disk->name, O_RDWR);
298 	MBR_make(mbr, &dos_mbr);
299 
300 	printf("Writing MBR at offset %d.\n", offset);
301 	if (MBR_write(fd, offset, &dos_mbr) == -1) {
302 		int saved_errno = errno;
303 		warn("error writing MBR");
304 		close(fd);
305 		errno = saved_errno;
306 		return (CMD_CONT);
307 	}
308 	close(fd);
309 
310 	/* Refresh in memory copy to reflect what was just written. */
311 	MBR_parse(disk, &dos_mbr, mbr->offset, mbr->reloffset, mbr);
312 
313 	return (CMD_CLEAN);
314 }
315 
316 int
317 Xquit(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
318     int offset)
319 {
320 
321 	/* Nothing to do here */
322 	return (CMD_SAVE);
323 }
324 
325 int
326 Xabort(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
327     int offset)
328 {
329 	exit(0);
330 
331 	/* NOTREACHED */
332 	return (CMD_CONT);
333 }
334 
335 int
336 Xexit(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
337     int offset)
338 {
339 
340 	/* Nothing to do here */
341 	return (CMD_EXIT);
342 }
343 
344 int
345 Xhelp(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
346     int offset)
347 {
348 	int i;
349 
350 	for (i = 0; cmd_table[i].cmd != NULL; i++)
351 		printf("\t%s\t\t%s\n", cmd_table[i].cmd, cmd_table[i].help);
352 	return (CMD_CONT);
353 }
354 
355 int
356 Xupdate(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
357     int offset)
358 {
359 	/* Update code */
360 	memcpy(mbr->code, tt->code, sizeof(mbr->code));
361 	mbr->signature = DOSMBR_SIGNATURE;
362 	printf("Machine code updated.\n");
363 	return (CMD_DIRTY);
364 }
365 
366 int
367 Xflag(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
368     int offset)
369 {
370 	const char *errstr;
371 	int i, pn = -1, val = -1;
372 	char *part, *flag;
373 
374 	flag = args;
375 	part = strsep(&flag, " \t");
376 
377 	pn = strtonum(part, 0, 3, &errstr);
378 	if (errstr) {
379 		printf("partition number is %s: %s.\n", errstr, part);
380 		return (CMD_CONT);
381 	}
382 
383 	if (flag != NULL) {
384 		val = (int)strtonum(flag, 0, 0xff, &errstr);
385 		if (errstr) {
386 			printf("flag value is %s: %s.\n", errstr, flag);
387 			return (CMD_CONT);
388 		}
389 	}
390 
391 	if (val == -1) {
392 		/* Set active flag */
393 		for (i = 0; i < 4; i++) {
394 			if (i == pn)
395 				mbr->part[i].flag = DOSACTIVE;
396 			else
397 				mbr->part[i].flag = 0x00;
398 		}
399 		printf("Partition %d marked active.\n", pn);
400 	} else {
401 		mbr->part[pn].flag = val;
402 		printf("Partition %d flag value set to 0x%x.\n", pn, val);
403 	}
404 	return (CMD_DIRTY);
405 }
406 
407 int
408 Xmanual(char *args, struct disk *disk, struct mbr *mbr, struct mbr *tt,
409     int offset)
410 {
411 	char *pager = "/usr/bin/less";
412 	char *p;
413 	sig_t opipe;
414 	extern const unsigned char manpage[];
415 	extern const int manpage_sz;
416 	FILE *f;
417 
418 	opipe = signal(SIGPIPE, SIG_IGN);
419 	if ((p = getenv("PAGER")) != NULL && (*p != '\0'))
420 		pager = p;
421 	if (asprintf(&p, "gunzip -qc|%s", pager) != -1) {
422 		f = popen(p, "w");
423 		if (f) {
424 			fwrite(manpage, manpage_sz, 1, f);
425 			pclose(f);
426 		}
427 		free(p);
428 	}
429 
430 	signal(SIGPIPE, opipe);
431 	return (CMD_CONT);
432 }
433