GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
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 |
50 |
size_t sz = sizeof(physmem); |
|
111 |
25 |
int mib[] = { CTL_HW, HW_PHYSMEM64 }; |
|
112 |
|||
113 |
✗✓ | 25 |
if (sysctl(mib, 2, &physmem, &sz, NULL, (size_t)0) == -1) |
114 |
errx(4, "can't get mem size"); |
||
115 |
25 |
} |
|
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 |
50 |
getphysmem(); |
|
125 |
|||
126 |
✓✓ | 66 |
while ((ch = getopt(argc, argv, "AEf:F:hRcdenp:tT:vw")) != -1) |
127 |
✗✗✗✗ ✗✗✗✗ ✗✗✗✓ ✗✗✗✗ |
16 |
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 |
✗✓ | 16 |
if (op != UNSPEC) |
171 |
usage(); |
||
172 |
16 |
op = WRITE; |
|
173 |
16 |
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 |
25 |
argc -= optind; |
|
193 |
25 |
argv += optind; |
|
194 |
|||
195 |
✓✓ | 25 |
if (op == UNSPEC) |
196 |
9 |
op = READ; |
|
197 |
|||
198 |
✓✗✗✓ |
75 |
if (argc < 1 || (fstabfile && !(op == EDITOR || op == RESTORE || |
199 |
25 |
aflag))) |
|
200 |
usage(); |
||
201 |
|||
202 |
✗✓ | 25 |
if (argv[0] == NULL) |
203 |
usage(); |
||
204 |
25 |
dkname = argv[0]; |
|
205 |
25 |
f = opendev(dkname, (op == READ ? O_RDONLY : O_RDWR), OPENDEV_PART, |
|
206 |
&specname); |
||
207 |
✗✓ | 25 |
if (f < 0) |
208 |
err(4, "%s", specname); |
||
209 |
|||
210 |
✓✓ | 25 |
if (op != WRITE || aflag || dflag) { |
211 |
9 |
readlabel(f); |
|
212 |
|||
213 |
✗✓ | 9 |
if (op == EDIT || op == EDITOR || aflag) { |
214 |
if (pledge("stdio rpath wpath cpath disklabel proc " |
||
215 |
"exec", NULL) == -1) |
||
216 |
err(1, "pledge"); |
||
217 |
✗✓ | 9 |
} else if (fstabfile) { |
218 |
if (pledge("stdio rpath wpath cpath disklabel flock", NULL) |
||
219 |
== -1) |
||
220 |
err(1, "pledge"); |
||
221 |
} else { |
||
222 |
✗✓ | 9 |
if (pledge("stdio rpath wpath disklabel flock cpath", NULL) == -1) |
223 |
err(1, "pledge"); |
||
224 |
} |
||
225 |
|||
226 |
✗✓ | 9 |
if (autotable != NULL) |
227 |
parse_autotable(autotable); |
||
228 |
9 |
error = parselabel(); |
|
229 |
✗✓ | 9 |
if (op == WRITE && aflag && error) |
230 |
errx(1, "autoalloc failed"); |
||
231 |
✓✗ | 16 |
} else if (argc == 2 || argc == 3) { |
232 |
/* Ensure f is a disk device before pledging. */ |
||
233 |
✗✓ | 16 |
if (ioctl(f, DIOCGDINFO, &lab) < 0) |
234 |
err(4, "ioctl DIOCGDINFO"); |
||
235 |
|||
236 |
✗✓ | 16 |
if (pledge("stdio rpath wpath disklabel flock cpath", NULL) == -1) |
237 |
err(1, "pledge"); |
||
238 |
|||
239 |
✗✓ | 32 |
makelabel(argv[1], argc == 3 ? argv[2] : NULL, &lab); |
240 |
16 |
} else |
|
241 |
usage(); |
||
242 |
|||
243 |
✗✗✓✗ ✓✓ |
50 |
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 |
✗✓ | 9 |
if (argc != 1) |
256 |
usage(); |
||
257 |
|||
258 |
✗✓ | 9 |
if (pledge("stdio flock rpath cpath wpath", NULL) == -1) |
259 |
err(1, "pledge"); |
||
260 |
|||
261 |
✗✓ | 9 |
if (tflag) |
262 |
makedisktab(stdout, &lab); |
||
263 |
else |
||
264 |
9 |
display(stdout, &lab, print_unit, 1); |
|
265 |
9 |
error = checklabel(&lab); |
|
266 |
9 |
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 |
16 |
error = checklabel(&lab); |
|
286 |
✓✗ | 16 |
if (error == 0) |
287 |
16 |
error = writelabel(f, &lab); |
|
288 |
break; |
||
289 |
default: |
||
290 |
break; |
||
291 |
} |
||
292 |
25 |
return error; |
|
293 |
25 |
} |
|
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 |
32 |
dp = getdiskbyname(type); |
|
306 |
✗✓ | 16 |
if (dp == NULL) |
307 |
errx(1, "unknown disk type: %s", type); |
||
308 |
16 |
*lp = *dp; |
|
309 |
/* d_packname is union d_boot[01], so zero */ |
||
310 |
16 |
memset(lp->d_packname, 0, sizeof(lp->d_packname)); |
|
311 |
✗✓ | 16 |
if (name) |
312 |
(void)strncpy(lp->d_packname, name, sizeof(lp->d_packname)); |
||
313 |
16 |
} |
|
314 |
|||
315 |
|||
316 |
int |
||
317 |
writelabel(int f, struct disklabel *lp) |
||
318 |
{ |
||
319 |
32 |
lp->d_magic = DISKMAGIC; |
|
320 |
16 |
lp->d_magic2 = DISKMAGIC; |
|
321 |
16 |
lp->d_checksum = 0; |
|
322 |
16 |
lp->d_checksum = dkcksum(lp); |
|
323 |
✓✗ | 16 |
if (!donothing) { |
324 |
✗✓ | 16 |
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 |
✓✗ | 16 |
if (!donothing) { |
332 |
/* First refresh our copy of the current label to get UID. */ |
||
333 |
✗✓ | 16 |
if (ioctl(f, DIOCGDINFO, &lab) < 0) |
334 |
err(4, "ioctl DIOCGDINFO"); |
||
335 |
16 |
mpsave(lp); |
|
336 |
16 |
} |
|
337 |
|||
338 |
16 |
return (0); |
|
339 |
16 |
} |
|
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 |
✗✓✗✗ |
18 |
if (cflag && ioctl(f, DIOCRLDINFO) < 0) |
374 |
err(4, "ioctl DIOCRLDINFO"); |
||
375 |
|||
376 |
✗✓ | 9 |
if ((op == RESTORE) || dflag || aflag) { |
377 |
if (ioctl(f, DIOCGPDINFO, &lab) < 0) |
||
378 |
err(4, "ioctl DIOCGPDINFO"); |
||
379 |
} else { |
||
380 |
✗✓ | 9 |
if (ioctl(f, DIOCGDINFO, &lab) < 0) |
381 |
err(4, "ioctl DIOCGDINFO"); |
||
382 |
} |
||
383 |
9 |
} |
|
384 |
|||
385 |
int |
||
386 |
parselabel(void) |
||
387 |
{ |
||
388 |
18 |
char *partname, *partduid; |
|
389 |
struct fstab *fsent; |
||
390 |
int i; |
||
391 |
|||
392 |
9 |
i = asprintf(&partname, "/dev/%s%c", dkname, 'a'); |
|
393 |
✗✓ | 9 |
if (i == -1) |
394 |
err(4, NULL); |
||
395 |
9 |
i = asprintf(&partduid, |
|
396 |
"%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.a", |
||
397 |
9 |
lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3], |
|
398 |
9 |
lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7]); |
|
399 |
✗✓ | 9 |
if (i == -1) |
400 |
err(4, NULL); |
||
401 |
9 |
setfsent(); |
|
402 |
✓✓ | 306 |
for (i = 0; i < MAXPARTITIONS; i++) { |
403 |
144 |
partname[strlen(dkname) + 5] = 'a' + i; |
|
404 |
144 |
partduid[strlen(partduid) - 1] = 'a' + i; |
|
405 |
144 |
fsent = getfsspec(partname); |
|
406 |
✓✗ | 144 |
if (fsent == NULL) |
407 |
144 |
fsent = getfsspec(partduid); |
|
408 |
✓✓ | 144 |
if (fsent) |
409 |
90 |
mountpoints[i] = strdup(fsent->fs_file); |
|
410 |
} |
||
411 |
9 |
endfsent(); |
|
412 |
9 |
free(partduid); |
|
413 |
9 |
free(partname); |
|
414 |
|||
415 |
✗✓ | 9 |
if (aflag) |
416 |
return editor_allocspace(&lab); |
||
417 |
9 |
return 0; |
|
418 |
9 |
} |
|
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 |
306 |
fsz = (double)sz * lp->d_secsize; |
|
495 |
|||
496 |
✗✗✗✗ ✗✗✓ |
153 |
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 |
153 |
return -1.0; |
|
511 |
} |
||
512 |
153 |
} |
|
513 |
|||
514 |
/* |
||
515 |
* Display a particular partition. |
||
516 |
*/ |
||
517 |
void |
||
518 |
display_partition(FILE *f, struct disklabel *lp, int i, char unit) |
||
519 |
{ |
||
520 |
288 |
volatile struct partition *pp = &lp->d_partitions[i]; |
|
521 |
double p_size; |
||
522 |
|||
523 |
144 |
p_size = scale(DL_GETPSIZE(pp), unit, lp); |
|
524 |
✓✓ | 144 |
if (DL_GETPSIZE(pp)) { |
525 |
✓✓ | 288 |
u_int32_t frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); |
526 |
✓✓✓✓ ✓✗✓✗ |
837 |
u_int32_t fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); |
527 |
|||
528 |
✓✗ | 99 |
if (p_size < 0) |
529 |
99 |
fprintf(f, " %c: %16llu %16llu ", 'a' + i, |
|
530 |
99 |
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 |
✓✗ | 99 |
if (pp->p_fstype < FSMAXTYPES) |
536 |
99 |
fprintf(f, "%7.7s", fstypenames[pp->p_fstype]); |
|
537 |
else |
||
538 |
fprintf(f, "%7d", pp->p_fstype); |
||
539 |
|||
540 |
✓✓ | 99 |
switch (pp->p_fstype) { |
541 |
case FS_BSDFFS: |
||
542 |
81 |
fprintf(f, " %5u %5u %5hu ", |
|
543 |
81 |
fsize, fsize * frag, |
|
544 |
81 |
pp->p_cpg); |
|
545 |
81 |
break; |
|
546 |
default: |
||
547 |
18 |
fprintf(f, "%20.20s", ""); |
|
548 |
18 |
break; |
|
549 |
} |
||
550 |
|||
551 |
✓✓ | 99 |
if (mountpoints[i] != NULL) |
552 |
90 |
fprintf(f, "# %s", mountpoints[i]); |
|
553 |
✓✗ | 198 |
putc('\n', f); |
554 |
99 |
} |
|
555 |
144 |
} |
|
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 |
✗✓ | 18 |
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 |
9 |
unit = toupper((unsigned char)unit); |
|
580 |
|||
581 |
9 |
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 |
18 |
unit = canonical_unit(lp, unit); |
|
591 |
|||
592 |
9 |
fprintf(f, "# %s:\n", specname); |
|
593 |
|||
594 |
✓✗ | 9 |
if (lp->d_type < DKMAXTYPES) |
595 |
9 |
fprintf(f, "type: %s\n", dktypenames[lp->d_type]); |
|
596 |
else |
||
597 |
fprintf(f, "type: %d\n", lp->d_type); |
||
598 |
9 |
fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename), |
|
599 |
9 |
lp->d_typename); |
|
600 |
9 |
fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), |
|
601 |
9 |
lp->d_packname); |
|
602 |
9 |
fprintf(f, "duid: %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n", |
|
603 |
9 |
lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3], |
|
604 |
9 |
lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]); |
|
605 |
9 |
fprintf(f, "flags:"); |
|
606 |
✗✓ | 9 |
if (lp->d_flags & D_BADSECT) |
607 |
fprintf(f, " badsect"); |
||
608 |
✗✓ | 9 |
if (lp->d_flags & D_VENDOR) |
609 |
fprintf(f, " vendor"); |
||
610 |
✓✗ | 18 |
putc('\n', f); |
611 |
|||
612 |
9 |
fprintf(f, "bytes/sector: %u\n", lp->d_secsize); |
|
613 |
9 |
fprintf(f, "sectors/track: %u\n", lp->d_nsectors); |
|
614 |
9 |
fprintf(f, "tracks/cylinder: %u\n", lp->d_ntracks); |
|
615 |
9 |
fprintf(f, "sectors/cylinder: %u\n", lp->d_secpercyl); |
|
616 |
9 |
fprintf(f, "cylinders: %u\n", lp->d_ncylinders); |
|
617 |
9 |
fprintf(f, "total sectors: %llu", DL_GETDSIZE(lp)); |
|
618 |
9 |
d = scale(DL_GETDSIZE(lp), unit, lp); |
|
619 |
✗✓ | 9 |
if (d > 0) |
620 |
fprintf(f, " # total bytes: %.*f%c", unit == 'B' ? 0 : 1, |
||
621 |
d, unit); |
||
622 |
9 |
fprintf(f, "\n"); |
|
623 |
|||
624 |
9 |
fprintf(f, "boundstart: %llu\n", DL_GETBSTART(lp)); |
|
625 |
9 |
fprintf(f, "boundend: %llu\n", DL_GETBEND(lp)); |
|
626 |
9 |
fprintf(f, "drivedata: "); |
|
627 |
✓✓ | 108 |
for (i = NDDATA - 1; i >= 0; i--) |
628 |
✓✗ | 45 |
if (lp->d_drivedata[i]) |
629 |
break; |
||
630 |
✓✗ | 9 |
if (i < 0) |
631 |
9 |
i = 0; |
|
632 |
✓✓ | 36 |
for (j = 0; j <= i; j++) |
633 |
9 |
fprintf(f, "%d ", lp->d_drivedata[j]); |
|
634 |
9 |
fprintf(f, "\n"); |
|
635 |
✓✗ | 9 |
if (all) { |
636 |
9 |
fprintf(f, "\n%hu partitions:\n", lp->d_npartitions); |
|
637 |
9 |
fprintf(f, "# %16.16s %16.16s fstype [fsize bsize cpg]\n", |
|
638 |
"size", "offset"); |
||
639 |
✓✓ | 306 |
for (i = 0; i < lp->d_npartitions; i++) |
640 |
144 |
display_partition(f, lp, i, unit); |
|
641 |
} |
||
642 |
9 |
fflush(f); |
|
643 |
9 |
} |
|
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 |
✗✓ | 50 |
if (lp->d_secsize == 0) { |
1144 |
warnx("sector size %d", lp->d_secsize); |
||
1145 |
return (1); |
||
1146 |
} |
||
1147 |
✗✓ | 25 |
if (lp->d_nsectors == 0) { |
1148 |
warnx("sectors/track %d", lp->d_nsectors); |
||
1149 |
return (1); |
||
1150 |
} |
||
1151 |
✗✓ | 25 |
if (lp->d_ntracks == 0) { |
1152 |
warnx("tracks/cylinder %d", lp->d_ntracks); |
||
1153 |
return (1); |
||
1154 |
} |
||
1155 |
✗✓ | 25 |
if (lp->d_ncylinders == 0) { |
1156 |
warnx("cylinders/unit %d", lp->d_ncylinders); |
||
1157 |
errors++; |
||
1158 |
} |
||
1159 |
✗✓ | 25 |
if (lp->d_secpercyl == 0) |
1160 |
lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; |
||
1161 |
✗✓ | 25 |
if (DL_GETDSIZE(lp) == 0) |
1162 |
DL_SETDSIZE(lp, (u_int64_t)lp->d_secpercyl * lp->d_ncylinders); |
||
1163 |
✗✓ | 25 |
if (lp->d_bbsize == 0) { |
1164 |
warnx("boot block size %d", lp->d_bbsize); |
||
1165 |
errors++; |
||
1166 |
✗✓ | 25 |
} else if (lp->d_bbsize % lp->d_secsize) |
1167 |
warnx("warning, boot block size %% sector-size != 0"); |
||
1168 |
✗✓ | 25 |
if (lp->d_sbsize == 0) { |
1169 |
warnx("super block size %d", lp->d_sbsize); |
||
1170 |
errors++; |
||
1171 |
✗✓ | 25 |
} else if (lp->d_sbsize % lp->d_secsize) |
1172 |
warnx("warning, super block size %% sector-size != 0"); |
||
1173 |
✗✓ | 25 |
if (lp->d_npartitions > MAXPARTITIONS) |
1174 |
warnx("warning, number of partitions (%d) > MAXPARTITIONS (%d)", |
||
1175 |
lp->d_npartitions, MAXPARTITIONS); |
||
1176 |
✓✓ | 434 |
for (i = 0; i < lp->d_npartitions; i++) { |
1177 |
192 |
part = 'a' + i; |
|
1178 |
192 |
pp = &lp->d_partitions[i]; |
|
1179 |
✓✓✗✓ |
239 |
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 |
✗✓ | 192 |
if (DL_GETPOFFSET(pp) > DL_GETDSIZE(lp)) { |
1201 |
warnx("partition %c: offset past end of unit", part); |
||
1202 |
errors++; |
||
1203 |
} |
||
1204 |
✗✓ | 192 |
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 |
✓✓ | 441 |
for (; i < MAXPARTITIONS; i++) { |
1217 |
208 |
part = 'a' + i; |
|
1218 |
208 |
pp = &lp->d_partitions[i]; |
|
1219 |
✓✗✗✓ |
416 |
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 |
25 |
return (errors > 0); |
|
1225 |
25 |
} |
|
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 |
} |
Generated by: GCOVR (Version 3.3) |