xref: /openbsd-src/sbin/fdisk/fdisk.c (revision 7f367d372299f11a3d56c8d74aaee6fdf5afbd42)
1*7f367d37Skrw /*	$OpenBSD: fdisk.c,v 1.146 2022/07/17 12:53:19 krw Exp $	*/
2df930be7Sderaadt 
3df930be7Sderaadt /*
4a1705421Sweingart  * Copyright (c) 1997 Tobias Weingartner
5df930be7Sderaadt  *
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.
9df930be7Sderaadt  *
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.
17df930be7Sderaadt  */
18df930be7Sderaadt 
1918c9df1dSkrw #include <sys/types.h>
20a7568474Sderaadt #include <sys/disklabel.h>
212331346fSkrw 
22543185b3Skrw #include <ctype.h>
232331346fSkrw #include <err.h>
246316a812Sguenther #include <fcntl.h>
252331346fSkrw #include <paths.h>
262331346fSkrw #include <stdint.h>
27df930be7Sderaadt #include <stdio.h>
28df930be7Sderaadt #include <stdlib.h>
29184a329bSmillert #include <string.h>
30df930be7Sderaadt #include <unistd.h>
31abc6f793Skrw 
32a5472107Skrw #include "part.h"
33199eafeaSkrw #include "disk.h"
34a5472107Skrw #include "mbr.h"
3544f86ab5Skrw #include "cmd.h"
365cbc8961Skrw #include "misc.h"
37a1705421Sweingart #include "user.h"
381cd24417Skrw #include "gpt.h"
39df930be7Sderaadt 
40f43a9f23Skrw #define	INIT_GPT		1
41f43a9f23Skrw #define	INIT_GPTPARTITIONS	2
42f43a9f23Skrw #define	INIT_MBR		3
43f43a9f23Skrw #define	INIT_MBRBOOTCODE	4
44f43a9f23Skrw 
45a1705421Sweingart #define	_PATH_MBR		_PATH_BOOTDIR "mbr"
46df930be7Sderaadt 
47f43a9f23Skrw int			y_flag;
4814813024Sderaadt 
49199eafeaSkrw void			parse_bootprt(const char *);
50be73884bSkrw void			get_default_dmbr(const char *);
51543185b3Skrw 
52b884d431Sderaadt static void
usage(void)538809fabbSderaadt usage(void)
54df930be7Sderaadt {
55d2628bdcSmickey 	extern char		* __progname;
568809fabbSderaadt 
57d2628bdcSmickey 	fprintf(stderr, "usage: %s "
58f43a9f23Skrw 	    "[-evy] [-A | -g | -i | -u] [-b blocks[@offset[:type]]]\n"
59*7f367d37Skrw 	    "\t[-l blocks | -c cylinders -h heads -s sectors] [-f file] "
6099e0469cSkrw 	    "disk\n", __progname);
61df930be7Sderaadt 	exit(1);
62df930be7Sderaadt }
63df930be7Sderaadt 
64df930be7Sderaadt int
main(int argc,char * argv[])658809fabbSderaadt main(int argc, char *argv[])
66df930be7Sderaadt {
678c10a749Skrw 	struct mbr		 mbr;
687ab3c701Skrw 	const char		*mbrfile = NULL;
6964969534Skrw 	const char		*errstr;
7064969534Skrw 	int			 ch;
71f43a9f23Skrw 	int			 e_flag = 0, init = 0;
723bbc645fSkrw 	int			 verbosity = TERSE;
73f9336ec7Skrw 	int			 oflags = O_RDONLY;
74df930be7Sderaadt 
7564969534Skrw 	while ((ch = getopt(argc, argv, "Ab:c:ef:gh:il:s:uvy")) != -1) {
76a1705421Sweingart 		switch(ch) {
7795e8765cSkrw 		case 'A':
78f43a9f23Skrw 			init = INIT_GPTPARTITIONS;
7995e8765cSkrw 			break;
8064969534Skrw 		case 'b':
8164969534Skrw 			parse_bootprt(optarg);
823220ebedSkrw 			if (disk.dk_bootprt.prt_id != DOSPTYP_EFISYS)
833220ebedSkrw 				disk.dk_bootprt.prt_flag = DOSACTIVE;
84a1705421Sweingart 			break;
85a1705421Sweingart 		case 'c':
86f9336ec7Skrw 			disk.dk_cylinders = strtonum(optarg, 1, 262144, &errstr);
8701f485fcSray 			if (errstr)
8801f485fcSray 				errx(1, "Cylinder argument %s [1..262144].",
8901f485fcSray 				    errstr);
90f9336ec7Skrw 			disk.dk_size = 0;
91a1705421Sweingart 			break;
9264969534Skrw 		case 'e':
9364969534Skrw 			e_flag = 1;
9464969534Skrw 			break;
9564969534Skrw 		case 'f':
9664969534Skrw 			mbrfile = optarg;
9764969534Skrw 			break;
9864969534Skrw 		case 'g':
9964969534Skrw 			init = INIT_GPT;
10064969534Skrw 			break;
101a1705421Sweingart 		case 'h':
102f9336ec7Skrw 			disk.dk_heads = strtonum(optarg, 1, 256, &errstr);
10301f485fcSray 			if (errstr)
10401f485fcSray 				errx(1, "Head argument %s [1..256].", errstr);
105f9336ec7Skrw 			disk.dk_size = 0;
106a1705421Sweingart 			break;
10764969534Skrw 		case 'i':
10864969534Skrw 			init = INIT_MBR;
109c1dfe7f7Skettenis 			break;
11015a33686Sderaadt 		case 'l':
11199e0469cSkrw 			disk.dk_size = strtonum(optarg, BLOCKALIGNMENT,
11299e0469cSkrw 			    UINT32_MAX, &errstr);
11315a33686Sderaadt 			if (errstr)
114893a2455Skrw 				errx(1, "Block argument %s [%u..%u].", errstr,
115893a2455Skrw 				    BLOCKALIGNMENT, UINT32_MAX);
116f9336ec7Skrw 			disk.dk_cylinders = disk.dk_heads = disk.dk_sectors = 0;
11715a33686Sderaadt 			break;
11864969534Skrw 		case 's':
11964969534Skrw 			disk.dk_sectors = strtonum(optarg, 1, 63, &errstr);
12064969534Skrw 			if (errstr)
12164969534Skrw 				errx(1, "Sector argument %s [1..63].", errstr);
12264969534Skrw 			disk.dk_size = 0;
12364969534Skrw 			break;
12464969534Skrw 		case 'u':
12564969534Skrw 			init = INIT_MBRBOOTCODE;
12614813024Sderaadt 			break;
127fbf68f68Skrw 		case 'v':
1283bbc645fSkrw 			verbosity = VERBOSE;
129fbf68f68Skrw 			break;
13064969534Skrw 		case 'y':
13164969534Skrw 			y_flag = 1;
13264969534Skrw 			break;
133a1705421Sweingart 		default:
134a1705421Sweingart 			usage();
135a1705421Sweingart 		}
136a1705421Sweingart 	}
137a1705421Sweingart 	argc -= optind;
138a1705421Sweingart 	argv += optind;
139a1705421Sweingart 
140f43a9f23Skrw 	if (argc != 1)
141a1705421Sweingart 		usage();
1427adf9600Skrw 
143f9336ec7Skrw 	if ((disk.dk_cylinders || disk.dk_heads || disk.dk_sectors) &&
144f9336ec7Skrw 	    (disk.dk_cylinders * disk.dk_heads * disk.dk_sectors == 0))
145f9336ec7Skrw 		usage();
146f9336ec7Skrw 
147f43a9f23Skrw 	if (init || e_flag)
148f43a9f23Skrw 		oflags = O_RDWR;
149f43a9f23Skrw 
1509b99195dSkrw 	get_default_dmbr(mbrfile);
1519b99195dSkrw 
152f9336ec7Skrw 	DISK_open(argv[0], oflags);
153199eafeaSkrw 	if (oflags == O_RDONLY) {
154199eafeaSkrw 		if (pledge("stdio", NULL) == -1)
155199eafeaSkrw 			err(1, "pledge");
156199eafeaSkrw 		USER_print_disk(verbosity);
157199eafeaSkrw 		goto done;
158353d3493Skrw 	}
1591f546e5fSjsing 
1609b99195dSkrw 	/*
1619b99195dSkrw 	 * "stdio" to talk to the outside world.
1629b99195dSkrw 	 * "proc exec" for man page display.
1639b99195dSkrw 	 * "disklabel" for DIOCRLDINFO.
1649b99195dSkrw 	 */
1659b99195dSkrw 	if (pledge("stdio disklabel proc exec", NULL) == -1)
1661dbdb6aeStb 		err(1, "pledge");
1671dbdb6aeStb 
168f43a9f23Skrw 	switch (init) {
169f43a9f23Skrw 	case INIT_GPT:
17065deb39bSkrw 		if (GPT_init(GHANDGP))
17165deb39bSkrw 			errx(1, "-g could not create valid GPT");
172f43a9f23Skrw 		if (ask_yn("Do you wish to write new GPT?"))
17344f86ab5Skrw 			Xwrite(NULL, &gmbr);
174f43a9f23Skrw 		break;
175f43a9f23Skrw 	case INIT_GPTPARTITIONS:
176afd1db78Skrw 		if (GPT_read(ANYGPT))
17795e8765cSkrw 			errx(1, "-A requires a valid GPT");
17865deb39bSkrw 		if (GPT_init(GPONLY))
17965deb39bSkrw 			errx(1, "-A could not create valid GPT");
180f43a9f23Skrw 		if (ask_yn("Do you wish to write new GPT?"))
18144f86ab5Skrw 			Xwrite(NULL, &gmbr);
182f43a9f23Skrw 		break;
183f43a9f23Skrw 	case INIT_MBR:
184f43a9f23Skrw 		mbr.mbr_lba_self = mbr.mbr_lba_firstembr = 0;
185f43a9f23Skrw 		MBR_init(&mbr);
186f43a9f23Skrw 		if (ask_yn("Do you wish to write new MBR?"))
18744f86ab5Skrw 			Xwrite(NULL, &mbr);
188f43a9f23Skrw 		break;
189f43a9f23Skrw 	case INIT_MBRBOOTCODE:
190d7e4e1b3Skrw 		if (GPT_read(ANYGPT) == 0)
191d7e4e1b3Skrw 			errx(1, "-u not available for GPT");
19264969534Skrw 		if (MBR_read(0, 0, &mbr))
193dfcac45eSkrw 			errx(1, "Can't read MBR!");
194f43a9f23Skrw 		memcpy(mbr.mbr_code, default_dmbr.dmbr_boot,
195f43a9f23Skrw 		    sizeof(mbr.mbr_code));
196f43a9f23Skrw 		if (ask_yn("Do you wish to write new MBR?"))
19744f86ab5Skrw 			Xwrite(NULL, &mbr);
198f43a9f23Skrw 		break;
199f43a9f23Skrw 	default:
200f43a9f23Skrw 		break;
201e78137c1Skrw 	}
202a1705421Sweingart 
203ab12137eSkrw 	if (e_flag)
2049317a2ddSkrw 		USER_edit(0, 0);
205a1705421Sweingart 
2060db57aa0Skrw done:
20733e90638Skrw 	close(disk.dk_fd);
2080468c08fSkrw 
2092a536aa2Skrw 	return 0;
210df930be7Sderaadt }
211543185b3Skrw 
212543185b3Skrw void
parse_bootprt(const char * arg)213199eafeaSkrw parse_bootprt(const char *arg)
214543185b3Skrw {
215543185b3Skrw 	const char		*errstr;
216543185b3Skrw 	char			*poffset, *ptype;
2177696a120Skrw 	int			 partitiontype;
218543185b3Skrw 	uint32_t		 blockcount, blockoffset;
219543185b3Skrw 
220543185b3Skrw 	blockoffset = BLOCKALIGNMENT;
221543185b3Skrw 	partitiontype = DOSPTYP_EFISYS;
222543185b3Skrw 	ptype = NULL;
223543185b3Skrw 
224543185b3Skrw 	/* First number: # of 512-byte blocks in boot partition. */
225543185b3Skrw 	poffset = strchr(arg, '@');
226543185b3Skrw 	if (poffset != NULL)
227543185b3Skrw 		*poffset++ = '\0';
228543185b3Skrw 	if (poffset != NULL) {
229543185b3Skrw 		ptype = strchr(poffset, ':');
230543185b3Skrw 		if (ptype != NULL)
231543185b3Skrw 			*ptype++ = '\0';
232543185b3Skrw 	}
233543185b3Skrw 
234130c00b7Skrw 	blockcount = strtonum(arg, 1, UINT32_MAX, &errstr);
235543185b3Skrw 	if (errstr)
236130c00b7Skrw 		errx(1, "Block argument %s [%u..%u].", errstr, 1, UINT32_MAX);
237543185b3Skrw 
238543185b3Skrw 	if (poffset == NULL)
239543185b3Skrw 		goto done;
240543185b3Skrw 
241543185b3Skrw 	/* Second number: # of 512-byte blocks to offset partition start. */
242130c00b7Skrw 	blockoffset = strtonum(poffset, 1, UINT32_MAX, &errstr);
243543185b3Skrw 	if (errstr)
244130c00b7Skrw 		errx(1, "Block offset argument %s [%u..%u].", errstr, 1,
245130c00b7Skrw 		    UINT32_MAX);
246543185b3Skrw 
247543185b3Skrw 	if (ptype == NULL)
248543185b3Skrw 		goto done;
249543185b3Skrw 
2507696a120Skrw 	partitiontype = hex_octet(ptype);
2517696a120Skrw 	if (partitiontype == -1)
2527696a120Skrw 		errx(1, "Block type is not a 1-2 digit hex value");
253543185b3Skrw 
254543185b3Skrw  done:
255199eafeaSkrw 	disk.dk_bootprt.prt_ns = blockcount;
256199eafeaSkrw 	disk.dk_bootprt.prt_bs = blockoffset;
257199eafeaSkrw 	disk.dk_bootprt.prt_id = partitiontype;
258543185b3Skrw }
25962b9ed03Skrw 
26062b9ed03Skrw void
get_default_dmbr(const char * mbrfile)261be73884bSkrw get_default_dmbr(const char *mbrfile)
26262b9ed03Skrw {
263be73884bSkrw 	struct dos_mbr		*dmbr = &default_dmbr;
264be73884bSkrw 	ssize_t			 len, sz;
26562b9ed03Skrw 	int			 fd;
26662b9ed03Skrw 
267be73884bSkrw 	if (mbrfile == NULL)
268be73884bSkrw #ifdef HAS_MBR
269be73884bSkrw 		mbrfile = _PATH_MBR;
270be73884bSkrw #else
271be73884bSkrw 		return;
272be73884bSkrw #endif
273be73884bSkrw 
27462b9ed03Skrw 	fd = open(mbrfile, O_RDONLY);
275be73884bSkrw 	if (fd == -1)
276be73884bSkrw 		err(1, "%s", mbrfile);
277be73884bSkrw 
278be73884bSkrw 	sz = sizeof(*dmbr);
279be73884bSkrw 	len = read(fd, dmbr, sz);
28062b9ed03Skrw 	if (len == -1)
281be73884bSkrw 		err(1, "read('%s')", mbrfile);
282be73884bSkrw 	else if (len != sz)
283be73884bSkrw 		errx(1, "read('%s'): read %zd bytes of %zd", mbrfile, len, sz);
28445a092d7Skrw 
28545a092d7Skrw 	close(fd);
28662b9ed03Skrw }
287