1 |
|
|
/* $OpenBSD: disklabel.c,v 1.226 2017/09/29 18:32:09 otto Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 1987, 1993 |
5 |
|
|
* The Regents of the University of California. All rights reserved. |
6 |
|
|
* |
7 |
|
|
* This code is derived from software contributed to Berkeley by |
8 |
|
|
* Symmetric Computer Systems. |
9 |
|
|
* |
10 |
|
|
* Redistribution and use in source and binary forms, with or without |
11 |
|
|
* modification, are permitted provided that the following conditions |
12 |
|
|
* are met: |
13 |
|
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
16 |
|
|
* notice, this list of conditions and the following disclaimer in the |
17 |
|
|
* documentation and/or other materials provided with the distribution. |
18 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
19 |
|
|
* may be used to endorse or promote products derived from this software |
20 |
|
|
* without specific prior written permission. |
21 |
|
|
* |
22 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 |
|
|
* SUCH DAMAGE. |
33 |
|
|
*/ |
34 |
|
|
|
35 |
|
|
#include <sys/param.h> /* DEV_BSIZE */ |
36 |
|
|
#include <sys/sysctl.h> |
37 |
|
|
#include <sys/ioctl.h> |
38 |
|
|
#include <sys/dkio.h> |
39 |
|
|
#include <sys/stat.h> |
40 |
|
|
#include <sys/wait.h> |
41 |
|
|
#define DKTYPENAMES |
42 |
|
|
#include <sys/disklabel.h> |
43 |
|
|
|
44 |
|
|
#include <ufs/ffs/fs.h> |
45 |
|
|
|
46 |
|
|
#include <ctype.h> |
47 |
|
|
#include <err.h> |
48 |
|
|
#include <errno.h> |
49 |
|
|
#include <fcntl.h> |
50 |
|
|
#include <limits.h> |
51 |
|
|
#include <signal.h> |
52 |
|
|
#include <string.h> |
53 |
|
|
#include <stdio.h> |
54 |
|
|
#include <stdlib.h> |
55 |
|
|
#include <unistd.h> |
56 |
|
|
#include <util.h> |
57 |
|
|
#include <fstab.h> |
58 |
|
|
#include "pathnames.h" |
59 |
|
|
#include "extern.h" |
60 |
|
|
|
61 |
|
|
/* |
62 |
|
|
* Disklabel: read and write disklabels. |
63 |
|
|
* The label is usually placed on one of the first sectors of the disk. |
64 |
|
|
* Many machines also place a bootstrap in the same area, |
65 |
|
|
* in which case the label is embedded in the bootstrap. |
66 |
|
|
* The bootstrap source must leave space at the proper offset |
67 |
|
|
* for the label on such machines. |
68 |
|
|
*/ |
69 |
|
|
|
70 |
|
|
#ifndef BBSIZE |
71 |
|
|
#define BBSIZE 8192 /* size of boot area, with label */ |
72 |
|
|
#endif |
73 |
|
|
|
74 |
|
|
char *dkname, *specname, *fstabfile; |
75 |
|
|
char tmpfil[] = _PATH_TMPFILE; |
76 |
|
|
char *mountpoints[MAXPARTITIONS]; |
77 |
|
|
struct disklabel lab; |
78 |
|
|
enum { |
79 |
|
|
UNSPEC, EDIT, EDITOR, READ, RESTORE, WRITE |
80 |
|
|
} op = UNSPEC; |
81 |
|
|
|
82 |
|
|
int aflag; |
83 |
|
|
int cflag; |
84 |
|
|
int dflag; |
85 |
|
|
int tflag; |
86 |
|
|
int uidflag; |
87 |
|
|
int verbose; |
88 |
|
|
int quiet; |
89 |
|
|
int donothing; |
90 |
|
|
char print_unit; |
91 |
|
|
|
92 |
|
|
void makedisktab(FILE *, struct disklabel *); |
93 |
|
|
void makelabel(char *, char *, struct disklabel *); |
94 |
|
|
int writelabel(int, struct disklabel *); |
95 |
|
|
void l_perror(char *); |
96 |
|
|
int edit(struct disklabel *, int); |
97 |
|
|
int editit(const char *); |
98 |
|
|
char *skip(char *); |
99 |
|
|
char *word(char *); |
100 |
|
|
int getasciilabel(FILE *, struct disklabel *); |
101 |
|
|
int cmplabel(struct disklabel *, struct disklabel *); |
102 |
|
|
void usage(void); |
103 |
|
|
u_int64_t getnum(char *, u_int64_t, u_int64_t, const char **); |
104 |
|
|
|
105 |
|
|
int64_t physmem; |
106 |
|
|
|
107 |
|
|
void |
108 |
|
|
getphysmem(void) |
109 |
|
|
{ |
110 |
|
|
size_t sz = sizeof(physmem); |
111 |
|
|
int mib[] = { CTL_HW, HW_PHYSMEM64 }; |
112 |
|
|
|
113 |
|
|
if (sysctl(mib, 2, &physmem, &sz, NULL, (size_t)0) == -1) |
114 |
|
|
errx(4, "can't get mem size"); |
115 |
|
|
} |
116 |
|
|
|
117 |
|
|
int |
118 |
|
|
main(int argc, char *argv[]) |
119 |
|
|
{ |
120 |
|
|
int ch, f, error = 0; |
121 |
|
|
FILE *t; |
122 |
|
|
char *autotable = NULL; |
123 |
|
|
|
124 |
|
|
getphysmem(); |
125 |
|
|
|
126 |
|
|
while ((ch = getopt(argc, argv, "AEf:F:hRcdenp:tT:vw")) != -1) |
127 |
|
|
switch (ch) { |
128 |
|
|
case 'A': |
129 |
|
|
aflag = 1; |
130 |
|
|
break; |
131 |
|
|
case 'R': |
132 |
|
|
if (op != UNSPEC) |
133 |
|
|
usage(); |
134 |
|
|
op = RESTORE; |
135 |
|
|
break; |
136 |
|
|
case 'c': |
137 |
|
|
cflag = 1; |
138 |
|
|
break; |
139 |
|
|
case 'd': |
140 |
|
|
dflag = 1; |
141 |
|
|
break; |
142 |
|
|
case 'e': |
143 |
|
|
if (op != UNSPEC) |
144 |
|
|
usage(); |
145 |
|
|
op = EDIT; |
146 |
|
|
break; |
147 |
|
|
case 'E': |
148 |
|
|
if (op != UNSPEC) |
149 |
|
|
usage(); |
150 |
|
|
op = EDITOR; |
151 |
|
|
break; |
152 |
|
|
case 'f': |
153 |
|
|
fstabfile = optarg; |
154 |
|
|
uidflag = 0; |
155 |
|
|
break; |
156 |
|
|
case 'F': |
157 |
|
|
fstabfile = optarg; |
158 |
|
|
uidflag = 1; |
159 |
|
|
break; |
160 |
|
|
case 'h': |
161 |
|
|
print_unit = '*'; |
162 |
|
|
break; |
163 |
|
|
case 't': |
164 |
|
|
tflag = 1; |
165 |
|
|
break; |
166 |
|
|
case 'T': |
167 |
|
|
autotable = optarg; |
168 |
|
|
break; |
169 |
|
|
case 'w': |
170 |
|
|
if (op != UNSPEC) |
171 |
|
|
usage(); |
172 |
|
|
op = WRITE; |
173 |
|
|
break; |
174 |
|
|
case 'p': |
175 |
|
|
if (strchr("bckmgtBCKMGT", optarg[0]) == NULL || |
176 |
|
|
optarg[1] != '\0') { |
177 |
|
|
fprintf(stderr, "Valid units are bckmgt\n"); |
178 |
|
|
return 1; |
179 |
|
|
} |
180 |
|
|
print_unit = tolower((unsigned char)optarg[0]); |
181 |
|
|
break; |
182 |
|
|
case 'n': |
183 |
|
|
donothing = 1; |
184 |
|
|
break; |
185 |
|
|
case 'v': |
186 |
|
|
verbose = 1; |
187 |
|
|
break; |
188 |
|
|
case '?': |
189 |
|
|
default: |
190 |
|
|
usage(); |
191 |
|
|
} |
192 |
|
|
argc -= optind; |
193 |
|
|
argv += optind; |
194 |
|
|
|
195 |
|
|
if (op == UNSPEC) |
196 |
|
|
op = READ; |
197 |
|
|
|
198 |
|
|
if (argc < 1 || (fstabfile && !(op == EDITOR || op == RESTORE || |
199 |
|
|
aflag))) |
200 |
|
|
usage(); |
201 |
|
|
|
202 |
|
|
if (argv[0] == NULL) |
203 |
|
|
usage(); |
204 |
|
|
dkname = argv[0]; |
205 |
|
|
f = opendev(dkname, (op == READ ? O_RDONLY : O_RDWR), OPENDEV_PART, |
206 |
|
|
&specname); |
207 |
|
|
if (f < 0) |
208 |
|
|
err(4, "%s", specname); |
209 |
|
|
|
210 |
|
|
if (op != WRITE || aflag || dflag) { |
211 |
|
|
readlabel(f); |
212 |
|
|
|
213 |
|
|
if (op == EDIT || op == EDITOR || aflag) { |
214 |
|
|
if (pledge("stdio rpath wpath cpath disklabel proc " |
215 |
|
|
"exec", NULL) == -1) |
216 |
|
|
err(1, "pledge"); |
217 |
|
|
} else if (fstabfile) { |
218 |
|
|
if (pledge("stdio rpath wpath cpath disklabel flock", NULL) |
219 |
|
|
== -1) |
220 |
|
|
err(1, "pledge"); |
221 |
|
|
} else { |
222 |
|
|
if (pledge("stdio rpath wpath disklabel flock cpath", NULL) == -1) |
223 |
|
|
err(1, "pledge"); |
224 |
|
|
} |
225 |
|
|
|
226 |
|
|
if (autotable != NULL) |
227 |
|
|
parse_autotable(autotable); |
228 |
|
|
error = parselabel(); |
229 |
|
|
if (op == WRITE && aflag && error) |
230 |
|
|
errx(1, "autoalloc failed"); |
231 |
|
|
} else if (argc == 2 || argc == 3) { |
232 |
|
|
/* Ensure f is a disk device before pledging. */ |
233 |
|
|
if (ioctl(f, DIOCGDINFO, &lab) < 0) |
234 |
|
|
err(4, "ioctl DIOCGDINFO"); |
235 |
|
|
|
236 |
|
|
if (pledge("stdio rpath wpath disklabel flock cpath", NULL) == -1) |
237 |
|
|
err(1, "pledge"); |
238 |
|
|
|
239 |
|
|
makelabel(argv[1], argc == 3 ? argv[2] : NULL, &lab); |
240 |
|
|
} else |
241 |
|
|
usage(); |
242 |
|
|
|
243 |
|
|
switch (op) { |
244 |
|
|
case EDIT: |
245 |
|
|
if (argc != 1) |
246 |
|
|
usage(); |
247 |
|
|
error = edit(&lab, f); |
248 |
|
|
break; |
249 |
|
|
case EDITOR: |
250 |
|
|
if (argc != 1) |
251 |
|
|
usage(); |
252 |
|
|
error = editor(f); |
253 |
|
|
break; |
254 |
|
|
case READ: |
255 |
|
|
if (argc != 1) |
256 |
|
|
usage(); |
257 |
|
|
|
258 |
|
|
if (pledge("stdio flock rpath cpath wpath", NULL) == -1) |
259 |
|
|
err(1, "pledge"); |
260 |
|
|
|
261 |
|
|
if (tflag) |
262 |
|
|
makedisktab(stdout, &lab); |
263 |
|
|
else |
264 |
|
|
display(stdout, &lab, print_unit, 1); |
265 |
|
|
error = checklabel(&lab); |
266 |
|
|
break; |
267 |
|
|
case RESTORE: |
268 |
|
|
if (argc < 2 || argc > 3) |
269 |
|
|
usage(); |
270 |
|
|
if (!(t = fopen(argv[1], "r"))) |
271 |
|
|
err(4, "%s", argv[1]); |
272 |
|
|
error = getasciilabel(t, &lab); |
273 |
|
|
memset(&lab.d_uid, 0, sizeof(lab.d_uid)); |
274 |
|
|
if (error == 0) { |
275 |
|
|
error = writelabel(f, &lab); |
276 |
|
|
if (error == 0) { |
277 |
|
|
if (ioctl(f, DIOCGDINFO, &lab) < 0) |
278 |
|
|
err(4, "ioctl DIOCGDINFO"); |
279 |
|
|
mpsave(&lab); |
280 |
|
|
} |
281 |
|
|
} |
282 |
|
|
fclose(t); |
283 |
|
|
break; |
284 |
|
|
case WRITE: |
285 |
|
|
error = checklabel(&lab); |
286 |
|
|
if (error == 0) |
287 |
|
|
error = writelabel(f, &lab); |
288 |
|
|
break; |
289 |
|
|
default: |
290 |
|
|
break; |
291 |
|
|
} |
292 |
|
|
return error; |
293 |
|
|
} |
294 |
|
|
|
295 |
|
|
/* |
296 |
|
|
* Construct a prototype disklabel from /etc/disktab. As a side |
297 |
|
|
* effect, set the names of the primary and secondary boot files |
298 |
|
|
* if specified. |
299 |
|
|
*/ |
300 |
|
|
void |
301 |
|
|
makelabel(char *type, char *name, struct disklabel *lp) |
302 |
|
|
{ |
303 |
|
|
struct disklabel *dp; |
304 |
|
|
|
305 |
|
|
dp = getdiskbyname(type); |
306 |
|
|
if (dp == NULL) |
307 |
|
|
errx(1, "unknown disk type: %s", type); |
308 |
|
|
*lp = *dp; |
309 |
|
|
/* d_packname is union d_boot[01], so zero */ |
310 |
|
|
memset(lp->d_packname, 0, sizeof(lp->d_packname)); |
311 |
|
|
if (name) |
312 |
|
|
(void)strncpy(lp->d_packname, name, sizeof(lp->d_packname)); |
313 |
|
|
} |
314 |
|
|
|
315 |
|
|
|
316 |
|
|
int |
317 |
|
|
writelabel(int f, struct disklabel *lp) |
318 |
|
|
{ |
319 |
|
|
lp->d_magic = DISKMAGIC; |
320 |
|
|
lp->d_magic2 = DISKMAGIC; |
321 |
|
|
lp->d_checksum = 0; |
322 |
|
|
lp->d_checksum = dkcksum(lp); |
323 |
|
|
if (!donothing) { |
324 |
|
|
if (ioctl(f, DIOCWDINFO, lp) < 0) { |
325 |
|
|
l_perror("ioctl DIOCWDINFO"); |
326 |
|
|
return (1); |
327 |
|
|
} |
328 |
|
|
} |
329 |
|
|
|
330 |
|
|
/* Finally, write out any mount point information. */ |
331 |
|
|
if (!donothing) { |
332 |
|
|
/* First refresh our copy of the current label to get UID. */ |
333 |
|
|
if (ioctl(f, DIOCGDINFO, &lab) < 0) |
334 |
|
|
err(4, "ioctl DIOCGDINFO"); |
335 |
|
|
mpsave(lp); |
336 |
|
|
} |
337 |
|
|
|
338 |
|
|
return (0); |
339 |
|
|
} |
340 |
|
|
|
341 |
|
|
void |
342 |
|
|
l_perror(char *s) |
343 |
|
|
{ |
344 |
|
|
|
345 |
|
|
switch (errno) { |
346 |
|
|
case ESRCH: |
347 |
|
|
warnx("%s: No disk label on disk", s); |
348 |
|
|
break; |
349 |
|
|
case EINVAL: |
350 |
|
|
warnx("%s: Label magic number or checksum is wrong!\n" |
351 |
|
|
"(disklabel or kernel is out of date?)", s); |
352 |
|
|
break; |
353 |
|
|
case EBUSY: |
354 |
|
|
warnx("%s: Open partition would move or shrink", s); |
355 |
|
|
break; |
356 |
|
|
case EXDEV: |
357 |
|
|
warnx("%s: Labeled partition or 'a' partition must start " |
358 |
|
|
"at beginning of disk", s); |
359 |
|
|
break; |
360 |
|
|
default: |
361 |
|
|
warn("%s", s); |
362 |
|
|
break; |
363 |
|
|
} |
364 |
|
|
} |
365 |
|
|
|
366 |
|
|
/* |
367 |
|
|
* Fetch requested disklabel into 'lab' using ioctl. |
368 |
|
|
*/ |
369 |
|
|
void |
370 |
|
|
readlabel(int f) |
371 |
|
|
{ |
372 |
|
|
|
373 |
|
|
if (cflag && ioctl(f, DIOCRLDINFO) < 0) |
374 |
|
|
err(4, "ioctl DIOCRLDINFO"); |
375 |
|
|
|
376 |
|
|
if ((op == RESTORE) || dflag || aflag) { |
377 |
|
|
if (ioctl(f, DIOCGPDINFO, &lab) < 0) |
378 |
|
|
err(4, "ioctl DIOCGPDINFO"); |
379 |
|
|
} else { |
380 |
|
|
if (ioctl(f, DIOCGDINFO, &lab) < 0) |
381 |
|
|
err(4, "ioctl DIOCGDINFO"); |
382 |
|
|
} |
383 |
|
|
} |
384 |
|
|
|
385 |
|
|
int |
386 |
|
|
parselabel(void) |
387 |
|
|
{ |
388 |
|
|
char *partname, *partduid; |
389 |
|
|
struct fstab *fsent; |
390 |
|
|
int i; |
391 |
|
|
|
392 |
|
|
i = asprintf(&partname, "/dev/%s%c", dkname, 'a'); |
393 |
|
|
if (i == -1) |
394 |
|
|
err(4, NULL); |
395 |
|
|
i = asprintf(&partduid, |
396 |
|
|
"%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.a", |
397 |
|
|
lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3], |
398 |
|
|
lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7]); |
399 |
|
|
if (i == -1) |
400 |
|
|
err(4, NULL); |
401 |
|
|
setfsent(); |
402 |
|
|
for (i = 0; i < MAXPARTITIONS; i++) { |
403 |
|
|
partname[strlen(dkname) + 5] = 'a' + i; |
404 |
|
|
partduid[strlen(partduid) - 1] = 'a' + i; |
405 |
|
|
fsent = getfsspec(partname); |
406 |
|
|
if (fsent == NULL) |
407 |
|
|
fsent = getfsspec(partduid); |
408 |
|
|
if (fsent) |
409 |
|
|
mountpoints[i] = strdup(fsent->fs_file); |
410 |
|
|
} |
411 |
|
|
endfsent(); |
412 |
|
|
free(partduid); |
413 |
|
|
free(partname); |
414 |
|
|
|
415 |
|
|
if (aflag) |
416 |
|
|
return editor_allocspace(&lab); |
417 |
|
|
return 0; |
418 |
|
|
} |
419 |
|
|
|
420 |
|
|
void |
421 |
|
|
makedisktab(FILE *f, struct disklabel *lp) |
422 |
|
|
{ |
423 |
|
|
int i; |
424 |
|
|
struct partition *pp; |
425 |
|
|
|
426 |
|
|
if (lp->d_packname[0]) |
427 |
|
|
(void)fprintf(f, "%.*s|", (int)sizeof(lp->d_packname), |
428 |
|
|
lp->d_packname); |
429 |
|
|
if (lp->d_typename[0]) |
430 |
|
|
(void)fprintf(f, "%.*s|", (int)sizeof(lp->d_typename), |
431 |
|
|
lp->d_typename); |
432 |
|
|
(void)fputs("Automatically generated label:\\\n\t:dt=", f); |
433 |
|
|
if (lp->d_type < DKMAXTYPES) |
434 |
|
|
(void)fprintf(f, "%s:", dktypenames[lp->d_type]); |
435 |
|
|
else |
436 |
|
|
(void)fprintf(f, "unknown%d:", lp->d_type); |
437 |
|
|
|
438 |
|
|
(void)fprintf(f, "se#%u:", lp->d_secsize); |
439 |
|
|
(void)fprintf(f, "ns#%u:", lp->d_nsectors); |
440 |
|
|
(void)fprintf(f, "nt#%u:", lp->d_ntracks); |
441 |
|
|
(void)fprintf(f, "nc#%u:", lp->d_ncylinders); |
442 |
|
|
(void)fprintf(f, "sc#%u:", lp->d_secpercyl); |
443 |
|
|
(void)fprintf(f, "su#%llu:", DL_GETDSIZE(lp)); |
444 |
|
|
|
445 |
|
|
/* |
446 |
|
|
* XXX We do not print have disktab information yet for |
447 |
|
|
* XXX DL_GETBSTART DL_GETBEND |
448 |
|
|
*/ |
449 |
|
|
for (i = 0; i < NDDATA; i++) |
450 |
|
|
if (lp->d_drivedata[i]) |
451 |
|
|
(void)fprintf(f, "d%d#%u", i, lp->d_drivedata[i]); |
452 |
|
|
pp = lp->d_partitions; |
453 |
|
|
for (i = 0; i < lp->d_npartitions; i++, pp++) { |
454 |
|
|
if (DL_GETPSIZE(pp)) { |
455 |
|
|
char c = 'a' + i; |
456 |
|
|
|
457 |
|
|
(void)fprintf(f, "\\\n\t:"); |
458 |
|
|
(void)fprintf(f, "p%c#%llu:", c, DL_GETPSIZE(pp)); |
459 |
|
|
(void)fprintf(f, "o%c#%llu:", c, DL_GETPOFFSET(pp)); |
460 |
|
|
if (pp->p_fstype != FS_UNUSED) { |
461 |
|
|
if (pp->p_fstype < FSMAXTYPES) |
462 |
|
|
(void)fprintf(f, "t%c=%s:", c, |
463 |
|
|
fstypenames[pp->p_fstype]); |
464 |
|
|
else |
465 |
|
|
(void)fprintf(f, "t%c=unknown%d:", |
466 |
|
|
c, pp->p_fstype); |
467 |
|
|
} |
468 |
|
|
switch (pp->p_fstype) { |
469 |
|
|
|
470 |
|
|
case FS_UNUSED: |
471 |
|
|
break; |
472 |
|
|
|
473 |
|
|
case FS_BSDFFS: |
474 |
|
|
(void)fprintf(f, "b%c#%u:", c, |
475 |
|
|
DISKLABELV1_FFS_BSIZE(pp->p_fragblock)); |
476 |
|
|
(void)fprintf(f, "f%c#%u:", c, |
477 |
|
|
DISKLABELV1_FFS_FSIZE(pp->p_fragblock)); |
478 |
|
|
break; |
479 |
|
|
|
480 |
|
|
default: |
481 |
|
|
break; |
482 |
|
|
} |
483 |
|
|
} |
484 |
|
|
} |
485 |
|
|
(void)fputc('\n', f); |
486 |
|
|
(void)fflush(f); |
487 |
|
|
} |
488 |
|
|
|
489 |
|
|
double |
490 |
|
|
scale(u_int64_t sz, char unit, struct disklabel *lp) |
491 |
|
|
{ |
492 |
|
|
double fsz; |
493 |
|
|
|
494 |
|
|
fsz = (double)sz * lp->d_secsize; |
495 |
|
|
|
496 |
|
|
switch (unit) { |
497 |
|
|
case 'B': |
498 |
|
|
return fsz; |
499 |
|
|
case 'C': |
500 |
|
|
return fsz / lp->d_secsize / lp->d_secpercyl; |
501 |
|
|
case 'K': |
502 |
|
|
return fsz / 1024; |
503 |
|
|
case 'M': |
504 |
|
|
return fsz / (1024 * 1024); |
505 |
|
|
case 'G': |
506 |
|
|
return fsz / (1024 * 1024 * 1024); |
507 |
|
|
case 'T': |
508 |
|
|
return fsz / (1024ULL * 1024 * 1024 * 1024); |
509 |
|
|
default: |
510 |
|
|
return -1.0; |
511 |
|
|
} |
512 |
|
|
} |
513 |
|
|
|
514 |
|
|
/* |
515 |
|
|
* Display a particular partition. |
516 |
|
|
*/ |
517 |
|
|
void |
518 |
|
|
display_partition(FILE *f, struct disklabel *lp, int i, char unit) |
519 |
|
|
{ |
520 |
|
|
volatile struct partition *pp = &lp->d_partitions[i]; |
521 |
|
|
double p_size; |
522 |
|
|
|
523 |
|
|
p_size = scale(DL_GETPSIZE(pp), unit, lp); |
524 |
|
|
if (DL_GETPSIZE(pp)) { |
525 |
|
|
u_int32_t frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); |
526 |
|
|
u_int32_t fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); |
527 |
|
|
|
528 |
|
|
if (p_size < 0) |
529 |
|
|
fprintf(f, " %c: %16llu %16llu ", 'a' + i, |
530 |
|
|
DL_GETPSIZE(pp), DL_GETPOFFSET(pp)); |
531 |
|
|
else |
532 |
|
|
fprintf(f, " %c: %15.*f%c %16llu ", 'a' + i, |
533 |
|
|
unit == 'B' ? 0 : 1, p_size, unit, |
534 |
|
|
DL_GETPOFFSET(pp)); |
535 |
|
|
if (pp->p_fstype < FSMAXTYPES) |
536 |
|
|
fprintf(f, "%7.7s", fstypenames[pp->p_fstype]); |
537 |
|
|
else |
538 |
|
|
fprintf(f, "%7d", pp->p_fstype); |
539 |
|
|
|
540 |
|
|
switch (pp->p_fstype) { |
541 |
|
|
case FS_BSDFFS: |
542 |
|
|
fprintf(f, " %5u %5u %5hu ", |
543 |
|
|
fsize, fsize * frag, |
544 |
|
|
pp->p_cpg); |
545 |
|
|
break; |
546 |
|
|
default: |
547 |
|
|
fprintf(f, "%20.20s", ""); |
548 |
|
|
break; |
549 |
|
|
} |
550 |
|
|
|
551 |
|
|
if (mountpoints[i] != NULL) |
552 |
|
|
fprintf(f, "# %s", mountpoints[i]); |
553 |
|
|
putc('\n', f); |
554 |
|
|
} |
555 |
|
|
} |
556 |
|
|
|
557 |
|
|
char |
558 |
|
|
canonical_unit(struct disklabel *lp, char unit) |
559 |
|
|
{ |
560 |
|
|
struct partition *pp; |
561 |
|
|
u_int64_t small; |
562 |
|
|
int i; |
563 |
|
|
|
564 |
|
|
if (unit == '*') { |
565 |
|
|
small = DL_GETDSIZE(lp); |
566 |
|
|
pp = &lp->d_partitions[0]; |
567 |
|
|
for (i = 0; i < lp->d_npartitions; i++, pp++) |
568 |
|
|
if (DL_GETPSIZE(pp) > 0 && DL_GETPSIZE(pp) < small) |
569 |
|
|
small = DL_GETPSIZE(pp); |
570 |
|
|
if (small < DL_BLKTOSEC(lp, MEG(1))) |
571 |
|
|
unit = 'K'; |
572 |
|
|
else if (small < DL_BLKTOSEC(lp, MEG(1024))) |
573 |
|
|
unit = 'M'; |
574 |
|
|
else if (small < DL_BLKTOSEC(lp, GIG(1024))) |
575 |
|
|
unit = 'G'; |
576 |
|
|
else |
577 |
|
|
unit = 'T'; |
578 |
|
|
} |
579 |
|
|
unit = toupper((unsigned char)unit); |
580 |
|
|
|
581 |
|
|
return (unit); |
582 |
|
|
} |
583 |
|
|
|
584 |
|
|
void |
585 |
|
|
display(FILE *f, struct disklabel *lp, char unit, int all) |
586 |
|
|
{ |
587 |
|
|
int i, j; |
588 |
|
|
double d; |
589 |
|
|
|
590 |
|
|
unit = canonical_unit(lp, unit); |
591 |
|
|
|
592 |
|
|
fprintf(f, "# %s:\n", specname); |
593 |
|
|
|
594 |
|
|
if (lp->d_type < DKMAXTYPES) |
595 |
|
|
fprintf(f, "type: %s\n", dktypenames[lp->d_type]); |
596 |
|
|
else |
597 |
|
|
fprintf(f, "type: %d\n", lp->d_type); |
598 |
|
|
fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename), |
599 |
|
|
lp->d_typename); |
600 |
|
|
fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), |
601 |
|
|
lp->d_packname); |
602 |
|
|
fprintf(f, "duid: %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n", |
603 |
|
|
lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3], |
604 |
|
|
lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]); |
605 |
|
|
fprintf(f, "flags:"); |
606 |
|
|
if (lp->d_flags & D_BADSECT) |
607 |
|
|
fprintf(f, " badsect"); |
608 |
|
|
if (lp->d_flags & D_VENDOR) |
609 |
|
|
fprintf(f, " vendor"); |
610 |
|
|
putc('\n', f); |
611 |
|
|
|
612 |
|
|
fprintf(f, "bytes/sector: %u\n", lp->d_secsize); |
613 |
|
|
fprintf(f, "sectors/track: %u\n", lp->d_nsectors); |
614 |
|
|
fprintf(f, "tracks/cylinder: %u\n", lp->d_ntracks); |
615 |
|
|
fprintf(f, "sectors/cylinder: %u\n", lp->d_secpercyl); |
616 |
|
|
fprintf(f, "cylinders: %u\n", lp->d_ncylinders); |
617 |
|
|
fprintf(f, "total sectors: %llu", DL_GETDSIZE(lp)); |
618 |
|
|
d = scale(DL_GETDSIZE(lp), unit, lp); |
619 |
|
|
if (d > 0) |
620 |
|
|
fprintf(f, " # total bytes: %.*f%c", unit == 'B' ? 0 : 1, |
621 |
|
|
d, unit); |
622 |
|
|
fprintf(f, "\n"); |
623 |
|
|
|
624 |
|
|
fprintf(f, "boundstart: %llu\n", DL_GETBSTART(lp)); |
625 |
|
|
fprintf(f, "boundend: %llu\n", DL_GETBEND(lp)); |
626 |
|
|
fprintf(f, "drivedata: "); |
627 |
|
|
for (i = NDDATA - 1; i >= 0; i--) |
628 |
|
|
if (lp->d_drivedata[i]) |
629 |
|
|
break; |
630 |
|
|
if (i < 0) |
631 |
|
|
i = 0; |
632 |
|
|
for (j = 0; j <= i; j++) |
633 |
|
|
fprintf(f, "%d ", lp->d_drivedata[j]); |
634 |
|
|
fprintf(f, "\n"); |
635 |
|
|
if (all) { |
636 |
|
|
fprintf(f, "\n%hu partitions:\n", lp->d_npartitions); |
637 |
|
|
fprintf(f, "# %16.16s %16.16s fstype [fsize bsize cpg]\n", |
638 |
|
|
"size", "offset"); |
639 |
|
|
for (i = 0; i < lp->d_npartitions; i++) |
640 |
|
|
display_partition(f, lp, i, unit); |
641 |
|
|
} |
642 |
|
|
fflush(f); |
643 |
|
|
} |
644 |
|
|
|
645 |
|
|
int |
646 |
|
|
edit(struct disklabel *lp, int f) |
647 |
|
|
{ |
648 |
|
|
int first, ch, fd, error = 0; |
649 |
|
|
struct disklabel label; |
650 |
|
|
FILE *fp; |
651 |
|
|
u_int64_t total_sectors, starting_sector, ending_sector; |
652 |
|
|
|
653 |
|
|
if ((fd = mkstemp(tmpfil)) == -1 || (fp = fdopen(fd, "w")) == NULL) { |
654 |
|
|
warn("%s", tmpfil); |
655 |
|
|
if (fd != -1) |
656 |
|
|
close(fd); |
657 |
|
|
return (1); |
658 |
|
|
} |
659 |
|
|
display(fp, lp, 0, 1); |
660 |
|
|
fprintf(fp, "\n# Notes:\n"); |
661 |
|
|
fprintf(fp, |
662 |
|
|
"# Up to 16 partitions are valid, named from 'a' to 'p'. Partition 'a' is\n" |
663 |
|
|
"# your root filesystem, 'b' is your swap, and 'c' should cover your whole\n" |
664 |
|
|
"# disk. Any other partition is free for any use. 'size' and 'offset' are\n" |
665 |
|
|
"# in 512-byte blocks. fstype should be '4.2BSD', 'swap', or 'none' or some\n" |
666 |
|
|
"# other values. fsize/bsize/cpg should typically be '2048 16384 16' for a\n" |
667 |
|
|
"# 4.2BSD filesystem (or '512 4096 16' except on alpha, sun4, ...)\n"); |
668 |
|
|
fclose(fp); |
669 |
|
|
for (;;) { |
670 |
|
|
if (editit(tmpfil) == -1) |
671 |
|
|
break; |
672 |
|
|
fp = fopen(tmpfil, "r"); |
673 |
|
|
if (fp == NULL) { |
674 |
|
|
warn("%s", tmpfil); |
675 |
|
|
break; |
676 |
|
|
} |
677 |
|
|
/* Get values set by OS and not the label. */ |
678 |
|
|
if (ioctl(f, DIOCGPDINFO, &label) < 0) |
679 |
|
|
err(4, "ioctl DIOCGPDINFO"); |
680 |
|
|
ending_sector = DL_GETBEND(&label); |
681 |
|
|
starting_sector = DL_GETBSTART(&label); |
682 |
|
|
total_sectors = DL_GETDSIZE(&label); |
683 |
|
|
error = getasciilabel(fp, &label); |
684 |
|
|
DL_SETBEND(&label, ending_sector); |
685 |
|
|
DL_SETBSTART(&label, starting_sector); |
686 |
|
|
DL_SETDSIZE(&label, total_sectors); |
687 |
|
|
|
688 |
|
|
if (error == 0) { |
689 |
|
|
if (cmplabel(lp, &label) == 0) { |
690 |
|
|
puts("No changes."); |
691 |
|
|
fclose(fp); |
692 |
|
|
(void) unlink(tmpfil); |
693 |
|
|
return (0); |
694 |
|
|
} |
695 |
|
|
*lp = label; |
696 |
|
|
if (writelabel(f, lp) == 0) { |
697 |
|
|
fclose(fp); |
698 |
|
|
(void) unlink(tmpfil); |
699 |
|
|
return (0); |
700 |
|
|
} |
701 |
|
|
} |
702 |
|
|
fclose(fp); |
703 |
|
|
printf("re-edit the label? [y]: "); |
704 |
|
|
fflush(stdout); |
705 |
|
|
first = ch = getchar(); |
706 |
|
|
while (ch != '\n' && ch != EOF) |
707 |
|
|
ch = getchar(); |
708 |
|
|
if (first == 'n' || first == 'N') |
709 |
|
|
break; |
710 |
|
|
} |
711 |
|
|
(void)unlink(tmpfil); |
712 |
|
|
return (1); |
713 |
|
|
} |
714 |
|
|
|
715 |
|
|
/* |
716 |
|
|
* Execute an editor on the specified pathname, which is interpreted |
717 |
|
|
* from the shell. This means flags may be included. |
718 |
|
|
* |
719 |
|
|
* Returns -1 on error, or the exit value on success. |
720 |
|
|
*/ |
721 |
|
|
int |
722 |
|
|
editit(const char *pathname) |
723 |
|
|
{ |
724 |
|
|
char *argp[] = {"sh", "-c", NULL, NULL}, *ed, *p; |
725 |
|
|
sig_t sighup, sigint, sigquit, sigchld; |
726 |
|
|
pid_t pid; |
727 |
|
|
int saved_errno, st, ret = -1; |
728 |
|
|
|
729 |
|
|
ed = getenv("VISUAL"); |
730 |
|
|
if (ed == NULL || ed[0] == '\0') |
731 |
|
|
ed = getenv("EDITOR"); |
732 |
|
|
if (ed == NULL || ed[0] == '\0') |
733 |
|
|
ed = _PATH_VI; |
734 |
|
|
if (asprintf(&p, "%s %s", ed, pathname) == -1) |
735 |
|
|
return (-1); |
736 |
|
|
argp[2] = p; |
737 |
|
|
|
738 |
|
|
sighup = signal(SIGHUP, SIG_IGN); |
739 |
|
|
sigint = signal(SIGINT, SIG_IGN); |
740 |
|
|
sigquit = signal(SIGQUIT, SIG_IGN); |
741 |
|
|
sigchld = signal(SIGCHLD, SIG_DFL); |
742 |
|
|
if ((pid = fork()) == -1) |
743 |
|
|
goto fail; |
744 |
|
|
if (pid == 0) { |
745 |
|
|
execv(_PATH_BSHELL, argp); |
746 |
|
|
_exit(127); |
747 |
|
|
} |
748 |
|
|
while (waitpid(pid, &st, 0) == -1) |
749 |
|
|
if (errno != EINTR) |
750 |
|
|
goto fail; |
751 |
|
|
if (!WIFEXITED(st)) |
752 |
|
|
errno = EINTR; |
753 |
|
|
else |
754 |
|
|
ret = WEXITSTATUS(st); |
755 |
|
|
|
756 |
|
|
fail: |
757 |
|
|
saved_errno = errno; |
758 |
|
|
(void)signal(SIGHUP, sighup); |
759 |
|
|
(void)signal(SIGINT, sigint); |
760 |
|
|
(void)signal(SIGQUIT, sigquit); |
761 |
|
|
(void)signal(SIGCHLD, sigchld); |
762 |
|
|
free(p); |
763 |
|
|
errno = saved_errno; |
764 |
|
|
return (ret); |
765 |
|
|
} |
766 |
|
|
|
767 |
|
|
char * |
768 |
|
|
skip(char *cp) |
769 |
|
|
{ |
770 |
|
|
|
771 |
|
|
cp += strspn(cp, " \t"); |
772 |
|
|
if (*cp == '\0') |
773 |
|
|
return (NULL); |
774 |
|
|
return (cp); |
775 |
|
|
} |
776 |
|
|
|
777 |
|
|
char * |
778 |
|
|
word(char *cp) |
779 |
|
|
{ |
780 |
|
|
|
781 |
|
|
cp += strcspn(cp, " \t"); |
782 |
|
|
if (*cp == '\0') |
783 |
|
|
return (NULL); |
784 |
|
|
*cp++ = '\0'; |
785 |
|
|
cp += strspn(cp, " \t"); |
786 |
|
|
if (*cp == '\0') |
787 |
|
|
return (NULL); |
788 |
|
|
return (cp); |
789 |
|
|
} |
790 |
|
|
|
791 |
|
|
/* Base the max value on the sizeof of the value we are reading */ |
792 |
|
|
#define GETNUM(field, nptr, min, errstr) \ |
793 |
|
|
getnum((nptr), (min), \ |
794 |
|
|
sizeof(field) == 8 ? LLONG_MAX : \ |
795 |
|
|
(sizeof(field) == 4 ? UINT_MAX : \ |
796 |
|
|
(sizeof(field) == 2 ? USHRT_MAX : UCHAR_MAX)), (errstr)) |
797 |
|
|
|
798 |
|
|
u_int64_t |
799 |
|
|
getnum(char *nptr, u_int64_t min, u_int64_t max, const char **errstr) |
800 |
|
|
{ |
801 |
|
|
char *p, c; |
802 |
|
|
u_int64_t ret; |
803 |
|
|
|
804 |
|
|
for (p = nptr; *p != '\0' && !isspace((unsigned char)*p); p++) |
805 |
|
|
; |
806 |
|
|
c = *p; |
807 |
|
|
*p = '\0'; |
808 |
|
|
ret = strtonum(nptr, min, max, errstr); |
809 |
|
|
*p = c; |
810 |
|
|
return (ret); |
811 |
|
|
} |
812 |
|
|
|
813 |
|
|
int |
814 |
|
|
duid_parse(struct disklabel *lp, char *s) |
815 |
|
|
{ |
816 |
|
|
u_char duid[8]; |
817 |
|
|
char c; |
818 |
|
|
int i; |
819 |
|
|
|
820 |
|
|
if (strlen(s) != 16) |
821 |
|
|
return -1; |
822 |
|
|
|
823 |
|
|
memset(duid, 0, sizeof(duid)); |
824 |
|
|
for (i = 0; i < 16; i++) { |
825 |
|
|
c = s[i]; |
826 |
|
|
if (c >= '0' && c <= '9') |
827 |
|
|
c -= '0'; |
828 |
|
|
else if (c >= 'a' && c <= 'f') |
829 |
|
|
c -= ('a' - 10); |
830 |
|
|
else if (c >= 'A' && c <= 'F') |
831 |
|
|
c -= ('A' - 10); |
832 |
|
|
else |
833 |
|
|
return -1; |
834 |
|
|
duid[i / 2] <<= 4; |
835 |
|
|
duid[i / 2] |= c & 0xf; |
836 |
|
|
} |
837 |
|
|
|
838 |
|
|
memcpy(lp->d_uid, &duid, sizeof(lp->d_uid)); |
839 |
|
|
return 0; |
840 |
|
|
} |
841 |
|
|
|
842 |
|
|
/* |
843 |
|
|
* Read an ascii label in from FILE f, |
844 |
|
|
* in the same format as that put out by display(), |
845 |
|
|
* and fill in lp. |
846 |
|
|
*/ |
847 |
|
|
int |
848 |
|
|
getasciilabel(FILE *f, struct disklabel *lp) |
849 |
|
|
{ |
850 |
|
|
char **cpp, *cp; |
851 |
|
|
const char *errstr; |
852 |
|
|
struct partition *pp; |
853 |
|
|
char *mp, *tp, *s, line[BUFSIZ]; |
854 |
|
|
char **omountpoints = NULL; |
855 |
|
|
int lineno = 0, errors = 0; |
856 |
|
|
u_int32_t v, fsize; |
857 |
|
|
u_int64_t lv; |
858 |
|
|
unsigned int part; |
859 |
|
|
|
860 |
|
|
lp->d_version = 1; |
861 |
|
|
lp->d_bbsize = BBSIZE; /* XXX */ |
862 |
|
|
lp->d_sbsize = SBSIZE; /* XXX */ |
863 |
|
|
|
864 |
|
|
if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *)))) |
865 |
|
|
errx(4, "out of memory"); |
866 |
|
|
|
867 |
|
|
mpcopy(omountpoints, mountpoints); |
868 |
|
|
for (part = 0; part < MAXPARTITIONS; part++) { |
869 |
|
|
free(mountpoints[part]); |
870 |
|
|
mountpoints[part] = NULL; |
871 |
|
|
} |
872 |
|
|
|
873 |
|
|
while (fgets(line, sizeof(line), f)) { |
874 |
|
|
lineno++; |
875 |
|
|
mp = NULL; |
876 |
|
|
if ((cp = strpbrk(line, "\r\n"))) |
877 |
|
|
*cp = '\0'; |
878 |
|
|
if ((cp = strpbrk(line, "#"))) { |
879 |
|
|
*cp = '\0'; |
880 |
|
|
mp = skip(cp+1); |
881 |
|
|
if (mp && *mp != '/') |
882 |
|
|
mp = NULL; |
883 |
|
|
} |
884 |
|
|
cp = skip(line); |
885 |
|
|
if (cp == NULL) |
886 |
|
|
continue; |
887 |
|
|
tp = strchr(cp, ':'); |
888 |
|
|
if (tp == NULL) { |
889 |
|
|
warnx("line %d: syntax error", lineno); |
890 |
|
|
errors++; |
891 |
|
|
continue; |
892 |
|
|
} |
893 |
|
|
*tp++ = '\0', tp = skip(tp); |
894 |
|
|
if (!strcmp(cp, "type")) { |
895 |
|
|
if (tp == NULL) |
896 |
|
|
tp = "unknown"; |
897 |
|
|
else if (strcasecmp(tp, "IDE") == 0) |
898 |
|
|
tp = "ESDI"; |
899 |
|
|
cpp = dktypenames; |
900 |
|
|
for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) |
901 |
|
|
if ((s = *cpp) && !strcasecmp(s, tp)) { |
902 |
|
|
lp->d_type = cpp - dktypenames; |
903 |
|
|
goto next; |
904 |
|
|
} |
905 |
|
|
v = GETNUM(lp->d_type, tp, 0, &errstr); |
906 |
|
|
if (errstr || v >= DKMAXTYPES) |
907 |
|
|
warnx("line %d: warning, unknown disk type: %s", |
908 |
|
|
lineno, tp); |
909 |
|
|
lp->d_type = v; |
910 |
|
|
continue; |
911 |
|
|
} |
912 |
|
|
if (!strcmp(cp, "flags")) { |
913 |
|
|
for (v = 0; (cp = tp) && *cp != '\0';) { |
914 |
|
|
tp = word(cp); |
915 |
|
|
if (!strcmp(cp, "badsect")) |
916 |
|
|
v |= D_BADSECT; |
917 |
|
|
else if (!strcmp(cp, "vendor")) |
918 |
|
|
v |= D_VENDOR; |
919 |
|
|
else { |
920 |
|
|
warnx("line %d: bad flag: %s", |
921 |
|
|
lineno, cp); |
922 |
|
|
errors++; |
923 |
|
|
} |
924 |
|
|
} |
925 |
|
|
lp->d_flags = v; |
926 |
|
|
continue; |
927 |
|
|
} |
928 |
|
|
if (!strcmp(cp, "drivedata")) { |
929 |
|
|
int i; |
930 |
|
|
|
931 |
|
|
for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { |
932 |
|
|
v = GETNUM(lp->d_drivedata[i], cp, 0, &errstr); |
933 |
|
|
if (errstr) |
934 |
|
|
warnx("line %d: bad drivedata %s", |
935 |
|
|
lineno, cp); |
936 |
|
|
lp->d_drivedata[i++] = v; |
937 |
|
|
tp = word(cp); |
938 |
|
|
} |
939 |
|
|
continue; |
940 |
|
|
} |
941 |
|
|
if (sscanf(cp, "%d partitions", &v) == 1) { |
942 |
|
|
if (v == 0 || v > MAXPARTITIONS) { |
943 |
|
|
warnx("line %d: bad # of partitions", lineno); |
944 |
|
|
lp->d_npartitions = MAXPARTITIONS; |
945 |
|
|
errors++; |
946 |
|
|
} else |
947 |
|
|
lp->d_npartitions = v; |
948 |
|
|
continue; |
949 |
|
|
} |
950 |
|
|
if (tp == NULL) |
951 |
|
|
tp = ""; |
952 |
|
|
if (!strcmp(cp, "disk")) { |
953 |
|
|
strncpy(lp->d_typename, tp, sizeof (lp->d_typename)); |
954 |
|
|
continue; |
955 |
|
|
} |
956 |
|
|
if (!strcmp(cp, "label")) { |
957 |
|
|
strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); |
958 |
|
|
continue; |
959 |
|
|
} |
960 |
|
|
if (!strcmp(cp, "duid")) { |
961 |
|
|
if (duid_parse(lp, tp) != 0) { |
962 |
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp); |
963 |
|
|
errors++; |
964 |
|
|
} |
965 |
|
|
continue; |
966 |
|
|
} |
967 |
|
|
if (!strcmp(cp, "bytes/sector")) { |
968 |
|
|
v = GETNUM(lp->d_secsize, tp, 1, &errstr); |
969 |
|
|
if (errstr || (v % 512) != 0) { |
970 |
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp); |
971 |
|
|
errors++; |
972 |
|
|
} else |
973 |
|
|
lp->d_secsize = v; |
974 |
|
|
continue; |
975 |
|
|
} |
976 |
|
|
if (!strcmp(cp, "sectors/track")) { |
977 |
|
|
v = GETNUM(lp->d_nsectors, tp, 1, &errstr); |
978 |
|
|
if (errstr) { |
979 |
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp); |
980 |
|
|
errors++; |
981 |
|
|
} else |
982 |
|
|
lp->d_nsectors = v; |
983 |
|
|
continue; |
984 |
|
|
} |
985 |
|
|
if (!strcmp(cp, "sectors/cylinder")) { |
986 |
|
|
v = GETNUM(lp->d_secpercyl, tp, 1, &errstr); |
987 |
|
|
if (errstr) { |
988 |
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp); |
989 |
|
|
errors++; |
990 |
|
|
} else |
991 |
|
|
lp->d_secpercyl = v; |
992 |
|
|
continue; |
993 |
|
|
} |
994 |
|
|
if (!strcmp(cp, "tracks/cylinder")) { |
995 |
|
|
v = GETNUM(lp->d_ntracks, tp, 1, &errstr); |
996 |
|
|
if (errstr) { |
997 |
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp); |
998 |
|
|
errors++; |
999 |
|
|
} else |
1000 |
|
|
lp->d_ntracks = v; |
1001 |
|
|
continue; |
1002 |
|
|
} |
1003 |
|
|
if (!strcmp(cp, "cylinders")) { |
1004 |
|
|
v = GETNUM(lp->d_ncylinders, tp, 1, &errstr); |
1005 |
|
|
if (errstr) { |
1006 |
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp); |
1007 |
|
|
errors++; |
1008 |
|
|
} else |
1009 |
|
|
lp->d_ncylinders = v; |
1010 |
|
|
continue; |
1011 |
|
|
} |
1012 |
|
|
|
1013 |
|
|
/* Ignore fields that are no longer in the disklabel. */ |
1014 |
|
|
if (!strcmp(cp, "rpm") || |
1015 |
|
|
!strcmp(cp, "interleave") || |
1016 |
|
|
!strcmp(cp, "trackskew") || |
1017 |
|
|
!strcmp(cp, "cylinderskew") || |
1018 |
|
|
!strcmp(cp, "headswitch") || |
1019 |
|
|
!strcmp(cp, "track-to-track seek")) |
1020 |
|
|
continue; |
1021 |
|
|
|
1022 |
|
|
/* Ignore fields that are forcibly set when label is read. */ |
1023 |
|
|
if (!strcmp(cp, "total sectors") || |
1024 |
|
|
!strcmp(cp, "boundstart") || |
1025 |
|
|
!strcmp(cp, "boundend")) |
1026 |
|
|
continue; |
1027 |
|
|
|
1028 |
|
|
if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') { |
1029 |
|
|
unsigned int part = *cp - 'a'; |
1030 |
|
|
|
1031 |
|
|
if (part >= lp->d_npartitions) { |
1032 |
|
|
if (part >= MAXPARTITIONS) { |
1033 |
|
|
warnx("line %d: bad partition name: %s", |
1034 |
|
|
lineno, cp); |
1035 |
|
|
errors++; |
1036 |
|
|
continue; |
1037 |
|
|
} else { |
1038 |
|
|
lp->d_npartitions = part + 1; |
1039 |
|
|
} |
1040 |
|
|
} |
1041 |
|
|
pp = &lp->d_partitions[part]; |
1042 |
|
|
#define NXTNUM(n, field, errstr) { \ |
1043 |
|
|
if (tp == NULL) { \ |
1044 |
|
|
warnx("line %d: too few fields", lineno); \ |
1045 |
|
|
errors++; \ |
1046 |
|
|
break; \ |
1047 |
|
|
} else \ |
1048 |
|
|
cp = tp, tp = word(cp), (n) = GETNUM(field, cp, 0, errstr); \ |
1049 |
|
|
} |
1050 |
|
|
NXTNUM(lv, lv, &errstr); |
1051 |
|
|
if (errstr) { |
1052 |
|
|
warnx("line %d: bad partition size: %s", |
1053 |
|
|
lineno, cp); |
1054 |
|
|
errors++; |
1055 |
|
|
} else { |
1056 |
|
|
DL_SETPSIZE(pp, lv); |
1057 |
|
|
} |
1058 |
|
|
NXTNUM(lv, lv, &errstr); |
1059 |
|
|
if (errstr) { |
1060 |
|
|
warnx("line %d: bad partition offset: %s", |
1061 |
|
|
lineno, cp); |
1062 |
|
|
errors++; |
1063 |
|
|
} else { |
1064 |
|
|
DL_SETPOFFSET(pp, lv); |
1065 |
|
|
} |
1066 |
|
|
if (tp == NULL) { |
1067 |
|
|
pp->p_fstype = FS_UNUSED; |
1068 |
|
|
goto gottype; |
1069 |
|
|
} |
1070 |
|
|
cp = tp, tp = word(cp); |
1071 |
|
|
cpp = fstypenames; |
1072 |
|
|
for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) |
1073 |
|
|
if ((s = *cpp) && !strcasecmp(s, cp)) { |
1074 |
|
|
pp->p_fstype = cpp - fstypenames; |
1075 |
|
|
goto gottype; |
1076 |
|
|
} |
1077 |
|
|
if (isdigit((unsigned char)*cp)) |
1078 |
|
|
v = GETNUM(pp->p_fstype, cp, 0, &errstr); |
1079 |
|
|
else |
1080 |
|
|
v = FSMAXTYPES; |
1081 |
|
|
if (errstr || v >= FSMAXTYPES) { |
1082 |
|
|
warnx("line %d: warning, unknown filesystem type: %s", |
1083 |
|
|
lineno, cp); |
1084 |
|
|
v = FS_UNUSED; |
1085 |
|
|
} |
1086 |
|
|
pp->p_fstype = v; |
1087 |
|
|
gottype: |
1088 |
|
|
switch (pp->p_fstype) { |
1089 |
|
|
|
1090 |
|
|
case FS_UNUSED: /* XXX */ |
1091 |
|
|
if (tp == NULL) /* ok to skip fsize/bsize */ |
1092 |
|
|
break; |
1093 |
|
|
NXTNUM(fsize, fsize, &errstr); |
1094 |
|
|
if (fsize == 0) |
1095 |
|
|
break; |
1096 |
|
|
NXTNUM(v, v, &errstr); |
1097 |
|
|
pp->p_fragblock = |
1098 |
|
|
DISKLABELV1_FFS_FRAGBLOCK(fsize, v / fsize); |
1099 |
|
|
break; |
1100 |
|
|
|
1101 |
|
|
case FS_BSDFFS: |
1102 |
|
|
NXTNUM(fsize, fsize, &errstr); |
1103 |
|
|
if (fsize == 0) |
1104 |
|
|
break; |
1105 |
|
|
NXTNUM(v, v, &errstr); |
1106 |
|
|
pp->p_fragblock = |
1107 |
|
|
DISKLABELV1_FFS_FRAGBLOCK(fsize, v / fsize); |
1108 |
|
|
NXTNUM(pp->p_cpg, pp->p_cpg, &errstr); |
1109 |
|
|
break; |
1110 |
|
|
|
1111 |
|
|
default: |
1112 |
|
|
break; |
1113 |
|
|
} |
1114 |
|
|
if (mp) |
1115 |
|
|
mountpoints[part] = strdup(mp); |
1116 |
|
|
continue; |
1117 |
|
|
} |
1118 |
|
|
warnx("line %d: unknown field: %s", lineno, cp); |
1119 |
|
|
errors++; |
1120 |
|
|
next: |
1121 |
|
|
; |
1122 |
|
|
} |
1123 |
|
|
errors += checklabel(lp); |
1124 |
|
|
|
1125 |
|
|
if (errors > 0) |
1126 |
|
|
mpcopy(mountpoints, omountpoints); |
1127 |
|
|
mpfree(omountpoints); |
1128 |
|
|
|
1129 |
|
|
return (errors > 0); |
1130 |
|
|
} |
1131 |
|
|
|
1132 |
|
|
/* |
1133 |
|
|
* Check disklabel for errors and fill in |
1134 |
|
|
* derived fields according to supplied values. |
1135 |
|
|
*/ |
1136 |
|
|
int |
1137 |
|
|
checklabel(struct disklabel *lp) |
1138 |
|
|
{ |
1139 |
|
|
struct partition *pp; |
1140 |
|
|
int i, errors = 0; |
1141 |
|
|
char part; |
1142 |
|
|
|
1143 |
|
|
if (lp->d_secsize == 0) { |
1144 |
|
|
warnx("sector size %d", lp->d_secsize); |
1145 |
|
|
return (1); |
1146 |
|
|
} |
1147 |
|
|
if (lp->d_nsectors == 0) { |
1148 |
|
|
warnx("sectors/track %d", lp->d_nsectors); |
1149 |
|
|
return (1); |
1150 |
|
|
} |
1151 |
|
|
if (lp->d_ntracks == 0) { |
1152 |
|
|
warnx("tracks/cylinder %d", lp->d_ntracks); |
1153 |
|
|
return (1); |
1154 |
|
|
} |
1155 |
|
|
if (lp->d_ncylinders == 0) { |
1156 |
|
|
warnx("cylinders/unit %d", lp->d_ncylinders); |
1157 |
|
|
errors++; |
1158 |
|
|
} |
1159 |
|
|
if (lp->d_secpercyl == 0) |
1160 |
|
|
lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; |
1161 |
|
|
if (DL_GETDSIZE(lp) == 0) |
1162 |
|
|
DL_SETDSIZE(lp, (u_int64_t)lp->d_secpercyl * lp->d_ncylinders); |
1163 |
|
|
if (lp->d_bbsize == 0) { |
1164 |
|
|
warnx("boot block size %d", lp->d_bbsize); |
1165 |
|
|
errors++; |
1166 |
|
|
} else if (lp->d_bbsize % lp->d_secsize) |
1167 |
|
|
warnx("warning, boot block size %% sector-size != 0"); |
1168 |
|
|
if (lp->d_sbsize == 0) { |
1169 |
|
|
warnx("super block size %d", lp->d_sbsize); |
1170 |
|
|
errors++; |
1171 |
|
|
} else if (lp->d_sbsize % lp->d_secsize) |
1172 |
|
|
warnx("warning, super block size %% sector-size != 0"); |
1173 |
|
|
if (lp->d_npartitions > MAXPARTITIONS) |
1174 |
|
|
warnx("warning, number of partitions (%d) > MAXPARTITIONS (%d)", |
1175 |
|
|
lp->d_npartitions, MAXPARTITIONS); |
1176 |
|
|
for (i = 0; i < lp->d_npartitions; i++) { |
1177 |
|
|
part = 'a' + i; |
1178 |
|
|
pp = &lp->d_partitions[i]; |
1179 |
|
|
if (DL_GETPSIZE(pp) == 0 && DL_GETPOFFSET(pp) != 0) |
1180 |
|
|
warnx("warning, partition %c: size 0, but offset %llu", |
1181 |
|
|
part, DL_GETPOFFSET(pp)); |
1182 |
|
|
#ifdef SUN_CYLCHECK |
1183 |
|
|
if (lp->d_flags & D_VENDOR) { |
1184 |
|
|
if (i != RAW_PART && DL_GETPSIZE(pp) % lp->d_secpercyl) |
1185 |
|
|
warnx("warning, partition %c: size %% " |
1186 |
|
|
"cylinder-size != 0", part); |
1187 |
|
|
if (i != RAW_PART && DL_GETPOFFSET(pp) % lp->d_secpercyl) |
1188 |
|
|
warnx("warning, partition %c: offset %% " |
1189 |
|
|
"cylinder-size != 0", part); |
1190 |
|
|
} |
1191 |
|
|
#endif |
1192 |
|
|
#ifdef SUN_AAT0 |
1193 |
|
|
if ((lp->d_flags & D_VENDOR) && |
1194 |
|
|
i == 0 && DL_GETPSIZE(pp) != 0 && DL_GETPOFFSET(pp) != 0) { |
1195 |
|
|
warnx("this architecture requires partition 'a' to " |
1196 |
|
|
"start at sector 0"); |
1197 |
|
|
errors++; |
1198 |
|
|
} |
1199 |
|
|
#endif |
1200 |
|
|
if (DL_GETPOFFSET(pp) > DL_GETDSIZE(lp)) { |
1201 |
|
|
warnx("partition %c: offset past end of unit", part); |
1202 |
|
|
errors++; |
1203 |
|
|
} |
1204 |
|
|
if (DL_GETPOFFSET(pp) + DL_GETPSIZE(pp) > DL_GETDSIZE(lp)) { |
1205 |
|
|
warnx("partition %c: partition extends past end of unit", |
1206 |
|
|
part); |
1207 |
|
|
errors++; |
1208 |
|
|
} |
1209 |
|
|
#if 0 |
1210 |
|
|
if (pp->p_frag == 0 && pp->p_fsize != 0) { |
1211 |
|
|
warnx("partition %c: block size < fragment size", part); |
1212 |
|
|
errors++; |
1213 |
|
|
} |
1214 |
|
|
#endif |
1215 |
|
|
} |
1216 |
|
|
for (; i < MAXPARTITIONS; i++) { |
1217 |
|
|
part = 'a' + i; |
1218 |
|
|
pp = &lp->d_partitions[i]; |
1219 |
|
|
if (DL_GETPSIZE(pp) || DL_GETPOFFSET(pp)) |
1220 |
|
|
warnx("warning, unused partition %c: size %llu " |
1221 |
|
|
"offset %llu", part, DL_GETPSIZE(pp), |
1222 |
|
|
DL_GETPOFFSET(pp)); |
1223 |
|
|
} |
1224 |
|
|
return (errors > 0); |
1225 |
|
|
} |
1226 |
|
|
|
1227 |
|
|
int |
1228 |
|
|
cmplabel(struct disklabel *lp1, struct disklabel *lp2) |
1229 |
|
|
{ |
1230 |
|
|
struct disklabel lab1 = *lp1; |
1231 |
|
|
struct disklabel lab2 = *lp2; |
1232 |
|
|
|
1233 |
|
|
/* We don't compare these fields */ |
1234 |
|
|
lab1.d_magic = lab2.d_magic; |
1235 |
|
|
lab1.d_magic2 = lab2.d_magic2; |
1236 |
|
|
lab1.d_checksum = lab2.d_checksum; |
1237 |
|
|
lab1.d_bbsize = lab2.d_bbsize; |
1238 |
|
|
lab1.d_sbsize = lab2.d_sbsize; |
1239 |
|
|
lab1.d_bstart = lab2.d_bstart; |
1240 |
|
|
lab1.d_bstarth = lab2.d_bstarth; |
1241 |
|
|
lab1.d_bend = lab2.d_bend; |
1242 |
|
|
lab1.d_bendh = lab2.d_bendh; |
1243 |
|
|
|
1244 |
|
|
return (memcmp(&lab1, &lab2, sizeof(struct disklabel))); |
1245 |
|
|
} |
1246 |
|
|
|
1247 |
|
|
void |
1248 |
|
|
usage(void) |
1249 |
|
|
{ |
1250 |
|
|
fprintf(stderr, |
1251 |
|
|
"usage: disklabel [-Acdtv] [-h | -p unit] [-T file] disk\t(read)\n"); |
1252 |
|
|
fprintf(stderr, |
1253 |
|
|
" disklabel -w [-Acdnv] [-T file] disk disktype [packid]\t(write)\n"); |
1254 |
|
|
fprintf(stderr, |
1255 |
|
|
" disklabel -e [-Acdnv] [-T file] disk\t\t\t(edit)\n"); |
1256 |
|
|
fprintf(stderr, |
1257 |
|
|
" disklabel -E [-Acdnv] [-F|-f file] [-T file] disk\t(simple editor)" |
1258 |
|
|
"\n"); |
1259 |
|
|
fprintf(stderr, |
1260 |
|
|
" disklabel -R [-nv] [-F|-f file] disk protofile\t\t(restore)\n\n"); |
1261 |
|
|
fprintf(stderr, |
1262 |
|
|
"`disk' may be of the form: sd0 or /dev/rsd0%c.\n", 'a'+RAW_PART); |
1263 |
|
|
fprintf(stderr, |
1264 |
|
|
"`disktype' is an entry from %s, see disktab(5) for more info.\n", |
1265 |
|
|
DISKTAB); |
1266 |
|
|
fprintf(stderr, |
1267 |
|
|
"`packid' is an identification string for the device.\n"); |
1268 |
|
|
fprintf(stderr, |
1269 |
|
|
"`protofile' is the output from the read cmd form; -R is powerful.\n"); |
1270 |
|
|
#ifdef SEEALSO |
1271 |
|
|
fprintf(stderr, |
1272 |
|
|
"For procedures specific to this architecture see: %s\n", SEEALSO); |
1273 |
|
|
#endif |
1274 |
|
|
exit(1); |
1275 |
|
|
} |