Bug Summary

File:src/sbin/disklabel/editor.c
Warning:line 2041, column 11
Division by zero

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name editor.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sbin/disklabel/obj -resource-dir /usr/local/llvm16/lib/clang/16 -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/disklabel/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/sbin/disklabel/editor.c
1/* $OpenBSD: editor.c,v 1.417 2023/09/06 12:45:19 robert Exp $ */
2
3/*
4 * Copyright (c) 1997-2000 Todd C. Miller <millert@openbsd.org>
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/param.h> /* MAXBSIZE DEV_BSIZE */
20#include <sys/types.h>
21#include <sys/signal.h>
22#include <sys/stat.h>
23#include <sys/ioctl.h>
24#include <sys/dkio.h>
25#include <sys/sysctl.h>
26#define DKTYPENAMES
27#include <sys/disklabel.h>
28
29#include <ufs/ffs/fs.h>
30
31#include <ctype.h>
32#include <err.h>
33#include <errno(*__errno()).h>
34#include <string.h>
35#include <libgen.h>
36#include <stdint.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <unistd.h>
40#include <limits.h>
41
42#include "extern.h"
43#include "pathnames.h"
44
45#define ROUNDUP(_s, _a)((((_s) + (_a) - 1) / (_a)) * (_a)) ((((_s) + (_a) - 1) / (_a)) * (_a))
46#define ROUNDDOWN(_s, _a)(((_s) / (_a)) * (_a)) (((_s) / (_a)) * (_a))
47#define CHUNKSZ(_c)((_c)->stop - (_c)->start) ((_c)->stop - (_c)->start)
48
49/* flags for getuint64() */
50#define DO_CONVERSIONS0x00000001 0x00000001
51#define DO_ROUNDING0x00000002 0x00000002
52
53/* flags for alignpartition() */
54#define ROUND_OFFSET_UP0x00000001 0x00000001
55#define ROUND_OFFSET_DOWN0x00000002 0x00000002
56#define ROUND_SIZE_UP0x00000004 0x00000004
57#define ROUND_SIZE_DOWN0x00000008 0x00000008
58#define ROUND_SIZE_OVERLAP0x00000010 0x00000010
59
60/* Special return values for getnumber and getuint64() */
61#define CMD_ABORTED(0xffffffffffffffffULL - 1) (ULLONG_MAX0xffffffffffffffffULL - 1)
62#define CMD_BADVALUE(0xffffffffffffffffULL) (ULLONG_MAX0xffffffffffffffffULL)
63
64/* structure to describe a portion of a disk */
65struct diskchunk {
66 u_int64_t start;
67 u_int64_t stop;
68};
69
70/* used when sorting mountpoints in mpsave() */
71struct mountinfo {
72 char *mountpoint;
73 int partno;
74};
75
76/* used when allocating all space according to recommendations */
77
78struct space_allocation {
79 u_int64_t minsz; /* starts as blocks, xlated to sectors. */
80 u_int64_t maxsz; /* starts as blocks, xlated to sectors. */
81 int rate; /* % of extra space to use */
82 char *mp;
83};
84
85/*
86 * NOTE! Changing partition sizes in the space_allocation tables
87 * requires corresponding updates to the *.ok files in
88 * /usr/src/regress/sbin/disklabel.
89 */
90
91/* entries for swap and var are changed by editor_allocspace() */
92struct space_allocation alloc_big[] = {
93 { MEG(150)((150) * 1024LL * (1024 / (1 << 9))), GIG(1)(((1) * 1024LL * (1024 / (1 << 9))) * 1024LL), 5, "/" },
94 { MEG(80)((80) * 1024LL * (1024 / (1 << 9))), MEG(256)((256) * 1024LL * (1024 / (1 << 9))), 10, "swap" },
95 { MEG(120)((120) * 1024LL * (1024 / (1 << 9))), GIG(4)(((4) * 1024LL * (1024 / (1 << 9))) * 1024LL), 8, "/tmp" },
96 { MEG(80)((80) * 1024LL * (1024 / (1 << 9))), GIG(4)(((4) * 1024LL * (1024 / (1 << 9))) * 1024LL), 13, "/var" },
97 { MEG(1500)((1500) * 1024LL * (1024 / (1 << 9))), GIG(30)(((30) * 1024LL * (1024 / (1 << 9))) * 1024LL), 10, "/usr" },
98 { MEG(384)((384) * 1024LL * (1024 / (1 << 9))), GIG(1)(((1) * 1024LL * (1024 / (1 << 9))) * 1024LL), 3, "/usr/X11R6" },
99 { GIG(1)(((1) * 1024LL * (1024 / (1 << 9))) * 1024LL), GIG(20)(((20) * 1024LL * (1024 / (1 << 9))) * 1024LL), 15, "/usr/local" },
100 { MEG(1500)((1500) * 1024LL * (1024 / (1 << 9))), GIG(3)(((3) * 1024LL * (1024 / (1 << 9))) * 1024LL), 2, "/usr/src" },
101 { GIG(5)(((5) * 1024LL * (1024 / (1 << 9))) * 1024LL), GIG(6)(((6) * 1024LL * (1024 / (1 << 9))) * 1024LL), 4, "/usr/obj" },
102 { GIG(1)(((1) * 1024LL * (1024 / (1 << 9))) * 1024LL), GIG(300)(((300) * 1024LL * (1024 / (1 << 9))) * 1024LL), 30, "/home" }
103 /* Anything beyond this leave for the user to decide */
104};
105
106struct space_allocation alloc_medium[] = {
107 { MEG(800)((800) * 1024LL * (1024 / (1 << 9))), GIG(2)(((2) * 1024LL * (1024 / (1 << 9))) * 1024LL), 5, "/" },
108 { MEG(80)((80) * 1024LL * (1024 / (1 << 9))), MEG(256)((256) * 1024LL * (1024 / (1 << 9))), 10, "swap" },
109 { MEG(1300)((1300) * 1024LL * (1024 / (1 << 9))), GIG(3)(((3) * 1024LL * (1024 / (1 << 9))) * 1024LL), 78, "/usr" },
110 { MEG(256)((256) * 1024LL * (1024 / (1 << 9))), GIG(2)(((2) * 1024LL * (1024 / (1 << 9))) * 1024LL), 7, "/home" }
111};
112
113struct space_allocation alloc_small[] = {
114 { MEG(700)((700) * 1024LL * (1024 / (1 << 9))), GIG(4)(((4) * 1024LL * (1024 / (1 << 9))) * 1024LL), 95, "/" },
115 { MEG(1)((1) * 1024LL * (1024 / (1 << 9))), MEG(256)((256) * 1024LL * (1024 / (1 << 9))), 5, "swap" }
116};
117
118struct space_allocation alloc_stupid[] = {
119 { MEG(1)((1) * 1024LL * (1024 / (1 << 9))), MEG(2048)((2048) * 1024LL * (1024 / (1 << 9))), 100, "/" }
120};
121
122#ifndef nitems
123#define nitems(_a)(sizeof((_a)) / sizeof((_a)[0])) (sizeof((_a)) / sizeof((_a)[0]))
124#endif
125
126struct alloc_table {
127 struct space_allocation *table;
128 int sz;
129};
130
131struct alloc_table alloc_table_default[] = {
132 { alloc_big, nitems(alloc_big)(sizeof((alloc_big)) / sizeof((alloc_big)[0])) },
133 { alloc_medium, nitems(alloc_medium)(sizeof((alloc_medium)) / sizeof((alloc_medium)[0])) },
134 { alloc_small, nitems(alloc_small)(sizeof((alloc_small)) / sizeof((alloc_small)[0])) },
135 { alloc_stupid, nitems(alloc_stupid)(sizeof((alloc_stupid)) / sizeof((alloc_stupid)[0])) }
136};
137struct alloc_table *alloc_table = alloc_table_default;
138int alloc_table_nitems = 4;
139
140void edit_packname(struct disklabel *);
141void editor_resize(struct disklabel *, const char *);
142void editor_add(struct disklabel *, const char *);
143void editor_change(struct disklabel *, const char *);
144u_int64_t editor_countfree(const struct disklabel *);
145void editor_delete(struct disklabel *, const char *);
146void editor_help(void);
147void editor_modify(struct disklabel *, const char *);
148void editor_name(const struct disklabel *, const char *);
149char *getstring(const char *, const char *, const char *);
150u_int64_t getuint64(const struct disklabel *, char *, char *, u_int64_t,
151 u_int64_t, int *);
152u_int64_t getnumber(const char *, const char *, u_int32_t, u_int32_t);
153int getpartno(const struct disklabel *, const char *, const char *);
154int has_overlap(struct disklabel *);
155int partition_cmp(const void *, const void *);
156const struct partition **sort_partitions(const struct disklabel *, int);
157void find_bounds(const struct disklabel *);
158void set_bounds(struct disklabel *);
159void set_duid(struct disklabel *);
160int set_fragblock(struct disklabel *, int);
161const struct diskchunk *free_chunks(const struct disklabel *, int);
162int micmp(const void *, const void *);
163int mpequal(char **, char **);
164int get_fstype(struct disklabel *, int);
165int get_mp(const struct disklabel *, int);
166int get_offset(struct disklabel *, int);
167int get_size(struct disklabel *, int);
168void zero_partitions(struct disklabel *);
169u_int64_t max_partition_size(const struct disklabel *, int);
170void display_edit(const struct disklabel *, char);
171void psize(u_int64_t sz, char unit, const struct disklabel *lp);
172char *get_token(char **);
173int apply_unit(double, u_char, u_int64_t *);
174int parse_sizespec(const char *, double *, char **);
175int parse_sizerange(char *, u_int64_t *, u_int64_t *);
176int parse_pct(char *, int *);
177int alignpartition(struct disklabel *, int, u_int64_t, u_int64_t, int);
178int allocate_space(struct disklabel *, const struct alloc_table *);
179void allocate_physmemincr(struct space_allocation *);
180int allocate_partition(struct disklabel *, struct space_allocation *);
181const struct diskchunk *allocate_diskchunk(const struct disklabel *,
182 const struct space_allocation *);
183
184static u_int64_t starting_sector;
185static u_int64_t ending_sector;
186static int resizeok;
187
188/*
189 * Simple partition editor.
190 */
191int
192editor(int f)
193{
194 struct disklabel origlabel, lastlabel, tmplabel, newlab = lab;
195 struct partition *pp;
196 FILE *fp;
197 char buf[BUFSIZ1024], *cmd, *arg;
198 char **omountpoints = NULL((void *)0);
199 char **origmountpoints = NULL((void *)0), **tmpmountpoints = NULL((void *)0);
200 int i, error = 0;
201
202 /* Alloc and init mount point info */
203 if (!(omountpoints = calloc(MAXPARTITIONS16, sizeof(char *))) ||
1
Assuming 'omountpoints' is non-null
4
Taking false branch
204 !(origmountpoints = calloc(MAXPARTITIONS16, sizeof(char *))) ||
2
Assuming 'origmountpoints' is non-null
205 !(tmpmountpoints = calloc(MAXPARTITIONS16, sizeof(char *))))
3
Assuming 'tmpmountpoints' is non-null
206 err(1, NULL((void *)0));
207
208 /* How big is the OpenBSD portion of the disk? */
209 find_bounds(&newlab);
210
211 /* Make sure there is no partition overlap. */
212 if (has_overlap(&newlab))
5
Taking false branch
213 errx(1, "can't run when there is partition overlap.");
214
215 /* If we don't have a 'c' partition, create one. */
216 pp = &newlab.d_partitions[RAW_PART2];
217 if (newlab.d_npartitions
5.1
Field 'd_npartitions' is <= RAW_PART
<= RAW_PART2 || DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) == 0) {
218 puts("No 'c' partition found, adding one that spans the disk.");
219 if (newlab.d_npartitions
5.2
Field 'd_npartitions' is <= RAW_PART
<= RAW_PART2)
6
Taking true branch
220 newlab.d_npartitions = RAW_PART2 + 1;
221 DL_SETPOFFSET(pp, 0)do { u_int64_t __x = (0); (pp)->p_offseth = __x >> 32
; (pp)->p_offset = __x; } while (0)
;
7
Loop condition is false. Exiting loop
222 DL_SETPSIZE(pp, DL_GETDSIZE(&newlab))do { u_int64_t __x = ((((u_int64_t)(&newlab)->d_secperunith
<< 32) + (&newlab)->d_secperunit)); (pp)->p_sizeh
= __x >> 32; (pp)->p_size = __x; } while (0)
;
8
Loop condition is false. Exiting loop
223 pp->p_fstype = FS_UNUSED0;
224 pp->p_fragblock = pp->p_cpg = 0;
225 }
226
227#ifdef SUN_CYLCHECK
228 if ((newlab.d_flags & D_VENDOR0x08) && !quiet) {
229 puts("This platform requires that partition offsets/sizes "
230 "be on cylinder boundaries.\n"
231 "Partition offsets/sizes will be rounded to the "
232 "nearest cylinder automatically.");
233 }
234#endif
235
236 /* Save the (U|u)ndo labels and mountpoints. */
237 mpcopy(origmountpoints, mountpoints);
238 origlabel = newlab;
239 lastlabel = newlab;
240
241 puts("Label editor (enter '?' for help at any prompt)");
242 for (;;) {
9
Loop condition is true. Entering loop body
243 fprintf(stdout(&__sF[1]), "%s%s> ", dkname,
244 (memcmp(&lab, &newlab, sizeof(newlab)) == 0) ? "" : "*");
10
Assuming the condition is false
11
'?' condition is false
245 if (fgets(buf, sizeof(buf), stdin(&__sF[0])) == NULL((void *)0)) {
12
Assuming the condition is false
13
Taking false branch
246 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
247 buf[0] = 'q';
248 buf[1] = '\0';
249 }
250 if ((cmd = strtok(buf, " \t\r\n")) == NULL((void *)0))
14
Assuming the condition is false
15
Taking false branch
251 continue;
252 arg = strtok(NULL((void *)0), " \t\r\n");
253
254 if ((*cmd != 'u') && (*cmd != 'U')) {
16
Assuming the condition is true
17
Assuming the condition is true
18
Taking true branch
255 /*
256 * Save undo info in case the command tries to make
257 * changes but decides not to.
258 */
259 tmplabel = lastlabel;
260 lastlabel = newlab;
261 mpcopy(tmpmountpoints, omountpoints);
262 mpcopy(omountpoints, mountpoints);
263 }
264
265 switch (*cmd) {
19
Control jumps to 'case 82:' at line 399
266 case '?':
267 case 'h':
268 editor_help();
269 break;
270
271 case 'A':
272 if (ioctl(f, DIOCGPDINFO((unsigned long)0x40000000 | ((sizeof(struct disklabel) &
0x1fff) << 16) | ((('d')) << 8) | ((114)))
, &newlab) == -1) {
273 warn("DIOCGPDINFO");
274 newlab = lastlabel;
275 } else {
276 int oquiet = quiet;
277 aflag = 1;
278 quiet = 0;
279 editor_allocspace(&newlab);
280 quiet = oquiet;
281 }
282 break;
283 case 'a':
284 editor_add(&newlab, arg);
285 break;
286
287 case 'b':
288 set_bounds(&newlab);
289 break;
290
291 case 'c':
292 editor_change(&newlab, arg);
293 break;
294
295 case 'D':
296 if (ioctl(f, DIOCGPDINFO((unsigned long)0x40000000 | ((sizeof(struct disklabel) &
0x1fff) << 16) | ((('d')) << 8) | ((114)))
, &newlab) == -1)
297 warn("DIOCGPDINFO");
298 else {
299 dflag = 1;
300 for (i = 0; i < MAXPARTITIONS16; i++) {
301 free(mountpoints[i]);
302 mountpoints[i] = NULL((void *)0);
303 }
304 }
305 break;
306
307 case 'd':
308 editor_delete(&newlab, arg);
309 break;
310
311 case 'e':
312 edit_packname(&newlab);
313 break;
314
315 case 'i':
316 set_duid(&newlab);
317 break;
318
319 case 'm':
320 editor_modify(&newlab, arg);
321 break;
322
323 case 'n':
324 if (!fstabfile) {
325 fputs("This option is not valid when run "
326 "without the -F or -f flags.\n", stderr(&__sF[2]));
327 break;
328 }
329 editor_name(&newlab, arg);
330 break;
331
332 case 'p':
333 display_edit(&newlab, arg ? *arg : 0);
334 break;
335
336 case 'l':
337 display(stdout(&__sF[1]), &newlab, arg ? *arg : 0, 0);
338 break;
339
340 case 'M': {
341 sig_t opipe = signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
342 char *pager, *comm = NULL((void *)0);
343 extern const u_char manpage[];
344 extern const int manpage_sz;
345
346 if ((pager = getenv("PAGER")) == NULL((void *)0) || *pager == '\0')
347 pager = _PATH_LESS"/usr/bin/less";
348
349 if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 &&
350 (fp = popen(comm, "w")) != NULL((void *)0)) {
351 (void) fwrite(manpage, manpage_sz, 1, fp);
352 pclose(fp);
353 } else
354 warn("unable to execute %s", pager);
355
356 free(comm);
357 (void)signal(SIGPIPE13, opipe);
358 break;
359 }
360
361 case 'q':
362 if (donothing) {
363 puts("In no change mode, not writing label.");
364 goto done;
365 }
366
367 /*
368 * If we haven't changed the original label, and it
369 * wasn't a default label or an auto-allocated label,
370 * there is no need to do anything before exiting. Note
371 * that 'w' will reset dflag and aflag to allow 'q' to
372 * exit without further questions.
373 */
374 if (!dflag && !aflag &&
375 memcmp(&lab, &newlab, sizeof(newlab)) == 0) {
376 puts("No label changes.");
377 /* Save mountpoint info. */
378 mpsave(&newlab);
379 goto done;
380 }
381 do {
382 arg = getstring("Write new label?",
383 "Write the modified label to disk?",
384 "y");
385 } while (arg && tolower((unsigned char)*arg) != 'y' &&
386 tolower((unsigned char)*arg) != 'n');
387 if (arg && tolower((unsigned char)*arg) == 'y') {
388 if (writelabel(f, &newlab) == 0) {
389 newlab = lab; /* lab now has UID info */
390 goto done;
391 }
392 warnx("unable to write label");
393 }
394 error = 1;
395 goto done;
396 /* NOTREACHED */
397 break;
398
399 case 'R':
400 if (aflag && resizeok)
20
Assuming 'aflag' is not equal to 0
21
Assuming 'resizeok' is not equal to 0
22
Taking true branch
401 editor_resize(&newlab, arg);
23
Calling 'editor_resize'
402 else
403 fputs("Resize only implemented for auto "
404 "allocated labels\n", stderr(&__sF[2]));
405 break;
406
407 case 'r': {
408 const struct diskchunk *chunk;
409 uint64_t total = 0;
410 /* Display free space. */
411 chunk = free_chunks(&newlab, -1);
412 for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
413 total += CHUNKSZ(chunk)((chunk)->stop - (chunk)->start);
414 fprintf(stderr(&__sF[2]), "Free sectors: %16llu - %16llu "
415 "(%16llu)\n",
416 chunk->start, chunk->stop - 1,
417 CHUNKSZ(chunk)((chunk)->stop - (chunk)->start));
418 }
419 fprintf(stderr(&__sF[2]), "Total free sectors: %llu.\n", total);
420 break;
421 }
422
423 case 's':
424 if (arg == NULL((void *)0)) {
425 arg = getstring("Filename",
426 "Name of the file to save label into.",
427 NULL((void *)0));
428 if (arg == NULL((void *)0) || *arg == '\0')
429 break;
430 }
431 if ((fp = fopen(arg, "w")) == NULL((void *)0)) {
432 warn("cannot open %s", arg);
433 } else {
434 display(fp, &newlab, 0, 1);
435 (void)fclose(fp);
436 }
437 break;
438
439 case 'U':
440 /*
441 * If we allow 'U' repeatedly, information would be
442 * lost. This way multiple 'U's followed by 'u' will
443 * undo the 'U's.
444 */
445 if (memcmp(&newlab, &origlabel, sizeof(newlab)) ||
446 !mpequal(mountpoints, origmountpoints)) {
447 tmplabel = newlab;
448 newlab = origlabel;
449 lastlabel = tmplabel;
450 mpcopy(tmpmountpoints, mountpoints);
451 mpcopy(mountpoints, origmountpoints);
452 mpcopy(omountpoints, tmpmountpoints);
453 }
454 puts("Original label and mount points restored.");
455 break;
456
457 case 'u':
458 tmplabel = newlab;
459 newlab = lastlabel;
460 lastlabel = tmplabel;
461 mpcopy(tmpmountpoints, mountpoints);
462 mpcopy(mountpoints, omountpoints);
463 mpcopy(omountpoints, tmpmountpoints);
464 puts("Last change undone.");
465 break;
466
467 case 'w':
468 if (donothing) {
469 puts("In no change mode, not writing label.");
470 break;
471 }
472
473 /* Write label to disk. */
474 if (writelabel(f, &newlab) != 0)
475 warnx("unable to write label");
476 else {
477 dflag = aflag = 0;
478 newlab = lab; /* lab now has UID info */
479 }
480 break;
481
482 case 'x':
483 goto done;
484 break;
485
486 case 'z':
487 zero_partitions(&newlab);
488 break;
489
490 case '\n':
491 break;
492
493 default:
494 printf("Unknown option: %c ('?' for help)\n", *cmd);
495 break;
496 }
497
498 /*
499 * If no changes were made to label or mountpoints, then
500 * restore undo info.
501 */
502 if (memcmp(&newlab, &lastlabel, sizeof(newlab)) == 0 &&
503 (mpequal(mountpoints, omountpoints))) {
504 lastlabel = tmplabel;
505 mpcopy(omountpoints, tmpmountpoints);
506 }
507 }
508done:
509 mpfree(omountpoints, DISCARD0);
510 mpfree(origmountpoints, DISCARD0);
511 mpfree(tmpmountpoints, DISCARD0);
512 return error;
513}
514
515/*
516 * Allocate all disk space according to standard recommendations for a
517 * root disk.
518 */
519int
520editor_allocspace(struct disklabel *lp_org)
521{
522 struct disklabel label;
523 struct partition *pp;
524 u_int64_t pstart, pend;
525 int i;
526
527 /* How big is the OpenBSD portion of the disk? */
528 find_bounds(lp_org);
529
530 resizeok = 1;
531 for (i = 0; i < MAXPARTITIONS16; i++) {
532 if (i == RAW_PART2)
533 continue;
534 pp = &lp_org->d_partitions[i];
535 if (DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) == 0 || pp->p_fstype == FS_UNUSED0)
536 continue;
537 pstart = DL_GETPOFFSET(pp)(((u_int64_t)(pp)->p_offseth << 32) + (pp)->p_offset
)
;
538 pend = pstart + DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size);
539 if (((pstart >= starting_sector && pstart < ending_sector) ||
540 (pend > starting_sector && pend <= ending_sector)))
541 resizeok = 0; /* Part of OBSD area is in use! */
542 }
543
544 for (i = 0; i < alloc_table_nitems; i++) {
545 memcpy(&label, lp_org, sizeof(label));
546 if (allocate_space(&label, &alloc_table[i]) == 0) {
547 memcpy(lp_org, &label, sizeof(struct disklabel));
548 return 0;
549 }
550 }
551
552 return 1;
553}
554
555const struct diskchunk *
556allocate_diskchunk(const struct disklabel *lp,
557 const struct space_allocation *sa)
558{
559 const struct diskchunk *chunk;
560 static struct diskchunk largest;
561 uint64_t maxstop;
562
563 largest.start = largest.stop = 0;
564
565 chunk = free_chunks(lp, -1);
566 for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
567 if (CHUNKSZ(chunk)((chunk)->stop - (chunk)->start) > CHUNKSZ(&largest)((&largest)->stop - (&largest)->start))
568 largest = *chunk;
569 }
570 maxstop = largest.start + DL_BLKTOSEC(lp, sa->maxsz)((sa->maxsz) / ((lp)->d_secsize / (1 << 9)));
571 if (maxstop > largest.stop)
572 maxstop = largest.stop;
573#ifdef SUN_CYLCHECK
574 if (lp->d_flags & D_VENDOR0x08) {
575 largest.start = ROUNDUP(largest.start, lp->d_secpercyl)((((largest.start) + (lp->d_secpercyl) - 1) / (lp->d_secpercyl
)) * (lp->d_secpercyl))
;
576 maxstop = ROUNDUP(maxstop, lp->d_secpercyl)((((maxstop) + (lp->d_secpercyl) - 1) / (lp->d_secpercyl
)) * (lp->d_secpercyl))
;
577 if (maxstop > largest.stop)
578 maxstop -= lp->d_secpercyl;
579 if (largest.start >= maxstop)
580 largest.start = largest.stop = maxstop = 0;
581 }
582#endif
583 if (maxstop < largest.stop)
584 largest.stop = maxstop;
585 if (CHUNKSZ(&largest)((&largest)->stop - (&largest)->start) < DL_BLKTOSEC(lp, sa->minsz)((sa->minsz) / ((lp)->d_secsize / (1 << 9))))
586 return NULL((void *)0);
587
588 return &largest;
589}
590
591int
592allocate_partition(struct disklabel *lp, struct space_allocation *sa)
593{
594 const struct diskchunk *chunk;
595 struct partition *pp;
596 unsigned int partno;
597
598 for (partno = 0; partno < nitems(lp->d_partitions)(sizeof((lp->d_partitions)) / sizeof((lp->d_partitions)
[0]))
; partno++) {
599 if (partno == RAW_PART2)
600 continue;
601 pp = &lp->d_partitions[partno];
602 if (DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) == 0 || pp->p_fstype == FS_UNUSED0)
603 break;
604 }
605 if (partno >= nitems(lp->d_partitions)(sizeof((lp->d_partitions)) / sizeof((lp->d_partitions)
[0]))
)
606 return 1; /* No free partition. */
607
608 /* Find appropriate chunk of free space. */
609 chunk = allocate_diskchunk(lp, sa);
610 if (chunk == NULL((void *)0))
611 return 1;
612
613 if (strcasecmp(sa->mp, "raid") == 0)
614 pp->p_fstype = FS_RAID19;
615 else if (strcasecmp(sa->mp, "swap") == 0)
616 pp->p_fstype = FS_SWAP1;
617 else if (sa->mp[0] == '/')
618 pp->p_fstype = FS_BSDFFS7;
619 else
620 return 1;
621
622 DL_SETPSIZE(pp, chunk->stop - chunk->start)do { u_int64_t __x = (chunk->stop - chunk->start); (pp)
->p_sizeh = __x >> 32; (pp)->p_size = __x; } while
(0)
;
623 DL_SETPOFFSET(pp, chunk->start)do { u_int64_t __x = (chunk->start); (pp)->p_offseth = __x
>> 32; (pp)->p_offset = __x; } while (0)
;
624
625 if (pp->p_fstype == FS_BSDFFS7 && DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) > 0) {
626 mountpoints[partno] = strdup(sa->mp);
627 if (mountpoints[partno] == NULL((void *)0))
628 err(1, NULL((void *)0));
629 if (set_fragblock(lp, partno))
630 return 1;
631 }
632
633 return 0;
634}
635
636void
637allocate_physmemincr(struct space_allocation *sa)
638{
639 u_int64_t memblks;
640 extern int64_t physmem;
641
642 if (physmem == 0)
643 return;
644
645 memblks = physmem / DEV_BSIZE(1 << 9);
646 if (strcasecmp(sa->mp, "swap") == 0) {
647 if (memblks < MEG(256)((256) * 1024LL * (1024 / (1 << 9))))
648 sa->minsz = sa->maxsz = 2 * memblks;
649 else
650 sa->maxsz += memblks;
651 } else if (strcasecmp(sa->mp, "/var") == 0) {
652 sa->maxsz += 2 * memblks;
653 }
654}
655
656int
657allocate_space(struct disklabel *lp, const struct alloc_table *alloc_table)
658{
659 struct space_allocation sa[MAXPARTITIONS16];
660 u_int64_t maxsz, xtrablks;
661 int i;
662
663 xtrablks = DL_SECTOBLK(lp, editor_countfree(lp))((editor_countfree(lp)) * ((lp)->d_secsize / (1 << 9
)))
;
664 memset(sa, 0, sizeof(sa));
665 for (i = 0; i < alloc_table->sz; i++) {
666 sa[i] = alloc_table->table[i];
667 if (alloc_table->table == alloc_big)
668 allocate_physmemincr(&sa[i]);
669 if (xtrablks < sa[i].minsz)
670 return 1; /* Too few free blocks. */
671 xtrablks -= sa[i].minsz;
672 }
673 sa[alloc_table->sz - 1].rate = 100; /* Last allocation is greedy. */
674
675 for (i = lp->d_npartitions; i < MAXPARTITIONS16; i++) {
676 if (i == RAW_PART2)
677 continue;
678 memset(&lp->d_partitions[i], 0, sizeof(lp->d_partitions[i]));
679 }
680 lp->d_npartitions = MAXPARTITIONS16;
681
682 mpfree(mountpoints, KEEP1);
683 for (i = 0; i < alloc_table->sz; i++) {
684 if (sa[i].rate == 100)
685 maxsz = sa[i].minsz + xtrablks;
686 else
687 maxsz = sa[i].minsz + (xtrablks / 100) * sa[i].rate;
688 if (maxsz < sa[i].maxsz)
689 sa[i].maxsz = maxsz;
690 if (allocate_partition(lp, &sa[i])) {
691 mpfree(mountpoints, KEEP1);
692 return 1;
693 }
694 }
695
696 return 0;
697}
698
699/*
700 * Resize a partition, moving all subsequent partitions
701 */
702void
703editor_resize(struct disklabel *lp, const char *p)
704{
705 struct disklabel label;
706 struct partition *pp, *prev;
707 u_int64_t ui, sz, off;
708 int partno, i, flags, shrunk;
709
710 label = *lp;
711
712 if ((partno = getpartno(&label, p, "resize")) == -1)
24
Taking false branch
713 return;
714
715 pp = &label.d_partitions[partno];
716 sz = DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size);
717 if (pp->p_fstype != FS_BSDFFS7 && pp->p_fstype != FS_SWAP1) {
25
Assuming field 'p_fstype' is equal to FS_BSDFFS
718 fputs("Cannot resize spoofed partition\n", stderr(&__sF[2]));
719 return;
720 }
721 flags = DO_CONVERSIONS0x00000001;
722 ui = getuint64(lp, "[+|-]new size (with unit)",
723 "new size or amount to grow (+) or shrink (-) partition including "
724 "unit", sz, sz + editor_countfree(lp), &flags);
725
726 if (ui == CMD_ABORTED(0xffffffffffffffffULL - 1))
26
Assuming the condition is false
27
Taking false branch
727 return;
728 else if (ui == CMD_BADVALUE(0xffffffffffffffffULL))
28
Assuming 'ui' is not equal to CMD_BADVALUE
29
Taking false branch
729 return;
730 else if (ui == 0) {
30
Assuming 'ui' is not equal to 0
31
Taking false branch
731 fputs("The size must be > 0 sectors\n", stderr(&__sF[2]));
732 return;
733 }
734
735#ifdef SUN_CYLCHECK
736 if (lp->d_flags & D_VENDOR0x08)
737 ui = ROUNDUP(ui, lp->d_secpercyl)((((ui) + (lp->d_secpercyl) - 1) / (lp->d_secpercyl)) *
(lp->d_secpercyl))
;
738#endif
739 if (DL_GETPOFFSET(pp)(((u_int64_t)(pp)->p_offseth << 32) + (pp)->p_offset
)
+ ui > ending_sector
) {
32
Assuming the condition is false
33
Taking false branch
740 fputs("Amount too big\n", stderr(&__sF[2]));
741 return;
742 }
743
744 DL_SETPSIZE(pp, ui)do { u_int64_t __x = (ui); (pp)->p_sizeh = __x >> 32
; (pp)->p_size = __x; } while (0)
;
34
Loop condition is false. Exiting loop
745 pp->p_fragblock = 0;
746 if (set_fragblock(&label, partno) == 1)
35
Calling 'set_fragblock'
747 return;
748
749 /*
750 * Pack partitions above the resized partition, leaving unused
751 * partitions alone.
752 */
753 shrunk = -1;
754 prev = pp;
755 for (i = partno + 1; i < MAXPARTITIONS16; i++) {
756 if (i == RAW_PART2)
757 continue;
758 pp = &label.d_partitions[i];
759 if (pp->p_fstype != FS_BSDFFS7 && pp->p_fstype != FS_SWAP1)
760 continue;
761 sz = DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size);
762 if (sz == 0)
763 continue;
764
765 off = DL_GETPOFFSET(prev)(((u_int64_t)(prev)->p_offseth << 32) + (prev)->p_offset
)
+ DL_GETPSIZE(prev)(((u_int64_t)(prev)->p_sizeh << 32) + (prev)->p_size
)
;
766
767 if (off < ending_sector) {
768 DL_SETPOFFSET(pp, off)do { u_int64_t __x = (off); (pp)->p_offseth = __x >>
32; (pp)->p_offset = __x; } while (0)
;
769 if (off + DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) > ending_sector) {
770 DL_SETPSIZE(pp, ending_sector - off)do { u_int64_t __x = (ending_sector - off); (pp)->p_sizeh =
__x >> 32; (pp)->p_size = __x; } while (0)
;
771 pp->p_fragblock = 0;
772 if (set_fragblock(&label, i) == 1)
773 return;
774 shrunk = i;
775 }
776 } else {
777 fputs("Amount too big\n", stderr(&__sF[2]));
778 return;
779 }
780 prev = pp;
781 }
782
783 if (shrunk != -1)
784 fprintf(stderr(&__sF[2]), "Partition %c shrunk to %llu sectors to make "
785 "room\n", 'a' + shrunk,
786 DL_GETPSIZE(&label.d_partitions[shrunk])(((u_int64_t)(&label.d_partitions[shrunk])->p_sizeh <<
32) + (&label.d_partitions[shrunk])->p_size)
);
787 *lp = label;
788}
789
790/*
791 * Add a new partition.
792 */
793void
794editor_add(struct disklabel *lp, const char *p)
795{
796 struct partition *pp;
797 const struct diskchunk *chunk;
798 int partno;
799 u_int64_t new_offset, new_size;
800
801 chunk = free_chunks(lp, -1);
802 new_size = new_offset = 0;
803 for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
804 if (CHUNKSZ(chunk)((chunk)->stop - (chunk)->start) > new_size) {
805 new_size = CHUNKSZ(chunk)((chunk)->stop - (chunk)->start);
806 new_offset = chunk->start;
807 }
808 }
809
810#ifdef SUN_CYLCHECK
811 if ((lp->d_flags & D_VENDOR0x08) && new_size < lp->d_secpercyl) {
812 fputs("No space left, you need to shrink a partition "
813 "(need at least one full cylinder)\n",
814 stderr(&__sF[2]));
815 return;
816 }
817#endif
818 if (new_size == 0) {
819 fputs("No space left, you need to shrink a partition\n",
820 stderr(&__sF[2]));
821 return;
822 }
823
824 if ((partno = getpartno(lp, p, "add")) == -1)
825 return;
826 pp = &lp->d_partitions[partno];
827 memset(pp, 0, sizeof(*pp));
828
829 /*
830 * Increase d_npartitions if necessary. Ensure all new partitions are
831 * zero'ed to avoid inadvertent overlaps.
832 */
833 for(; lp->d_npartitions <= partno; lp->d_npartitions++)
834 memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp));
835
836 DL_SETPSIZE(pp, new_size)do { u_int64_t __x = (new_size); (pp)->p_sizeh = __x >>
32; (pp)->p_size = __x; } while (0)
;
837 DL_SETPOFFSET(pp, new_offset)do { u_int64_t __x = (new_offset); (pp)->p_offseth = __x >>
32; (pp)->p_offset = __x; } while (0)
;
838 pp->p_fstype = partno == 1 ? FS_SWAP1 : FS_BSDFFS7;
839
840 if (get_offset(lp, partno) == 0 &&
841 get_size(lp, partno) == 0 &&
842 get_fstype(lp, partno) == 0 &&
843 get_mp(lp, partno) == 0 &&
844 set_fragblock(lp, partno) == 0)
845 return;
846
847 /* Bailed out at some point, so effectively delete the partition. */
848 memset(pp, 0, sizeof(*pp));
849}
850
851/*
852 * Set the mountpoint of an existing partition ('name').
853 */
854void
855editor_name(const struct disklabel *lp, const char *p)
856{
857 int partno;
858
859 if ((partno = getpartno(lp, p, "name")) == -1)
860 return;
861
862 get_mp(lp, partno);
863}
864
865/*
866 * Change an existing partition.
867 */
868void
869editor_modify(struct disklabel *lp, const char *p)
870{
871 struct partition opp, *pp;
872 int partno;
873
874 if ((partno = getpartno(lp, p, "modify")) == -1)
875 return;
876
877 pp = &lp->d_partitions[partno];
878 opp = *pp;
879
880 if (get_offset(lp, partno) == 0 &&
881 get_size(lp, partno) == 0 &&
882 get_fstype(lp, partno) == 0 &&
883 get_mp(lp, partno) == 0 &&
884 set_fragblock(lp, partno) == 0)
885 return;
886
887 /* Bailed out at some point, so undo any changes. */
888 *pp = opp;
889}
890
891/*
892 * Delete an existing partition.
893 */
894void
895editor_delete(struct disklabel *lp, const char *p)
896{
897 struct partition *pp;
898 int partno;
899
900 if ((partno = getpartno(lp, p, "delete")) == -1)
901 return;
902 if (partno == lp->d_npartitions) {
903 zero_partitions(lp);
904 return;
905 }
906 pp = &lp->d_partitions[partno];
907
908 /* Really delete it (as opposed to just setting to "unused") */
909 memset(pp, 0, sizeof(*pp));
910 free(mountpoints[partno]);
911 mountpoints[partno] = NULL((void *)0);
912}
913
914/*
915 * Change the size of an existing partition.
916 */
917void
918editor_change(struct disklabel *lp, const char *p)
919{
920 struct partition *pp;
921 int partno;
922
923 if ((partno = getpartno(lp, p, "change size")) == -1)
924 return;
925
926 pp = &lp->d_partitions[partno];
927 printf("Partition %c is currently %llu sectors in size, and can have "
928 "a maximum\nsize of %llu sectors.\n",
929 'a' + partno, DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size), max_partition_size(lp, partno));
930
931 /* Get new size */
932 get_size(lp, partno);
933}
934
935/*
936 * Sort the partitions based on starting offset.
937 * This assumes there can be no overlap.
938 */
939int
940partition_cmp(const void *e1, const void *e2)
941{
942 struct partition *p1 = *(struct partition **)e1;
943 struct partition *p2 = *(struct partition **)e2;
944 u_int64_t o1 = DL_GETPOFFSET(p1)(((u_int64_t)(p1)->p_offseth << 32) + (p1)->p_offset
)
;
945 u_int64_t o2 = DL_GETPOFFSET(p2)(((u_int64_t)(p2)->p_offseth << 32) + (p2)->p_offset
)
;
946
947 if (o1 < o2)
948 return -1;
949 else if (o1 > o2)
950 return 1;
951 else
952 return 0;
953}
954
955char *
956getstring(const char *prompt, const char *helpstring, const char *oval)
957{
958 static char buf[BUFSIZ1024];
959 int n;
960
961 buf[0] = '\0';
962 do {
963 printf("%s: [%s] ", prompt, oval ? oval : "");
964 if (fgets(buf, sizeof(buf), stdin(&__sF[0])) == NULL((void *)0)) {
965 buf[0] = '\0';
966 if (feof(stdin)(!__isthreaded ? ((((&__sF[0]))->_flags & 0x0020) !=
0) : (feof)((&__sF[0])))
) {
967 clearerr(stdin)(!__isthreaded ? ((void)(((&__sF[0]))->_flags &= ~
(0x0040|0x0020))) : (clearerr)((&__sF[0])))
;
968 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
969 fputs("Command aborted\n", stderr(&__sF[2]));
970 return NULL((void *)0);
971 }
972 }
973 n = strlen(buf);
974 if (n > 0 && buf[n-1] == '\n')
975 buf[--n] = '\0';
976 if (buf[0] == '?')
977 puts(helpstring);
978 else if (oval != NULL((void *)0) && buf[0] == '\0')
979 strlcpy(buf, oval, sizeof(buf));
980 } while (buf[0] == '?');
981
982 return &buf[0];
983}
984
985int
986getpartno(const struct disklabel *lp, const char *p, const char *action)
987{
988 char buf[2] = { '\0', '\0'};
989 const char *promptfmt = "partition to %s";
990 const char *helpfmt = "Partition must be between 'a' and '%c' "
991 "(excluding 'c')%s.\n";
992 const struct partition *pp;
993 char *help = NULL((void *)0), *prompt = NULL((void *)0);
994 unsigned char maxpart;
995 unsigned int partno;
996 int add, delete, inuse;
997
998 add = strcmp("add", action) == 0;
999 delete = strcmp("delete", action) == 0;
1000 maxpart = 'a' - 1 + (add ? MAXPARTITIONS16 : lp->d_npartitions);
1001
1002 if (p == NULL((void *)0)) {
1003 if (asprintf(&prompt, promptfmt, action) == -1 ||
1004 asprintf(&help, helpfmt, maxpart, delete ? ", or '*'" : "")
1005 == -1) {
1006 fprintf(stderr(&__sF[2]), "Unable to build prompt or help\n");
1007 goto done;
1008 }
1009 if (add) {
1010 /* Default to first unused partition. */
1011 for (partno = 0; partno < MAXPARTITIONS16; partno++) {
1012 if (partno == RAW_PART2)
1013 continue;
1014 pp = &lp->d_partitions[partno];
1015 if (partno >= lp->d_npartitions ||
1016 DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) == 0 ||
1017 pp->p_fstype == FS_UNUSED0) {
1018 buf[0] = 'a' + partno;
1019 p = buf;
1020 break;
1021 }
1022 }
1023 }
1024 p = getstring(prompt, help, p);
1025 free(prompt);
1026 free(help);
1027 if (p == NULL((void *)0) || *p == '\0')
1028 goto done;
1029 }
1030
1031 if (delete && strlen(p) == 1 && *p == '*')
1032 return lp->d_npartitions;
1033
1034 if (strlen(p) > 1 || *p < 'a' || *p > maxpart || *p == 'c') {
1035 fprintf(stderr(&__sF[2]), helpfmt, maxpart, delete ? ", or '*'" : "");
1036 goto done;
1037 }
1038
1039 partno = *p - 'a';
1040 pp = &lp->d_partitions[partno];
1041 inuse = partno < lp->d_npartitions && DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) > 0 &&
1042 pp->p_fstype != FS_UNUSED0;
1043
1044 if ((add && !inuse) || (!add && inuse))
1045 return partno;
1046
1047 fprintf(stderr(&__sF[2]), "Partition '%c' is %sin use.\n", *p,
1048 inuse ? "" : "not ");
1049
1050 done:
1051 return -1;
1052}
1053
1054/*
1055 * Returns
1056 * 0 .. CMD_ABORTED - 1 ==> valid value
1057 * CMD_BADVALUE ==> invalid value
1058 * CMD_ABORTED ==> ^D on input
1059 */
1060u_int64_t
1061getnumber(const char *prompt, const char *helpstring, u_int32_t oval,
1062 u_int32_t maxval)
1063{
1064 char buf[BUFSIZ1024], *p;
1065 int rslt;
1066 long long rval;
1067 const char *errstr;
1068
1069 rslt = snprintf(buf, sizeof(buf), "%u", oval);
1070 if (rslt < 0 || (unsigned int)rslt >= sizeof(buf))
1071 return CMD_BADVALUE(0xffffffffffffffffULL);
1072
1073 p = getstring(prompt, helpstring, buf);
1074 if (p == NULL((void *)0))
1075 return CMD_ABORTED(0xffffffffffffffffULL - 1);
1076 if (strlen(p) == 0)
1077 return oval;
1078
1079 rval = strtonum(p, 0, maxval, &errstr);
1080 if (errstr != NULL((void *)0)) {
1081 printf("%s must be between 0 and %u\n", prompt, maxval);
1082 return CMD_BADVALUE(0xffffffffffffffffULL);
1083 }
1084
1085 return rval;
1086}
1087
1088/*
1089 * Returns
1090 * 0 .. CMD_ABORTED - 1 ==> valid value
1091 * CMD_BADVALUE ==> invalid value
1092 * CMD_ABORTED ==> ^D on input
1093 */
1094u_int64_t
1095getuint64(const struct disklabel *lp, char *prompt, char *helpstring,
1096 u_int64_t oval, u_int64_t maxval, int *flags)
1097{
1098 char buf[21], *p, operator = '\0';
1099 char *unit = NULL((void *)0);
1100 u_int64_t rval = oval;
1101 double d;
1102 int rslt;
1103
1104 rslt = snprintf(buf, sizeof(buf), "%llu", oval);
1105 if (rslt < 0 || (unsigned int)rslt >= sizeof(buf))
1106 goto invalid;
1107
1108 p = getstring(prompt, helpstring, buf);
1109 if (p == NULL((void *)0))
1110 return CMD_ABORTED(0xffffffffffffffffULL - 1);
1111 else if (p[0] == '\0')
1112 rval = oval;
1113 else if (p[0] == '*' && p[1] == '\0')
1114 rval = maxval;
1115 else {
1116 if (*p == '+' || *p == '-')
1117 operator = *p++;
1118 if (parse_sizespec(p, &d, &unit) == -1)
1119 goto invalid;
1120 if (unit == NULL((void *)0))
1121 rval = d;
1122 else if (flags != NULL((void *)0) && (*flags & DO_CONVERSIONS0x00000001) == 0)
1123 goto invalid;
1124 else {
1125 switch (tolower((unsigned char)*unit)) {
1126 case 'b':
1127 rval = d / lp->d_secsize;
1128 break;
1129 case 'c':
1130 rval = d * lp->d_secpercyl;
1131 break;
1132 case '%':
1133 rval = DL_GETDSIZE(lp)(((u_int64_t)(lp)->d_secperunith << 32) + (lp)->d_secperunit
)
* (d / 100.0);
1134 break;
1135 case '&':
1136 rval = maxval * (d / 100.0);
1137 break;
1138 default:
1139 if (apply_unit(d, *unit, &rval) == -1)
1140 goto invalid;
1141 rval = DL_BLKTOSEC(lp, rval)((rval) / ((lp)->d_secsize / (1 << 9)));
1142 break;
1143 }
1144 }
1145
1146 /* Range check then apply [+-] operator */
1147 if (operator == '+') {
1148 if (CMD_ABORTED(0xffffffffffffffffULL - 1) - oval > rval)
1149 rval += oval;
1150 else {
1151 goto invalid;
1152 }
1153 } else if (operator == '-') {
1154 if (oval >= rval)
1155 rval = oval - rval;
1156 else {
1157 goto invalid;
1158 }
1159 }
1160 }
1161
1162 if (flags != NULL((void *)0)) {
1163 if (unit != NULL((void *)0))
1164 *flags |= DO_ROUNDING0x00000002;
1165#ifdef SUN_CYLCHECK
1166 if (lp->d_flags & D_VENDOR0x08)
1167 *flags |= DO_ROUNDING0x00000002;
1168#endif
1169 }
1170 return rval;
1171
1172invalid:
1173 fputs("Invalid entry\n", stderr(&__sF[2]));
1174 return CMD_BADVALUE(0xffffffffffffffffULL);
1175}
1176
1177/*
1178 * Check for partition overlap in lp and prompt the user to resolve the overlap
1179 * if any is found. Returns 1 if unable to resolve, else 0.
1180 */
1181int
1182has_overlap(struct disklabel *lp)
1183{
1184 const struct partition **spp;
1185 int i, p1, p2;
1186 char *line = NULL((void *)0);
1187 size_t linesize = 0;
1188 ssize_t linelen;
1189
1190 for (;;) {
1191 spp = sort_partitions(lp, -1);
1192 for (i = 0; spp[i+1] != NULL((void *)0); i++) {
1193 if (DL_GETPOFFSET(spp[i])(((u_int64_t)(spp[i])->p_offseth << 32) + (spp[i])->
p_offset)
+ DL_GETPSIZE(spp[i])(((u_int64_t)(spp[i])->p_sizeh << 32) + (spp[i])->
p_size)
>
1194 DL_GETPOFFSET(spp[i+1])(((u_int64_t)(spp[i+1])->p_offseth << 32) + (spp[i+1
])->p_offset)
)
1195 break;
1196 }
1197 if (spp[i+1] == NULL((void *)0)) {
1198 free(line);
1199 return 0;
1200 }
1201
1202 p1 = 'a' + (spp[i] - lp->d_partitions);
1203 p2 = 'a' + (spp[i+1] - lp->d_partitions);
1204 printf("\nError, partitions %c and %c overlap:\n", p1, p2);
1205 printf("# %16.16s %16.16s fstype [fsize bsize cpg]\n",
1206 "size", "offset");
1207 display_partition(stdout(&__sF[1]), lp, p1 - 'a', 0);
1208 display_partition(stdout(&__sF[1]), lp, p2 - 'a', 0);
1209
1210 for (;;) {
1211 printf("Disable which one? (%c %c) ", p1, p2);
1212 linelen = getline(&line, &linesize, stdin(&__sF[0]));
1213 if (linelen == -1)
1214 goto done;
1215 if (linelen == 2 && (line[0] == p1 || line[0] == p2))
1216 break;
1217 }
1218 lp->d_partitions[line[0] - 'a'].p_fstype = FS_UNUSED0;
1219 }
1220
1221done:
1222 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
1223 free(line);
1224 return 1;
1225}
1226
1227void
1228edit_packname(struct disklabel *lp)
1229{
1230 char *p;
1231 struct disklabel oldlabel = *lp;
1232
1233 printf("Changing label description for %s:\n", specname);
1234
1235 /* pack/label id */
1236 p = getstring("label name",
1237 "15 char string that describes this label, usually the disk name.",
1238 lp->d_packname);
1239 if (p == NULL((void *)0)) {
1240 *lp = oldlabel; /* undo damage */
1241 return;
1242 }
1243 strncpy(lp->d_packname, p, sizeof(lp->d_packname)); /* checked */
1244}
1245
1246const struct partition **
1247sort_partitions(const struct disklabel *lp, int ignore)
1248{
1249 const static struct partition *spp[MAXPARTITIONS16+2];
1250 int i, npartitions;
1251
1252 memset(spp, 0, sizeof(spp));
1253
1254 for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1255 if (i != ignore && lp->d_partitions[i].p_fstype != FS_UNUSED0 &&
1256 DL_GETPSIZE(&lp->d_partitions[i])(((u_int64_t)(&lp->d_partitions[i])->p_sizeh <<
32) + (&lp->d_partitions[i])->p_size)
!= 0)
1257 spp[npartitions++] = &lp->d_partitions[i];
1258 }
1259
1260 /*
1261 * Sort the partitions based on starting offset.
1262 * This is safe because we guarantee no overlap.
1263 */
1264 if (npartitions > 1)
1265 if (mergesort((void *)spp, npartitions, sizeof(spp[0]),
1266 partition_cmp))
1267 err(4, "failed to sort partition table");
1268
1269 return spp;
1270}
1271
1272/*
1273 * Get beginning and ending sectors of the OpenBSD portion of the disk
1274 * from the user.
1275 */
1276void
1277set_bounds(struct disklabel *lp)
1278{
1279 u_int64_t ui, start_temp;
1280
1281 /* Starting sector */
1282 for (;;) {
1283 ui = getuint64(lp, "Starting sector",
1284 "The start of the OpenBSD portion of the disk.",
1285 starting_sector, DL_GETDSIZE(lp)(((u_int64_t)(lp)->d_secperunith << 32) + (lp)->d_secperunit
)
, NULL((void *)0));
1286 if (ui == CMD_ABORTED(0xffffffffffffffffULL - 1))
1287 return;
1288 else if (ui == CMD_BADVALUE(0xffffffffffffffffULL))
1289 ; /* Try again. */
1290 else if (ui >= DL_GETDSIZE(lp)(((u_int64_t)(lp)->d_secperunith << 32) + (lp)->d_secperunit
)
)
1291 fprintf(stderr(&__sF[2]), "starting sector must be < %llu\n",
1292 DL_GETDSIZE(lp)(((u_int64_t)(lp)->d_secperunith << 32) + (lp)->d_secperunit
)
);
1293 else
1294 break;
1295 }
1296 start_temp = ui;
1297
1298 /* Size */
1299 for (;;) {
1300 ui = getuint64(lp, "Size ('*' for entire disk)",
1301 "The size of the OpenBSD portion of the disk ('*' for the "
1302 "entire disk).", ending_sector - starting_sector,
1303 DL_GETDSIZE(lp)(((u_int64_t)(lp)->d_secperunith << 32) + (lp)->d_secperunit
)
- start_temp, NULL((void *)0));
1304 if (ui == CMD_ABORTED(0xffffffffffffffffULL - 1))
1305 return;
1306 else if (ui == CMD_BADVALUE(0xffffffffffffffffULL))
1307 ; /* Try again. */
1308 else if (ui > DL_GETDSIZE(lp)(((u_int64_t)(lp)->d_secperunith << 32) + (lp)->d_secperunit
)
- start_temp)
1309 fprintf(stderr(&__sF[2]), "size must be <= %llu\n",
1310 DL_GETDSIZE(lp)(((u_int64_t)(lp)->d_secperunith << 32) + (lp)->d_secperunit
)
- start_temp);
1311 else
1312 break;
1313 }
1314 ending_sector = start_temp + ui;
1315 DL_SETBEND(lp, ending_sector)do { u_int64_t __x = (ending_sector); (lp)->d_bendh = __x >>
32; (lp)->d_bend = __x; } while (0)
;
1316 starting_sector = start_temp;
1317 DL_SETBSTART(lp, starting_sector)do { u_int64_t __x = (starting_sector); (lp)->d_bstarth = __x
>> 32; (lp)->d_bstart = __x; } while (0)
;
1318}
1319
1320/*
1321 * Allow user to interactively change disklabel UID.
1322 */
1323void
1324set_duid(struct disklabel *lp)
1325{
1326 char *s;
1327 int i;
1328
1329 printf("The disklabel UID is currently: "
1330 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n",
1331 lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3],
1332 lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]);
1333
1334 do {
1335 s = getstring("duid", "The disklabel UID, given as a 16 "
1336 "character hexadecimal string.", NULL((void *)0));
1337 if (s == NULL((void *)0) || strlen(s) == 0) {
1338 fputs("Command aborted\n", stderr(&__sF[2]));
1339 return;
1340 }
1341 i = duid_parse(lp, s);
1342 if (i != 0)
1343 fputs("Invalid UID entered.\n", stderr(&__sF[2]));
1344 } while (i != 0);
1345}
1346
1347/*
1348 * Return a list of the "chunks" of free space available
1349 */
1350const struct diskchunk *
1351free_chunks(const struct disklabel *lp, int partno)
1352{
1353 const struct partition **spp;
1354 static struct diskchunk chunks[MAXPARTITIONS16 + 2];
1355 u_int64_t start, stop;
1356 int i, numchunks;
1357
1358 /* Sort the in-use partitions based on offset */
1359 spp = sort_partitions(lp, partno);
1360
1361 /* If there are no partitions, it's all free. */
1362 if (spp[0] == NULL((void *)0)) {
1363 chunks[0].start = starting_sector;
1364 chunks[0].stop = ending_sector;
1365 chunks[1].start = chunks[1].stop = 0;
1366 return chunks;
1367 }
1368
1369 /* Find chunks of free space */
1370 numchunks = 0;
1371 if (DL_GETPOFFSET(spp[0])(((u_int64_t)(spp[0])->p_offseth << 32) + (spp[0])->
p_offset)
> starting_sector) {
1372 chunks[0].start = starting_sector;
1373 chunks[0].stop = DL_GETPOFFSET(spp[0])(((u_int64_t)(spp[0])->p_offseth << 32) + (spp[0])->
p_offset)
;
1374 numchunks++;
1375 }
1376 for (i = 0; spp[i] != NULL((void *)0); i++) {
1377 start = DL_GETPOFFSET(spp[i])(((u_int64_t)(spp[i])->p_offseth << 32) + (spp[i])->
p_offset)
+ DL_GETPSIZE(spp[i])(((u_int64_t)(spp[i])->p_sizeh << 32) + (spp[i])->
p_size)
;
1378 if (start < starting_sector)
1379 start = starting_sector;
1380 else if (start > ending_sector)
1381 start = ending_sector;
1382 if (spp[i + 1] != NULL((void *)0))
1383 stop = DL_GETPOFFSET(spp[i+1])(((u_int64_t)(spp[i+1])->p_offseth << 32) + (spp[i+1
])->p_offset)
;
1384 else
1385 stop = ending_sector;
1386 if (stop < starting_sector)
1387 stop = starting_sector;
1388 else if (stop > ending_sector)
1389 stop = ending_sector;
1390 if (start < stop) {
1391 chunks[numchunks].start = start;
1392 chunks[numchunks].stop = stop;
1393 numchunks++;
1394 }
1395 }
1396
1397 /* Terminate and return */
1398 chunks[numchunks].start = chunks[numchunks].stop = 0;
1399 return chunks;
1400}
1401
1402void
1403find_bounds(const struct disklabel *lp)
1404{
1405 starting_sector = DL_GETBSTART(lp)(((u_int64_t)(lp)->d_bstarth << 32) + (lp)->d_bstart
)
;
1406 ending_sector = DL_GETBEND(lp)(((u_int64_t)(lp)->d_bendh << 32) + (lp)->d_bend);
1407
1408 if (ending_sector) {
1409 if (verbose)
1410 printf("Treating sectors %llu-%llu as the OpenBSD"
1411 " portion of the disk.\nYou can use the 'b'"
1412 " command to change this.\n\n", starting_sector,
1413 ending_sector);
1414 }
1415}
1416
1417/*
1418 * Calculate free space.
1419 */
1420u_int64_t
1421editor_countfree(const struct disklabel *lp)
1422{
1423 const struct diskchunk *chunk;
1424 u_int64_t freesectors = 0;
1425
1426 chunk = free_chunks(lp, -1);
1427
1428 for (; chunk->start != 0 || chunk->stop != 0; chunk++)
1429 freesectors += CHUNKSZ(chunk)((chunk)->stop - (chunk)->start);
1430
1431 return freesectors;
1432}
1433
1434void
1435editor_help(void)
1436{
1437 puts("Available commands:");
1438 puts(
1439" ? | h - show help n [part] - set mount point\n"
1440" A - auto partition all space p [unit] - print partitions\n"
1441" a [part] - add partition q - quit & save changes\n"
1442" b - set OpenBSD boundaries R [part] - resize auto allocated partition\n"
1443" c [part] - change partition size r - display free space\n"
1444" D - reset label to default s [path] - save label to file\n"
1445" d [part] - delete partition U - undo all changes\n"
1446" e - edit label description u - undo last change\n"
1447" i - modify disklabel UID w - write label to disk\n"
1448" l [unit] - print disk label header x - exit & lose changes\n"
1449" M - disklabel(8) man page z - delete all partitions\n"
1450" m [part] - modify partition\n"
1451"\n"
1452"Suffixes can be used to indicate units other than sectors:\n"
1453" 'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes) 't' (terabytes)\n"
1454" 'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n"
1455"Values in non-sector units are truncated to the nearest cylinder boundary.");
1456
1457}
1458
1459void
1460mpcopy(char **to, char **from)
1461{
1462 int i;
1463
1464 for (i = 0; i < MAXPARTITIONS16; i++) {
1465 free(to[i]);
1466 to[i] = NULL((void *)0);
1467 if (from[i] != NULL((void *)0)) {
1468 to[i] = strdup(from[i]);
1469 if (to[i] == NULL((void *)0))
1470 err(1, NULL((void *)0));
1471 }
1472 }
1473}
1474
1475int
1476mpequal(char **mp1, char **mp2)
1477{
1478 int i;
1479
1480 for (i = 0; i < MAXPARTITIONS16; i++) {
1481 if (mp1[i] == NULL((void *)0) && mp2[i] == NULL((void *)0))
1482 continue;
1483
1484 if ((mp1[i] != NULL((void *)0) && mp2[i] == NULL((void *)0)) ||
1485 (mp1[i] == NULL((void *)0) && mp2[i] != NULL((void *)0)) ||
1486 (strcmp(mp1[i], mp2[i]) != 0))
1487 return 0;
1488 }
1489 return 1;
1490}
1491
1492void
1493mpsave(const struct disklabel *lp)
1494{
1495 int i, j;
1496 char bdev[PATH_MAX1024], *p;
1497 struct mountinfo mi[MAXPARTITIONS16];
1498 FILE *fp;
1499 u_int8_t fstype;
1500
1501 if (!fstabfile)
1502 return;
1503
1504 memset(&mi, 0, sizeof(mi));
1505
1506 for (i = 0; i < MAXPARTITIONS16; i++) {
1507 fstype = lp->d_partitions[i].p_fstype;
1508 if (mountpoints[i] != NULL((void *)0) || fstype == FS_SWAP1) {
1509 mi[i].mountpoint = mountpoints[i];
1510 mi[i].partno = i;
1511 }
1512 }
1513
1514 /* Convert specname to bdev */
1515 if (uidflag) {
1516 snprintf(bdev, sizeof(bdev),
1517 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
1518 lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3],
1519 lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7],
1520 specname[strlen(specname)-1]);
1521 } else if (strncmp(_PATH_DEV"/dev/", specname, sizeof(_PATH_DEV"/dev/") - 1) == 0 &&
1522 specname[sizeof(_PATH_DEV"/dev/") - 1] == 'r') {
1523 snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV"/dev/",
1524 &specname[sizeof(_PATH_DEV"/dev/")]);
1525 } else {
1526 if ((p = strrchr(specname, '/')) == NULL((void *)0) || *(++p) != 'r')
1527 return;
1528 *p = '\0';
1529 snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1);
1530 *p = 'r';
1531 }
1532 bdev[strlen(bdev) - 1] = '\0';
1533
1534 /* Sort mountpoints so we don't try to mount /usr/local before /usr */
1535 qsort((void *)mi, MAXPARTITIONS16, sizeof(struct mountinfo), micmp);
1536
1537 if ((fp = fopen(fstabfile, "w"))) {
1538 for (i = 0; i < MAXPARTITIONS16; i++) {
1539 j = mi[i].partno;
1540 fstype = lp->d_partitions[j].p_fstype;
1541 if (fstype == FS_RAID19)
1542 continue;
1543 if (fstype == FS_SWAP1) {
1544 fprintf(fp, "%s%c none swap sw\n", bdev, 'a'+j);
1545 } else if (mi[i].mountpoint) {
1546 fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev,
1547 'a' + j, mi[i].mountpoint,
1548 fstypesnames[fstype], j == 0 ? 1 : 2);
1549 }
1550 }
1551 fclose(fp);
1552 }
1553}
1554
1555void
1556mpfree(char **mp, int action)
1557{
1558 int part;
1559
1560 if (mp == NULL((void *)0))
1561 return;
1562
1563 for (part = 0; part < MAXPARTITIONS16; part++) {
1564 free(mp[part]);
1565 mp[part] = NULL((void *)0);
1566 }
1567
1568 if (action == DISCARD0) {
1569 free(mp);
1570 mp = NULL((void *)0);
1571 }
1572}
1573
1574int
1575get_offset(struct disklabel *lp, int partno)
1576{
1577 struct partition opp, *pp = &lp->d_partitions[partno];
1578 u_int64_t ui, offsetalign;
1579 int flags;
1580
1581 flags = DO_CONVERSIONS0x00000001;
1582 ui = getuint64(lp, "offset",
1583 "Starting sector for this partition.",
1584 DL_GETPOFFSET(pp)(((u_int64_t)(pp)->p_offseth << 32) + (pp)->p_offset
)
,
1585 DL_GETPOFFSET(pp)(((u_int64_t)(pp)->p_offseth << 32) + (pp)->p_offset
)
, &flags);
1586
1587 if (ui == CMD_ABORTED(0xffffffffffffffffULL - 1) || ui == CMD_BADVALUE(0xffffffffffffffffULL))
1588 return 1;
1589#ifdef SUN_AAT0
1590 if (partno == 0 && ui != 0) {
1591 fprintf(stderr(&__sF[2]), "This architecture requires that "
1592 "partition 'a' start at sector 0.\n");
1593 return 1;
1594 }
1595#endif
1596 opp = *pp;
1597 DL_SETPOFFSET(pp, ui)do { u_int64_t __x = (ui); (pp)->p_offseth = __x >> 32
; (pp)->p_offset = __x; } while (0)
;
1598 offsetalign = 1;
1599 if ((flags & DO_ROUNDING0x00000002) != 0 && pp->p_fstype == FS_BSDFFS7)
1600 offsetalign = lp->d_secpercyl;
1601
1602 if (alignpartition(lp, partno, offsetalign, 1, ROUND_OFFSET_UP0x00000001) == 1) {
1603 *pp = opp;
1604 return 1;
1605 }
1606
1607 return 0;
1608}
1609
1610int
1611get_size(struct disklabel *lp, int partno)
1612{
1613 struct partition opp, *pp = &lp->d_partitions[partno];
1614 u_int64_t maxsize, ui, sizealign;
1615 int flags;
1616
1617 maxsize = max_partition_size(lp, partno);
1618 flags = DO_CONVERSIONS0x00000001;
1619 ui = getuint64(lp, "size", "Size of the partition. "
1620 "You may also say +/- amount for a relative change.",
1621 DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size), maxsize, &flags);
1622
1623 if (ui == CMD_ABORTED(0xffffffffffffffffULL - 1) || ui == CMD_BADVALUE(0xffffffffffffffffULL))
1624 return 1;
1625
1626 opp = *pp;
1627 DL_SETPSIZE(pp, ui)do { u_int64_t __x = (ui); (pp)->p_sizeh = __x >> 32
; (pp)->p_size = __x; } while (0)
;
1628 sizealign = 1;
1629 if ((flags & DO_ROUNDING0x00000002) != 0 && (pp->p_fstype == FS_SWAP1 ||
1630 pp->p_fstype == FS_BSDFFS7))
1631 sizealign = lp->d_secpercyl;
1632
1633 if (alignpartition(lp, partno, 1, sizealign, ROUND_SIZE_UP0x00000004) == 1) {
1634 *pp = opp;
1635 return 1;
1636 }
1637
1638 return 0;
1639}
1640
1641int
1642set_fragblock(struct disklabel *lp, int partno)
1643{
1644 struct partition opp, *pp = &lp->d_partitions[partno];
1645 u_int64_t bytes, offsetalign, sizealign;
1646 u_int32_t frag, fsize;
1647
1648 if (pp->p_fstype
35.1
Field 'p_fstype' is equal to FS_BSDFFS
!= FS_BSDFFS7)
36
Taking false branch
1649 return 0;
1650
1651 if (pp->p_cpg == 0)
37
Assuming field 'p_cpg' is not equal to 0
1652 pp->p_cpg = 1;
1653
1654 fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock)(((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock
) & 0x07) - 1))) == 0 ? 0 : (((pp->p_fragblock) == 0 ?
0 : (1 << (((pp->p_fragblock) >> 3) + 12))) /
((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock
) & 0x07) - 1)))))
;
38
Taking false branch
39
'?' condition is true
40
'?' condition is true
1655 frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock)((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock
) & 0x07) - 1)))
;
41
'?' condition is true
1656 if (fsize
41.1
'fsize' is equal to 0
== 0) {
42
Taking true branch
1657 fsize = 2048;
1658 frag = 8;
1659 bytes = DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) * lp->d_secsize;
1660 if (bytes > 128ULL * 1024 * 1024 * 1024)
43
Assuming the condition is false
44
Taking false branch
1661 fsize *= 2;
1662 if (bytes > 512ULL * 1024 * 1024 * 1024)
45
Taking false branch
1663 fsize *= 2;
1664 if (fsize < lp->d_secsize)
46
Assuming 'fsize' is >= field 'd_secsize'
47
Taking false branch
1665 fsize = lp->d_secsize;
1666 if (fsize > MAXBSIZE(64 * 1024) / frag)
1667 fsize = MAXBSIZE(64 * 1024) / frag;
1668 pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, frag)((fsize) * (frag) == 0 ? 0 : (((ffs((fsize) * (frag)) - 13) <<
3) | (ffs(frag))))
;
48
Taking false branch
49
'?' condition is false
1669 }
1670#ifdef SUN_CYLCHECK
1671 return 0;
1672#endif
1673 opp = *pp;
1674 sizealign = (DISKLABELV1_FFS_FRAG(pp->p_fragblock)((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock
) & 0x07) - 1)))
*
50
Assuming field 'p_fragblock' is equal to 0
51
'?' condition is true
54
The value 0 is assigned to 'sizealign'
1675 DISKLABELV1_FFS_FSIZE(pp->p_fragblock)(((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock
) & 0x07) - 1))) == 0 ? 0 : (((pp->p_fragblock) == 0 ?
0 : (1 << (((pp->p_fragblock) >> 3) + 12))) /
((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock
) & 0x07) - 1)))))
) / lp->d_secsize
;
52
'?' condition is true
53
'?' condition is true
1676 offsetalign = 1;
1677 if (DL_GETPOFFSET(pp)(((u_int64_t)(pp)->p_offseth << 32) + (pp)->p_offset
)
!= starting_sector
)
55
Assuming the condition is true
56
Taking true branch
1678 offsetalign = sizealign;
57
The value 0 is assigned to 'offsetalign'
1679
1680 if (alignpartition(lp, partno, offsetalign, sizealign, ROUND_OFFSET_UP0x00000001 |
58
Passing the value 0 via 3rd parameter 'startalign'
59
Calling 'alignpartition'
1681 ROUND_SIZE_DOWN0x00000008 | ROUND_SIZE_OVERLAP0x00000010) == 1) {
1682 *pp = opp;
1683 return 1;
1684 }
1685
1686 return 0;
1687}
1688
1689int
1690get_fstype(struct disklabel *lp, int partno)
1691{
1692 char *p;
1693 u_int64_t ui;
1694 struct partition *pp = &lp->d_partitions[partno];
1695
1696 if (pp->p_fstype < FSMAXTYPES(sizeof(fstypenames) / sizeof(fstypenames[0]) - 1)) {
1697 p = getstring("FS type",
1698 "Filesystem type (usually 4.2BSD or swap)",
1699 fstypenames[pp->p_fstype]);
1700 if (p == NULL((void *)0)) {
1701 return 1;
1702 }
1703 for (ui = 0; ui < FSMAXTYPES(sizeof(fstypenames) / sizeof(fstypenames[0]) - 1); ui++) {
1704 if (!strcasecmp(p, fstypenames[ui])) {
1705 pp->p_fstype = ui;
1706 break;
1707 }
1708 }
1709 if (ui >= FSMAXTYPES(sizeof(fstypenames) / sizeof(fstypenames[0]) - 1)) {
1710 printf("Unrecognized filesystem type '%s', treating "
1711 "as 'unknown'\n", p);
1712 pp->p_fstype = FS_OTHER10;
1713 }
1714 } else {
1715 for (;;) {
1716 ui = getnumber("FS type (decimal)",
1717 "Filesystem type as a decimal number; usually 7 "
1718 "(4.2BSD) or 1 (swap).",
1719 pp->p_fstype, UINT8_MAX0xff);
1720 if (ui == CMD_ABORTED(0xffffffffffffffffULL - 1))
1721 return 1;
1722 else if (ui == CMD_BADVALUE(0xffffffffffffffffULL))
1723 ; /* Try again. */
1724 else
1725 break;
1726 }
1727 pp->p_fstype = ui;
1728 }
1729 return 0;
1730}
1731
1732int
1733get_mp(const struct disklabel *lp, int partno)
1734{
1735 const struct partition *pp = &lp->d_partitions[partno];
1736 char *p;
1737 int i;
1738
1739 if (fstabfile == NULL((void *)0) ||
1740 pp->p_fstype == FS_UNUSED0 ||
1741 pp->p_fstype == FS_SWAP1 ||
1742 pp->p_fstype == FS_BOOT13 ||
1743 pp->p_fstype == FS_OTHER10 ||
1744 pp->p_fstype == FS_RAID19) {
1745 /* No fstabfile, no names. Not all fstypes can be named */
1746 return 0;
1747 }
1748
1749 for (;;) {
1750 p = getstring("mount point",
1751 "Where to mount this filesystem (ie: / /var /usr)",
1752 mountpoints[partno] ? mountpoints[partno] : "none");
1753 if (p == NULL((void *)0))
1754 return 1;
1755 if (strcasecmp(p, "none") == 0) {
1756 free(mountpoints[partno]);
1757 mountpoints[partno] = NULL((void *)0);
1758 break;
1759 }
1760 for (i = 0; i < MAXPARTITIONS16; i++)
1761 if (mountpoints[i] != NULL((void *)0) && i != partno &&
1762 strcmp(p, mountpoints[i]) == 0)
1763 break;
1764 if (i < MAXPARTITIONS16) {
1765 fprintf(stderr(&__sF[2]), "'%c' already being mounted at "
1766 "'%s'\n", 'a'+i, p);
1767 break;
1768 }
1769 if (*p == '/') {
1770 /* XXX - might as well realloc */
1771 free(mountpoints[partno]);
1772 if ((mountpoints[partno] = strdup(p)) == NULL((void *)0))
1773 err(1, NULL((void *)0));
1774 break;
1775 }
1776 fputs("Mount points must start with '/'\n", stderr(&__sF[2]));
1777 }
1778
1779 return 0;
1780}
1781
1782int
1783micmp(const void *a1, const void *a2)
1784{
1785 struct mountinfo *mi1 = (struct mountinfo *)a1;
1786 struct mountinfo *mi2 = (struct mountinfo *)a2;
1787
1788 /* We want all the NULLs at the end... */
1789 if (mi1->mountpoint == NULL((void *)0) && mi2->mountpoint == NULL((void *)0))
1790 return 0;
1791 else if (mi1->mountpoint == NULL((void *)0))
1792 return 1;
1793 else if (mi2->mountpoint == NULL((void *)0))
1794 return -1;
1795 else
1796 return strcmp(mi1->mountpoint, mi2->mountpoint);
1797}
1798
1799void
1800zero_partitions(struct disklabel *lp)
1801{
1802 memset(lp->d_partitions, 0, sizeof(lp->d_partitions));
1803 DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp))do { u_int64_t __x = ((((u_int64_t)(lp)->d_secperunith <<
32) + (lp)->d_secperunit)); (&lp->d_partitions[2])
->p_sizeh = __x >> 32; (&lp->d_partitions[2])
->p_size = __x; } while (0)
;
1804
1805 mpfree(mountpoints, KEEP1);
1806}
1807
1808u_int64_t
1809max_partition_size(const struct disklabel *lp, int partno)
1810{
1811 const struct diskchunk *chunk;
1812 u_int64_t maxsize = 0, offset;
1813
1814 chunk = free_chunks(lp, partno);
1815
1816 offset = DL_GETPOFFSET(&lp->d_partitions[partno])(((u_int64_t)(&lp->d_partitions[partno])->p_offseth
<< 32) + (&lp->d_partitions[partno])->p_offset
)
;
1817 for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
1818 if (offset < chunk->start || offset >= chunk->stop)
1819 continue;
1820 maxsize = chunk->stop - offset;
1821 break;
1822 }
1823 return maxsize;
1824}
1825
1826void
1827psize(u_int64_t sz, char unit, const struct disklabel *lp)
1828{
1829 double d = scale(sz, unit, lp);
1830 if (d < 0)
1831 printf("%llu", sz);
1832 else
1833 printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit);
1834}
1835
1836void
1837display_edit(const struct disklabel *lp, char unit)
1838{
1839 u_int64_t fr;
1840 int i;
1841
1842 fr = editor_countfree(lp);
1843 unit = canonical_unit(lp, unit);
1844
1845 printf("OpenBSD area: ");
1846 psize(starting_sector, 0, lp);
1847 printf("-");
1848 psize(ending_sector, 0, lp);
1849 printf("; size: ");
1850 psize(ending_sector - starting_sector, unit, lp);
1851 printf("; free: ");
1852 psize(fr, unit, lp);
1853
1854 printf("\n# %16.16s %16.16s fstype [fsize bsize cpg]\n",
1855 "size", "offset");
1856 for (i = 0; i < lp->d_npartitions; i++)
1857 display_partition(stdout(&__sF[1]), lp, i, unit);
1858}
1859
1860void
1861parse_autotable(char *filename)
1862{
1863 FILE *cfile;
1864 size_t linesize = 0;
1865 char *line = NULL((void *)0), *buf, *t;
1866 uint idx = 0, pctsum = 0;
1867 struct space_allocation *sa;
1868
1869 if (strcmp(filename, "-") == 0)
1870 cfile = stdin(&__sF[0]);
1871 else if ((cfile = fopen(filename, "r")) == NULL((void *)0))
1872 err(1, "%s", filename);
1873 if ((alloc_table = calloc(1, sizeof(struct alloc_table))) == NULL((void *)0))
1874 err(1, NULL((void *)0));
1875 alloc_table_nitems = 1;
1876
1877 while (getline(&line, &linesize, cfile) != -1) {
1878 if ((alloc_table[0].table = reallocarray(alloc_table[0].table,
1879 idx + 1, sizeof(*sa))) == NULL((void *)0))
1880 err(1, NULL((void *)0));
1881 sa = &(alloc_table[0].table[idx]);
1882 memset(sa, 0, sizeof(*sa));
1883 idx++;
1884
1885 buf = line;
1886 if ((sa->mp = get_token(&buf)) == NULL((void *)0) ||
1887 (sa->mp[0] != '/' && strcasecmp(sa->mp, "swap") &&
1888 strcasecmp(sa->mp, "raid")))
1889 errx(1, "%s: parse error on line %u", filename, idx);
1890 if ((t = get_token(&buf)) == NULL((void *)0) ||
1891 parse_sizerange(t, &sa->minsz, &sa->maxsz) == -1)
1892 errx(1, "%s: parse error on line %u", filename, idx);
1893 if ((t = get_token(&buf)) != NULL((void *)0) &&
1894 parse_pct(t, &sa->rate) == -1)
1895 errx(1, "%s: parse error on line %u", filename, idx);
1896 if (sa->minsz > sa->maxsz)
1897 errx(1, "%s: min size > max size on line %u", filename,
1898 idx);
1899 pctsum += sa->rate;
1900 }
1901 if (pctsum > 100)
1902 errx(1, "%s: sum of extra space allocation > 100%%", filename);
1903 alloc_table[0].sz = idx;
1904 free(line);
1905 fclose(cfile);
1906}
1907
1908char *
1909get_token(char **s)
1910{
1911 char *p, *r;
1912 size_t tlen = 0;
1913
1914 p = *s;
1915 while (**s != '\0' && !isspace((u_char)**s)) {
1916 (*s)++;
1917 tlen++;
1918 }
1919 if (tlen == 0)
1920 return NULL((void *)0);
1921
1922 /* eat whitespace */
1923 while (isspace((u_char)**s))
1924 (*s)++;
1925
1926 if ((r = strndup(p, tlen)) == NULL((void *)0))
1927 err(1, NULL((void *)0));
1928 return r;
1929}
1930
1931int
1932apply_unit(double val, u_char unit, u_int64_t *n)
1933{
1934 u_int64_t factor = 1;
1935
1936 switch (tolower(unit)) {
1937 case 't':
1938 factor *= 1024;
1939 /* FALLTHROUGH */
1940 case 'g':
1941 factor *= 1024;
1942 /* FALLTHROUGH */
1943 case 'm':
1944 factor *= 1024;
1945 /* FALLTHROUGH */
1946 case 'k':
1947 factor *= 1024;
1948 break;
1949 default:
1950 return -1;
1951 }
1952
1953 val *= factor / DEV_BSIZE(1 << 9);
1954 if (val > (double)ULLONG_MAX0xffffffffffffffffULL)
1955 return -1;
1956 *n = val;
1957 return 0;
1958}
1959
1960int
1961parse_sizespec(const char *buf, double *val, char **unit)
1962{
1963 errno(*__errno()) = 0;
1964 *val = strtod(buf, unit);
1965 if (errno(*__errno()) == ERANGE34 || *val < 0 || *val > (double)ULLONG_MAX0xffffffffffffffffULL)
1966 return -1; /* too big/small */
1967 if (*val == 0 && *unit == buf)
1968 return -1; /* No conversion performed. */
1969 if (*unit != NULL((void *)0) && *unit[0] == '\0')
1970 *unit = NULL((void *)0);
1971 return 0;
1972}
1973
1974int
1975parse_sizerange(char *buf, u_int64_t *min, u_int64_t *max)
1976{
1977 char *p, *unit1 = NULL((void *)0), *unit2 = NULL((void *)0);
1978 double val1 = 0, val2 = 0;
1979
1980 if (strcmp(buf, "*") == 0) {
1981 *min = 0;
1982 *max = UINT64_MAX0xffffffffffffffffULL;
1983 goto done;
1984 }
1985
1986 if ((p = strchr(buf, '-')) != NULL((void *)0)) {
1987 p[0] = '\0';
1988 p++;
1989 }
1990 *max = 0;
1991 if (parse_sizespec(buf, &val1, &unit1) == -1)
1992 return -1;
1993 if (p != NULL((void *)0) && p[0] != '\0') {
1994 if (p[0] == '*')
1995 *max = UINT64_MAX0xffffffffffffffffULL;
1996 else
1997 if (parse_sizespec(p, &val2, &unit2) == -1)
1998 return -1;
1999 }
2000 if (unit1 == NULL((void *)0) && (unit1 = unit2) == NULL((void *)0))
2001 return -1;
2002 if (apply_unit(val1, unit1[0], min) == -1)
2003 return -1;
2004 if (val2 > 0) {
2005 if (apply_unit(val2, unit2[0], max) == -1)
2006 return -1;
2007 } else
2008 if (*max == 0)
2009 *max = *min;
2010 done:
2011 free(buf);
2012 return 0;
2013}
2014
2015int
2016parse_pct(char *buf, int *n)
2017{
2018 const char *errstr;
2019
2020 if (buf[strlen(buf) - 1] == '%')
2021 buf[strlen(buf) - 1] = '\0';
2022 *n = strtonum(buf, 0, 100, &errstr);
2023 if (errstr) {
2024 warnx("parse percent %s: %s", buf, errstr);
2025 return -1;
2026 }
2027 free(buf);
2028 return 0;
2029}
2030
2031int
2032alignpartition(struct disklabel *lp, int partno, u_int64_t startalign,
2033 u_int64_t stopalign, int flags)
2034{
2035 struct partition *pp = &lp->d_partitions[partno];
2036 const struct diskchunk *chunk;
2037 u_int64_t start, stop, maxstop;
2038
2039 start = DL_GETPOFFSET(pp)(((u_int64_t)(pp)->p_offseth << 32) + (pp)->p_offset
)
;
2040 if ((flags & ROUND_OFFSET_UP0x00000001) == ROUND_OFFSET_UP0x00000001)
60
Taking true branch
2041 start = ROUNDUP(start, startalign)((((start) + (startalign) - 1) / (startalign)) * (startalign)
)
;
61
Division by zero
2042 else if ((flags & ROUND_OFFSET_DOWN0x00000002) == ROUND_OFFSET_DOWN0x00000002)
2043 start = ROUNDDOWN(start, startalign)(((start) / (startalign)) * (startalign));
2044
2045 /* Find the chunk that contains 'start'. */
2046 chunk = free_chunks(lp, partno);
2047 for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
2048 if (start >= chunk->start && start < chunk->stop)
2049 break;
2050 }
2051 if (chunk->stop == 0) {
2052 fprintf(stderr(&__sF[2]), "'%c' aligned offset %llu lies outside "
2053 "the OpenBSD bounds or inside another partition\n",
2054 'a' + partno, start);
2055 return 1;
2056 }
2057
2058 /* Calculate the new 'stop' sector, the sector after the partition. */
2059 if ((flags & ROUND_SIZE_OVERLAP0x00000010) == 0)
2060 maxstop = ROUNDDOWN(chunk->stop, stopalign)(((chunk->stop) / (stopalign)) * (stopalign));
2061 else
2062 maxstop = ROUNDDOWN(ending_sector, stopalign)(((ending_sector) / (stopalign)) * (stopalign));
2063
2064 stop = DL_GETPOFFSET(pp)(((u_int64_t)(pp)->p_offseth << 32) + (pp)->p_offset
)
+ DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size);
2065 if ((flags & ROUND_SIZE_UP0x00000004) == ROUND_SIZE_UP0x00000004)
2066 stop = ROUNDUP(stop, stopalign)((((stop) + (stopalign) - 1) / (stopalign)) * (stopalign));
2067 else if ((flags & ROUND_SIZE_DOWN0x00000008) == ROUND_SIZE_DOWN0x00000008)
2068 stop = ROUNDDOWN(stop, stopalign)(((stop) / (stopalign)) * (stopalign));
2069 if (stop > maxstop)
2070 stop = maxstop;
2071
2072 if (stop <= start) {
2073 fprintf(stderr(&__sF[2]), "not enough space\n");
2074 return 1;
2075 }
2076
2077 if (start != DL_GETPOFFSET(pp)(((u_int64_t)(pp)->p_offseth << 32) + (pp)->p_offset
)
)
2078 DL_SETPOFFSET(pp, start)do { u_int64_t __x = (start); (pp)->p_offseth = __x >>
32; (pp)->p_offset = __x; } while (0)
;
2079 if (stop != DL_GETPOFFSET(pp)(((u_int64_t)(pp)->p_offseth << 32) + (pp)->p_offset
)
+ DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size))
2080 DL_SETPSIZE(pp, stop - start)do { u_int64_t __x = (stop - start); (pp)->p_sizeh = __x >>
32; (pp)->p_size = __x; } while (0)
;
2081
2082 return 0;
2083}