xref: /openbsd-src/sbin/fdisk/cmd.c (revision 01a159e4e48da4a3ea85f84e5cb86a1b3dddaa32)
1*01a159e4Skrw /*	$OpenBSD: cmd.c,v 1.180 2024/03/01 17:48:03 krw Exp $	*/
2a1705421Sweingart 
3a1705421Sweingart /*
4a1705421Sweingart  * Copyright (c) 1997 Tobias Weingartner
5a1705421Sweingart  *
610a68084Skrw  * Permission to use, copy, modify, and distribute this software for any
710a68084Skrw  * purpose with or without fee is hereby granted, provided that the above
810a68084Skrw  * copyright notice and this permission notice appear in all copies.
9a1705421Sweingart  *
1010a68084Skrw  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1110a68084Skrw  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1210a68084Skrw  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1310a68084Skrw  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1410a68084Skrw  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1510a68084Skrw  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1610a68084Skrw  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a1705421Sweingart  */
18a1705421Sweingart 
19a7568474Sderaadt #include <sys/types.h>
20a7568474Sderaadt #include <sys/disklabel.h>
21729290c0Skrw 
22e8252b55Skrw #include <err.h>
2385135147Skrw #include <errno.h>
24729290c0Skrw #include <signal.h>
25729290c0Skrw #include <stdint.h>
26a1705421Sweingart #include <stdio.h>
27a1705421Sweingart #include <stdlib.h>
28bdf84265Skrw #include <string.h>
29fba7235cSkrw #include <uuid.h>
30abc6f793Skrw 
31199eafeaSkrw #include "part.h"
32a5472107Skrw #include "disk.h"
33e8252b55Skrw #include "misc.h"
34a5472107Skrw #include "mbr.h"
35fba7235cSkrw #include "gpt.h"
36a1705421Sweingart #include "user.h"
37a1705421Sweingart #include "cmd.h"
38a1705421Sweingart 
39859be6c9Skrw int		 gedit(const int);
40859be6c9Skrw int		 edit(const int, struct mbr *);
41859be6c9Skrw int		 gsetpid(const int);
42859be6c9Skrw int		 setpid(const int, struct mbr *);
43859be6c9Skrw int		 parsepn(const char *);
4485135147Skrw int		 parseflag(const char *, uint64_t *);
45fba7235cSkrw 
46543185b3Skrw int		 ask_num(const char *, int, int, int);
47ede3ff43Skrw int		 ask_pid(const int);
488c6d22aeSkrw const struct uuid *ask_uuid(const struct uuid *);
49543185b3Skrw 
508c10a749Skrw extern const unsigned char	manpage[];
518c10a749Skrw extern const int		manpage_sz;
528c10a749Skrw 
53a1705421Sweingart int
Xreinit(const char * args,struct mbr * mbr)54c5fb5a34Skrw Xreinit(const char *args, struct mbr *mbr)
55a1705421Sweingart {
56c94b0391Skrw 	int			dogpt;
5717eb2d2cSkrw 
58c94b0391Skrw 	dogpt = 0;
59fba7235cSkrw 
60380d744dSkrw 	if (strcasecmp(args, "gpt") == 0)
61fba7235cSkrw 		dogpt = 1;
62380d744dSkrw 	else if (strcasecmp(args, "mbr") == 0)
63fba7235cSkrw 		dogpt = 0;
64fba7235cSkrw 	else if (strlen(args) > 0) {
65fba7235cSkrw 		printf("Unrecognized modifier '%s'\n", args);
662a536aa2Skrw 		return CMD_CONT;
67c94b0391Skrw 	}
68a1705421Sweingart 
69fba7235cSkrw 	if (dogpt) {
70199eafeaSkrw 		GPT_init(GHANDGP);
713bbc645fSkrw 		GPT_print("s", TERSE);
72fba7235cSkrw 	} else {
73ac519580Skrw 		MBR_init(mbr);
74fba7235cSkrw 		MBR_print(mbr, "s");
75fba7235cSkrw 	}
76e627f006Spefo 
77a1705421Sweingart 	printf("Use 'write' to update disk.\n");
78a1705421Sweingart 
792a536aa2Skrw 	return CMD_DIRTY;
80a1705421Sweingart }
81a1705421Sweingart 
82a1705421Sweingart int
Xswap(const char * args,struct mbr * mbr)83c5fb5a34Skrw Xswap(const char *args, struct mbr *mbr)
8498d2b0d2Sderaadt {
85c5fb5a34Skrw 	char			 lbuf[LINEBUFSZ];
864f0166f6Skrw 	char			*from, *to;
87996aff7bSkrw 	int			 pf, pt;
8853f0474fSkrw 	struct prt		 pp;
89fba7235cSkrw 	struct gpt_partition	 gg;
9098d2b0d2Sderaadt 
91c5fb5a34Skrw 	if (strlcpy(lbuf, args, sizeof(lbuf)) >= sizeof(lbuf)) {
92c5fb5a34Skrw 		printf("argument string too long\n");
93c5fb5a34Skrw 		return CMD_CONT;
94c5fb5a34Skrw 	}
95c5fb5a34Skrw 
96c5fb5a34Skrw 	to = lbuf;
97380d744dSkrw 	from = strsep(&to, WHITESPACE);
984f0166f6Skrw 
99996aff7bSkrw 	pt = parsepn(to);
100996aff7bSkrw 	if (pt == -1)
1012a536aa2Skrw 		return CMD_CONT;
10298d2b0d2Sderaadt 
103996aff7bSkrw 	pf = parsepn(from);
104996aff7bSkrw 	if (pf == -1)
1052a536aa2Skrw 		return CMD_CONT;
10698d2b0d2Sderaadt 
10798d2b0d2Sderaadt 	if (pt == pf) {
10898d2b0d2Sderaadt 		printf("%d same partition as %d, doing nothing.\n", pt, pf);
1092a536aa2Skrw 		return CMD_CONT;
11098d2b0d2Sderaadt 	}
11198d2b0d2Sderaadt 
112ad6c5e72Skrw 	if (gh.gh_sig == GPTSIGNATURE) {
113fba7235cSkrw 		gg = gp[pt];
114fba7235cSkrw 		gp[pt] = gp[pf];
115fba7235cSkrw 		gp[pf] = gg;
116fba7235cSkrw 	} else {
117061e6e0aSkrw 		pp = mbr->mbr_prt[pt];
118061e6e0aSkrw 		mbr->mbr_prt[pt] = mbr->mbr_prt[pf];
119061e6e0aSkrw 		mbr->mbr_prt[pf] = pp;
120fba7235cSkrw 	}
12198d2b0d2Sderaadt 
1222a536aa2Skrw 	return CMD_DIRTY;
12398d2b0d2Sderaadt }
12498d2b0d2Sderaadt 
12598d2b0d2Sderaadt int
gedit(const int pn)126859be6c9Skrw gedit(const int pn)
127fba7235cSkrw {
128386fe449Skrw 	struct uuid		 oldtype;
129fba7235cSkrw 
130e4e9ede8Skrw 	oldtype = gp[pn].gp_type;
131fba7235cSkrw 
132386fe449Skrw 	if (gsetpid(pn))
133386fe449Skrw 		return -1;
134320e14e3Skrw 
135e4e9ede8Skrw 	if (uuid_is_nil(&gp[pn].gp_type, NULL)) {
136386fe449Skrw 		if (uuid_is_nil(&oldtype, NULL) == 0) {
137e4e9ede8Skrw 			memset(&gp[pn], 0, sizeof(gp[pn]));
138fba7235cSkrw 			printf("Partition %d is disabled.\n", pn);
139386fe449Skrw 		}
140386fe449Skrw 		return 0;
141fba7235cSkrw 	}
142fba7235cSkrw 
143c2d03168Skrw 	if (GPT_get_lba_start(pn) == -1 ||
144a66d82b0Skrw 	    GPT_get_lba_end(pn) == -1 ||
145a66d82b0Skrw 	    GPT_get_name(pn) == -1) {
146386fe449Skrw 		return -1;
147c2d03168Skrw 	}
148fba7235cSkrw 
149386fe449Skrw 	return 0;
150fba7235cSkrw }
151fba7235cSkrw 
152fba7235cSkrw int
parsepn(const char * pnstr)153859be6c9Skrw parsepn(const char *pnstr)
154996aff7bSkrw {
155996aff7bSkrw 	const char		*errstr;
156996aff7bSkrw 	int			 maxpn, pn;
157996aff7bSkrw 
158996aff7bSkrw 	if (pnstr == NULL) {
159996aff7bSkrw 		printf("no partition number\n");
160996aff7bSkrw 		return -1;
161996aff7bSkrw 	}
162996aff7bSkrw 
163ad6c5e72Skrw 	if (gh.gh_sig == GPTSIGNATURE)
164ad6c5e72Skrw 		maxpn = gh.gh_part_num - 1;
165996aff7bSkrw 	else
166996aff7bSkrw 		maxpn = NDOSPART - 1;
167996aff7bSkrw 
168996aff7bSkrw 	pn = strtonum(pnstr, 0, maxpn, &errstr);
169996aff7bSkrw 	if (errstr) {
170996aff7bSkrw 		printf("partition number is %s: %s\n", errstr, pnstr);
171996aff7bSkrw 		return -1;
172996aff7bSkrw 	}
173996aff7bSkrw 
174996aff7bSkrw 	return pn;
175996aff7bSkrw }
176996aff7bSkrw 
177996aff7bSkrw int
parseflag(const char * flagstr,uint64_t * flagvalue)17885135147Skrw parseflag(const char *flagstr, uint64_t *flagvalue)
17985135147Skrw {
18085135147Skrw 	const char		*errstr;
18185135147Skrw 	char			*ep;
18285135147Skrw 	uint64_t		 val;
18385135147Skrw 
18414c04d21Skrw 	flagstr += strspn(flagstr, WHITESPACE);
18585135147Skrw 	if (flagstr[0] == '0' && (flagstr[1] == 'x' || flagstr[1] == 'X')) {
18685135147Skrw 		errno = 0;
18785135147Skrw 		val = strtoull(flagstr, &ep, 16);
18885135147Skrw 		if (errno || ep == flagstr || *ep != '\0' ||
18985135147Skrw 		    (gh.gh_sig != GPTSIGNATURE && val > 0xff)) {
19085135147Skrw 			printf("flag value is invalid: %s\n", flagstr);
19185135147Skrw 			return -1;
19285135147Skrw 		}
19385135147Skrw 		goto done;
19485135147Skrw 	}
19585135147Skrw 
19685135147Skrw 	if (gh.gh_sig == GPTSIGNATURE)
19785135147Skrw 		val = strtonum(flagstr, 0, INT64_MAX, &errstr);
19885135147Skrw 	else
19985135147Skrw 		val = strtonum(flagstr, 0, 0xff, &errstr);
20085135147Skrw 	if (errstr) {
20185135147Skrw 		printf("flag value is %s: %s\n", errstr, flagstr);
20285135147Skrw 		return -1;
20385135147Skrw 	}
20485135147Skrw 
20585135147Skrw  done:
20685135147Skrw 	*flagvalue = val;
20785135147Skrw 	return 0;
20885135147Skrw }
20985135147Skrw 
21085135147Skrw int
edit(const int pn,struct mbr * mbr)211859be6c9Skrw edit(const int pn, struct mbr *mbr)
212a1705421Sweingart {
21377392607Skrw 	struct chs		 start, end;
21453f0474fSkrw 	struct prt		*pp;
21545d8ccdeSkrw 	uint64_t		 track;
216386fe449Skrw 	unsigned char		 oldid;
217c2b81596Skrw 
218061e6e0aSkrw 	pp = &mbr->mbr_prt[pn];
219386fe449Skrw 	oldid = pp->prt_id;
22099b7b375Smickey 
221386fe449Skrw 	if (setpid(pn, mbr))
222386fe449Skrw 		return -1;
223386fe449Skrw 
224ee38fe33Skrw 	if (pp->prt_id == DOSPTYP_UNUSED) {
225386fe449Skrw 		if (oldid != DOSPTYP_UNUSED) {
226a1705421Sweingart 			memset(pp, 0, sizeof(*pp));
227a2f126afSderaadt 			printf("Partition %d is disabled.\n", pn);
2287f41e46fSkrw 		}
229386fe449Skrw 		return 0;
230a1705421Sweingart 	}
231a1705421Sweingart 
232a1705421Sweingart 	if (ask_yn("Do you wish to edit in CHS mode?")) {
23377392607Skrw 		PRT_lba_to_chs(pp, &start, &end);
23477392607Skrw 		start.chs_cyl = ask_num("BIOS Starting cylinder", start.chs_cyl,
235d91eacccSkrw 		    0, disk.dk_cylinders - 1);
23677392607Skrw 		start.chs_head = ask_num("BIOS Starting head", start.chs_head,
237d91eacccSkrw 		    0, disk.dk_heads - 1);
23877392607Skrw 		start.chs_sect = ask_num("BIOS Starting sector", start.chs_sect,
239d91eacccSkrw 		    1, disk.dk_sectors);
240a1705421Sweingart 
24177392607Skrw 		end.chs_cyl = ask_num("BIOS Ending cylinder", end.chs_cyl,
24277392607Skrw 		    start.chs_cyl, disk.dk_cylinders - 1);
24377392607Skrw 		end.chs_head = ask_num("BIOS Ending head", end.chs_head,
24477392607Skrw 		    (start.chs_cyl == end.chs_cyl) ? start.chs_head : 0,
245d91eacccSkrw 		    disk.dk_heads - 1);
24677392607Skrw 		end.chs_sect = ask_num("BIOS Ending sector", end.chs_sect,
24777392607Skrw 		    (start.chs_cyl == end.chs_cyl && start.chs_head ==
24877392607Skrw 		    end.chs_head) ? start.chs_sect : 1, disk.dk_sectors);
249a1705421Sweingart 
25045d8ccdeSkrw 		/* The ATA/ATAPI spec says LBA = (C × HPC + H) × SPT + (S − 1) */
25177392607Skrw 		track = start.chs_cyl * disk.dk_heads + start.chs_head;
25277392607Skrw 		pp->prt_bs = track * disk.dk_sectors + (start.chs_sect - 1);
25377392607Skrw 		track = end.chs_cyl * disk.dk_heads + end.chs_head;
25477392607Skrw 		pp->prt_ns = track * disk.dk_sectors + (end.chs_sect - 1) -
25545d8ccdeSkrw 		    pp->prt_bs + 1;
256a1705421Sweingart 	} else {
257d91eacccSkrw 		pp->prt_bs = getuint64("Partition offset", pp->prt_bs, 0,
258d91eacccSkrw 		    disk.dk_size - 1);
259ee38fe33Skrw 		pp->prt_ns = getuint64("Partition size",   pp->prt_ns, 1,
26033e90638Skrw 		    disk.dk_size - pp->prt_bs);
261a1705421Sweingart 	}
2627126966cSkrw 
263386fe449Skrw 	return 0;
264a1705421Sweingart }
265a1705421Sweingart 
266a1705421Sweingart int
Xedit(const char * args,struct mbr * mbr)267c5fb5a34Skrw Xedit(const char *args, struct mbr *mbr)
268f05f27a7Skrw {
269386fe449Skrw 	struct gpt_partition	 oldgg;
270386fe449Skrw 	struct prt		 oldprt;
271f05f27a7Skrw 	int			 pn;
272f05f27a7Skrw 
273f05f27a7Skrw 	pn = parsepn(args);
274f05f27a7Skrw 	if (pn == -1)
2752a536aa2Skrw 		return CMD_CONT;
276f05f27a7Skrw 
277ad6c5e72Skrw 	if (gh.gh_sig == GPTSIGNATURE) {
278386fe449Skrw 		oldgg = gp[pn];
279386fe449Skrw 		if (gedit(pn))
280386fe449Skrw 			gp[pn] = oldgg;
281e4e9ede8Skrw 		else if (memcmp(&gp[pn], &oldgg, sizeof(gp[pn])))
282386fe449Skrw 			return CMD_DIRTY;
283386fe449Skrw 	} else {
284386fe449Skrw 		oldprt = mbr->mbr_prt[pn];
285386fe449Skrw 		if (edit(pn, mbr))
286386fe449Skrw 			mbr->mbr_prt[pn] = oldprt;
287386fe449Skrw 		else if (memcmp(&mbr->mbr_prt[pn], &oldprt, sizeof(oldprt)))
288386fe449Skrw 			return CMD_DIRTY;
289386fe449Skrw 	}
290386fe449Skrw 
291386fe449Skrw 	return CMD_CONT;
292f05f27a7Skrw }
293f05f27a7Skrw 
294f05f27a7Skrw int
gsetpid(const int pn)295a3a83fc4Skrw gsetpid(const int pn)
296fba7235cSkrw {
297*01a159e4Skrw 	int32_t			 is_nil;
298351f0068Skrw 	uint32_t		 status;
299fba7235cSkrw 
3003bbc645fSkrw 	GPT_print_parthdr(TERSE);
3013bbc645fSkrw 	GPT_print_part(pn, "s", TERSE);
302fba7235cSkrw 
303490259bdSkrw 	if (PRT_protected_uuid(&gp[pn].gp_type)) {
30495e8765cSkrw 		printf("can't edit partition type %s\n",
305d8f6db85Skrw 		    PRT_uuid_to_desc(&gp[pn].gp_type));
306386fe449Skrw 		return -1;
30795e8765cSkrw 	}
30895e8765cSkrw 
309*01a159e4Skrw 	is_nil = uuid_is_nil(&gp[pn].gp_type, NULL);
3102de77560Skrw 	gp[pn].gp_type = *ask_uuid(&gp[pn].gp_type);
311*01a159e4Skrw 	if (PRT_protected_uuid(&gp[pn].gp_type) && is_nil == 0) {
31295e8765cSkrw 		printf("can't change partition type to %s\n",
313d8f6db85Skrw 		    PRT_uuid_to_desc(&gp[pn].gp_type));
314386fe449Skrw 		return -1;
31595e8765cSkrw 	}
316fba7235cSkrw 
3172de77560Skrw 	if (uuid_is_nil(&gp[pn].gp_guid, NULL)) {
3182de77560Skrw 		uuid_create(&gp[pn].gp_guid, &status);
319fba7235cSkrw 		if (status != uuid_s_ok) {
320fba7235cSkrw 			printf("could not create guid for partition\n");
321386fe449Skrw 			return -1;
322fba7235cSkrw 		}
323386fe449Skrw 	}
324386fe449Skrw 
325386fe449Skrw 	return 0;
326fba7235cSkrw }
327fba7235cSkrw 
328fba7235cSkrw int
setpid(const int pn,struct mbr * mbr)329a3a83fc4Skrw setpid(const int pn, struct mbr *mbr)
3305c65ba20Sangelos {
33153f0474fSkrw 	struct prt		*pp;
332c2b81596Skrw 
333061e6e0aSkrw 	pp = &mbr->mbr_prt[pn];
3345c65ba20Sangelos 
3357b70791fSkrw 	PRT_print_parthdr();
3367b70791fSkrw 	PRT_print_part(pn, pp, "s");
3375c65ba20Sangelos 
338ede3ff43Skrw 	pp->prt_id = ask_pid(pp->prt_id);
3395c65ba20Sangelos 
340386fe449Skrw 	return 0;
3415c65ba20Sangelos }
3425675a19dSderaadt 
3435c65ba20Sangelos int
Xsetpid(const char * args,struct mbr * mbr)344c5fb5a34Skrw Xsetpid(const char *args, struct mbr *mbr)
345f05f27a7Skrw {
346386fe449Skrw 	struct gpt_partition	oldgg;
347386fe449Skrw 	struct prt		oldprt;
348f05f27a7Skrw 	int			pn;
349f05f27a7Skrw 
350f05f27a7Skrw 	pn = parsepn(args);
351f05f27a7Skrw 	if (pn == -1)
3522a536aa2Skrw 		return CMD_CONT;
353f05f27a7Skrw 
354ad6c5e72Skrw 	if (gh.gh_sig == GPTSIGNATURE) {
355386fe449Skrw 		oldgg = gp[pn];
356386fe449Skrw 		if (gsetpid(pn))
357386fe449Skrw 			gp[pn] = oldgg;
358e4e9ede8Skrw 		else if (memcmp(&gp[pn], &oldgg, sizeof(gp[pn])))
359386fe449Skrw 			return CMD_DIRTY;
360386fe449Skrw 	} else {
361386fe449Skrw 		oldprt = mbr->mbr_prt[pn];
362386fe449Skrw 		if (setpid(pn, mbr))
363386fe449Skrw 			mbr->mbr_prt[pn] = oldprt;
364386fe449Skrw 		else if (memcmp(&mbr->mbr_prt[pn], &oldprt, sizeof(oldprt)))
365386fe449Skrw 			return CMD_DIRTY;
366386fe449Skrw 	}
367386fe449Skrw 
368386fe449Skrw 	return CMD_CONT;
369f05f27a7Skrw }
370f05f27a7Skrw 
371f05f27a7Skrw int
Xselect(const char * args,struct mbr * mbr)372c5fb5a34Skrw Xselect(const char *args, struct mbr *mbr)
373a1705421Sweingart {
3740cd9e2afSkrw 	static uint64_t		lba_firstembr = 0;
3750cd9e2afSkrw 	uint64_t		lba_self;
37699b7b375Smickey 	int			pn;
377a1705421Sweingart 
378996aff7bSkrw 	pn = parsepn(args);
379996aff7bSkrw 	if (pn == -1)
3802a536aa2Skrw 		return CMD_CONT;
381a1705421Sweingart 
3820cd9e2afSkrw 	lba_self = mbr->mbr_prt[pn].prt_bs;
383a1705421Sweingart 
384ee38fe33Skrw 	if ((mbr->mbr_prt[pn].prt_id != DOSPTYP_EXTEND) &&
385ee38fe33Skrw 	    (mbr->mbr_prt[pn].prt_id != DOSPTYP_EXTENDL)) {
38699b7b375Smickey 		printf("Partition %d is not an extended partition.\n", pn);
3872a536aa2Skrw 		return CMD_CONT;
388a1705421Sweingart 	}
389ca2e86e1Sprovos 
3900cd9e2afSkrw 	if (lba_firstembr == 0)
3910cd9e2afSkrw 		lba_firstembr = lba_self;
392ca2e86e1Sprovos 
3930cd9e2afSkrw 	if (lba_self == 0) {
3940cd9e2afSkrw 		printf("Loop to MBR (sector 0)! Not selected.\n");
3952a536aa2Skrw 		return CMD_CONT;
396a1705421Sweingart 	} else {
39799b7b375Smickey 		printf("Selected extended partition %d\n", pn);
3980cd9e2afSkrw 		printf("New EMBR at offset %llu.\n", lba_self);
399a1705421Sweingart 	}
400a1705421Sweingart 
4010cd9e2afSkrw 	USER_edit(lba_self, lba_firstembr);
4027126966cSkrw 
4032a536aa2Skrw 	return CMD_CONT;
404a1705421Sweingart }
405a1705421Sweingart 
406a1705421Sweingart int
Xprint(const char * args,struct mbr * mbr)407c5fb5a34Skrw Xprint(const char *args, struct mbr *mbr)
408a1705421Sweingart {
409ad6c5e72Skrw 	if (gh.gh_sig == GPTSIGNATURE)
4103bbc645fSkrw 		GPT_print(args, VERBOSE);
4119ba61043Skrw 	else if (MBR_valid_prt(mbr))
41287dc5144Skrw 		MBR_print(mbr, args);
4139ba61043Skrw 	else {
4149ba61043Skrw 		DISK_printgeometry("s");
4159ba61043Skrw 		printf("Offset: %d\tSignature: 0x%X.\tNo MBR or GPT.\n",
4169ba61043Skrw 		    DOSBBSECTOR, (int)mbr->mbr_signature);
4179ba61043Skrw 	}
418a1705421Sweingart 
4192a536aa2Skrw 	return CMD_CONT;
420a1705421Sweingart }
421a1705421Sweingart 
422a1705421Sweingart int
Xwrite(const char * args,struct mbr * mbr)423c5fb5a34Skrw Xwrite(const char *args, struct mbr *mbr)
424a1705421Sweingart {
4255f7fe693Skrw 	unsigned int		i, n;
426f1102820Smatthew 
4275f7fe693Skrw 	for (i = 0, n = 0; i < nitems(mbr->mbr_prt); i++)
42844ce0cacSkrw 		if (mbr->mbr_prt[i].prt_id == DOSPTYP_OPENBSD)
429f1102820Smatthew 			n++;
43044ce0cacSkrw 	if (n > 1) {
431f1102820Smatthew 		warnx("MBR contains more than one OpenBSD partition!");
43244ce0cacSkrw 		if (ask_yn("Write MBR anyway?") == 0)
4332a536aa2Skrw 			return CMD_CONT;
434f1102820Smatthew 	}
435a1705421Sweingart 
436ad6c5e72Skrw 	if (gh.gh_sig == GPTSIGNATURE) {
437dfcac45eSkrw 		printf("Writing GPT.\n");
438dfcac45eSkrw 		if (GPT_write() == -1) {
43945a092d7Skrw 			warnx("error writing GPT");
440dfcac45eSkrw 			return CMD_CONT;
441dfcac45eSkrw 		}
442dfcac45eSkrw 	} else {
443530f0457Skrw 		printf("Writing MBR at offset %llu.\n", mbr->mbr_lba_self);
444e79775dbSkrw 		if (MBR_write(mbr) == -1) {
44545a092d7Skrw 			warnx("error writing MBR");
4462a536aa2Skrw 			return CMD_CONT;
4472ab1ffe2Skrw 		}
448c94b0391Skrw 		GPT_zap_headers();
449fba7235cSkrw 	}
4502ab1ffe2Skrw 
4512a536aa2Skrw 	return CMD_CLEAN;
452a1705421Sweingart }
453a1705421Sweingart 
454a1705421Sweingart int
Xquit(const char * args,struct mbr * mbr)455c5fb5a34Skrw Xquit(const char *args, struct mbr *mbr)
456a1705421Sweingart {
457711fb9d5Skrw 	return CMD_QUIT;
458a1705421Sweingart }
459a1705421Sweingart 
460a1705421Sweingart int
Xabort(const char * args,struct mbr * mbr)461c5fb5a34Skrw Xabort(const char *args, struct mbr *mbr)
4624b464610Sderaadt {
4634b464610Sderaadt 	exit(0);
4644b464610Sderaadt }
4654b464610Sderaadt 
4664b464610Sderaadt int
Xexit(const char * args,struct mbr * mbr)467c5fb5a34Skrw Xexit(const char *args, struct mbr *mbr)
468a1705421Sweingart {
4692a536aa2Skrw 	return CMD_EXIT;
470a1705421Sweingart }
471a1705421Sweingart 
472a1705421Sweingart int
Xhelp(const char * args,struct mbr * mbr)473c5fb5a34Skrw Xhelp(const char *args, struct mbr *mbr)
474a1705421Sweingart {
4759ba61043Skrw 	USER_help(mbr);
476fba7235cSkrw 
4772a536aa2Skrw 	return CMD_CONT;
478a1705421Sweingart }
479a1705421Sweingart 
480a1705421Sweingart int
Xupdate(const char * args,struct mbr * mbr)481c5fb5a34Skrw Xupdate(const char *args, struct mbr *mbr)
482a1705421Sweingart {
483f43a9f23Skrw 	memcpy(mbr->mbr_code, default_dmbr.dmbr_boot, sizeof(mbr->mbr_code));
484061e6e0aSkrw 	mbr->mbr_signature = DOSMBR_SIGNATURE;
485a1705421Sweingart 	printf("Machine code updated.\n");
4862a536aa2Skrw 	return CMD_DIRTY;
487a1705421Sweingart }
488a1705421Sweingart 
489a1705421Sweingart int
Xflag(const char * args,struct mbr * mbr)490c5fb5a34Skrw Xflag(const char *args, struct mbr *mbr)
491a1705421Sweingart {
492c5fb5a34Skrw 	char			 lbuf[LINEBUFSZ];
49399f63382Skrw 	char			*part, *flag;
49485135147Skrw 	uint64_t		 val;
4958c10a749Skrw 	int			 i, pn;
496a1705421Sweingart 
497c5fb5a34Skrw 	if (strlcpy(lbuf, args, sizeof(lbuf)) >= sizeof(lbuf)) {
498c5fb5a34Skrw 		printf("argument string too long\n");
499c5fb5a34Skrw 		return CMD_CONT;
500c5fb5a34Skrw 	}
501c5fb5a34Skrw 
502c5fb5a34Skrw 	flag = lbuf;
503380d744dSkrw 	part = strsep(&flag, WHITESPACE);
50499f63382Skrw 
50529fb24ffSkrw 	pn = parsepn(part);
50629fb24ffSkrw 	if (pn == -1)
5072a536aa2Skrw 		return CMD_CONT;
508a1705421Sweingart 
50999f63382Skrw 	if (flag != NULL) {
51085135147Skrw 		if (parseflag(flag, &val) == -1)
5112a536aa2Skrw 			return CMD_CONT;
512ad6c5e72Skrw 		if (gh.gh_sig == GPTSIGNATURE)
5132de77560Skrw 			gp[pn].gp_attrs = val;
514fba7235cSkrw 		else
515ee38fe33Skrw 			mbr->mbr_prt[pn].prt_flag = val;
516fba7235cSkrw 		printf("Partition %d flag value set to 0x%llx.\n", pn, val);
517fba7235cSkrw 	} else {
518ad6c5e72Skrw 		if (gh.gh_sig == GPTSIGNATURE) {
519ad6c5e72Skrw 			for (i = 0; i < gh.gh_part_num; i++) {
520fba7235cSkrw 				if (i == pn)
52195a0034fSkrw 					gp[i].gp_attrs = GPTPARTATTR_BOOTABLE;
522fba7235cSkrw 				else
52354ee4acdSkrw 					gp[i].gp_attrs &= ~GPTPARTATTR_BOOTABLE;
524fba7235cSkrw 			}
525fba7235cSkrw 		} else {
5265f7fe693Skrw 			for (i = 0; i < nitems(mbr->mbr_prt); i++) {
5279d22187fSderaadt 				if (i == pn)
528ee38fe33Skrw 					mbr->mbr_prt[i].prt_flag = DOSACTIVE;
5299d22187fSderaadt 				else
530ee38fe33Skrw 					mbr->mbr_prt[i].prt_flag = 0x00;
531a1705421Sweingart 			}
532fba7235cSkrw 		}
53399b7b375Smickey 		printf("Partition %d marked active.\n", pn);
534513623c8Sotto 	}
5357126966cSkrw 
5362a536aa2Skrw 	return CMD_DIRTY;
537a1705421Sweingart }
538a1705421Sweingart 
539a807549cSderaadt int
Xmanual(const char * args,struct mbr * mbr)540c5fb5a34Skrw Xmanual(const char *args, struct mbr *mbr)
541a807549cSderaadt {
5429d22187fSderaadt 	char			*pager = "/usr/bin/less";
543489bd112Spjanzen 	char			*p;
544a807549cSderaadt 	FILE			*f;
5458c10a749Skrw 	sig_t			 opipe;
546a807549cSderaadt 
54778b4f672Sweingart 	opipe = signal(SIGPIPE, SIG_IGN);
548489bd112Spjanzen 	if ((p = getenv("PAGER")) != NULL && (*p != '\0'))
549489bd112Spjanzen 		pager = p;
55008f8e31fSotto 	if (asprintf(&p, "gunzip -qc|%s", pager) != -1) {
55108f8e31fSotto 		f = popen(p, "w");
552a807549cSderaadt 		if (f) {
553a5472107Skrw 			fwrite(manpage, manpage_sz, 1, f);
554a807549cSderaadt 			pclose(f);
555a807549cSderaadt 		}
55608f8e31fSotto 		free(p);
55708f8e31fSotto 	}
558a807549cSderaadt 
559a5472107Skrw 	signal(SIGPIPE, opipe);
5607126966cSkrw 
5612a536aa2Skrw 	return CMD_CONT;
562a807549cSderaadt }
563543185b3Skrw 
564543185b3Skrw int
ask_num(const char * str,int dflt,int low,int high)565543185b3Skrw ask_num(const char *str, int dflt, int low, int high)
566543185b3Skrw {
56763400da5Skrw 	char			 lbuf[LINEBUFSZ];
568543185b3Skrw 	const char		*errstr;
569543185b3Skrw 	int			 num;
570543185b3Skrw 
571543185b3Skrw 	if (dflt < low)
572543185b3Skrw 		dflt = low;
573543185b3Skrw 	else if (dflt > high)
574543185b3Skrw 		dflt = high;
575543185b3Skrw 
576543185b3Skrw 	do {
577543185b3Skrw 		printf("%s [%d - %d]: [%d] ", str, low, high, dflt);
578380d744dSkrw 		string_from_line(lbuf, sizeof(lbuf), TRIMMED);
579543185b3Skrw 
580543185b3Skrw 		if (lbuf[0] == '\0') {
581543185b3Skrw 			num = dflt;
582543185b3Skrw 			errstr = NULL;
583543185b3Skrw 		} else {
584543185b3Skrw 			num = (int)strtonum(lbuf, low, high, &errstr);
585543185b3Skrw 			if (errstr)
586543185b3Skrw 				printf("%s is %s: %s.\n", str, errstr, lbuf);
587543185b3Skrw 		}
588543185b3Skrw 	} while (errstr);
589543185b3Skrw 
590543185b3Skrw 	return num;
591543185b3Skrw }
592543185b3Skrw 
593543185b3Skrw int
ask_pid(const int dflt)594ede3ff43Skrw ask_pid(const int dflt)
595543185b3Skrw {
59663400da5Skrw 	char			lbuf[LINEBUFSZ];
597ede3ff43Skrw 	int			num;
598543185b3Skrw 
5997696a120Skrw 	for (;;) {
6007696a120Skrw 		printf("Partition id ('0' to disable) [01 - FF]: [%02X] ", dflt);
601543185b3Skrw 		printf("(? for help) ");
602380d744dSkrw 		string_from_line(lbuf, sizeof(lbuf), TRIMMED);
603543185b3Skrw 
6047696a120Skrw 		if (strlen(lbuf) == 0)
6057696a120Skrw 			return dflt;
606380d744dSkrw 		if (strcmp(lbuf, "?") == 0) {
607a0193349Skrw 			PRT_print_mbrmenu(lbuf, sizeof(lbuf));
608a0193349Skrw 			if (strlen(lbuf) == 0)
609543185b3Skrw 				continue;
610543185b3Skrw 		}
611543185b3Skrw 
6127696a120Skrw 		num = hex_octet(lbuf);
6137696a120Skrw 		if (num != -1)
614543185b3Skrw 			return num;
6157696a120Skrw 
6167696a120Skrw 		printf("'%s' is not a valid partition id.\n", lbuf);
6177696a120Skrw 	}
618543185b3Skrw }
619543185b3Skrw 
6208c6d22aeSkrw const struct uuid *
ask_uuid(const struct uuid * olduuid)621ede3ff43Skrw ask_uuid(const struct uuid *olduuid)
622ede3ff43Skrw {
62363400da5Skrw 	char			 lbuf[LINEBUFSZ];
624f3cf20a5Skrw 	static struct uuid	 uuid;
625f3cf20a5Skrw 	const char		*guid;
626f3cf20a5Skrw 	char			*dflt;
627351f0068Skrw 	uint32_t		 status;
628ede3ff43Skrw 
629f3cf20a5Skrw 	dflt = PRT_uuid_to_menudflt(olduuid);
630f3cf20a5Skrw 	if (dflt == NULL) {
631717a7d06Skrw 		if (asprintf(&dflt, "00") == -1) {
632ede3ff43Skrw 			warn("asprintf()");
633ede3ff43Skrw 			goto done;
634ede3ff43Skrw 		}
635f3cf20a5Skrw 	}
636ede3ff43Skrw 
637ede3ff43Skrw 	for (;;) {
638ede3ff43Skrw 		printf("Partition id ('0' to disable) [01 - FF, <uuid>]: [%s] ",
639ede3ff43Skrw 		    dflt);
640ede3ff43Skrw 		printf("(? for help) ");
641ede3ff43Skrw 		string_from_line(lbuf, sizeof(lbuf), TRIMMED);
642ede3ff43Skrw 
643ede3ff43Skrw 		if (strcmp(lbuf, "?") == 0) {
644a0193349Skrw 			PRT_print_gptmenu(lbuf, sizeof(lbuf));
645a0193349Skrw 			if (strlen(lbuf) == 0)
646ede3ff43Skrw 				continue;
647ede3ff43Skrw 		} else if (strlen(lbuf) == 0) {
648ede3ff43Skrw 			uuid = *olduuid;
649ede3ff43Skrw 			goto done;
650ede3ff43Skrw 		}
651ede3ff43Skrw 
652f3cf20a5Skrw 		guid = PRT_menuid_to_guid(hex_octet(lbuf));
653f3cf20a5Skrw 		if (guid == NULL)
654f3cf20a5Skrw 			guid = lbuf;
655f3cf20a5Skrw 
656f3cf20a5Skrw 		uuid_from_string(guid, &uuid, &status);
657ede3ff43Skrw 		if (status == uuid_s_ok)
658ede3ff43Skrw 			goto done;
659ede3ff43Skrw 
660ede3ff43Skrw 		printf("'%s' has no associated UUID\n", lbuf);
661ede3ff43Skrw 	}
662ede3ff43Skrw 
663ede3ff43Skrw  done:
664ede3ff43Skrw 	free(dflt);
665ede3ff43Skrw 	return &uuid;
666ede3ff43Skrw }
667