1 /* $OpenBSD: fdisk.c,v 1.146 2022/07/17 12:53:19 krw Exp $ */
2
3 /*
4 * Copyright (c) 1997 Tobias Weingartner
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/types.h>
20 #include <sys/disklabel.h>
21
22 #include <ctype.h>
23 #include <err.h>
24 #include <fcntl.h>
25 #include <paths.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 #include "part.h"
33 #include "disk.h"
34 #include "mbr.h"
35 #include "cmd.h"
36 #include "misc.h"
37 #include "user.h"
38 #include "gpt.h"
39
40 #define INIT_GPT 1
41 #define INIT_GPTPARTITIONS 2
42 #define INIT_MBR 3
43 #define INIT_MBRBOOTCODE 4
44
45 #define _PATH_MBR _PATH_BOOTDIR "mbr"
46
47 int y_flag;
48
49 void parse_bootprt(const char *);
50 void get_default_dmbr(const char *);
51
52 static void
usage(void)53 usage(void)
54 {
55 extern char * __progname;
56
57 fprintf(stderr, "usage: %s "
58 "[-evy] [-A | -g | -i | -u] [-b blocks[@offset[:type]]]\n"
59 "\t[-l blocks | -c cylinders -h heads -s sectors] [-f file] "
60 "disk\n", __progname);
61 exit(1);
62 }
63
64 int
main(int argc,char * argv[])65 main(int argc, char *argv[])
66 {
67 struct mbr mbr;
68 const char *mbrfile = NULL;
69 const char *errstr;
70 int ch;
71 int e_flag = 0, init = 0;
72 int verbosity = TERSE;
73 int oflags = O_RDONLY;
74
75 while ((ch = getopt(argc, argv, "Ab:c:ef:gh:il:s:uvy")) != -1) {
76 switch(ch) {
77 case 'A':
78 init = INIT_GPTPARTITIONS;
79 break;
80 case 'b':
81 parse_bootprt(optarg);
82 if (disk.dk_bootprt.prt_id != DOSPTYP_EFISYS)
83 disk.dk_bootprt.prt_flag = DOSACTIVE;
84 break;
85 case 'c':
86 disk.dk_cylinders = strtonum(optarg, 1, 262144, &errstr);
87 if (errstr)
88 errx(1, "Cylinder argument %s [1..262144].",
89 errstr);
90 disk.dk_size = 0;
91 break;
92 case 'e':
93 e_flag = 1;
94 break;
95 case 'f':
96 mbrfile = optarg;
97 break;
98 case 'g':
99 init = INIT_GPT;
100 break;
101 case 'h':
102 disk.dk_heads = strtonum(optarg, 1, 256, &errstr);
103 if (errstr)
104 errx(1, "Head argument %s [1..256].", errstr);
105 disk.dk_size = 0;
106 break;
107 case 'i':
108 init = INIT_MBR;
109 break;
110 case 'l':
111 disk.dk_size = strtonum(optarg, BLOCKALIGNMENT,
112 UINT32_MAX, &errstr);
113 if (errstr)
114 errx(1, "Block argument %s [%u..%u].", errstr,
115 BLOCKALIGNMENT, UINT32_MAX);
116 disk.dk_cylinders = disk.dk_heads = disk.dk_sectors = 0;
117 break;
118 case 's':
119 disk.dk_sectors = strtonum(optarg, 1, 63, &errstr);
120 if (errstr)
121 errx(1, "Sector argument %s [1..63].", errstr);
122 disk.dk_size = 0;
123 break;
124 case 'u':
125 init = INIT_MBRBOOTCODE;
126 break;
127 case 'v':
128 verbosity = VERBOSE;
129 break;
130 case 'y':
131 y_flag = 1;
132 break;
133 default:
134 usage();
135 }
136 }
137 argc -= optind;
138 argv += optind;
139
140 if (argc != 1)
141 usage();
142
143 if ((disk.dk_cylinders || disk.dk_heads || disk.dk_sectors) &&
144 (disk.dk_cylinders * disk.dk_heads * disk.dk_sectors == 0))
145 usage();
146
147 if (init || e_flag)
148 oflags = O_RDWR;
149
150 get_default_dmbr(mbrfile);
151
152 DISK_open(argv[0], oflags);
153 if (oflags == O_RDONLY) {
154 if (pledge("stdio", NULL) == -1)
155 err(1, "pledge");
156 USER_print_disk(verbosity);
157 goto done;
158 }
159
160 /*
161 * "stdio" to talk to the outside world.
162 * "proc exec" for man page display.
163 * "disklabel" for DIOCRLDINFO.
164 */
165 if (pledge("stdio disklabel proc exec", NULL) == -1)
166 err(1, "pledge");
167
168 switch (init) {
169 case INIT_GPT:
170 if (GPT_init(GHANDGP))
171 errx(1, "-g could not create valid GPT");
172 if (ask_yn("Do you wish to write new GPT?"))
173 Xwrite(NULL, &gmbr);
174 break;
175 case INIT_GPTPARTITIONS:
176 if (GPT_read(ANYGPT))
177 errx(1, "-A requires a valid GPT");
178 if (GPT_init(GPONLY))
179 errx(1, "-A could not create valid GPT");
180 if (ask_yn("Do you wish to write new GPT?"))
181 Xwrite(NULL, &gmbr);
182 break;
183 case INIT_MBR:
184 mbr.mbr_lba_self = mbr.mbr_lba_firstembr = 0;
185 MBR_init(&mbr);
186 if (ask_yn("Do you wish to write new MBR?"))
187 Xwrite(NULL, &mbr);
188 break;
189 case INIT_MBRBOOTCODE:
190 if (GPT_read(ANYGPT) == 0)
191 errx(1, "-u not available for GPT");
192 if (MBR_read(0, 0, &mbr))
193 errx(1, "Can't read MBR!");
194 memcpy(mbr.mbr_code, default_dmbr.dmbr_boot,
195 sizeof(mbr.mbr_code));
196 if (ask_yn("Do you wish to write new MBR?"))
197 Xwrite(NULL, &mbr);
198 break;
199 default:
200 break;
201 }
202
203 if (e_flag)
204 USER_edit(0, 0);
205
206 done:
207 close(disk.dk_fd);
208
209 return 0;
210 }
211
212 void
parse_bootprt(const char * arg)213 parse_bootprt(const char *arg)
214 {
215 const char *errstr;
216 char *poffset, *ptype;
217 int partitiontype;
218 uint32_t blockcount, blockoffset;
219
220 blockoffset = BLOCKALIGNMENT;
221 partitiontype = DOSPTYP_EFISYS;
222 ptype = NULL;
223
224 /* First number: # of 512-byte blocks in boot partition. */
225 poffset = strchr(arg, '@');
226 if (poffset != NULL)
227 *poffset++ = '\0';
228 if (poffset != NULL) {
229 ptype = strchr(poffset, ':');
230 if (ptype != NULL)
231 *ptype++ = '\0';
232 }
233
234 blockcount = strtonum(arg, 1, UINT32_MAX, &errstr);
235 if (errstr)
236 errx(1, "Block argument %s [%u..%u].", errstr, 1, UINT32_MAX);
237
238 if (poffset == NULL)
239 goto done;
240
241 /* Second number: # of 512-byte blocks to offset partition start. */
242 blockoffset = strtonum(poffset, 1, UINT32_MAX, &errstr);
243 if (errstr)
244 errx(1, "Block offset argument %s [%u..%u].", errstr, 1,
245 UINT32_MAX);
246
247 if (ptype == NULL)
248 goto done;
249
250 partitiontype = hex_octet(ptype);
251 if (partitiontype == -1)
252 errx(1, "Block type is not a 1-2 digit hex value");
253
254 done:
255 disk.dk_bootprt.prt_ns = blockcount;
256 disk.dk_bootprt.prt_bs = blockoffset;
257 disk.dk_bootprt.prt_id = partitiontype;
258 }
259
260 void
get_default_dmbr(const char * mbrfile)261 get_default_dmbr(const char *mbrfile)
262 {
263 struct dos_mbr *dmbr = &default_dmbr;
264 ssize_t len, sz;
265 int fd;
266
267 if (mbrfile == NULL)
268 #ifdef HAS_MBR
269 mbrfile = _PATH_MBR;
270 #else
271 return;
272 #endif
273
274 fd = open(mbrfile, O_RDONLY);
275 if (fd == -1)
276 err(1, "%s", mbrfile);
277
278 sz = sizeof(*dmbr);
279 len = read(fd, dmbr, sz);
280 if (len == -1)
281 err(1, "read('%s')", mbrfile);
282 else if (len != sz)
283 errx(1, "read('%s'): read %zd bytes of %zd", mbrfile, len, sz);
284
285 close(fd);
286 }
287