From a2c1f847f3bfd3c3aa4632d78d07dbe15e109346 Mon Sep 17 00:00:00 2001 From: henning Date: Wed, 29 Apr 2015 09:58:16 +0000 Subject: [PATCH] support passing a template file for the auto-allocation to disklabel. template gives mountpoints, min-max size ranges and percentage of disk foremost intended for autoinstalls, installer bits to follow soon. with input from many, ok theo --- sbin/disklabel/disklabel.8 | 38 +++++++- sbin/disklabel/disklabel.c | 19 ++-- sbin/disklabel/editor.c | 186 +++++++++++++++++++++++++++++++++++-- sbin/disklabel/extern.h | 3 +- 4 files changed, 228 insertions(+), 18 deletions(-) diff --git a/sbin/disklabel/disklabel.8 b/sbin/disklabel/disklabel.8 index 4adb090d2de..b73c1f81eab 100644 --- a/sbin/disklabel/disklabel.8 +++ b/sbin/disklabel/disklabel.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: disklabel.8,v 1.112 2015/02/28 21:51:57 bentley Exp $ +.\" $OpenBSD: disklabel.8,v 1.113 2015/04/29 09:58:16 henning Exp $ .\" $NetBSD: disklabel.8,v 1.9 1995/03/18 14:54:38 cgd Exp $ .\" .\" Copyright (c) 1987, 1988, 1991, 1993 @@ -33,7 +33,7 @@ .\" .\" @(#)disklabel.8 8.2 (Berkeley) 4/19/94 .\" -.Dd $Mdocdate: February 28 2015 $ +.Dd $Mdocdate: April 29 2015 $ .Dt DISKLABEL 8 .Os .Sh NAME @@ -42,20 +42,24 @@ .Sh SYNOPSIS .Nm disklabel .Op Fl Acdtv +.Op Fl T Ar file .Op Fl h | p Ar unit .Ar disk .Nm disklabel .Fl w .Op Fl Acdnv +.Op Fl T Ar file .Ar disk Ar disktype .Op Ar packid .Nm disklabel .Fl e .Op Fl Acdnv +.Op Fl T Ar file .Ar disk .Nm disklabel .Fl E .Op Fl Acdnv +.Op Fl T Ar file .Op Fl F Ns | Ns Fl f Ar file .Ar disk .Nm disklabel @@ -196,6 +200,13 @@ file. Format the label as a .Xr disktab 5 entry. +.It Fl T Ar file +Read the template for automatic allocation from +.Ar file +instead of using the builtin one. +See +.Sx AUTOMATIC DISK ALLOCATION +below for the format. .It Fl v Print additional information during operation .Pq verbose mode . @@ -590,6 +601,29 @@ swap 10% of disk. 80M \(en 2x max physical memory / 95% of disk. 700M \(en 4G swap 5% of disk. 1M \(en 2x max physical memory .Ed +.Pp +A template for the automatic allocation can be passed to disklabel using +the +.Fl T +option. +The template consists of one line per partition, with each line giving +mountpoint, min-max size range, and percentage of disk, space-separated. +Max can be unlimited by specifying '*'. +If only mountpoint and min size are given, the partition is created with that +exact size. +.Pp +.Bd -literal -offset indent -compact +/ 250M +swap 80-256M 10% +/tmp 120M-4G 8% +/var 80M-4G 13% +/usr 900M-2G 5% +/usr/X11R6 512M-1G 3% +/usr/local 2G-10G 10% +/usr/src 1-2G 2% +/usr/obj 1.3G-2G 4% +/home 1G-* 45% +.Ed .Sh FILES .Bl -tag -width Pa -compact .It Pa /etc/disktab diff --git a/sbin/disklabel/disklabel.c b/sbin/disklabel/disklabel.c index 68e36118a20..d9a6226e776 100644 --- a/sbin/disklabel/disklabel.c +++ b/sbin/disklabel/disklabel.c @@ -1,4 +1,4 @@ -/* $OpenBSD: disklabel.c,v 1.199 2015/02/07 02:09:13 deraadt Exp $ */ +/* $OpenBSD: disklabel.c,v 1.200 2015/04/29 09:58:16 henning Exp $ */ /* * Copyright (c) 1987, 1993 @@ -122,8 +122,9 @@ main(int argc, char *argv[]) int ch, f, error = 0; struct disklabel *lp; FILE *t; + char *autotable = NULL; - while ((ch = getopt(argc, argv, "ABEf:F:hRb:cdenp:tvw")) != -1) + while ((ch = getopt(argc, argv, "ABEf:F:hRb:cdenp:tT:vw")) != -1) switch (ch) { case 'A': aflag = 1; @@ -171,6 +172,9 @@ main(int argc, char *argv[]) case 't': tflag = 1; break; + case 'T': + autotable = optarg; + break; case 'w': if (op != UNSPEC) usage(); @@ -220,6 +224,9 @@ main(int argc, char *argv[]) if (f < 0) err(4, "%s", specname); + if (autotable != NULL) + parse_autotable(autotable); + switch (op) { case EDIT: if (argc != 1) @@ -1467,13 +1474,13 @@ void usage(void) { fprintf(stderr, - "usage: disklabel [-Acdtv] [-h | -p unit] disk\t(read)\n"); + "usage: disklabel [-Acdtv] [-h | -p unit] disk\t\t(read)\n"); fprintf(stderr, - " disklabel -w [-Acdnv] disk disktype [packid]\t(write)\n"); + " disklabel -w [-Acdnv] [-T file] disk disktype [packid]\t(write)\n"); fprintf(stderr, - " disklabel -e [-Acdnv] disk\t\t\t(edit)\n"); + " disklabel -e [-Acdnv] [-T file] disk\t\t\t(edit)\n"); fprintf(stderr, - " disklabel -E [-Acdnv] [-F|-f file] disk\t\t(simple editor)" + " disklabel -E [-Acdnv] [-T file] [-F|-f file] disk\t(simple editor)" "\n"); fprintf(stderr, " disklabel -R [-nv] [-F|-f file] disk protofile\t\t(restore)\n\n"); diff --git a/sbin/disklabel/editor.c b/sbin/disklabel/editor.c index abd494433f0..36df5cd8322 100644 --- a/sbin/disklabel/editor.c +++ b/sbin/disklabel/editor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: editor.c,v 1.292 2015/03/17 19:11:55 otto Exp $ */ +/* $OpenBSD: editor.c,v 1.293 2015/04/29 09:58:16 henning Exp $ */ /* * Copyright (c) 1997-2000 Todd C. Miller @@ -73,7 +73,7 @@ struct space_allocation { }; /* entries for swap and var are changed by editor_allocspace() */ -const struct space_allocation alloc_big[] = { +struct space_allocation alloc_big[] = { { MEG(80), GIG(1), 5, "/" }, { MEG(80), MEG(256), 10, "swap" }, { MEG(120), GIG(4), 8, "/tmp" }, @@ -91,19 +91,19 @@ const struct space_allocation alloc_big[] = { /* Anything beyond this leave for the user to decide */ }; -const struct space_allocation alloc_medium[] = { +struct space_allocation alloc_medium[] = { { MEG(800), GIG(2), 5, "/" }, { MEG(80), MEG(256), 10, "swap" }, { MEG(900), GIG(3), 78, "/usr" }, { MEG(256), GIG(2), 7, "/home" } }; -const struct space_allocation alloc_small[] = { +struct space_allocation alloc_small[] = { { MEG(700), GIG(4), 95, "/" }, { MEG(1), MEG(256), 5, "swap" } }; -const struct space_allocation alloc_stupid[] = { +struct space_allocation alloc_stupid[] = { { MEG(1), MEG(2048), 100, "/" } }; @@ -111,15 +111,18 @@ const struct space_allocation alloc_stupid[] = { #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif -const struct { - const struct space_allocation *table; +struct alloc_table { + struct space_allocation *table; int sz; -} alloc_table[] = { +}; + +struct alloc_table alloc_table_default[] = { { alloc_big, nitems(alloc_big) }, { alloc_medium, nitems(alloc_medium) }, { alloc_small, nitems(alloc_small) }, { alloc_stupid, nitems(alloc_stupid) } }; +struct alloc_table *alloc_table = alloc_table_default; void edit_parms(struct disklabel *); void editor_resize(struct disklabel *, char *); @@ -157,6 +160,11 @@ u_int64_t max_partition_size(struct disklabel *, int); void display_edit(struct disklabel *, char, u_int64_t); int64_t getphysmem(void); void psize(u_int64_t sz, char unit, struct disklabel *lp); +char *get_token(char **, size_t *); +int apply_unit(double, u_char, u_int64_t *); +int parse_sizespec(const char *, double *, char **); +int parse_sizerange(char *, u_int64_t *, u_int64_t *); +int parse_pct(char *, int *); static u_int64_t starting_sector; static u_int64_t ending_sector; @@ -578,7 +586,7 @@ again: lastalloc * sizeof(struct space_allocation)); /* bump max swap based on phys mem, little physmem gets 2x swap */ - if (index == 0) { + if (index == 0 && alloc_table == alloc_table_default) { if (physmem < MEG(256)) alloc[1].minsz = alloc[1].maxsz = 2 * physmem; else @@ -2363,3 +2371,163 @@ display_edit(struct disklabel *lp, char unit, u_int64_t fr) for (i = 0; i < lp->d_npartitions; i++) display_partition(stdout, lp, i, unit); } + +void +parse_autotable(char *filename) +{ + FILE *cfile; + size_t len; + char *buf, *p, *t; + uint idx = 0, pctsum = 0; + struct space_allocation *sa; + + if ((cfile = fopen(filename, "r")) == NULL) + err(1, "%s", filename); + if ((alloc_table = calloc(1, sizeof(struct alloc_table))) == NULL) + err(1, NULL); + + while ((buf = fgetln(cfile, &len)) != NULL) { + if ((alloc_table[0].table = reallocarray(alloc_table[0].table, + idx + 1, sizeof(*sa))) == NULL) + err(1, NULL); + sa = &(alloc_table[0].table[idx]); + idx++; + + p = buf; + if ((sa->mp = get_token(&p, &len)) == NULL || + (sa->mp[0] != '/' && strcmp(sa->mp, "swap"))) + errx(1, "%s: parse error on line %u", filename, idx); + if ((t = get_token(&p, &len)) == NULL || + parse_sizerange(t, &sa->minsz, &sa->maxsz) == -1) + errx(1, "%s: parse error on line %u", filename, idx); + if ((t = get_token(&p, &len)) != NULL && + parse_pct(t, &sa->rate) == -1) + errx(1, "%s: parse error on line %u", filename, idx); + if (sa->minsz > sa->maxsz) + errx(1, "%s: min size > max size on line %u", filename, + idx); + pctsum += sa->rate; + } + if (pctsum > 100) + errx(1, "%s: sum of extra space allocation > 100%%", filename); + alloc_table[0].sz = idx; + fclose(cfile); +} + +char * +get_token(char **s, size_t *len) +{ + char *p, *r; + size_t tlen = 0; + + p = *s; + while (*len > 0 && !isspace((u_char)*s[0])) { + (*s)++; + (*len)--; + tlen++; + } + if (tlen == 0) + return (NULL); + + /* eat whitespace */ + while (*len > 0 && isspace((u_char)*s[0])) { + (*s)++; + (*len)--; + } + + tlen++; /* null termination */ + if ((r = malloc(tlen)) == NULL) + err(1, NULL); + strlcpy(r, p, tlen); + return (r); +} + +int +apply_unit(double val, u_char unit, u_int64_t *n) +{ + u_int64_t factor = 1; + + switch (tolower(unit)) { + case 't': + factor *= 1024; + /* FALLTHROUGH */ + case 'g': + factor *= 1024; + /* FALLTHROUGH */ + case 'm': + factor *= 1024; + /* FALLTHROUGH */ + case 'k': + factor *= 1024; + break; + default: + return (-1); + } + + val *= factor / DEV_BSIZE; + if (val > ULLONG_MAX) + return (-1); + *n = val; + return (0); +} + +int +parse_sizespec(const char *buf, double *val, char **unit) +{ + *val = strtod(buf, unit); + if ((*val == 0 && *unit == buf) || *val <= 0) + return (-1); + if (*unit != NULL && *unit[0] == '\0') + *unit = NULL; + return (0); +} + +int +parse_sizerange(char *buf, u_int64_t *min, u_int64_t *max) +{ + char *p, *unit1 = NULL, *unit2 = NULL; + double val1 = 0, val2 = 0; + + if ((p = strchr(buf, '-')) != NULL) { + p[0] = '\0'; + p++; + } + *max = 0; + if (parse_sizespec(buf, &val1, &unit1) == -1) + return (-1); + if (p != NULL && p[0] != '\0') { + if (p[0] == '*') + *max = -1; + else + if (parse_sizespec(p, &val2, &unit2) == -1) + return (-1); + } + if (unit1 == NULL && (unit1 = unit2) == NULL) + return (-1); + if (apply_unit(val1, unit1[0], min) == -1) + return (-1); + if (val2 > 0) { + if (apply_unit(val2, unit2[0], max) == -1) + return (-1); + } else + if (*max == 0) + *max = *min; + free(buf); + return (0); +} + +int +parse_pct(char *buf, int *n) +{ + const char *errstr; + + if (buf[strlen(buf) - 1] == '%') + buf[strlen(buf) - 1] = '\0'; + *n = strtonum(buf, 0, 100, &errstr); + if (errstr) { + warnx("parse percent %s: %s", buf, errstr); + return (-1); + } + free(buf); + return (0); +} diff --git a/sbin/disklabel/extern.h b/sbin/disklabel/extern.h index 2ddea11139d..92311d4d737 100644 --- a/sbin/disklabel/extern.h +++ b/sbin/disklabel/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.25 2014/07/10 13:31:23 florian Exp $ */ +/* $OpenBSD: extern.h,v 1.26 2015/04/29 09:58:16 henning Exp $ */ /* * Copyright (c) 2003 Theo de Raadt @@ -34,6 +34,7 @@ void editor_allocspace(struct disklabel *); void mpsave(struct disklabel *); void mpcopy(char **, char **); void mpfree(char **); +void parse_autotable(char *); int writelabel(int, char *, struct disklabel *); extern char bootarea[], *specname, *fstabfile; -- 2.20.1