xref: /openbsd/sbin/fdisk/fdisk.c (revision 4cfece93)
1 /*	$OpenBSD: fdisk.c,v 1.103 2018/04/26 15:55:14 guenther 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 u_int32_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, error;
75 	int e_flag = 0, g_flag = 0, i_flag = 0, u_flag = 0;
76 	int verbosity = 0;
77 	int c_arg = 0, h_arg = 0, s_arg = 0;
78 	u_int32_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++;
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 	if (MBR_protective_mbr(&mbr) == 0)
179 		GPT_get_gpt(0);
180 
181 	if (!(i_flag || u_flag || e_flag)) {
182 		if (pledge("stdio", NULL) == -1)
183 			err(1, "pledge");
184 		USER_print_disk(verbosity);
185 		goto done;
186 	}
187 
188 	/* Create initial/default MBR. */
189 	if (mbrfile == NULL) {
190 		memcpy(&dos_mbr, builtin_mbr, sizeof(dos_mbr));
191 	} else {
192 		fd = open(mbrfile, O_RDONLY);
193 		if (fd == -1) {
194 			warn("%s", mbrfile);
195 			warnx("using builtin MBR");
196 			memcpy(&dos_mbr, builtin_mbr, sizeof(dos_mbr));
197 		} else {
198 			len = read(fd, &dos_mbr, sizeof(dos_mbr));
199 			close(fd);
200 			if (len == -1)
201 				err(1, "Unable to read MBR from '%s'", mbrfile);
202 			else if (len != sizeof(dos_mbr))
203 				errx(1, "Unable to read complete MBR from '%s'",
204 				    mbrfile);
205 		}
206 	}
207 	MBR_parse(&dos_mbr, 0, 0, &initial_mbr);
208 
209 	query = NULL;
210 	if (i_flag) {
211 		reinited = 1;
212 		if (g_flag) {
213 			MBR_init_GPT(&initial_mbr);
214 			GPT_init();
215 			query = "Do you wish to write new GPT?";
216 		} else {
217 			MBR_init(&initial_mbr);
218 			query = "Do you wish to write new MBR and "
219 			    "partition table?";
220 		}
221 	} else if (u_flag) {
222 		memcpy(initial_mbr.part, mbr.part, sizeof(initial_mbr.part));
223 		query = "Do you wish to write new MBR?";
224 	}
225 	if (query && ask_yn(query))
226 		Xwrite(NULL, &initial_mbr);
227 
228 	if (e_flag)
229 		USER_edit(0, 0);
230 
231 done:
232 	close(disk.fd);
233 
234 	return (0);
235 }
236