xref: /openbsd-src/sbin/fdisk/fdisk.c (revision f1dd7b858388b4a23f4f67a4957ec5ff656ebbe8)
1 /*	$OpenBSD: fdisk.c,v 1.107 2021/05/14 15:31:01 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 <err.h>
23 #include <fcntl.h>
24 #include <paths.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 #include "disk.h"
32 #include "part.h"
33 #include "mbr.h"
34 #include "misc.h"
35 #include "cmd.h"
36 #include "user.h"
37 #include "gpt.h"
38 
39 #define _PATH_MBR _PATH_BOOTDIR "mbr"
40 static unsigned char builtin_mbr[] = {
41 #include "mbrcode.h"
42 };
43 
44 uint32_t b_arg;
45 int	y_flag;
46 
47 static void
48 usage(void)
49 {
50 	extern char * __progname;
51 
52 	fprintf(stderr, "usage: %s "
53 	    "[-egvy] [-i|-u] [-b #] [-c # -h # -s #] "
54 	    "[-f mbrfile] [-l # ] disk\n"
55 	    "\t-b: specify special boot partition block count; requires -i\n"
56 	    "\t-chs: specify disk geometry; all three must be specified\n"
57 	    "\t-e: interactively edit MBR or GPT\n"
58 	    "\t-f: specify non-standard MBR template\n"
59 	    "\t-g: initialize disk with GPT; requires -i\n"
60 	    "\t-i: initialize disk with MBR unless -g is also specified\n"
61 	    "\t-l: specify LBA block count; cannot be used with -chs\n"
62 	    "\t-u: update MBR code; preserve partition table\n"
63 	    "\t-v: print the MBR, the Primary GPT and the Secondary GPT\n"
64 	    "\t-y: do not ask questions\n"
65 	    "`disk' may be of the forms: sd0 or /dev/rsd0c.\n",
66 	    __progname);
67 	exit(1);
68 }
69 
70 int
71 main(int argc, char *argv[])
72 {
73 	ssize_t len;
74 	int ch, fd, efi, error;
75 	int e_flag = 0, g_flag = 0, i_flag = 0, u_flag = 0;
76 	int verbosity = TERSE;
77 	int c_arg = 0, h_arg = 0, s_arg = 0;
78 	uint32_t l_arg = 0;
79 	char *query;
80 #ifdef HAS_MBR
81 	char *mbrfile = _PATH_MBR;
82 #else
83 	char *mbrfile = NULL;
84 #endif
85 	struct dos_mbr dos_mbr;
86 	struct mbr mbr;
87 
88 	while ((ch = getopt(argc, argv, "iegpuvf:c:h:s:l:b:y")) != -1) {
89 		const char *errstr;
90 
91 		switch(ch) {
92 		case 'i':
93 			i_flag = 1;
94 			break;
95 		case 'u':
96 			u_flag = 1;
97 			break;
98 		case 'e':
99 			e_flag = 1;
100 			break;
101 		case 'f':
102 			mbrfile = optarg;
103 			break;
104 		case 'c':
105 			c_arg = strtonum(optarg, 1, 262144, &errstr);
106 			if (errstr)
107 				errx(1, "Cylinder argument %s [1..262144].",
108 				    errstr);
109 			disk.cylinders = c_arg;
110 			disk.size = c_arg * h_arg * s_arg;
111 			break;
112 		case 'h':
113 			h_arg = strtonum(optarg, 1, 256, &errstr);
114 			if (errstr)
115 				errx(1, "Head argument %s [1..256].", errstr);
116 			disk.heads = h_arg;
117 			disk.size = c_arg * h_arg * s_arg;
118 			break;
119 		case 's':
120 			s_arg = strtonum(optarg, 1, 63, &errstr);
121 			if (errstr)
122 				errx(1, "Sector argument %s [1..63].", errstr);
123 			disk.sectors = s_arg;
124 			disk.size = c_arg * h_arg * s_arg;
125 			break;
126 		case 'g':
127 			g_flag = 1;
128 			break;
129 		case 'b':
130 			b_arg = strtonum(optarg, 64, UINT32_MAX, &errstr);
131 			if (errstr)
132 				errx(1, "Block argument %s [64..%u].", errstr,
133 				    UINT32_MAX);
134 			break;
135 		case 'l':
136 			l_arg = strtonum(optarg, 64, UINT32_MAX, &errstr);
137 			if (errstr)
138 				errx(1, "Block argument %s [64..%u].", errstr,
139 				    UINT32_MAX);
140 			disk.cylinders = l_arg / 64;
141 			disk.heads = 1;
142 			disk.sectors = 64;
143 			disk.size = l_arg;
144 			break;
145 		case 'y':
146 			y_flag = 1;
147 			break;
148 		case 'v':
149 			verbosity = VERBOSE;
150 			break;
151 		default:
152 			usage();
153 		}
154 	}
155 	argc -= optind;
156 	argv += optind;
157 
158 	/* Argument checking */
159 	if (argc != 1 || (i_flag && u_flag) ||
160 	    (i_flag == 0 && (b_arg || g_flag)) ||
161 	    ((c_arg | h_arg | s_arg) && !(c_arg && h_arg && s_arg)) ||
162 	    ((c_arg | h_arg | s_arg) && l_arg))
163 		usage();
164 
165 	disk.name = argv[0];
166 	DISK_open(i_flag || u_flag || e_flag);
167 
168 	/* "proc exec" for man page display */
169 	if (pledge("stdio rpath wpath disklabel proc exec", NULL) == -1)
170 		err(1, "pledge");
171 
172 	error = MBR_read(0, &dos_mbr);
173 	if (error)
174 		errx(1, "Can't read sector 0!");
175 	MBR_parse(&dos_mbr, 0, 0, &mbr);
176 
177 	/* Get the GPT if present. Either primary or secondary is ok. */
178 	efi = MBR_protective_mbr(&mbr);
179 	if (efi != -1)
180 		GPT_read(ANYGPT);
181 
182 	if (!(i_flag || u_flag || e_flag)) {
183 		if (pledge("stdio", NULL) == -1)
184 			err(1, "pledge");
185 		USER_print_disk(verbosity);
186 		goto done;
187 	}
188 
189 	/* Create initial/default MBR. */
190 	if (mbrfile == NULL) {
191 		memcpy(&dos_mbr, builtin_mbr, sizeof(dos_mbr));
192 	} else {
193 		fd = open(mbrfile, O_RDONLY);
194 		if (fd == -1) {
195 			warn("%s", mbrfile);
196 			warnx("using builtin MBR");
197 			memcpy(&dos_mbr, builtin_mbr, sizeof(dos_mbr));
198 		} else {
199 			len = read(fd, &dos_mbr, sizeof(dos_mbr));
200 			close(fd);
201 			if (len == -1)
202 				err(1, "Unable to read MBR from '%s'", mbrfile);
203 			else if (len != sizeof(dos_mbr))
204 				errx(1, "Unable to read complete MBR from '%s'",
205 				    mbrfile);
206 		}
207 	}
208 	MBR_parse(&dos_mbr, 0, 0, &initial_mbr);
209 
210 	query = NULL;
211 	if (i_flag) {
212 		reinited = 1;
213 		if (g_flag) {
214 			MBR_init_GPT(&initial_mbr);
215 			GPT_init();
216 			query = "Do you wish to write new GPT?";
217 		} else {
218 			memset(&gh, 0, sizeof(gh));
219 			MBR_init(&initial_mbr);
220 			query = "Do you wish to write new MBR and "
221 			    "partition table?";
222 		}
223 	} else if (u_flag) {
224 		memcpy(initial_mbr.part, mbr.part, sizeof(initial_mbr.part));
225 		query = "Do you wish to write new MBR?";
226 	}
227 	if (query && ask_yn(query))
228 		Xwrite(NULL, &initial_mbr);
229 
230 	if (e_flag)
231 		USER_edit(0, 0);
232 
233 done:
234 	close(disk.fd);
235 
236 	return (0);
237 }
238