xref: /openbsd-src/sbin/fdisk/cmd.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: cmd.c,v 1.33 2003/06/11 06:22:12 deraadt 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 int
64 Xdisk(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
65 {
66 	int maxcyl  = 1024;
67 	int maxhead = 256;
68 	int maxsec  = 63;
69 
70 	/* Print out disk info */
71 	DISK_printmetrics(disk, cmd->args);
72 
73 #if defined (__powerpc__) || defined (__mips__)
74 	maxcyl  = 9999999;
75 	maxhead = 9999999;
76 	maxsec  = 9999999;
77 #endif
78 
79 	/* Ask for new info */
80 	if (ask_yn("Change disk geometry?")) {
81 		disk->real->cylinders = ask_num("BIOS Cylinders", ASK_DEC,
82 		    disk->real->cylinders, 1, maxcyl, NULL);
83 		disk->real->heads = ask_num("BIOS Heads", ASK_DEC,
84 		    disk->real->heads, 1, maxhead, NULL);
85 		disk->real->sectors = ask_num("BIOS Sectors", ASK_DEC,
86 		    disk->real->sectors, 1, maxsec, NULL);
87 
88 		disk->real->size = disk->real->cylinders * disk->real->heads
89 			* disk->real->sectors;
90 	}
91 
92 	return (CMD_CONT);
93 }
94 
95 int
96 Xedit(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
97 {
98 	int pn, num, ret;
99 	prt_t *pp;
100 
101 	ret = CMD_CONT;
102 
103 	if (!isdigit(cmd->args[0])) {
104 		printf("Invalid argument: %s <partition number>\n", cmd->cmd);
105 		return (ret);
106 	}
107 	pn = atoi(cmd->args);
108 
109 	if (pn < 0 || pn > 3) {
110 		printf("Invalid partition number.\n");
111 		return (ret);
112 	}
113 
114 	/* Print out current table entry */
115 	pp = &mbr->part[pn];
116 	PRT_print(0, NULL, NULL);
117 	PRT_print(pn, pp, NULL);
118 
119 #define	EDIT(p, f, v, n, m, h)				\
120 	if ((num = ask_num(p, f, v, n, m, h)) != v)	\
121 		ret = CMD_DIRTY;			\
122 	v = num;
123 
124 	/* Ask for partition type */
125 	EDIT("Partition id ('0' to disable) ", ASK_HEX, pp->id, 0, 0xFF, PRT_printall);
126 
127 	/* Unused, so just zero out */
128 	if (pp->id == DOSPTYP_UNUSED) {
129 		memset(pp, 0, sizeof(*pp));
130 		printf("Partition %d is disabled.\n", pn);
131 		return (ret);
132 	}
133 
134 	/* Change table entry */
135 	if (ask_yn("Do you wish to edit in CHS mode?")) {
136 		int maxcyl, maxhead, maxsect;
137 
138 		/* Shorter */
139 		maxcyl = disk->real->cylinders - 1;
140 		maxhead = disk->real->heads - 1;
141 		maxsect = disk->real->sectors;
142 
143 		/* Get data */
144 		EDIT("BIOS Starting cylinder", ASK_DEC, pp->scyl,  0, maxcyl, NULL);
145 		EDIT("BIOS Starting head",     ASK_DEC, pp->shead, 0, maxhead, NULL);
146 		EDIT("BIOS Starting sector",   ASK_DEC, pp->ssect, 1, maxsect, NULL);
147 		EDIT("BIOS Ending cylinder",   ASK_DEC, pp->ecyl,  0, maxcyl, NULL);
148 		EDIT("BIOS Ending head",       ASK_DEC, pp->ehead, 0, maxhead, NULL);
149 		EDIT("BIOS Ending sector",     ASK_DEC, pp->esect, 1, maxsect, NULL);
150 		/* Fix up off/size values */
151 		PRT_fix_BN(disk, pp, pn);
152 		/* Fix up CHS values for LBA */
153 		PRT_fix_CHS(disk, pp, pn);
154 	} else {
155 		u_int m;
156 
157 		/* Get data */
158 		pp->bs = getuint(disk, "offset",
159 		   "Starting sector for this partition.", pp->bs,
160 		   disk->real->size, 0, DO_CONVERSIONS |
161 		   (pp->id == FS_BSDFFS ? DO_ROUNDING : 0));
162 
163 		m = MAX(pp->ns, disk->real->size - pp->bs);
164 		if ( m > disk->real->size - pp->bs) {
165 			/* dont have default value extend beyond end of disk */
166 			m = disk->real->size - pp->bs;
167 		}
168 		pp->ns = getuint(disk, "size", "Size of the partition.",
169 		    pp->ns, m, pp->bs , DO_CONVERSIONS |
170 		    ((pp->id == FS_BSDFFS || pp->id == FS_SWAP) ?
171 		    DO_ROUNDING : 0));
172 
173 		/* Fix up CHS values */
174 		PRT_fix_CHS(disk, pp, pn);
175 	}
176 #undef EDIT
177 	return (ret);
178 }
179 
180 int
181 Xsetpid(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
182 {
183 	int pn, num, ret;
184 	prt_t *pp;
185 
186 	ret = CMD_CONT;
187 
188 	if (!isdigit(cmd->args[0])) {
189 		printf("Invalid argument: %s <partition number>\n", cmd->cmd);
190 		return (ret);
191 	}
192 	pn = atoi(cmd->args);
193 
194 	if (pn < 0 || pn > 3) {
195 		printf("Invalid partition number.\n");
196 		return (ret);
197 	}
198 
199 	/* Print out current table entry */
200 	pp = &mbr->part[pn];
201 	PRT_print(0, NULL, NULL);
202 	PRT_print(pn, pp, NULL);
203 
204 #define	EDIT(p, f, v, n, m, h)				\
205 	if ((num = ask_num(p, f, v, n, m, h)) != v)	\
206 		ret = CMD_DIRTY;			\
207 	v = num;
208 
209 	/* Ask for partition type */
210 	EDIT("Partition id ('0' to disable) ", ASK_HEX, pp->id, 0, 0xFF, PRT_printall);
211 
212 #undef EDIT
213 	return (ret);
214 }
215 int
216 Xselect(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
217 {
218 	static int firstoff = 0;
219 	int off;
220 	int pn;
221 
222 	if (!isdigit(cmd->args[0])) {
223 		printf("Invalid argument: %s <partition number>\n", cmd->cmd);
224 		return (CMD_CONT);
225 	}
226 
227 	pn = atoi(cmd->args);
228 	off = mbr->part[pn].bs;
229 
230 	/* Sanity checks */
231 	if ((mbr->part[pn].id != DOSPTYP_EXTEND) &&
232 	    (mbr->part[pn].id != DOSPTYP_EXTENDL)) {
233 		printf("Partition %d is not an extended partition.\n", pn);
234 		return (CMD_CONT);
235 	}
236 
237 	if (firstoff == 0)
238 		firstoff = off;
239 
240 	if (!off) {
241 		printf("Loop to offset 0!  Not selected.\n");
242 		return (CMD_CONT);
243 	} else {
244 		printf("Selected extended partition %d\n", pn);
245 		printf("New MBR at offset %d.\n", off);
246 	}
247 
248 	/* Recursion is beautifull! */
249 	USER_modify(disk, tt, off, firstoff);
250 	return (CMD_CONT);
251 }
252 
253 int
254 Xprint(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
255 {
256 
257 	DISK_printmetrics(disk, cmd->args);
258 	printf("Offset: %d\t", offset);
259 	MBR_print(mbr, cmd->args);
260 
261 	return (CMD_CONT);
262 }
263 
264 int
265 Xwrite(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
266 {
267 	char mbr_buf[DEV_BSIZE];
268 	int fd;
269 
270 	printf("Writing MBR at offset %d.\n", offset);
271 
272 	fd = DISK_open(disk->name, O_RDWR);
273 	MBR_make(mbr, mbr_buf);
274 	MBR_write(fd, offset, mbr_buf);
275 	close(fd);
276 	return (CMD_CLEAN);
277 }
278 
279 int
280 Xquit(cmd, disk, r, tt, offset)
281 	cmd_t *cmd;
282 	disk_t *disk;
283 	mbr_t *r;
284 	mbr_t *tt;
285 	int offset;
286 {
287 
288 	/* Nothing to do here */
289 	return (CMD_SAVE);
290 }
291 
292 int
293 Xabort(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
294 {
295 	exit(0);
296 
297 	/* NOTREACHED */
298 	return (CMD_CONT);
299 }
300 
301 
302 int
303 Xexit(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
304 {
305 
306 	/* Nothing to do here */
307 	return (CMD_EXIT);
308 }
309 
310 int
311 Xhelp(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
312 {
313 	cmd_table_t *cmd_table = cmd->table;
314 	int i;
315 
316 	/* Hmm, print out cmd_table here... */
317 	for (i = 0; cmd_table[i].cmd != NULL; i++)
318 		printf("\t%s\t\t%s\n", cmd_table[i].cmd, cmd_table[i].help);
319 	return (CMD_CONT);
320 }
321 
322 int
323 Xupdate(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
324 {
325 
326 	/* Update code */
327 	memcpy(mbr->code, tt->code, MBR_CODE_SIZE);
328 	printf("Machine code updated.\n");
329 	return (CMD_DIRTY);
330 }
331 
332 int
333 Xflag(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
334 {
335 	int i, pn = -1;
336 
337 	/* Parse partition table entry number */
338 	if (!isdigit(cmd->args[0])) {
339 		printf("Invalid argument: %s <partition number>\n", cmd->cmd);
340 		return (CMD_CONT);
341 	}
342 	pn = atoi(cmd->args);
343 
344 	if (pn < 0 || pn > 3) {
345 		printf("Invalid partition number.\n");
346 		return (CMD_CONT);
347 	}
348 
349 	/* Set active flag */
350 	for (i = 0; i < 4; i++) {
351 		if (i == pn)
352 			mbr->part[i].flag = DOSACTIVE;
353 		else
354 			mbr->part[i].flag = 0x00;
355 	}
356 
357 	printf("Partition %d marked active.\n", pn);
358 	return (CMD_DIRTY);
359 }
360 
361 int
362 Xmanual(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset)
363 {
364 	char *pager = "/usr/bin/less";
365 	char *p;
366 	sig_t opipe;
367 	extern char manpage[];
368 	FILE *f;
369 
370 	opipe = signal(SIGPIPE, SIG_IGN);
371 	if ((p = getenv("PAGER")) != NULL && (*p != '\0'))
372 		pager = p;
373 	f = popen(pager, "w");
374 	if (f) {
375 		(void) fwrite(manpage, strlen(manpage), 1, f);
376 		pclose(f);
377 	}
378 
379 	(void)signal(SIGPIPE, opipe);
380 	return (CMD_CONT);
381 }
382 
383