1*854d339cSjan /* $OpenBSD: editor.c,v 1.418 2024/03/22 21:49:52 jan Exp $ */
26fe57b42Smillert
36fe57b42Smillert /*
4bf198cc6Smillert * Copyright (c) 1997-2000 Todd C. Miller <millert@openbsd.org>
56fe57b42Smillert *
606f01696Smillert * Permission to use, copy, modify, and distribute this software for any
706f01696Smillert * purpose with or without fee is hereby granted, provided that the above
806f01696Smillert * copyright notice and this permission notice appear in all copies.
96fe57b42Smillert *
10328f1f07Smillert * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11328f1f07Smillert * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12328f1f07Smillert * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13328f1f07Smillert * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14328f1f07Smillert * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15328f1f07Smillert * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16328f1f07Smillert * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176fe57b42Smillert */
186fe57b42Smillert
1978eb0b7eSderaadt #include <sys/param.h> /* MAXBSIZE DEV_BSIZE */
206fe57b42Smillert #include <sys/types.h>
21b9fc9a72Sderaadt #include <sys/signal.h>
22c33fcabaSmillert #include <sys/stat.h>
23c33fcabaSmillert #include <sys/ioctl.h>
2491f4f7d8Sdlg #include <sys/dkio.h>
258dde8bb6Sotto #include <sys/sysctl.h>
266fe57b42Smillert #define DKTYPENAMES
276fe57b42Smillert #include <sys/disklabel.h>
286fe57b42Smillert
296fe57b42Smillert #include <ufs/ffs/fs.h>
306fe57b42Smillert
316fe57b42Smillert #include <ctype.h>
326fe57b42Smillert #include <err.h>
336fe57b42Smillert #include <errno.h>
346fe57b42Smillert #include <string.h>
35803ff7d5Smillert #include <libgen.h>
36f1bc1b27Skrw #include <stdint.h>
376fe57b42Smillert #include <stdio.h>
386fe57b42Smillert #include <stdlib.h>
396fe57b42Smillert #include <unistd.h>
40b9fc9a72Sderaadt #include <limits.h>
416fe57b42Smillert
42f21a098bSotto #include "extern.h"
434793b14cSmillert #include "pathnames.h"
444793b14cSmillert
45f409a94aSkrw #define ROUNDUP(_s, _a) ((((_s) + (_a) - 1) / (_a)) * (_a))
46f409a94aSkrw #define ROUNDDOWN(_s, _a) (((_s) / (_a)) * (_a))
47b46f7512Skrw #define CHUNKSZ(_c) ((_c)->stop - (_c)->start)
48b9fc9a72Sderaadt
49117239d3Skrw /* flags for getuint64() */
506fe57b42Smillert #define DO_CONVERSIONS 0x00000001
516fe57b42Smillert #define DO_ROUNDING 0x00000002
526fe57b42Smillert
5340b226e8Skrw /* flags for alignpartition() */
5440b226e8Skrw #define ROUND_OFFSET_UP 0x00000001
5540b226e8Skrw #define ROUND_OFFSET_DOWN 0x00000002
5640b226e8Skrw #define ROUND_SIZE_UP 0x00000004
5740b226e8Skrw #define ROUND_SIZE_DOWN 0x00000008
58922b28b8Skrw #define ROUND_SIZE_OVERLAP 0x00000010
5940b226e8Skrw
600db7769aSkrw /* Special return values for getnumber and getuint64() */
61aa3970cdSkrw #define CMD_ABORTED (ULLONG_MAX - 1)
62aa3970cdSkrw #define CMD_BADVALUE (ULLONG_MAX)
63aa3970cdSkrw
6496a888c6Smillert /* structure to describe a portion of a disk */
6596a888c6Smillert struct diskchunk {
661e0ad43cSotto u_int64_t start;
671e0ad43cSotto u_int64_t stop;
6896a888c6Smillert };
6996a888c6Smillert
703f843443Smillert /* used when sorting mountpoints in mpsave() */
713f843443Smillert struct mountinfo {
723f843443Smillert char *mountpoint;
733f843443Smillert int partno;
743f843443Smillert };
753f843443Smillert
76557f712bSkrw /* used when allocating all space according to recommendations */
77557f712bSkrw
78557f712bSkrw struct space_allocation {
79eafadddfSkrw u_int64_t minsz; /* starts as blocks, xlated to sectors. */
80eafadddfSkrw u_int64_t maxsz; /* starts as blocks, xlated to sectors. */
81557f712bSkrw int rate; /* % of extra space to use */
82557f712bSkrw char *mp;
83557f712bSkrw };
84557f712bSkrw
85e485502dSkrw /*
86e485502dSkrw * NOTE! Changing partition sizes in the space_allocation tables
87e485502dSkrw * requires corresponding updates to the *.ok files in
88e485502dSkrw * /usr/src/regress/sbin/disklabel.
89e485502dSkrw */
90e485502dSkrw
918dde8bb6Sotto /* entries for swap and var are changed by editor_allocspace() */
92a2c1f847Shenning struct space_allocation alloc_big[] = {
93d190517aSotto { MEG(150), GIG(1), 5, "/" },
94559340afSotto { MEG(80), MEG(256), 10, "swap" },
954ab111d2Sderaadt { MEG(120), GIG(4), 8, "/tmp" },
9692adb55fSderaadt { MEG(80), GIG(4), 13, "/var" },
97cc2b79a5Smbuhl { MEG(1500), GIG(30), 10, "/usr" },
98ecf06799Sajacoutot { MEG(384), GIG(1), 3, "/usr/X11R6" },
9997f090a4Ssolene { GIG(1), GIG(20), 15, "/usr/local" },
100*854d339cSjan { GIG(2), GIG(5), 2, "/usr/src" },
101d6b9791fSbluhm { GIG(5), GIG(6), 4, "/usr/obj" },
10226e633f4Sotto { GIG(1), GIG(300), 30, "/home" }
1034ab111d2Sderaadt /* Anything beyond this leave for the user to decide */
1048dde8bb6Sotto };
1058dde8bb6Sotto
106a2c1f847Shenning struct space_allocation alloc_medium[] = {
107905e8239Sderaadt { MEG(800), GIG(2), 5, "/" },
1088dde8bb6Sotto { MEG(80), MEG(256), 10, "swap" },
109ad1fb99dSphessler { MEG(1300), GIG(3), 78, "/usr" },
110905e8239Sderaadt { MEG(256), GIG(2), 7, "/home" }
1118dde8bb6Sotto };
1128dde8bb6Sotto
113a2c1f847Shenning struct space_allocation alloc_small[] = {
11492adb55fSderaadt { MEG(700), GIG(4), 95, "/" },
1158dde8bb6Sotto { MEG(1), MEG(256), 5, "swap" }
1168dde8bb6Sotto };
1178dde8bb6Sotto
118a2c1f847Shenning struct space_allocation alloc_stupid[] = {
1198dde8bb6Sotto { MEG(1), MEG(2048), 100, "/" }
1208dde8bb6Sotto };
1218dde8bb6Sotto
122b2813ff1Sderaadt #ifndef nitems
123b2813ff1Sderaadt #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
124b2813ff1Sderaadt #endif
125b2813ff1Sderaadt
126a2c1f847Shenning struct alloc_table {
127a2c1f847Shenning struct space_allocation *table;
1288a862940Sderaadt int sz;
129a2c1f847Shenning };
130a2c1f847Shenning
131a2c1f847Shenning struct alloc_table alloc_table_default[] = {
1328dde8bb6Sotto { alloc_big, nitems(alloc_big) },
1338dde8bb6Sotto { alloc_medium, nitems(alloc_medium) },
1348dde8bb6Sotto { alloc_small, nitems(alloc_small) },
1358dde8bb6Sotto { alloc_stupid, nitems(alloc_stupid) }
136557f712bSkrw };
137a2c1f847Shenning struct alloc_table *alloc_table = alloc_table_default;
138f55524eaSsthen int alloc_table_nitems = 4;
139557f712bSkrw
1401cc333d2Skrw void edit_packname(struct disklabel *);
141c0bc1f19Skrw void editor_resize(struct disklabel *, const char *);
142c0bc1f19Skrw void editor_add(struct disklabel *, const char *);
143c0bc1f19Skrw void editor_change(struct disklabel *, const char *);
14443ba7787Skrw u_int64_t editor_countfree(const struct disklabel *);
145c0bc1f19Skrw void editor_delete(struct disklabel *, const char *);
1464d812bb6Slum void editor_help(void);
147c0bc1f19Skrw void editor_modify(struct disklabel *, const char *);
14841d86e10Skrw void editor_name(const struct disklabel *, const char *);
149b228e876Smiod char *getstring(const char *, const char *, const char *);
15043ba7787Skrw u_int64_t getuint64(const struct disklabel *, char *, char *, u_int64_t,
15140b226e8Skrw u_int64_t, int *);
152c0bc1f19Skrw u_int64_t getnumber(const char *, const char *, u_int32_t, u_int32_t);
15378ff4c86Skrw int getpartno(const struct disklabel *, const char *, const char *);
1541f0f871dSkrw int has_overlap(struct disklabel *);
155c72b5b24Smillert int partition_cmp(const void *, const void *);
15643ba7787Skrw const struct partition **sort_partitions(const struct disklabel *, int);
15743ba7787Skrw void find_bounds(const struct disklabel *);
1589fdcb4d6Skrw void set_bounds(struct disklabel *);
15969a6ffbcSjsing void set_duid(struct disklabel *);
160728b9255Skrw int set_fragblock(struct disklabel *, int);
161ab2017adSkrw const struct diskchunk *free_chunks(const struct disklabel *, int);
162c72b5b24Smillert int micmp(const void *, const void *);
163c72b5b24Smillert int mpequal(char **, char **);
164c72b5b24Smillert int get_fstype(struct disklabel *, int);
16541d86e10Skrw int get_mp(const struct disklabel *, int);
166604d3bdeSkrw int get_offset(struct disklabel *, int);
1679fdcb4d6Skrw int get_size(struct disklabel *, int);
1689fdcb4d6Skrw void zero_partitions(struct disklabel *);
16943ba7787Skrw u_int64_t max_partition_size(const struct disklabel *, int);
17043ba7787Skrw void display_edit(const struct disklabel *, char);
17143ba7787Skrw void psize(u_int64_t sz, char unit, const struct disklabel *lp);
17258c7d7acSnaddy char *get_token(char **);
173a2c1f847Shenning int apply_unit(double, u_char, u_int64_t *);
174a2c1f847Shenning int parse_sizespec(const char *, double *, char **);
175a2c1f847Shenning int parse_sizerange(char *, u_int64_t *, u_int64_t *);
176a2c1f847Shenning int parse_pct(char *, int *);
17740b226e8Skrw int alignpartition(struct disklabel *, int, u_int64_t, u_int64_t, int);
178756bef51Skrw int allocate_space(struct disklabel *, const struct alloc_table *);
179756bef51Skrw void allocate_physmemincr(struct space_allocation *);
180756bef51Skrw int allocate_partition(struct disklabel *, struct space_allocation *);
181756bef51Skrw const struct diskchunk *allocate_diskchunk(const struct disklabel *,
182756bef51Skrw const struct space_allocation *);
18396a888c6Smillert
1841e0ad43cSotto static u_int64_t starting_sector;
1851e0ad43cSotto static u_int64_t ending_sector;
186c2c8bb79Skrw static int resizeok;
1876fe57b42Smillert
1886fe57b42Smillert /*
1894d4a335eSkrw * Simple partition editor.
1906fe57b42Smillert */
1916fe57b42Smillert int
editor(int f)192d6d80bb0Skrw editor(int f)
1936fe57b42Smillert {
194d6d80bb0Skrw struct disklabel origlabel, lastlabel, tmplabel, newlab = lab;
19596a888c6Smillert struct partition *pp;
1966fe57b42Smillert FILE *fp;
1976fe57b42Smillert char buf[BUFSIZ], *cmd, *arg;
19834ae4198Skrw char **omountpoints = NULL;
1994f3bbbf0Skrw char **origmountpoints = NULL, **tmpmountpoints = NULL;
2007e28fb0fSderaadt int i, error = 0;
201bd6726faSmillert
202bd6726faSmillert /* Alloc and init mount point info */
20334ae4198Skrw if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
2044f3bbbf0Skrw !(origmountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
205bd6726faSmillert !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *))))
206b7cc13deSkrw err(1, NULL);
2076fe57b42Smillert
208d09f3941Smillert /* How big is the OpenBSD portion of the disk? */
209d6d80bb0Skrw find_bounds(&newlab);
210d09f3941Smillert
21196a888c6Smillert /* Make sure there is no partition overlap. */
212d6d80bb0Skrw if (has_overlap(&newlab))
2136fe57b42Smillert errx(1, "can't run when there is partition overlap.");
2146fe57b42Smillert
21596a888c6Smillert /* If we don't have a 'c' partition, create one. */
216d6d80bb0Skrw pp = &newlab.d_partitions[RAW_PART];
217d4e23fe7Skrw if (newlab.d_npartitions <= RAW_PART || DL_GETPSIZE(pp) == 0) {
21896a888c6Smillert puts("No 'c' partition found, adding one that spans the disk.");
219d4e23fe7Skrw if (newlab.d_npartitions <= RAW_PART)
220d4e23fe7Skrw newlab.d_npartitions = RAW_PART + 1;
22134af67a3Sotto DL_SETPOFFSET(pp, 0);
222d6d80bb0Skrw DL_SETPSIZE(pp, DL_GETDSIZE(&newlab));
22396a888c6Smillert pp->p_fstype = FS_UNUSED;
224ddfcbf38Sotto pp->p_fragblock = pp->p_cpg = 0;
22596a888c6Smillert }
2260f820bbbSmillert
227fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
2284bf1fc9dSotto if ((newlab.d_flags & D_VENDOR) && !quiet) {
229fc1a4cc6Sderaadt puts("This platform requires that partition offsets/sizes "
230fc1a4cc6Sderaadt "be on cylinder boundaries.\n"
231fc1a4cc6Sderaadt "Partition offsets/sizes will be rounded to the "
232fc1a4cc6Sderaadt "nearest cylinder automatically.");
233fc1a4cc6Sderaadt }
2346fe57b42Smillert #endif
2356fe57b42Smillert
23693160b9bSkrw /* Save the (U|u)ndo labels and mountpoints. */
23793160b9bSkrw mpcopy(origmountpoints, mountpoints);
238d6d80bb0Skrw origlabel = newlab;
239d6d80bb0Skrw lastlabel = newlab;
24034ae4198Skrw
24134ae4198Skrw puts("Label editor (enter '?' for help at any prompt)");
2426fe57b42Smillert for (;;) {
243953cd4efSkrw fprintf(stdout, "%s%s> ", dkname,
244953cd4efSkrw (memcmp(&lab, &newlab, sizeof(newlab)) == 0) ? "" : "*");
2456e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) {
2466e0becc5Smillert putchar('\n');
2476e0becc5Smillert buf[0] = 'q';
2486e0becc5Smillert buf[1] = '\0';
2496e0becc5Smillert }
250260513deSmillert if ((cmd = strtok(buf, " \t\r\n")) == NULL)
251260513deSmillert continue;
252260513deSmillert arg = strtok(NULL, " \t\r\n");
2536fe57b42Smillert
2544f3bbbf0Skrw if ((*cmd != 'u') && (*cmd != 'U')) {
2554f3bbbf0Skrw /*
2564f3bbbf0Skrw * Save undo info in case the command tries to make
2574f3bbbf0Skrw * changes but decides not to.
2584f3bbbf0Skrw */
2594f3bbbf0Skrw tmplabel = lastlabel;
260d6d80bb0Skrw lastlabel = newlab;
2614f3bbbf0Skrw mpcopy(tmpmountpoints, omountpoints);
2624f3bbbf0Skrw mpcopy(omountpoints, mountpoints);
2634f3bbbf0Skrw }
2646fe57b42Smillert
2654f3bbbf0Skrw switch (*cmd) {
2666fe57b42Smillert case '?':
267ea37abd3Sderaadt case 'h':
2684d812bb6Slum editor_help();
2696fe57b42Smillert break;
2706fe57b42Smillert
271557f712bSkrw case 'A':
27290b0764fSkrw if (ioctl(f, DIOCGPDINFO, &newlab) == -1) {
27390b0764fSkrw warn("DIOCGPDINFO");
27490b0764fSkrw newlab = lastlabel;
27590b0764fSkrw } else {
276953cd4efSkrw int oquiet = quiet;
2774bf1fc9dSotto aflag = 1;
278953cd4efSkrw quiet = 0;
279d6d80bb0Skrw editor_allocspace(&newlab);
28040b226e8Skrw quiet = oquiet;
28190b0764fSkrw }
282557f712bSkrw break;
2836fe57b42Smillert case 'a':
284d6d80bb0Skrw editor_add(&newlab, arg);
28596a888c6Smillert break;
28696a888c6Smillert
28796a888c6Smillert case 'b':
288d6d80bb0Skrw set_bounds(&newlab);
2896fe57b42Smillert break;
2906fe57b42Smillert
2916fe57b42Smillert case 'c':
292d6d80bb0Skrw editor_change(&newlab, arg);
2936fe57b42Smillert break;
2946fe57b42Smillert
2959afbe9eeSmillert case 'D':
29690b0764fSkrw if (ioctl(f, DIOCGPDINFO, &newlab) == -1)
29790b0764fSkrw warn("DIOCGPDINFO");
29890b0764fSkrw else {
29971bba4ecSkrw dflag = 1;
30093160b9bSkrw for (i = 0; i < MAXPARTITIONS; i++) {
30193160b9bSkrw free(mountpoints[i]);
30293160b9bSkrw mountpoints[i] = NULL;
30393160b9bSkrw }
30490b0764fSkrw }
3059afbe9eeSmillert break;
3069afbe9eeSmillert
3076fe57b42Smillert case 'd':
308d6d80bb0Skrw editor_delete(&newlab, arg);
3096fe57b42Smillert break;
3106fe57b42Smillert
3119afbe9eeSmillert case 'e':
3121cc333d2Skrw edit_packname(&newlab);
3139afbe9eeSmillert break;
3149afbe9eeSmillert
3150d63cfbaSjsing case 'i':
316d6d80bb0Skrw set_duid(&newlab);
3170d63cfbaSjsing break;
3180d63cfbaSjsing
3196fe57b42Smillert case 'm':
320d6d80bb0Skrw editor_modify(&newlab, arg);
321bd6726faSmillert break;
322bd6726faSmillert
323bd6726faSmillert case 'n':
3245c79e1cfSkrw if (!fstabfile) {
325bd6726faSmillert fputs("This option is not valid when run "
3266b27d9e0Sjmc "without the -F or -f flags.\n", stderr);
327bd6726faSmillert break;
328bd6726faSmillert }
329d6d80bb0Skrw editor_name(&newlab, arg);
3306fe57b42Smillert break;
3316fe57b42Smillert
3326fe57b42Smillert case 'p':
3337ad973c1Skrw display_edit(&newlab, arg ? *arg : 0);
3346fe57b42Smillert break;
3356fe57b42Smillert
336aff3f969Sotto case 'l':
337d6d80bb0Skrw display(stdout, &newlab, arg ? *arg : 0, 0);
338aff3f969Sotto break;
339aff3f969Sotto
340508086e9Smillert case 'M': {
341508086e9Smillert sig_t opipe = signal(SIGPIPE, SIG_IGN);
34245decb36Sderaadt char *pager, *comm = NULL;
343e7936562Sderaadt extern const u_char manpage[];
34408f8e31fSotto extern const int manpage_sz;
3455d12b01bSderaadt
346489bd112Spjanzen if ((pager = getenv("PAGER")) == NULL || *pager == '\0')
347508086e9Smillert pager = _PATH_LESS;
34808f8e31fSotto
34945decb36Sderaadt if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 &&
35045decb36Sderaadt (fp = popen(comm, "w")) != NULL) {
35108f8e31fSotto (void) fwrite(manpage, manpage_sz, 1, fp);
3525d12b01bSderaadt pclose(fp);
353508086e9Smillert } else
354508086e9Smillert warn("unable to execute %s", pager);
355508086e9Smillert
35645decb36Sderaadt free(comm);
357508086e9Smillert (void)signal(SIGPIPE, opipe);
3585d12b01bSderaadt break;
359508086e9Smillert }
3605d12b01bSderaadt
3616fe57b42Smillert case 'q':
36269220492Smillert if (donothing) {
36369220492Smillert puts("In no change mode, not writing label.");
3647e28fb0fSderaadt goto done;
36569220492Smillert }
36693160b9bSkrw
36771bba4ecSkrw /*
36893160b9bSkrw * If we haven't changed the original label, and it
36993160b9bSkrw * wasn't a default label or an auto-allocated label,
37093160b9bSkrw * there is no need to do anything before exiting. Note
37193160b9bSkrw * that 'w' will reset dflag and aflag to allow 'q' to
37293160b9bSkrw * exit without further questions.
37371bba4ecSkrw */
374ab20a3eaSkrw if (!dflag && !aflag &&
375d6d80bb0Skrw memcmp(&lab, &newlab, sizeof(newlab)) == 0) {
376bd6726faSmillert puts("No label changes.");
377d6d80bb0Skrw /* Save mountpoint info. */
378d6d80bb0Skrw mpsave(&newlab);
3797e28fb0fSderaadt goto done;
3806fe57b42Smillert }
3816fe57b42Smillert do {
382d0e67762Smillert arg = getstring("Write new label?",
383d0e67762Smillert "Write the modified label to disk?",
384d0e67762Smillert "y");
385025f5691Sderaadt } while (arg && tolower((unsigned char)*arg) != 'y' &&
386025f5691Sderaadt tolower((unsigned char)*arg) != 'n');
387025f5691Sderaadt if (arg && tolower((unsigned char)*arg) == 'y') {
38840bba581Skrw if (writelabel(f, &newlab) == 0) {
389d6d80bb0Skrw newlab = lab; /* lab now has UID info */
3907e28fb0fSderaadt goto done;
3916fe57b42Smillert }
392d0e67762Smillert warnx("unable to write label");
393d0e67762Smillert }
3947e28fb0fSderaadt error = 1;
3957e28fb0fSderaadt goto done;
3966fe57b42Smillert /* NOTREACHED */
3976fe57b42Smillert break;
3986fe57b42Smillert
3996aaa4aabSotto case 'R':
400c2c8bb79Skrw if (aflag && resizeok)
401d6d80bb0Skrw editor_resize(&newlab, arg);
4026aaa4aabSotto else
4036aaa4aabSotto fputs("Resize only implemented for auto "
404fc6e9c48Sotto "allocated labels\n", stderr);
4056aaa4aabSotto break;
4066aaa4aabSotto
40725f9c360Skrw case 'r': {
408d9355c7dSkrw const struct diskchunk *chunk;
409d9355c7dSkrw uint64_t total = 0;
4109fdcb4d6Skrw /* Display free space. */
411411a261cSkrw chunk = free_chunks(&newlab, -1);
412d9355c7dSkrw for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
413b46f7512Skrw total += CHUNKSZ(chunk);
41425f9c360Skrw fprintf(stderr, "Free sectors: %16llu - %16llu "
41525f9c360Skrw "(%16llu)\n",
416d9355c7dSkrw chunk->start, chunk->stop - 1,
417b46f7512Skrw CHUNKSZ(chunk));
418d9355c7dSkrw }
419d9355c7dSkrw fprintf(stderr, "Total free sectors: %llu.\n", total);
420c0bdc608Smillert break;
42125f9c360Skrw }
422c0bdc608Smillert
4236fe57b42Smillert case 's':
4246fe57b42Smillert if (arg == NULL) {
425c33fcabaSmillert arg = getstring("Filename",
4266fe57b42Smillert "Name of the file to save label into.",
4276fe57b42Smillert NULL);
428e97229a3Scnst if (arg == NULL || *arg == '\0')
4296fe57b42Smillert break;
4306fe57b42Smillert }
4316fe57b42Smillert if ((fp = fopen(arg, "w")) == NULL) {
4326fe57b42Smillert warn("cannot open %s", arg);
4336fe57b42Smillert } else {
434d6d80bb0Skrw display(fp, &newlab, 0, 1);
4356fe57b42Smillert (void)fclose(fp);
4366fe57b42Smillert }
4376fe57b42Smillert break;
4386fe57b42Smillert
4394f3bbbf0Skrw case 'U':
44093160b9bSkrw /*
441430e1380Skrw * If we allow 'U' repeatedly, information would be
442430e1380Skrw * lost. This way multiple 'U's followed by 'u' will
443430e1380Skrw * undo the 'U's.
44493160b9bSkrw */
445d6d80bb0Skrw if (memcmp(&newlab, &origlabel, sizeof(newlab)) ||
44693160b9bSkrw !mpequal(mountpoints, origmountpoints)) {
447d6d80bb0Skrw tmplabel = newlab;
448d6d80bb0Skrw newlab = origlabel;
4494f3bbbf0Skrw lastlabel = tmplabel;
4504f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints);
4514f3bbbf0Skrw mpcopy(mountpoints, origmountpoints);
4524f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints);
4534f3bbbf0Skrw }
45493160b9bSkrw puts("Original label and mount points restored.");
4554f3bbbf0Skrw break;
4564f3bbbf0Skrw
4576fe57b42Smillert case 'u':
458d6d80bb0Skrw tmplabel = newlab;
459d6d80bb0Skrw newlab = lastlabel;
4606fe57b42Smillert lastlabel = tmplabel;
4614f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints);
462bd6726faSmillert mpcopy(mountpoints, omountpoints);
4634f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints);
4646fe57b42Smillert puts("Last change undone.");
4656fe57b42Smillert break;
4666fe57b42Smillert
467040947cfSmillert case 'w':
468bd6726faSmillert if (donothing) {
469040947cfSmillert puts("In no change mode, not writing label.");
470bd6726faSmillert break;
471bd6726faSmillert }
47293160b9bSkrw
47341f684b9Skrw /* Write label to disk. */
47440bba581Skrw if (writelabel(f, &newlab) != 0)
475040947cfSmillert warnx("unable to write label");
47671bba4ecSkrw else {
477ab20a3eaSkrw dflag = aflag = 0;
478d6d80bb0Skrw newlab = lab; /* lab now has UID info */
47971bba4ecSkrw }
480040947cfSmillert break;
481040947cfSmillert
4826fe57b42Smillert case 'x':
4837e28fb0fSderaadt goto done;
4846fe57b42Smillert break;
4856fe57b42Smillert
4869afbe9eeSmillert case 'z':
487d6d80bb0Skrw zero_partitions(&newlab);
4886fe57b42Smillert break;
4896fe57b42Smillert
4909afbe9eeSmillert case '\n':
4916fe57b42Smillert break;
4926fe57b42Smillert
4936fe57b42Smillert default:
4946fe57b42Smillert printf("Unknown option: %c ('?' for help)\n", *cmd);
4956fe57b42Smillert break;
4966fe57b42Smillert }
4974f3bbbf0Skrw
4984f3bbbf0Skrw /*
4994f3bbbf0Skrw * If no changes were made to label or mountpoints, then
5004f3bbbf0Skrw * restore undo info.
5014f3bbbf0Skrw */
502d6d80bb0Skrw if (memcmp(&newlab, &lastlabel, sizeof(newlab)) == 0 &&
50393160b9bSkrw (mpequal(mountpoints, omountpoints))) {
5044f3bbbf0Skrw lastlabel = tmplabel;
5054f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints);
5064f3bbbf0Skrw }
5076fe57b42Smillert }
5087e28fb0fSderaadt done:
509e46ff49bSkrw mpfree(omountpoints, DISCARD);
510e46ff49bSkrw mpfree(origmountpoints, DISCARD);
511e46ff49bSkrw mpfree(tmpmountpoints, DISCARD);
512bb12209fSkrw return error;
5136fe57b42Smillert }
5146fe57b42Smillert
5156fe57b42Smillert /*
516557f712bSkrw * Allocate all disk space according to standard recommendations for a
517557f712bSkrw * root disk.
518557f712bSkrw */
519185664b4Sotto int
editor_allocspace(struct disklabel * lp_org)5208dde8bb6Sotto editor_allocspace(struct disklabel *lp_org)
521557f712bSkrw {
522756bef51Skrw struct disklabel label;
5233c750429Skrw struct partition *pp;
524756bef51Skrw u_int64_t pstart, pend;
525756bef51Skrw int i;
5268dde8bb6Sotto
52734ae4198Skrw /* How big is the OpenBSD portion of the disk? */
5288dde8bb6Sotto find_bounds(lp_org);
529557f712bSkrw
530c2c8bb79Skrw resizeok = 1;
531fc6e9c48Sotto for (i = 0; i < MAXPARTITIONS; i++) {
532c2c8bb79Skrw if (i == RAW_PART)
533c2c8bb79Skrw continue;
5343c750429Skrw pp = &lp_org->d_partitions[i];
5353c750429Skrw if (DL_GETPSIZE(pp) == 0 || pp->p_fstype == FS_UNUSED)
5363c750429Skrw continue;
5373c750429Skrw pstart = DL_GETPOFFSET(pp);
5383c750429Skrw pend = pstart + DL_GETPSIZE(pp);
539114ca9f3Skrw if (((pstart >= starting_sector && pstart < ending_sector) ||
540114ca9f3Skrw (pend > starting_sector && pend <= ending_sector)))
541114ca9f3Skrw resizeok = 0; /* Part of OBSD area is in use! */
542fc6e9c48Sotto }
543fc6e9c48Sotto
544756bef51Skrw for (i = 0; i < alloc_table_nitems; i++) {
545756bef51Skrw memcpy(&label, lp_org, sizeof(label));
546756bef51Skrw if (allocate_space(&label, &alloc_table[i]) == 0) {
547756bef51Skrw memcpy(lp_org, &label, sizeof(struct disklabel));
548756bef51Skrw return 0;
549756bef51Skrw }
550756bef51Skrw }
551756bef51Skrw
552598ec681Skrw return 1;
5538dde8bb6Sotto }
5548dde8bb6Sotto
555756bef51Skrw const struct diskchunk *
allocate_diskchunk(const struct disklabel * lp,const struct space_allocation * sa)556756bef51Skrw allocate_diskchunk(const struct disklabel *lp,
557756bef51Skrw const struct space_allocation *sa)
558756bef51Skrw {
559756bef51Skrw const struct diskchunk *chunk;
560756bef51Skrw static struct diskchunk largest;
561756bef51Skrw uint64_t maxstop;
562557f712bSkrw
563756bef51Skrw largest.start = largest.stop = 0;
564557f712bSkrw
565411a261cSkrw chunk = free_chunks(lp, -1);
566cfdfc664Skrw for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
567756bef51Skrw if (CHUNKSZ(chunk) > CHUNKSZ(&largest))
568756bef51Skrw largest = *chunk;
569756bef51Skrw }
570756bef51Skrw maxstop = largest.start + DL_BLKTOSEC(lp, sa->maxsz);
571756bef51Skrw if (maxstop > largest.stop)
572756bef51Skrw maxstop = largest.stop;
57334ae4198Skrw #ifdef SUN_CYLCHECK
57434ae4198Skrw if (lp->d_flags & D_VENDOR) {
575756bef51Skrw largest.start = ROUNDUP(largest.start, lp->d_secpercyl);
576756bef51Skrw maxstop = ROUNDUP(maxstop, lp->d_secpercyl);
577756bef51Skrw if (maxstop > largest.stop)
578756bef51Skrw maxstop -= lp->d_secpercyl;
579756bef51Skrw if (largest.start >= maxstop)
580756bef51Skrw largest.start = largest.stop = maxstop = 0;
58134ae4198Skrw }
58234ae4198Skrw #endif
583756bef51Skrw if (maxstop < largest.stop)
584756bef51Skrw largest.stop = maxstop;
585756bef51Skrw if (CHUNKSZ(&largest) < DL_BLKTOSEC(lp, sa->minsz))
586756bef51Skrw return NULL;
587756bef51Skrw
588756bef51Skrw return &largest;
589859c13c7Skrw }
590859c13c7Skrw
591756bef51Skrw int
allocate_partition(struct disklabel * lp,struct space_allocation * sa)592756bef51Skrw allocate_partition(struct disklabel *lp, struct space_allocation *sa)
593756bef51Skrw {
594756bef51Skrw const struct diskchunk *chunk;
595756bef51Skrw struct partition *pp;
596756bef51Skrw unsigned int partno;
59759c4e6f1Skrw
598756bef51Skrw for (partno = 0; partno < nitems(lp->d_partitions); partno++) {
599756bef51Skrw if (partno == RAW_PART)
600756bef51Skrw continue;
601756bef51Skrw pp = &lp->d_partitions[partno];
602756bef51Skrw if (DL_GETPSIZE(pp) == 0 || pp->p_fstype == FS_UNUSED)
603756bef51Skrw break;
604557f712bSkrw }
605756bef51Skrw if (partno >= nitems(lp->d_partitions))
606756bef51Skrw return 1; /* No free partition. */
60734ae4198Skrw
608756bef51Skrw /* Find appropriate chunk of free space. */
609756bef51Skrw chunk = allocate_diskchunk(lp, sa);
610756bef51Skrw if (chunk == NULL)
611756bef51Skrw return 1;
612756bef51Skrw
613756bef51Skrw if (strcasecmp(sa->mp, "raid") == 0)
6144536786eSkrw pp->p_fstype = FS_RAID;
615756bef51Skrw else if (strcasecmp(sa->mp, "swap") == 0)
61634ae4198Skrw pp->p_fstype = FS_SWAP;
617756bef51Skrw else if (sa->mp[0] == '/')
61834ae4198Skrw pp->p_fstype = FS_BSDFFS;
619756bef51Skrw else
620756bef51Skrw return 1;
621756bef51Skrw
622756bef51Skrw DL_SETPSIZE(pp, chunk->stop - chunk->start);
623756bef51Skrw DL_SETPOFFSET(pp, chunk->start);
624756bef51Skrw
625756bef51Skrw if (pp->p_fstype == FS_BSDFFS && DL_GETPSIZE(pp) > 0) {
626756bef51Skrw mountpoints[partno] = strdup(sa->mp);
627756bef51Skrw if (mountpoints[partno] == NULL)
628756bef51Skrw err(1, NULL);
629756bef51Skrw if (set_fragblock(lp, partno))
630d68164a2Skrw return 1;
631d68164a2Skrw }
632756bef51Skrw
633756bef51Skrw return 0;
634756bef51Skrw }
635756bef51Skrw
636756bef51Skrw void
allocate_physmemincr(struct space_allocation * sa)637756bef51Skrw allocate_physmemincr(struct space_allocation *sa)
638756bef51Skrw {
639756bef51Skrw u_int64_t memblks;
640756bef51Skrw extern int64_t physmem;
641756bef51Skrw
642756bef51Skrw if (physmem == 0)
643756bef51Skrw return;
644756bef51Skrw
645756bef51Skrw memblks = physmem / DEV_BSIZE;
646756bef51Skrw if (strcasecmp(sa->mp, "swap") == 0) {
647756bef51Skrw if (memblks < MEG(256))
648756bef51Skrw sa->minsz = sa->maxsz = 2 * memblks;
649756bef51Skrw else
650756bef51Skrw sa->maxsz += memblks;
651756bef51Skrw } else if (strcasecmp(sa->mp, "/var") == 0) {
652756bef51Skrw sa->maxsz += 2 * memblks;
653557f712bSkrw }
654557f712bSkrw }
655557f712bSkrw
656756bef51Skrw int
allocate_space(struct disklabel * lp,const struct alloc_table * alloc_table)657756bef51Skrw allocate_space(struct disklabel *lp, const struct alloc_table *alloc_table)
658756bef51Skrw {
659756bef51Skrw struct space_allocation sa[MAXPARTITIONS];
660756bef51Skrw u_int64_t maxsz, xtrablks;
661756bef51Skrw int i;
662756bef51Skrw
663756bef51Skrw xtrablks = DL_SECTOBLK(lp, editor_countfree(lp));
664756bef51Skrw memset(sa, 0, sizeof(sa));
665756bef51Skrw for (i = 0; i < alloc_table->sz; i++) {
666756bef51Skrw sa[i] = alloc_table->table[i];
667756bef51Skrw if (alloc_table->table == alloc_big)
668756bef51Skrw allocate_physmemincr(&sa[i]);
669756bef51Skrw if (xtrablks < sa[i].minsz)
670756bef51Skrw return 1; /* Too few free blocks. */
671756bef51Skrw xtrablks -= sa[i].minsz;
672756bef51Skrw }
673756bef51Skrw sa[alloc_table->sz - 1].rate = 100; /* Last allocation is greedy. */
674756bef51Skrw
675756bef51Skrw for (i = lp->d_npartitions; i < MAXPARTITIONS; i++) {
676756bef51Skrw if (i == RAW_PART)
677756bef51Skrw continue;
678756bef51Skrw memset(&lp->d_partitions[i], 0, sizeof(lp->d_partitions[i]));
679756bef51Skrw }
680756bef51Skrw lp->d_npartitions = MAXPARTITIONS;
681756bef51Skrw
682756bef51Skrw mpfree(mountpoints, KEEP);
683756bef51Skrw for (i = 0; i < alloc_table->sz; i++) {
684775a2993Skrw if (sa[i].rate == 100)
685775a2993Skrw maxsz = sa[i].minsz + xtrablks;
686775a2993Skrw else
687756bef51Skrw maxsz = sa[i].minsz + (xtrablks / 100) * sa[i].rate;
688756bef51Skrw if (maxsz < sa[i].maxsz)
689756bef51Skrw sa[i].maxsz = maxsz;
690756bef51Skrw if (allocate_partition(lp, &sa[i])) {
691756bef51Skrw mpfree(mountpoints, KEEP);
692756bef51Skrw return 1;
693756bef51Skrw }
694756bef51Skrw }
695756bef51Skrw
696185664b4Sotto return 0;
697557f712bSkrw }
698557f712bSkrw
699557f712bSkrw /*
7006aaa4aabSotto * Resize a partition, moving all subsequent partitions
7016aaa4aabSotto */
7026aaa4aabSotto void
editor_resize(struct disklabel * lp,const char * p)703c0bc1f19Skrw editor_resize(struct disklabel *lp, const char *p)
7046aaa4aabSotto {
7056aaa4aabSotto struct disklabel label;
7066aaa4aabSotto struct partition *pp, *prev;
707914b3475Skrw u_int64_t ui, sz, off;
70877370cdaSkrw int partno, i, flags, shrunk;
7096aaa4aabSotto
7106aaa4aabSotto label = *lp;
7116aaa4aabSotto
71278ff4c86Skrw if ((partno = getpartno(&label, p, "resize")) == -1)
7136aaa4aabSotto return;
7146aaa4aabSotto
7156aaa4aabSotto pp = &label.d_partitions[partno];
716fc6e9c48Sotto sz = DL_GETPSIZE(pp);
717fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) {
718fc6e9c48Sotto fputs("Cannot resize spoofed partition\n", stderr);
719fc6e9c48Sotto return;
720fc6e9c48Sotto }
72140b226e8Skrw flags = DO_CONVERSIONS;
722914b3475Skrw ui = getuint64(lp, "[+|-]new size (with unit)",
723e0befca8Skrw "new size or amount to grow (+) or shrink (-) partition including "
72440b226e8Skrw "unit", sz, sz + editor_countfree(lp), &flags);
7256aaa4aabSotto
726914b3475Skrw if (ui == CMD_ABORTED)
7276aaa4aabSotto return;
728914b3475Skrw else if (ui == CMD_BADVALUE)
7299f0bdc2aSkrw return;
730914b3475Skrw else if (ui == 0) {
7311298f28aSkrw fputs("The size must be > 0 sectors\n", stderr);
7321298f28aSkrw return;
7336aaa4aabSotto }
7346aaa4aabSotto
7356aaa4aabSotto #ifdef SUN_CYLCHECK
7367233a2b0Skrw if (lp->d_flags & D_VENDOR)
7377233a2b0Skrw ui = ROUNDUP(ui, lp->d_secpercyl);
7386aaa4aabSotto #endif
739914b3475Skrw if (DL_GETPOFFSET(pp) + ui > ending_sector) {
7406aaa4aabSotto fputs("Amount too big\n", stderr);
7416aaa4aabSotto return;
7426aaa4aabSotto }
7436aaa4aabSotto
744914b3475Skrw DL_SETPSIZE(pp, ui);
745d68164a2Skrw pp->p_fragblock = 0;
746728b9255Skrw if (set_fragblock(&label, partno) == 1)
747d68164a2Skrw return;
7486aaa4aabSotto
7496aaa4aabSotto /*
7506aaa4aabSotto * Pack partitions above the resized partition, leaving unused
751c7e00dc5Skrw * partitions alone.
7526aaa4aabSotto */
75377370cdaSkrw shrunk = -1;
7546aaa4aabSotto prev = pp;
7556aaa4aabSotto for (i = partno + 1; i < MAXPARTITIONS; i++) {
7566aaa4aabSotto if (i == RAW_PART)
7576aaa4aabSotto continue;
758fc6e9c48Sotto pp = &label.d_partitions[i];
759fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP)
760fc6e9c48Sotto continue;
761fc6e9c48Sotto sz = DL_GETPSIZE(pp);
7626aaa4aabSotto if (sz == 0)
7636aaa4aabSotto continue;
7646aaa4aabSotto
7656aaa4aabSotto off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev);
7666aaa4aabSotto
7676aaa4aabSotto if (off < ending_sector) {
7686aaa4aabSotto DL_SETPOFFSET(pp, off);
7696aaa4aabSotto if (off + DL_GETPSIZE(pp) > ending_sector) {
7706aaa4aabSotto DL_SETPSIZE(pp, ending_sector - off);
7714ef23daeSkrw pp->p_fragblock = 0;
772728b9255Skrw if (set_fragblock(&label, i) == 1)
773d68164a2Skrw return;
77477370cdaSkrw shrunk = i;
7756aaa4aabSotto }
7766aaa4aabSotto } else {
77777370cdaSkrw fputs("Amount too big\n", stderr);
7786aaa4aabSotto return;
7796aaa4aabSotto }
7806aaa4aabSotto prev = pp;
7816aaa4aabSotto }
78277370cdaSkrw
78377370cdaSkrw if (shrunk != -1)
78477370cdaSkrw fprintf(stderr, "Partition %c shrunk to %llu sectors to make "
78577370cdaSkrw "room\n", 'a' + shrunk,
78677370cdaSkrw DL_GETPSIZE(&label.d_partitions[shrunk]));
7876aaa4aabSotto *lp = label;
7886aaa4aabSotto }
7896aaa4aabSotto
7906aaa4aabSotto /*
7916fe57b42Smillert * Add a new partition.
7926fe57b42Smillert */
7936fe57b42Smillert void
editor_add(struct disklabel * lp,const char * p)794c0bc1f19Skrw editor_add(struct disklabel *lp, const char *p)
7956fe57b42Smillert {
79696a888c6Smillert struct partition *pp;
797ab2017adSkrw const struct diskchunk *chunk;
798a83eeb72Skrw int partno;
7992fcfb0f5Skrw u_int64_t new_offset, new_size;
8009fdcb4d6Skrw
8012fcfb0f5Skrw chunk = free_chunks(lp, -1);
8022fcfb0f5Skrw new_size = new_offset = 0;
8032fcfb0f5Skrw for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
804b46f7512Skrw if (CHUNKSZ(chunk) > new_size) {
805b46f7512Skrw new_size = CHUNKSZ(chunk);
8062fcfb0f5Skrw new_offset = chunk->start;
8072fcfb0f5Skrw }
8082fcfb0f5Skrw }
8096fe57b42Smillert
810fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
8112fcfb0f5Skrw if ((lp->d_flags & D_VENDOR) && new_size < lp->d_secpercyl) {
812fc1a4cc6Sderaadt fputs("No space left, you need to shrink a partition "
813fc1a4cc6Sderaadt "(need at least one full cylinder)\n",
814fc1a4cc6Sderaadt stderr);
815fc1a4cc6Sderaadt return;
816fc1a4cc6Sderaadt }
8178390cf28Smillert #endif
8182fcfb0f5Skrw if (new_size == 0) {
8196fe57b42Smillert fputs("No space left, you need to shrink a partition\n",
8206fe57b42Smillert stderr);
8216fe57b42Smillert return;
8226fe57b42Smillert }
8236fe57b42Smillert
82496b465e9Skrw if ((partno = getpartno(lp, p, "add")) == -1)
8255caa08b2Skrw return;
8265caa08b2Skrw pp = &lp->d_partitions[partno];
8272fcfb0f5Skrw memset(pp, 0, sizeof(*pp));
82896a888c6Smillert
829caf41f96Skrw /*
830caf41f96Skrw * Increase d_npartitions if necessary. Ensure all new partitions are
831855d4e83Ssobrado * zero'ed to avoid inadvertent overlaps.
832caf41f96Skrw */
833caf41f96Skrw for(; lp->d_npartitions <= partno; lp->d_npartitions++)
834caf41f96Skrw memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp));
83596a888c6Smillert
8361e0ad43cSotto DL_SETPSIZE(pp, new_size);
8371e0ad43cSotto DL_SETPOFFSET(pp, new_offset);
83896a888c6Smillert pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS;
839c88f83bdSotto
840c88f83bdSotto if (get_offset(lp, partno) == 0 &&
841a3ad4147Skrw get_size(lp, partno) == 0 &&
842a3ad4147Skrw get_fstype(lp, partno) == 0 &&
84334ae4198Skrw get_mp(lp, partno) == 0 &&
844728b9255Skrw set_fragblock(lp, partno) == 0)
84596a888c6Smillert return;
846a3ad4147Skrw
847a4c87e64Skrw /* Bailed out at some point, so effectively delete the partition. */
848da2bd3f5Skrw memset(pp, 0, sizeof(*pp));
8496fe57b42Smillert }
8506fe57b42Smillert
8516fe57b42Smillert /*
852bd6726faSmillert * Set the mountpoint of an existing partition ('name').
853bd6726faSmillert */
854bd6726faSmillert void
editor_name(const struct disklabel * lp,const char * p)85541d86e10Skrw editor_name(const struct disklabel *lp, const char *p)
856bd6726faSmillert {
857bd6726faSmillert int partno;
858bd6726faSmillert
85978ff4c86Skrw if ((partno = getpartno(lp, p, "name")) == -1)
860bd6726faSmillert return;
861bd6726faSmillert
86234ae4198Skrw get_mp(lp, partno);
863bd6726faSmillert }
864bd6726faSmillert
865bd6726faSmillert /*
8666fe57b42Smillert * Change an existing partition.
8676fe57b42Smillert */
8686fe57b42Smillert void
editor_modify(struct disklabel * lp,const char * p)869c0bc1f19Skrw editor_modify(struct disklabel *lp, const char *p)
8706fe57b42Smillert {
87140b226e8Skrw struct partition opp, *pp;
872f8ab7229Schl int partno;
8736fe57b42Smillert
87478ff4c86Skrw if ((partno = getpartno(lp, p, "modify")) == -1)
87596a888c6Smillert return;
87678ff4c86Skrw
87766df1f0cSkrw pp = &lp->d_partitions[partno];
87840b226e8Skrw opp = *pp;
87966df1f0cSkrw
880a4c87e64Skrw if (get_offset(lp, partno) == 0 &&
881a4c87e64Skrw get_size(lp, partno) == 0 &&
882a4c87e64Skrw get_fstype(lp, partno) == 0 &&
88334ae4198Skrw get_mp(lp, partno) == 0 &&
884728b9255Skrw set_fragblock(lp, partno) == 0)
88596a888c6Smillert return;
8866fe57b42Smillert
887a4c87e64Skrw /* Bailed out at some point, so undo any changes. */
88840b226e8Skrw *pp = opp;
8896fe57b42Smillert }
8906fe57b42Smillert
8916fe57b42Smillert /*
8926fe57b42Smillert * Delete an existing partition.
8936fe57b42Smillert */
8946fe57b42Smillert void
editor_delete(struct disklabel * lp,const char * p)895c0bc1f19Skrw editor_delete(struct disklabel *lp, const char *p)
8966fe57b42Smillert {
89766df1f0cSkrw struct partition *pp;
898135c90d1Skrw int partno;
8996fe57b42Smillert
90081f2740fSkrw if ((partno = getpartno(lp, p, "delete")) == -1)
90196a888c6Smillert return;
90281f2740fSkrw if (partno == lp->d_npartitions) {
9039fdcb4d6Skrw zero_partitions(lp);
904945ae268Smillert return;
905945ae268Smillert }
906135c90d1Skrw pp = &lp->d_partitions[partno];
90766df1f0cSkrw
9086fe57b42Smillert /* Really delete it (as opposed to just setting to "unused") */
909135c90d1Skrw memset(pp, 0, sizeof(*pp));
91034ae4198Skrw free(mountpoints[partno]);
91134ae4198Skrw mountpoints[partno] = NULL;
9126fe57b42Smillert }
9136fe57b42Smillert
9146fe57b42Smillert /*
9156fe57b42Smillert * Change the size of an existing partition.
9166fe57b42Smillert */
9176fe57b42Smillert void
editor_change(struct disklabel * lp,const char * p)918c0bc1f19Skrw editor_change(struct disklabel *lp, const char *p)
9196fe57b42Smillert {
9204b9a3bdaSmillert struct partition *pp;
92166df1f0cSkrw int partno;
9226fe57b42Smillert
92378ff4c86Skrw if ((partno = getpartno(lp, p, "change size")) == -1)
92496a888c6Smillert return;
92578ff4c86Skrw
9264b9a3bdaSmillert pp = &lp->d_partitions[partno];
92714192793Skrw printf("Partition %c is currently %llu sectors in size, and can have "
92814192793Skrw "a maximum\nsize of %llu sectors.\n",
92978ff4c86Skrw 'a' + partno, DL_GETPSIZE(pp), max_partition_size(lp, partno));
9307da73705Skrw
93159ccf790Skrw /* Get new size */
9329fdcb4d6Skrw get_size(lp, partno);
9336fe57b42Smillert }
9346fe57b42Smillert
9356fe57b42Smillert /*
9366fe57b42Smillert * Sort the partitions based on starting offset.
9376fe57b42Smillert * This assumes there can be no overlap.
9386fe57b42Smillert */
9396fe57b42Smillert int
partition_cmp(const void * e1,const void * e2)9408809fabbSderaadt partition_cmp(const void *e1, const void *e2)
9416fe57b42Smillert {
9426fe57b42Smillert struct partition *p1 = *(struct partition **)e1;
9436fe57b42Smillert struct partition *p2 = *(struct partition **)e2;
9441e0ad43cSotto u_int64_t o1 = DL_GETPOFFSET(p1);
9451e0ad43cSotto u_int64_t o2 = DL_GETPOFFSET(p2);
9466fe57b42Smillert
9471e0ad43cSotto if (o1 < o2)
948651d5bd9Sotto return -1;
9491e0ad43cSotto else if (o1 > o2)
950651d5bd9Sotto return 1;
951651d5bd9Sotto else
952651d5bd9Sotto return 0;
9536fe57b42Smillert }
9546fe57b42Smillert
9556fe57b42Smillert char *
getstring(const char * prompt,const char * helpstring,const char * oval)956b228e876Smiod getstring(const char *prompt, const char *helpstring, const char *oval)
9576fe57b42Smillert {
9586fe57b42Smillert static char buf[BUFSIZ];
9596fe57b42Smillert int n;
9606fe57b42Smillert
9616fe57b42Smillert buf[0] = '\0';
9626fe57b42Smillert do {
9636fe57b42Smillert printf("%s: [%s] ", prompt, oval ? oval : "");
9646e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) {
965260513deSmillert buf[0] = '\0';
96696a888c6Smillert if (feof(stdin)) {
96724c6582eSmillert clearerr(stdin);
96896a888c6Smillert putchar('\n');
969ac30837aSkrw fputs("Command aborted\n", stderr);
970bb12209fSkrw return NULL;
97196a888c6Smillert }
9726e0becc5Smillert }
9736fe57b42Smillert n = strlen(buf);
9746fe57b42Smillert if (n > 0 && buf[n-1] == '\n')
9756fe57b42Smillert buf[--n] = '\0';
9766fe57b42Smillert if (buf[0] == '?')
9776fe57b42Smillert puts(helpstring);
9784fb6ab7cSmillert else if (oval != NULL && buf[0] == '\0')
9794fb6ab7cSmillert strlcpy(buf, oval, sizeof(buf));
9806fe57b42Smillert } while (buf[0] == '?');
9816fe57b42Smillert
982bb12209fSkrw return &buf[0];
9836fe57b42Smillert }
9846fe57b42Smillert
98578ff4c86Skrw int
getpartno(const struct disklabel * lp,const char * p,const char * action)98696b465e9Skrw getpartno(const struct disklabel *lp, const char *p, const char *action)
98778ff4c86Skrw {
98896b465e9Skrw char buf[2] = { '\0', '\0'};
98978ff4c86Skrw const char *promptfmt = "partition to %s";
99078ff4c86Skrw const char *helpfmt = "Partition must be between 'a' and '%c' "
99181f2740fSkrw "(excluding 'c')%s.\n";
99278ff4c86Skrw const struct partition *pp;
99378ff4c86Skrw char *help = NULL, *prompt = NULL;
99496b465e9Skrw unsigned char maxpart;
99578ff4c86Skrw unsigned int partno;
99681f2740fSkrw int add, delete, inuse;
99778ff4c86Skrw
99896b465e9Skrw add = strcmp("add", action) == 0;
99981f2740fSkrw delete = strcmp("delete", action) == 0;
100096b465e9Skrw maxpart = 'a' - 1 + (add ? MAXPARTITIONS : lp->d_npartitions);
100196b465e9Skrw
100278ff4c86Skrw if (p == NULL) {
100378ff4c86Skrw if (asprintf(&prompt, promptfmt, action) == -1 ||
100481f2740fSkrw asprintf(&help, helpfmt, maxpart, delete ? ", or '*'" : "")
100581f2740fSkrw == -1) {
100678ff4c86Skrw fprintf(stderr, "Unable to build prompt or help\n");
100796b465e9Skrw goto done;
100896b465e9Skrw }
100996b465e9Skrw if (add) {
101096b465e9Skrw /* Default to first unused partition. */
101196b465e9Skrw for (partno = 0; partno < MAXPARTITIONS; partno++) {
101296b465e9Skrw if (partno == RAW_PART)
101396b465e9Skrw continue;
101496b465e9Skrw pp = &lp->d_partitions[partno];
101596b465e9Skrw if (partno >= lp->d_npartitions ||
101696b465e9Skrw DL_GETPSIZE(pp) == 0 ||
101796b465e9Skrw pp->p_fstype == FS_UNUSED) {
101896b465e9Skrw buf[0] = 'a' + partno;
101996b465e9Skrw p = buf;
102096b465e9Skrw break;
102196b465e9Skrw }
102296b465e9Skrw }
102396b465e9Skrw }
102496b465e9Skrw p = getstring(prompt, help, p);
102578ff4c86Skrw free(prompt);
102678ff4c86Skrw free(help);
102778ff4c86Skrw if (p == NULL || *p == '\0')
102878ff4c86Skrw goto done;
102978ff4c86Skrw }
103078ff4c86Skrw
103181f2740fSkrw if (delete && strlen(p) == 1 && *p == '*')
1032bb12209fSkrw return lp->d_npartitions;
103381f2740fSkrw
1034715dd5c0Skrw if (strlen(p) > 1 || *p < 'a' || *p > maxpart || *p == 'c') {
103581f2740fSkrw fprintf(stderr, helpfmt, maxpart, delete ? ", or '*'" : "");
103678ff4c86Skrw goto done;
103778ff4c86Skrw }
103878ff4c86Skrw
103978ff4c86Skrw partno = *p - 'a';
104078ff4c86Skrw pp = &lp->d_partitions[partno];
104196b465e9Skrw inuse = partno < lp->d_npartitions && DL_GETPSIZE(pp) > 0 &&
104296b465e9Skrw pp->p_fstype != FS_UNUSED;
104396b465e9Skrw
104496b465e9Skrw if ((add && !inuse) || (!add && inuse))
1045bb12209fSkrw return partno;
104678ff4c86Skrw
104796b465e9Skrw fprintf(stderr, "Partition '%c' is %sin use.\n", *p,
104896b465e9Skrw inuse ? "" : "not ");
104978ff4c86Skrw
105078ff4c86Skrw done:
1051bb12209fSkrw return -1;
105278ff4c86Skrw }
105378ff4c86Skrw
10546fe57b42Smillert /*
1055aa3970cdSkrw * Returns
1056aa3970cdSkrw * 0 .. CMD_ABORTED - 1 ==> valid value
1057aa3970cdSkrw * CMD_BADVALUE ==> invalid value
1058aa3970cdSkrw * CMD_ABORTED ==> ^D on input
10596fe57b42Smillert */
10601e0ad43cSotto u_int64_t
getnumber(const char * prompt,const char * helpstring,u_int32_t oval,u_int32_t maxval)1061c0bc1f19Skrw getnumber(const char *prompt, const char *helpstring, u_int32_t oval,
1062c0bc1f19Skrw u_int32_t maxval)
10630db7769aSkrw {
10640db7769aSkrw char buf[BUFSIZ], *p;
10650db7769aSkrw int rslt;
10660db7769aSkrw long long rval;
10670db7769aSkrw const char *errstr;
10680db7769aSkrw
10690db7769aSkrw rslt = snprintf(buf, sizeof(buf), "%u", oval);
1070515e489cSderaadt if (rslt < 0 || (unsigned int)rslt >= sizeof(buf))
1071bb12209fSkrw return CMD_BADVALUE;
10720db7769aSkrw
10730db7769aSkrw p = getstring(prompt, helpstring, buf);
10740db7769aSkrw if (p == NULL)
1075bb12209fSkrw return CMD_ABORTED;
10760db7769aSkrw if (strlen(p) == 0)
1077bb12209fSkrw return oval;
10780db7769aSkrw
10790db7769aSkrw rval = strtonum(p, 0, maxval, &errstr);
10800db7769aSkrw if (errstr != NULL) {
10810db7769aSkrw printf("%s must be between 0 and %u\n", prompt, maxval);
1082bb12209fSkrw return CMD_BADVALUE;
10830db7769aSkrw }
10840db7769aSkrw
1085bb12209fSkrw return rval;
10860db7769aSkrw }
10870db7769aSkrw
10880db7769aSkrw /*
10890db7769aSkrw * Returns
10900db7769aSkrw * 0 .. CMD_ABORTED - 1 ==> valid value
10910db7769aSkrw * CMD_BADVALUE ==> invalid value
10920db7769aSkrw * CMD_ABORTED ==> ^D on input
10930db7769aSkrw */
10940db7769aSkrw u_int64_t
getuint64(const struct disklabel * lp,char * prompt,char * helpstring,u_int64_t oval,u_int64_t maxval,int * flags)109543ba7787Skrw getuint64(const struct disklabel *lp, char *prompt, char *helpstring,
109640b226e8Skrw u_int64_t oval, u_int64_t maxval, int *flags)
10976fe57b42Smillert {
10981fec2892Skrw char buf[21], *p, operator = '\0';
10991fec2892Skrw char *unit = NULL;
11001e0ad43cSotto u_int64_t rval = oval;
11011fec2892Skrw double d;
11029a4afaafSkrw int rslt;
11036fe57b42Smillert
11049a4afaafSkrw rslt = snprintf(buf, sizeof(buf), "%llu", oval);
1105515e489cSderaadt if (rslt < 0 || (unsigned int)rslt >= sizeof(buf))
11069a4afaafSkrw goto invalid;
11079a4afaafSkrw
11089a4afaafSkrw p = getstring(prompt, helpstring, buf);
11099a4afaafSkrw if (p == NULL)
1110bb12209fSkrw return CMD_ABORTED;
11111fec2892Skrw else if (p[0] == '\0')
11121fec2892Skrw rval = oval;
11131fec2892Skrw else if (p[0] == '*' && p[1] == '\0')
11146fe57b42Smillert rval = maxval;
11151fec2892Skrw else {
11161fec2892Skrw if (*p == '+' || *p == '-')
11171fec2892Skrw operator = *p++;
11181fec2892Skrw if (parse_sizespec(p, &d, &unit) == -1)
11191fec2892Skrw goto invalid;
11201fec2892Skrw if (unit == NULL)
11211fec2892Skrw rval = d;
11221fec2892Skrw else if (flags != NULL && (*flags & DO_CONVERSIONS) == 0)
11231fec2892Skrw goto invalid;
11241fec2892Skrw else {
11251fec2892Skrw switch (tolower((unsigned char)*unit)) {
11266fe57b42Smillert case 'b':
11271fec2892Skrw rval = d / lp->d_secsize;
11286fe57b42Smillert break;
11291fec2892Skrw case 'c':
11301fec2892Skrw rval = d * lp->d_secpercyl;
11311a51a1eeSmillert break;
113214cc915fSmillert case '%':
11331fec2892Skrw rval = DL_GETDSIZE(lp) * (d / 100.0);
113414cc915fSmillert break;
113514cc915fSmillert case '&':
11361fec2892Skrw rval = maxval * (d / 100.0);
11371fec2892Skrw break;
11381fec2892Skrw default:
11391fec2892Skrw if (apply_unit(d, *unit, &rval) == -1)
11401fec2892Skrw goto invalid;
11411fec2892Skrw rval = DL_BLKTOSEC(lp, rval);
114214cc915fSmillert break;
11436fe57b42Smillert }
114496a888c6Smillert }
11456fe57b42Smillert
1146e15dcdb4Skrw /* Range check then apply [+-] operator */
1147e15dcdb4Skrw if (operator == '+') {
1148aa3970cdSkrw if (CMD_ABORTED - oval > rval)
11496fe57b42Smillert rval += oval;
1150e15dcdb4Skrw else {
1151ac30837aSkrw goto invalid;
1152e15dcdb4Skrw }
1153e15dcdb4Skrw } else if (operator == '-') {
1154e15dcdb4Skrw if (oval >= rval)
11556fe57b42Smillert rval = oval - rval;
1156e15dcdb4Skrw else {
1157ac30837aSkrw goto invalid;
1158e15dcdb4Skrw }
1159e15dcdb4Skrw }
11606fe57b42Smillert }
116140b226e8Skrw
116240b226e8Skrw if (flags != NULL) {
11631fec2892Skrw if (unit != NULL)
116440b226e8Skrw *flags |= DO_ROUNDING;
1165fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
116640b226e8Skrw if (lp->d_flags & D_VENDOR)
116740b226e8Skrw *flags |= DO_ROUNDING;
1168dbffb156Smillert #endif
11696fe57b42Smillert }
1170bb12209fSkrw return rval;
1171ac30837aSkrw
1172ac30837aSkrw invalid:
1173ac30837aSkrw fputs("Invalid entry\n", stderr);
1174bb12209fSkrw return CMD_BADVALUE;
11756fe57b42Smillert }
11766fe57b42Smillert
11776fe57b42Smillert /*
11781f0f871dSkrw * Check for partition overlap in lp and prompt the user to resolve the overlap
11791f0f871dSkrw * if any is found. Returns 1 if unable to resolve, else 0.
11806fe57b42Smillert */
11816fe57b42Smillert int
has_overlap(struct disklabel * lp)11821f0f871dSkrw has_overlap(struct disklabel *lp)
11836fe57b42Smillert {
118443ba7787Skrw const struct partition **spp;
11850f1cd5a2Skrw int i, p1, p2;
11860f1cd5a2Skrw char *line = NULL;
11870f1cd5a2Skrw size_t linesize = 0;
11880f1cd5a2Skrw ssize_t linelen;
11896fe57b42Smillert
11900f1cd5a2Skrw for (;;) {
1191411a261cSkrw spp = sort_partitions(lp, -1);
11920f1cd5a2Skrw for (i = 0; spp[i+1] != NULL; i++) {
1193430e1380Skrw if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) >
11940f1cd5a2Skrw DL_GETPOFFSET(spp[i+1]))
11950f1cd5a2Skrw break;
1196616cd1c4Smillert }
11970f1cd5a2Skrw if (spp[i+1] == NULL) {
11980f1cd5a2Skrw free(line);
1199bb12209fSkrw return 0;
12006fe57b42Smillert }
12016fe57b42Smillert
12020f1cd5a2Skrw p1 = 'a' + (spp[i] - lp->d_partitions);
12030f1cd5a2Skrw p2 = 'a' + (spp[i+1] - lp->d_partitions);
12040f1cd5a2Skrw printf("\nError, partitions %c and %c overlap:\n", p1, p2);
12050f1cd5a2Skrw printf("# %16.16s %16.16s fstype [fsize bsize cpg]\n",
12060f1cd5a2Skrw "size", "offset");
12070f1cd5a2Skrw display_partition(stdout, lp, p1 - 'a', 0);
12080f1cd5a2Skrw display_partition(stdout, lp, p2 - 'a', 0);
12090f1cd5a2Skrw
12100f1cd5a2Skrw for (;;) {
12110f1cd5a2Skrw printf("Disable which one? (%c %c) ", p1, p2);
12120f1cd5a2Skrw linelen = getline(&line, &linesize, stdin);
12130f1cd5a2Skrw if (linelen == -1)
12140f1cd5a2Skrw goto done;
12150f1cd5a2Skrw if (linelen == 2 && (line[0] == p1 || line[0] == p2))
12160f1cd5a2Skrw break;
12170f1cd5a2Skrw }
12180f1cd5a2Skrw lp->d_partitions[line[0] - 'a'].p_fstype = FS_UNUSED;
12190f1cd5a2Skrw }
12200f1cd5a2Skrw
12210f1cd5a2Skrw done:
12220f1cd5a2Skrw putchar('\n');
12230f1cd5a2Skrw free(line);
1224bb12209fSkrw return 1;
12250f1cd5a2Skrw }
12260f1cd5a2Skrw
12276fe57b42Smillert void
edit_packname(struct disklabel * lp)12281cc333d2Skrw edit_packname(struct disklabel *lp)
12296fe57b42Smillert {
12306fe57b42Smillert char *p;
123196a888c6Smillert struct disklabel oldlabel = *lp;
12326fe57b42Smillert
12331cc333d2Skrw printf("Changing label description for %s:\n", specname);
12340f820bbbSmillert
12356fe57b42Smillert /* pack/label id */
1236c33fcabaSmillert p = getstring("label name",
12376fe57b42Smillert "15 char string that describes this label, usually the disk name.",
12386fe57b42Smillert lp->d_packname);
123996a888c6Smillert if (p == NULL) {
124096a888c6Smillert *lp = oldlabel; /* undo damage */
124196a888c6Smillert return;
124296a888c6Smillert }
12434fb6ab7cSmillert strncpy(lp->d_packname, p, sizeof(lp->d_packname)); /* checked */
12446fe57b42Smillert }
1245a7e61405Smillert
124643ba7787Skrw const struct partition **
sort_partitions(const struct disklabel * lp,int ignore)124743ba7787Skrw sort_partitions(const struct disklabel *lp, int ignore)
1248a7e61405Smillert {
124943ba7787Skrw const static struct partition *spp[MAXPARTITIONS+2];
12500fbd3c97Skrw int i, npartitions;
1251a7e61405Smillert
1252d18c2a43Skrw memset(spp, 0, sizeof(spp));
1253d18c2a43Skrw
1254a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1255411a261cSkrw if (i != ignore && lp->d_partitions[i].p_fstype != FS_UNUSED &&
12561e0ad43cSotto DL_GETPSIZE(&lp->d_partitions[i]) != 0)
1257a7e61405Smillert spp[npartitions++] = &lp->d_partitions[i];
1258a7e61405Smillert }
1259a7e61405Smillert
1260a7e61405Smillert /*
1261a7e61405Smillert * Sort the partitions based on starting offset.
1262a7e61405Smillert * This is safe because we guarantee no overlap.
1263a7e61405Smillert */
1264a7e61405Smillert if (npartitions > 1)
12650f1cd5a2Skrw if (mergesort((void *)spp, npartitions, sizeof(spp[0]),
1266a7e61405Smillert partition_cmp))
1267a7e61405Smillert err(4, "failed to sort partition table");
1268a7e61405Smillert
1269bb12209fSkrw return spp;
1270a7e61405Smillert }
12710f820bbbSmillert
12720f820bbbSmillert /*
127396a888c6Smillert * Get beginning and ending sectors of the OpenBSD portion of the disk
127496a888c6Smillert * from the user.
127596a888c6Smillert */
127696a888c6Smillert void
set_bounds(struct disklabel * lp)12779fdcb4d6Skrw set_bounds(struct disklabel *lp)
127896a888c6Smillert {
12791e0ad43cSotto u_int64_t ui, start_temp;
128096a888c6Smillert
128196a888c6Smillert /* Starting sector */
1282f1bc1b27Skrw for (;;) {
1283117239d3Skrw ui = getuint64(lp, "Starting sector",
128496a888c6Smillert "The start of the OpenBSD portion of the disk.",
128540b226e8Skrw starting_sector, DL_GETDSIZE(lp), NULL);
1286aa3970cdSkrw if (ui == CMD_ABORTED)
128796a888c6Smillert return;
1288aa3970cdSkrw else if (ui == CMD_BADVALUE)
1289f1bc1b27Skrw ; /* Try again. */
1290f1bc1b27Skrw else if (ui >= DL_GETDSIZE(lp))
1291f1bc1b27Skrw fprintf(stderr, "starting sector must be < %llu\n",
1292f1bc1b27Skrw DL_GETDSIZE(lp));
1293f1bc1b27Skrw else
1294f1bc1b27Skrw break;
1295f1bc1b27Skrw }
129696a888c6Smillert start_temp = ui;
129796a888c6Smillert
12984793b14cSmillert /* Size */
1299f1bc1b27Skrw for (;;) {
1300117239d3Skrw ui = getuint64(lp, "Size ('*' for entire disk)",
1301f98aebd4Smillert "The size of the OpenBSD portion of the disk ('*' for the "
1302f98aebd4Smillert "entire disk).", ending_sector - starting_sector,
130340b226e8Skrw DL_GETDSIZE(lp) - start_temp, NULL);
1304aa3970cdSkrw if (ui == CMD_ABORTED)
130596a888c6Smillert return;
1306aa3970cdSkrw else if (ui == CMD_BADVALUE)
1307f1bc1b27Skrw ; /* Try again. */
1308f1bc1b27Skrw else if (ui > DL_GETDSIZE(lp) - start_temp)
1309f1bc1b27Skrw fprintf(stderr, "size must be <= %llu\n",
1310f1bc1b27Skrw DL_GETDSIZE(lp) - start_temp);
1311f1bc1b27Skrw else
1312f1bc1b27Skrw break;
1313f1bc1b27Skrw }
13144793b14cSmillert ending_sector = start_temp + ui;
131578f0fb17Skrw DL_SETBEND(lp, ending_sector);
131696a888c6Smillert starting_sector = start_temp;
131778f0fb17Skrw DL_SETBSTART(lp, starting_sector);
131896a888c6Smillert }
131996a888c6Smillert
132096a888c6Smillert /*
13210d63cfbaSjsing * Allow user to interactively change disklabel UID.
13220d63cfbaSjsing */
13230d63cfbaSjsing void
set_duid(struct disklabel * lp)132469a6ffbcSjsing set_duid(struct disklabel *lp)
13250d63cfbaSjsing {
13260d63cfbaSjsing char *s;
13270d63cfbaSjsing int i;
13280d63cfbaSjsing
1329f6ad9e2dSjsing printf("The disklabel UID is currently: "
1330f6ad9e2dSjsing "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n",
1331f6ad9e2dSjsing lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3],
1332f6ad9e2dSjsing lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]);
13330d63cfbaSjsing
13340d63cfbaSjsing do {
133569a6ffbcSjsing s = getstring("duid", "The disklabel UID, given as a 16 "
13360d63cfbaSjsing "character hexadecimal string.", NULL);
1337ce98d1aeShalex if (s == NULL || strlen(s) == 0) {
13380d63cfbaSjsing fputs("Command aborted\n", stderr);
13390d63cfbaSjsing return;
13400d63cfbaSjsing }
134169a6ffbcSjsing i = duid_parse(lp, s);
13420d63cfbaSjsing if (i != 0)
13430d63cfbaSjsing fputs("Invalid UID entered.\n", stderr);
13440d63cfbaSjsing } while (i != 0);
13450d63cfbaSjsing }
13460d63cfbaSjsing
13470d63cfbaSjsing /*
134896a888c6Smillert * Return a list of the "chunks" of free space available
134996a888c6Smillert */
1350ab2017adSkrw const struct diskchunk *
free_chunks(const struct disklabel * lp,int partno)135143ba7787Skrw free_chunks(const struct disklabel *lp, int partno)
135296a888c6Smillert {
135343ba7787Skrw const struct partition **spp;
135496a888c6Smillert static struct diskchunk chunks[MAXPARTITIONS + 2];
135599bd27d2Skrw u_int64_t start, stop;
135696a888c6Smillert int i, numchunks;
135796a888c6Smillert
13580fbd3c97Skrw /* Sort the in-use partitions based on offset */
1359411a261cSkrw spp = sort_partitions(lp, partno);
136096a888c6Smillert
136196a888c6Smillert /* If there are no partitions, it's all free. */
13620fbd3c97Skrw if (spp[0] == NULL) {
13632d8451b0Smillert chunks[0].start = starting_sector;
136496a888c6Smillert chunks[0].stop = ending_sector;
136596a888c6Smillert chunks[1].start = chunks[1].stop = 0;
1366bb12209fSkrw return chunks;
136796a888c6Smillert }
136896a888c6Smillert
136996a888c6Smillert /* Find chunks of free space */
137096a888c6Smillert numchunks = 0;
13710fbd3c97Skrw if (DL_GETPOFFSET(spp[0]) > starting_sector) {
13722d8451b0Smillert chunks[0].start = starting_sector;
13731e0ad43cSotto chunks[0].stop = DL_GETPOFFSET(spp[0]);
137496a888c6Smillert numchunks++;
137596a888c6Smillert }
13760fbd3c97Skrw for (i = 0; spp[i] != NULL; i++) {
137799bd27d2Skrw start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]);
1378aff3f969Sotto if (start < starting_sector)
1379aff3f969Sotto start = starting_sector;
1380aff3f969Sotto else if (start > ending_sector)
1381aff3f969Sotto start = ending_sector;
138299bd27d2Skrw if (spp[i + 1] != NULL)
138399bd27d2Skrw stop = DL_GETPOFFSET(spp[i+1]);
138499bd27d2Skrw else
138599bd27d2Skrw stop = ending_sector;
1386aff3f969Sotto if (stop < starting_sector)
1387aff3f969Sotto stop = starting_sector;
1388aff3f969Sotto else if (stop > ending_sector)
1389aff3f969Sotto stop = ending_sector;
139099bd27d2Skrw if (start < stop) {
139199bd27d2Skrw chunks[numchunks].start = start;
139299bd27d2Skrw chunks[numchunks].stop = stop;
139396a888c6Smillert numchunks++;
139496a888c6Smillert }
139596a888c6Smillert }
139696a888c6Smillert
139796a888c6Smillert /* Terminate and return */
139896a888c6Smillert chunks[numchunks].start = chunks[numchunks].stop = 0;
1399bb12209fSkrw return chunks;
140096a888c6Smillert }
14014793b14cSmillert
14024793b14cSmillert void
find_bounds(const struct disklabel * lp)140343ba7787Skrw find_bounds(const struct disklabel *lp)
14044793b14cSmillert {
14056534e983Sderaadt starting_sector = DL_GETBSTART(lp);
14066534e983Sderaadt ending_sector = DL_GETBEND(lp);
1407b2d4a455Smiod
14086534e983Sderaadt if (ending_sector) {
140934ae4198Skrw if (verbose)
141034ae4198Skrw printf("Treating sectors %llu-%llu as the OpenBSD"
141134ae4198Skrw " portion of the disk.\nYou can use the 'b'"
141234ae4198Skrw " command to change this.\n\n", starting_sector,
141334ae4198Skrw ending_sector);
14144793b14cSmillert }
1415b2d4a455Smiod }
1416c0bdc608Smillert
1417c0bdc608Smillert /*
1418c0bdc608Smillert * Calculate free space.
1419c0bdc608Smillert */
14209fdcb4d6Skrw u_int64_t
editor_countfree(const struct disklabel * lp)142143ba7787Skrw editor_countfree(const struct disklabel *lp)
1422c0bdc608Smillert {
142343ba7787Skrw const struct diskchunk *chunk;
14249fdcb4d6Skrw u_int64_t freesectors = 0;
1425c0bdc608Smillert
1426a83eeb72Skrw chunk = free_chunks(lp, -1);
1427509930fbSotto
1428a83eeb72Skrw for (; chunk->start != 0 || chunk->stop != 0; chunk++)
1429b46f7512Skrw freesectors += CHUNKSZ(chunk);
14309fdcb4d6Skrw
1431bb12209fSkrw return freesectors;
1432c0bdc608Smillert }
1433617e6e4aSmillert
1434617e6e4aSmillert void
editor_help(void)14354d812bb6Slum editor_help(void)
1436617e6e4aSmillert {
1437617e6e4aSmillert puts("Available commands:");
1438617e6e4aSmillert puts(
14394d812bb6Slum " ? | h - show help n [part] - set mount point\n"
144049159a67Skrw " A - auto partition all space p [unit] - print partitions\n"
144149159a67Skrw " a [part] - add partition q - quit & save changes\n"
14424659aa0dSotto " b - set OpenBSD boundaries R [part] - resize auto allocated partition\n"
144349159a67Skrw " c [part] - change partition size r - display free space\n"
14446aaa4aabSotto " D - reset label to default s [path] - save label to file\n"
14456aaa4aabSotto " d [part] - delete partition U - undo all changes\n"
14461cc333d2Skrw " e - edit label description u - undo last change\n"
1447ba275c17Skrw " i - modify disklabel UID w - write label to disk\n"
1448953cd4efSkrw " l [unit] - print disk label header x - exit & lose changes\n"
1449953cd4efSkrw " M - disklabel(8) man page z - delete all partitions\n"
1450953cd4efSkrw " m [part] - modify partition\n"
1451c4884206Skrw "\n"
1452c4884206Skrw "Suffixes can be used to indicate units other than sectors:\n"
1453e5f81948Sotto " 'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes) 't' (terabytes)\n"
1454e5f81948Sotto " 'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n"
1455c4884206Skrw "Values in non-sector units are truncated to the nearest cylinder boundary.");
14564d812bb6Slum
1457617e6e4aSmillert }
1458bd6726faSmillert
14594f3bbbf0Skrw void
mpcopy(char ** to,char ** from)14608809fabbSderaadt mpcopy(char **to, char **from)
1461bd6726faSmillert {
1462bd6726faSmillert int i;
1463bd6726faSmillert
1464bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) {
1465bd6726faSmillert free(to[i]);
1466bd6726faSmillert to[i] = NULL;
1467408ab9bcSkrw if (from[i] != NULL) {
1468408ab9bcSkrw to[i] = strdup(from[i]);
1469408ab9bcSkrw if (to[i] == NULL)
1470b7cc13deSkrw err(1, NULL);
1471bd6726faSmillert }
1472bd6726faSmillert }
1473bd6726faSmillert }
1474bd6726faSmillert
1475bd6726faSmillert int
mpequal(char ** mp1,char ** mp2)14768809fabbSderaadt mpequal(char **mp1, char **mp2)
1477bd6726faSmillert {
1478bd6726faSmillert int i;
1479bd6726faSmillert
1480bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) {
1481bd6726faSmillert if (mp1[i] == NULL && mp2[i] == NULL)
1482bd6726faSmillert continue;
1483bd6726faSmillert
1484bd6726faSmillert if ((mp1[i] != NULL && mp2[i] == NULL) ||
1485bd6726faSmillert (mp1[i] == NULL && mp2[i] != NULL) ||
1486bd6726faSmillert (strcmp(mp1[i], mp2[i]) != 0))
1487bb12209fSkrw return 0;
1488bd6726faSmillert }
1489bb12209fSkrw return 1;
1490bd6726faSmillert }
1491bd6726faSmillert
149293160b9bSkrw void
mpsave(const struct disklabel * lp)149343ba7787Skrw mpsave(const struct disklabel *lp)
1494bd6726faSmillert {
1495d8b446ceSderaadt int i, j;
1496b9fc9a72Sderaadt char bdev[PATH_MAX], *p;
14973f843443Smillert struct mountinfo mi[MAXPARTITIONS];
1498bd6726faSmillert FILE *fp;
1499fe01da94Skrw u_int8_t fstype;
1500bd6726faSmillert
150193160b9bSkrw if (!fstabfile)
150293160b9bSkrw return;
150393160b9bSkrw
15043f843443Smillert memset(&mi, 0, sizeof(mi));
15053f843443Smillert
1506d8b446ceSderaadt for (i = 0; i < MAXPARTITIONS; i++) {
1507fe01da94Skrw fstype = lp->d_partitions[i].p_fstype;
1508fe01da94Skrw if (mountpoints[i] != NULL || fstype == FS_SWAP) {
150934ae4198Skrw mi[i].mountpoint = mountpoints[i];
15103f843443Smillert mi[i].partno = i;
1511bd6726faSmillert }
1512bd6726faSmillert }
1513bd6726faSmillert
151434ae4198Skrw /* Convert specname to bdev */
1515d6d80bb0Skrw if (uidflag) {
1516d6d80bb0Skrw snprintf(bdev, sizeof(bdev),
1517d6d80bb0Skrw "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
1518d6d80bb0Skrw lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3],
1519d6d80bb0Skrw lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7],
1520d6d80bb0Skrw specname[strlen(specname)-1]);
1521d6d80bb0Skrw } else if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 &&
152234ae4198Skrw specname[sizeof(_PATH_DEV) - 1] == 'r') {
1523bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV,
152434ae4198Skrw &specname[sizeof(_PATH_DEV)]);
1525bd6726faSmillert } else {
152634ae4198Skrw if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r')
152793160b9bSkrw return;
1528bd6726faSmillert *p = '\0';
152934ae4198Skrw snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1);
1530bd6726faSmillert *p = 'r';
1531bd6726faSmillert }
1532bd6726faSmillert bdev[strlen(bdev) - 1] = '\0';
1533bd6726faSmillert
15343f843443Smillert /* Sort mountpoints so we don't try to mount /usr/local before /usr */
15353f843443Smillert qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp);
15363f843443Smillert
1537d71533c9Stedu if ((fp = fopen(fstabfile, "w"))) {
1538fe01da94Skrw for (i = 0; i < MAXPARTITIONS; i++) {
15395fea0b85Smillert j = mi[i].partno;
1540fe01da94Skrw fstype = lp->d_partitions[j].p_fstype;
15414536786eSkrw if (fstype == FS_RAID)
15424536786eSkrw continue;
1543fe01da94Skrw if (fstype == FS_SWAP) {
1544fe01da94Skrw fprintf(fp, "%s%c none swap sw\n", bdev, 'a'+j);
1545fe01da94Skrw } else if (mi[i].mountpoint) {
1546fe01da94Skrw fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev,
1547fe01da94Skrw 'a' + j, mi[i].mountpoint,
1548fe01da94Skrw fstypesnames[fstype], j == 0 ? 1 : 2);
1549fe01da94Skrw }
1550bd6726faSmillert }
1551bd6726faSmillert fclose(fp);
155293160b9bSkrw }
1553bd6726faSmillert }
155424a2c1a4Smillert
1555408ab9bcSkrw void
mpfree(char ** mp,int action)1556e46ff49bSkrw mpfree(char **mp, int action)
1557408ab9bcSkrw {
1558408ab9bcSkrw int part;
1559408ab9bcSkrw
1560408ab9bcSkrw if (mp == NULL)
1561408ab9bcSkrw return;
1562408ab9bcSkrw
1563e46ff49bSkrw for (part = 0; part < MAXPARTITIONS; part++) {
1564408ab9bcSkrw free(mp[part]);
1565e46ff49bSkrw mp[part] = NULL;
1566e46ff49bSkrw }
1567408ab9bcSkrw
1568e46ff49bSkrw if (action == DISCARD) {
1569408ab9bcSkrw free(mp);
1570e46ff49bSkrw mp = NULL;
1571e46ff49bSkrw }
1572408ab9bcSkrw }
1573408ab9bcSkrw
157424a2c1a4Smillert int
get_offset(struct disklabel * lp,int partno)1575604d3bdeSkrw get_offset(struct disklabel *lp, int partno)
157624a2c1a4Smillert {
157740b226e8Skrw struct partition opp, *pp = &lp->d_partitions[partno];
157840b226e8Skrw u_int64_t ui, offsetalign;
157940b226e8Skrw int flags;
158024a2c1a4Smillert
158140b226e8Skrw flags = DO_CONVERSIONS;
1582117239d3Skrw ui = getuint64(lp, "offset",
15831e0ad43cSotto "Starting sector for this partition.",
15841e0ad43cSotto DL_GETPOFFSET(pp),
158540b226e8Skrw DL_GETPOFFSET(pp), &flags);
1586e9ff19beSkrw
158740b226e8Skrw if (ui == CMD_ABORTED || ui == CMD_BADVALUE)
1588bb12209fSkrw return 1;
1589fc1a4cc6Sderaadt #ifdef SUN_AAT0
159040b226e8Skrw if (partno == 0 && ui != 0) {
159149bf537cSderaadt fprintf(stderr, "This architecture requires that "
159240f544cdSderaadt "partition 'a' start at sector 0.\n");
1593bb12209fSkrw return 1;
159424a2c1a4Smillert }
159540b226e8Skrw #endif
159640b226e8Skrw opp = *pp;
159740b226e8Skrw DL_SETPOFFSET(pp, ui);
159840b226e8Skrw offsetalign = 1;
159940b226e8Skrw if ((flags & DO_ROUNDING) != 0 && pp->p_fstype == FS_BSDFFS)
160040b226e8Skrw offsetalign = lp->d_secpercyl;
160140b226e8Skrw
160240b226e8Skrw if (alignpartition(lp, partno, offsetalign, 1, ROUND_OFFSET_UP) == 1) {
160340b226e8Skrw *pp = opp;
1604bb12209fSkrw return 1;
160515c15d8aSkrw }
1606e9ff19beSkrw
1607bb12209fSkrw return 0;
160815c15d8aSkrw }
160924a2c1a4Smillert
161024a2c1a4Smillert int
get_size(struct disklabel * lp,int partno)16119fdcb4d6Skrw get_size(struct disklabel *lp, int partno)
161224a2c1a4Smillert {
161340b226e8Skrw struct partition opp, *pp = &lp->d_partitions[partno];
161440b226e8Skrw u_int64_t maxsize, ui, sizealign;
161540b226e8Skrw int flags;
161614192793Skrw
161714192793Skrw maxsize = max_partition_size(lp, partno);
161840b226e8Skrw flags = DO_CONVERSIONS;
1619117239d3Skrw ui = getuint64(lp, "size", "Size of the partition. "
16207da73705Skrw "You may also say +/- amount for a relative change.",
162140b226e8Skrw DL_GETPSIZE(pp), maxsize, &flags);
1622e9ff19beSkrw
162340b226e8Skrw if (ui == CMD_ABORTED || ui == CMD_BADVALUE)
1624bb12209fSkrw return 1;
162540b226e8Skrw
162640b226e8Skrw opp = *pp;
162759ccf790Skrw DL_SETPSIZE(pp, ui);
162840b226e8Skrw sizealign = 1;
162940b226e8Skrw if ((flags & DO_ROUNDING) != 0 && (pp->p_fstype == FS_SWAP ||
163040b226e8Skrw pp->p_fstype == FS_BSDFFS))
163140b226e8Skrw sizealign = lp->d_secpercyl;
163240b226e8Skrw
163340b226e8Skrw if (alignpartition(lp, partno, 1, sizealign, ROUND_SIZE_UP) == 1) {
163440b226e8Skrw *pp = opp;
1635bb12209fSkrw return 1;
163624a2c1a4Smillert }
1637e9ff19beSkrw
1638bb12209fSkrw return 0;
1639e9ff19beSkrw }
164024a2c1a4Smillert
164124a2c1a4Smillert int
set_fragblock(struct disklabel * lp,int partno)1642728b9255Skrw set_fragblock(struct disklabel *lp, int partno)
1643a95dd767Sotto {
1644728b9255Skrw struct partition opp, *pp = &lp->d_partitions[partno];
1645728b9255Skrw u_int64_t bytes, offsetalign, sizealign;
1646728b9255Skrw u_int32_t frag, fsize;
1647a95dd767Sotto
16484aa85578Skrw if (pp->p_fstype != FS_BSDFFS)
1649bb12209fSkrw return 0;
16504aa85578Skrw
16514aa85578Skrw if (pp->p_cpg == 0)
16524aa85578Skrw pp->p_cpg = 1;
16534aa85578Skrw
1654ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
1655ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock);
1656a3ad4147Skrw if (fsize == 0) {
1657a3ad4147Skrw fsize = 2048;
1658ddfcbf38Sotto frag = 8;
1659a3ad4147Skrw bytes = DL_GETPSIZE(pp) * lp->d_secsize;
1660a3ad4147Skrw if (bytes > 128ULL * 1024 * 1024 * 1024)
1661a3ad4147Skrw fsize *= 2;
1662a3ad4147Skrw if (bytes > 512ULL * 1024 * 1024 * 1024)
1663a3ad4147Skrw fsize *= 2;
1664a3ad4147Skrw if (fsize < lp->d_secsize)
1665a3ad4147Skrw fsize = lp->d_secsize;
1666a3ad4147Skrw if (fsize > MAXBSIZE / frag)
1667a3ad4147Skrw fsize = MAXBSIZE / frag;
1668a3ad4147Skrw pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, frag);
1669a3ad4147Skrw }
1670953cd4efSkrw #ifdef SUN_CYLCHECK
1671bb12209fSkrw return 0;
1672953cd4efSkrw #endif
167340b226e8Skrw opp = *pp;
167440b226e8Skrw sizealign = (DISKLABELV1_FFS_FRAG(pp->p_fragblock) *
167540b226e8Skrw DISKLABELV1_FFS_FSIZE(pp->p_fragblock)) / lp->d_secsize;
167640b226e8Skrw offsetalign = 1;
167740b226e8Skrw if (DL_GETPOFFSET(pp) != starting_sector)
167840b226e8Skrw offsetalign = sizealign;
167940b226e8Skrw
1680922b28b8Skrw if (alignpartition(lp, partno, offsetalign, sizealign, ROUND_OFFSET_UP |
1681922b28b8Skrw ROUND_SIZE_DOWN | ROUND_SIZE_OVERLAP) == 1) {
168240b226e8Skrw *pp = opp;
1683bb12209fSkrw return 1;
168440b226e8Skrw }
168540b226e8Skrw
1686bb12209fSkrw return 0;
168724a2c1a4Smillert }
168824a2c1a4Smillert
168924a2c1a4Smillert int
get_fstype(struct disklabel * lp,int partno)16908809fabbSderaadt get_fstype(struct disklabel *lp, int partno)
169124a2c1a4Smillert {
169224a2c1a4Smillert char *p;
16931e0ad43cSotto u_int64_t ui;
169424a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno];
169524a2c1a4Smillert
169624a2c1a4Smillert if (pp->p_fstype < FSMAXTYPES) {
1697c33fcabaSmillert p = getstring("FS type",
169824a2c1a4Smillert "Filesystem type (usually 4.2BSD or swap)",
169924a2c1a4Smillert fstypenames[pp->p_fstype]);
170024a2c1a4Smillert if (p == NULL) {
1701bb12209fSkrw return 1;
170224a2c1a4Smillert }
170324a2c1a4Smillert for (ui = 0; ui < FSMAXTYPES; ui++) {
170424a2c1a4Smillert if (!strcasecmp(p, fstypenames[ui])) {
170524a2c1a4Smillert pp->p_fstype = ui;
170624a2c1a4Smillert break;
170724a2c1a4Smillert }
170824a2c1a4Smillert }
170924a2c1a4Smillert if (ui >= FSMAXTYPES) {
1710430e1380Skrw printf("Unrecognized filesystem type '%s', treating "
1711430e1380Skrw "as 'unknown'\n", p);
171224a2c1a4Smillert pp->p_fstype = FS_OTHER;
171324a2c1a4Smillert }
171424a2c1a4Smillert } else {
171524a2c1a4Smillert for (;;) {
17160db7769aSkrw ui = getnumber("FS type (decimal)",
1717430e1380Skrw "Filesystem type as a decimal number; usually 7 "
1718430e1380Skrw "(4.2BSD) or 1 (swap).",
17190db7769aSkrw pp->p_fstype, UINT8_MAX);
1720aa3970cdSkrw if (ui == CMD_ABORTED)
1721bb12209fSkrw return 1;
1722aa3970cdSkrw else if (ui == CMD_BADVALUE)
1723ac30837aSkrw ; /* Try again. */
172424a2c1a4Smillert else
172524a2c1a4Smillert break;
172624a2c1a4Smillert }
172724a2c1a4Smillert pp->p_fstype = ui;
172824a2c1a4Smillert }
1729bb12209fSkrw return 0;
173024a2c1a4Smillert }
173124a2c1a4Smillert
173224a2c1a4Smillert int
get_mp(const struct disklabel * lp,int partno)173341d86e10Skrw get_mp(const struct disklabel *lp, int partno)
173424a2c1a4Smillert {
173541d86e10Skrw const struct partition *pp = &lp->d_partitions[partno];
1736ec9fde5fSkrw char *p;
1737ec9fde5fSkrw int i;
173824a2c1a4Smillert
1739b308f3d4Skrw if (fstabfile == NULL ||
1740b308f3d4Skrw pp->p_fstype == FS_UNUSED ||
1741b308f3d4Skrw pp->p_fstype == FS_SWAP ||
1742b308f3d4Skrw pp->p_fstype == FS_BOOT ||
1743b308f3d4Skrw pp->p_fstype == FS_OTHER ||
1744b308f3d4Skrw pp->p_fstype == FS_RAID) {
1745b308f3d4Skrw /* No fstabfile, no names. Not all fstypes can be named */
1746b308f3d4Skrw return 0;
1747b308f3d4Skrw }
1748b308f3d4Skrw
1749ddaff619Smillert for (;;) {
1750c33fcabaSmillert p = getstring("mount point",
175124a2c1a4Smillert "Where to mount this filesystem (ie: / /var /usr)",
175234ae4198Skrw mountpoints[partno] ? mountpoints[partno] : "none");
1753ac30837aSkrw if (p == NULL)
1754bb12209fSkrw return 1;
1755ddaff619Smillert if (strcasecmp(p, "none") == 0) {
175634ae4198Skrw free(mountpoints[partno]);
175734ae4198Skrw mountpoints[partno] = NULL;
1758ddaff619Smillert break;
1759ddaff619Smillert }
1760ec9fde5fSkrw for (i = 0; i < MAXPARTITIONS; i++)
176193160b9bSkrw if (mountpoints[i] != NULL && i != partno &&
1762ec9fde5fSkrw strcmp(p, mountpoints[i]) == 0)
1763ec9fde5fSkrw break;
1764ec9fde5fSkrw if (i < MAXPARTITIONS) {
176593160b9bSkrw fprintf(stderr, "'%c' already being mounted at "
176693160b9bSkrw "'%s'\n", 'a'+i, p);
1767ec9fde5fSkrw break;
1768ec9fde5fSkrw }
1769ddaff619Smillert if (*p == '/') {
1770ddaff619Smillert /* XXX - might as well realloc */
177134ae4198Skrw free(mountpoints[partno]);
177234ae4198Skrw if ((mountpoints[partno] = strdup(p)) == NULL)
1773b7cc13deSkrw err(1, NULL);
1774ddaff619Smillert break;
1775ddaff619Smillert }
1776ddaff619Smillert fputs("Mount points must start with '/'\n", stderr);
177724a2c1a4Smillert }
1778b308f3d4Skrw
1779bb12209fSkrw return 0;
178024a2c1a4Smillert }
17813f843443Smillert
17823f843443Smillert int
micmp(const void * a1,const void * a2)17838809fabbSderaadt micmp(const void *a1, const void *a2)
17843f843443Smillert {
17853f843443Smillert struct mountinfo *mi1 = (struct mountinfo *)a1;
17863f843443Smillert struct mountinfo *mi2 = (struct mountinfo *)a2;
17873f843443Smillert
17883f843443Smillert /* We want all the NULLs at the end... */
17893f843443Smillert if (mi1->mountpoint == NULL && mi2->mountpoint == NULL)
1790bb12209fSkrw return 0;
17913f843443Smillert else if (mi1->mountpoint == NULL)
1792bb12209fSkrw return 1;
17933f843443Smillert else if (mi2->mountpoint == NULL)
1794bb12209fSkrw return -1;
17953f843443Smillert else
1796bb12209fSkrw return strcmp(mi1->mountpoint, mi2->mountpoint);
17973f843443Smillert }
1798c33fcabaSmillert
1799c33fcabaSmillert void
zero_partitions(struct disklabel * lp)18009fdcb4d6Skrw zero_partitions(struct disklabel *lp)
18019afbe9eeSmillert {
1802e46ff49bSkrw memset(lp->d_partitions, 0, sizeof(lp->d_partitions));
180334af67a3Sotto DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
1804e46ff49bSkrw
1805e46ff49bSkrw mpfree(mountpoints, KEEP);
18069afbe9eeSmillert }
180714192793Skrw
180814192793Skrw u_int64_t
max_partition_size(const struct disklabel * lp,int partno)180943ba7787Skrw max_partition_size(const struct disklabel *lp, int partno)
181014192793Skrw {
1811ab2017adSkrw const struct diskchunk *chunk;
181244ffe03bSotto u_int64_t maxsize = 0, offset;
181314192793Skrw
1814411a261cSkrw chunk = free_chunks(lp, partno);
181514192793Skrw
1816411a261cSkrw offset = DL_GETPOFFSET(&lp->d_partitions[partno]);
1817411a261cSkrw for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
1818411a261cSkrw if (offset < chunk->start || offset >= chunk->stop)
181914192793Skrw continue;
1820411a261cSkrw maxsize = chunk->stop - offset;
182114192793Skrw break;
182214192793Skrw }
1823bb12209fSkrw return maxsize;
182414192793Skrw }
1825aff3f969Sotto
1826aff3f969Sotto void
psize(u_int64_t sz,char unit,const struct disklabel * lp)182743ba7787Skrw psize(u_int64_t sz, char unit, const struct disklabel *lp)
1828aff3f969Sotto {
1829aff3f969Sotto double d = scale(sz, unit, lp);
1830aff3f969Sotto if (d < 0)
1831aff3f969Sotto printf("%llu", sz);
1832aff3f969Sotto else
1833aff3f969Sotto printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit);
1834aff3f969Sotto }
1835aff3f969Sotto
1836aff3f969Sotto void
display_edit(const struct disklabel * lp,char unit)183743ba7787Skrw display_edit(const struct disklabel *lp, char unit)
1838aff3f969Sotto {
18397ad973c1Skrw u_int64_t fr;
1840aff3f969Sotto int i;
1841aff3f969Sotto
18427ad973c1Skrw fr = editor_countfree(lp);
1843352d199bSkrw unit = canonical_unit(lp, unit);
1844aff3f969Sotto
1845aff3f969Sotto printf("OpenBSD area: ");
184659882f1dSkrw psize(starting_sector, 0, lp);
1847aff3f969Sotto printf("-");
184859882f1dSkrw psize(ending_sector, 0, lp);
1849aff3f969Sotto printf("; size: ");
1850aff3f969Sotto psize(ending_sector - starting_sector, unit, lp);
1851aff3f969Sotto printf("; free: ");
1852aff3f969Sotto psize(fr, unit, lp);
1853aff3f969Sotto
1854aff3f969Sotto printf("\n# %16.16s %16.16s fstype [fsize bsize cpg]\n",
1855aff3f969Sotto "size", "offset");
1856aff3f969Sotto for (i = 0; i < lp->d_npartitions; i++)
185734ae4198Skrw display_partition(stdout, lp, i, unit);
1858aff3f969Sotto }
1859a2c1f847Shenning
1860a2c1f847Shenning void
parse_autotable(char * filename)1861a2c1f847Shenning parse_autotable(char *filename)
1862a2c1f847Shenning {
1863a2c1f847Shenning FILE *cfile;
18645f012d92Snaddy size_t linesize = 0;
18655f012d92Snaddy char *line = NULL, *buf, *t;
1866a2c1f847Shenning uint idx = 0, pctsum = 0;
1867a2c1f847Shenning struct space_allocation *sa;
1868a2c1f847Shenning
1869bc9d58e0Skrw if (strcmp(filename, "-") == 0)
1870bc9d58e0Skrw cfile = stdin;
1871bc9d58e0Skrw else if ((cfile = fopen(filename, "r")) == NULL)
1872a2c1f847Shenning err(1, "%s", filename);
1873a2c1f847Shenning if ((alloc_table = calloc(1, sizeof(struct alloc_table))) == NULL)
1874a2c1f847Shenning err(1, NULL);
1875f55524eaSsthen alloc_table_nitems = 1;
1876a2c1f847Shenning
18775f012d92Snaddy while (getline(&line, &linesize, cfile) != -1) {
1878a2c1f847Shenning if ((alloc_table[0].table = reallocarray(alloc_table[0].table,
1879a2c1f847Shenning idx + 1, sizeof(*sa))) == NULL)
1880a2c1f847Shenning err(1, NULL);
1881a2c1f847Shenning sa = &(alloc_table[0].table[idx]);
1882ee18520dSotto memset(sa, 0, sizeof(*sa));
1883a2c1f847Shenning idx++;
1884a2c1f847Shenning
18855f012d92Snaddy buf = line;
188658c7d7acSnaddy if ((sa->mp = get_token(&buf)) == NULL ||
18874536786eSkrw (sa->mp[0] != '/' && strcasecmp(sa->mp, "swap") &&
18884536786eSkrw strcasecmp(sa->mp, "raid")))
1889a2c1f847Shenning errx(1, "%s: parse error on line %u", filename, idx);
189058c7d7acSnaddy if ((t = get_token(&buf)) == NULL ||
1891a2c1f847Shenning parse_sizerange(t, &sa->minsz, &sa->maxsz) == -1)
1892a2c1f847Shenning errx(1, "%s: parse error on line %u", filename, idx);
189358c7d7acSnaddy if ((t = get_token(&buf)) != NULL &&
1894a2c1f847Shenning parse_pct(t, &sa->rate) == -1)
1895a2c1f847Shenning errx(1, "%s: parse error on line %u", filename, idx);
1896a2c1f847Shenning if (sa->minsz > sa->maxsz)
1897a2c1f847Shenning errx(1, "%s: min size > max size on line %u", filename,
1898a2c1f847Shenning idx);
1899a2c1f847Shenning pctsum += sa->rate;
1900a2c1f847Shenning }
1901a2c1f847Shenning if (pctsum > 100)
1902a2c1f847Shenning errx(1, "%s: sum of extra space allocation > 100%%", filename);
1903a2c1f847Shenning alloc_table[0].sz = idx;
19045f012d92Snaddy free(line);
1905a2c1f847Shenning fclose(cfile);
1906a2c1f847Shenning }
1907a2c1f847Shenning
1908a2c1f847Shenning char *
get_token(char ** s)190958c7d7acSnaddy get_token(char **s)
1910a2c1f847Shenning {
1911a2c1f847Shenning char *p, *r;
1912a2c1f847Shenning size_t tlen = 0;
1913a2c1f847Shenning
1914a2c1f847Shenning p = *s;
191558c7d7acSnaddy while (**s != '\0' && !isspace((u_char)**s)) {
1916a2c1f847Shenning (*s)++;
1917a2c1f847Shenning tlen++;
1918a2c1f847Shenning }
1919a2c1f847Shenning if (tlen == 0)
1920bb12209fSkrw return NULL;
1921a2c1f847Shenning
1922a2c1f847Shenning /* eat whitespace */
192358c7d7acSnaddy while (isspace((u_char)**s))
1924a2c1f847Shenning (*s)++;
1925a2c1f847Shenning
1926104c1c3cSmillert if ((r = strndup(p, tlen)) == NULL)
1927a2c1f847Shenning err(1, NULL);
1928bb12209fSkrw return r;
1929a2c1f847Shenning }
1930a2c1f847Shenning
1931a2c1f847Shenning int
apply_unit(double val,u_char unit,u_int64_t * n)1932a2c1f847Shenning apply_unit(double val, u_char unit, u_int64_t *n)
1933a2c1f847Shenning {
1934a2c1f847Shenning u_int64_t factor = 1;
1935a2c1f847Shenning
1936a2c1f847Shenning switch (tolower(unit)) {
1937a2c1f847Shenning case 't':
1938a2c1f847Shenning factor *= 1024;
1939a2c1f847Shenning /* FALLTHROUGH */
1940a2c1f847Shenning case 'g':
1941a2c1f847Shenning factor *= 1024;
1942a2c1f847Shenning /* FALLTHROUGH */
1943a2c1f847Shenning case 'm':
1944a2c1f847Shenning factor *= 1024;
1945a2c1f847Shenning /* FALLTHROUGH */
1946a2c1f847Shenning case 'k':
1947a2c1f847Shenning factor *= 1024;
1948a2c1f847Shenning break;
1949a2c1f847Shenning default:
1950bb12209fSkrw return -1;
1951a2c1f847Shenning }
1952a2c1f847Shenning
1953a2c1f847Shenning val *= factor / DEV_BSIZE;
1954b4709bb3Srobert if (val > (double)ULLONG_MAX)
1955bb12209fSkrw return -1;
1956a2c1f847Shenning *n = val;
1957bb12209fSkrw return 0;
1958a2c1f847Shenning }
1959a2c1f847Shenning
1960a2c1f847Shenning int
parse_sizespec(const char * buf,double * val,char ** unit)1961a2c1f847Shenning parse_sizespec(const char *buf, double *val, char **unit)
1962a2c1f847Shenning {
19635f6cf98aSkrw errno = 0;
1964a2c1f847Shenning *val = strtod(buf, unit);
1965b4709bb3Srobert if (errno == ERANGE || *val < 0 || *val > (double)ULLONG_MAX)
1966bb12209fSkrw return -1; /* too big/small */
19675f6cf98aSkrw if (*val == 0 && *unit == buf)
1968bb12209fSkrw return -1; /* No conversion performed. */
1969a2c1f847Shenning if (*unit != NULL && *unit[0] == '\0')
1970a2c1f847Shenning *unit = NULL;
1971bb12209fSkrw return 0;
1972a2c1f847Shenning }
1973a2c1f847Shenning
1974a2c1f847Shenning int
parse_sizerange(char * buf,u_int64_t * min,u_int64_t * max)1975a2c1f847Shenning parse_sizerange(char *buf, u_int64_t *min, u_int64_t *max)
1976a2c1f847Shenning {
1977a2c1f847Shenning char *p, *unit1 = NULL, *unit2 = NULL;
1978a2c1f847Shenning double val1 = 0, val2 = 0;
1979a2c1f847Shenning
1980bc9d58e0Skrw if (strcmp(buf, "*") == 0) {
1981bc9d58e0Skrw *min = 0;
1982bc9d58e0Skrw *max = UINT64_MAX;
1983bc9d58e0Skrw goto done;
1984bc9d58e0Skrw }
1985bc9d58e0Skrw
1986a2c1f847Shenning if ((p = strchr(buf, '-')) != NULL) {
1987a2c1f847Shenning p[0] = '\0';
1988a2c1f847Shenning p++;
1989a2c1f847Shenning }
1990a2c1f847Shenning *max = 0;
1991a2c1f847Shenning if (parse_sizespec(buf, &val1, &unit1) == -1)
1992bb12209fSkrw return -1;
1993a2c1f847Shenning if (p != NULL && p[0] != '\0') {
1994a2c1f847Shenning if (p[0] == '*')
1995583b3ed6Skrw *max = UINT64_MAX;
1996a2c1f847Shenning else
1997a2c1f847Shenning if (parse_sizespec(p, &val2, &unit2) == -1)
1998bb12209fSkrw return -1;
1999a2c1f847Shenning }
2000a2c1f847Shenning if (unit1 == NULL && (unit1 = unit2) == NULL)
2001bb12209fSkrw return -1;
2002a2c1f847Shenning if (apply_unit(val1, unit1[0], min) == -1)
2003bb12209fSkrw return -1;
2004a2c1f847Shenning if (val2 > 0) {
2005a2c1f847Shenning if (apply_unit(val2, unit2[0], max) == -1)
2006bb12209fSkrw return -1;
2007a2c1f847Shenning } else
2008a2c1f847Shenning if (*max == 0)
2009a2c1f847Shenning *max = *min;
2010bc9d58e0Skrw done:
2011a2c1f847Shenning free(buf);
2012bb12209fSkrw return 0;
2013a2c1f847Shenning }
2014a2c1f847Shenning
2015a2c1f847Shenning int
parse_pct(char * buf,int * n)2016a2c1f847Shenning parse_pct(char *buf, int *n)
2017a2c1f847Shenning {
2018a2c1f847Shenning const char *errstr;
2019a2c1f847Shenning
2020a2c1f847Shenning if (buf[strlen(buf) - 1] == '%')
2021a2c1f847Shenning buf[strlen(buf) - 1] = '\0';
2022a2c1f847Shenning *n = strtonum(buf, 0, 100, &errstr);
2023a2c1f847Shenning if (errstr) {
2024a2c1f847Shenning warnx("parse percent %s: %s", buf, errstr);
2025bb12209fSkrw return -1;
2026a2c1f847Shenning }
2027a2c1f847Shenning free(buf);
2028bb12209fSkrw return 0;
2029a2c1f847Shenning }
203040b226e8Skrw
203140b226e8Skrw int
alignpartition(struct disklabel * lp,int partno,u_int64_t startalign,u_int64_t stopalign,int flags)203240b226e8Skrw alignpartition(struct disklabel *lp, int partno, u_int64_t startalign,
203340b226e8Skrw u_int64_t stopalign, int flags)
203440b226e8Skrw {
203540b226e8Skrw struct partition *pp = &lp->d_partitions[partno];
2036ab2017adSkrw const struct diskchunk *chunk;
203740b226e8Skrw u_int64_t start, stop, maxstop;
203840b226e8Skrw
203940b226e8Skrw start = DL_GETPOFFSET(pp);
204040b226e8Skrw if ((flags & ROUND_OFFSET_UP) == ROUND_OFFSET_UP)
20417233a2b0Skrw start = ROUNDUP(start, startalign);
204240b226e8Skrw else if ((flags & ROUND_OFFSET_DOWN) == ROUND_OFFSET_DOWN)
2043dbdb4107Skrw start = ROUNDDOWN(start, startalign);
204440b226e8Skrw
204540b226e8Skrw /* Find the chunk that contains 'start'. */
2046411a261cSkrw chunk = free_chunks(lp, partno);
2047411a261cSkrw for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
2048411a261cSkrw if (start >= chunk->start && start < chunk->stop)
204940b226e8Skrw break;
205040b226e8Skrw }
2051411a261cSkrw if (chunk->stop == 0) {
2052aef735d2Skrw fprintf(stderr, "'%c' aligned offset %llu lies outside "
2053aef735d2Skrw "the OpenBSD bounds or inside another partition\n",
2054aef735d2Skrw 'a' + partno, start);
2055bb12209fSkrw return 1;
205640b226e8Skrw }
205740b226e8Skrw
205840b226e8Skrw /* Calculate the new 'stop' sector, the sector after the partition. */
2059aef735d2Skrw if ((flags & ROUND_SIZE_OVERLAP) == 0)
2060dbdb4107Skrw maxstop = ROUNDDOWN(chunk->stop, stopalign);
2061aef735d2Skrw else
2062dbdb4107Skrw maxstop = ROUNDDOWN(ending_sector, stopalign);
2063aef735d2Skrw
206440b226e8Skrw stop = DL_GETPOFFSET(pp) + DL_GETPSIZE(pp);
206540b226e8Skrw if ((flags & ROUND_SIZE_UP) == ROUND_SIZE_UP)
20667233a2b0Skrw stop = ROUNDUP(stop, stopalign);
206740b226e8Skrw else if ((flags & ROUND_SIZE_DOWN) == ROUND_SIZE_DOWN)
2068dbdb4107Skrw stop = ROUNDDOWN(stop, stopalign);
2069aef735d2Skrw if (stop > maxstop)
207040b226e8Skrw stop = maxstop;
207140b226e8Skrw
2072aef735d2Skrw if (stop <= start) {
20739b5c4600Skrw fprintf(stderr, "not enough space\n");
2074bb12209fSkrw return 1;
2075aef735d2Skrw }
2076aef735d2Skrw
207740b226e8Skrw if (start != DL_GETPOFFSET(pp))
207840b226e8Skrw DL_SETPOFFSET(pp, start);
2079aef735d2Skrw if (stop != DL_GETPOFFSET(pp) + DL_GETPSIZE(pp))
208040b226e8Skrw DL_SETPSIZE(pp, stop - start);
208140b226e8Skrw
2082bb12209fSkrw return 0;
208340b226e8Skrw }
2084