1 |
|
|
/* $OpenBSD: fdisk.c,v 1.101 2016/06/25 17:03:22 tb 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/fcntl.h> |
21 |
|
|
#include <sys/disklabel.h> |
22 |
|
|
|
23 |
|
|
#include <err.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 cpath", 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 (letoh64(gh.gh_sig) != GPTSIGNATURE) { |
182 |
|
|
if (DL_GETDSIZE(&dl) > disk.size) |
183 |
|
|
warnx("disk too large (%llu sectors). size truncated.", |
184 |
|
|
(unsigned long long)DL_GETDSIZE(&dl)); |
185 |
|
|
} |
186 |
|
|
|
187 |
|
|
if (!(i_flag || u_flag || e_flag)) { |
188 |
|
|
if (pledge("stdio rpath cpath wpath", NULL) == -1) |
189 |
|
|
err(1, "pledge"); |
190 |
|
|
USER_print_disk(verbosity); |
191 |
|
|
goto done; |
192 |
|
|
} |
193 |
|
|
|
194 |
|
|
/* Create initial/default MBR. */ |
195 |
|
|
if (mbrfile == NULL) { |
196 |
|
|
memcpy(&dos_mbr, builtin_mbr, sizeof(dos_mbr)); |
197 |
|
|
} else { |
198 |
|
|
fd = open(mbrfile, O_RDONLY); |
199 |
|
|
if (fd == -1) { |
200 |
|
|
warn("%s", mbrfile); |
201 |
|
|
warnx("using builtin MBR"); |
202 |
|
|
memcpy(&dos_mbr, builtin_mbr, sizeof(dos_mbr)); |
203 |
|
|
} else { |
204 |
|
|
len = read(fd, &dos_mbr, sizeof(dos_mbr)); |
205 |
|
|
close(fd); |
206 |
|
|
if (len == -1) |
207 |
|
|
err(1, "Unable to read MBR from '%s'", mbrfile); |
208 |
|
|
else if (len != sizeof(dos_mbr)) |
209 |
|
|
errx(1, "Unable to read complete MBR from '%s'", |
210 |
|
|
mbrfile); |
211 |
|
|
} |
212 |
|
|
} |
213 |
|
|
MBR_parse(&dos_mbr, 0, 0, &initial_mbr); |
214 |
|
|
|
215 |
|
|
query = NULL; |
216 |
|
|
if (i_flag) { |
217 |
|
|
reinited = 1; |
218 |
|
|
if (g_flag) { |
219 |
|
|
MBR_init_GPT(&initial_mbr); |
220 |
|
|
GPT_init(); |
221 |
|
|
query = "Do you wish to write new GPT?"; |
222 |
|
|
} else { |
223 |
|
|
MBR_init(&initial_mbr); |
224 |
|
|
query = "Do you wish to write new MBR and " |
225 |
|
|
"partition table?"; |
226 |
|
|
} |
227 |
|
|
} else if (u_flag) { |
228 |
|
|
memcpy(initial_mbr.part, mbr.part, sizeof(initial_mbr.part)); |
229 |
|
|
query = "Do you wish to write new MBR?"; |
230 |
|
|
} |
231 |
|
|
if (query && ask_yn(query)) |
232 |
|
|
Xwrite(NULL, &initial_mbr); |
233 |
|
|
|
234 |
|
|
if (e_flag) |
235 |
|
|
USER_edit(0, 0); |
236 |
|
|
|
237 |
|
|
done: |
238 |
|
|
close(disk.fd); |
239 |
|
|
|
240 |
|
|
return (0); |
241 |
|
|
} |