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