Add the ability to specify absolute and relative offsets to size partitions.

To create hybrid boot media we want to specify a partition at a known location.
This extends the syntax of size partitions to include an optional offset that
can be absolute or relative. It also introduces validation to make sure that
this hasn't resulted in overlapping partitions. I haven't added this to the
file and process partition specifications yet but the mechanics are designed
such that if someone comes up with a good way of specifying the offset it
will be fairly easy to add in.

Reviewed by:	imp
Sponsored by:	iXsystems, Inc.
Differential Revision:	https://reviews.freebsd.org/D14916
This commit is contained in:
Benno Rice 2018-04-12 15:47:47 +00:00
parent 3d5b3b0a44
commit 459a61fd2d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=332436
2 changed files with 104 additions and 21 deletions

View File

@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <getopt.h> #include <getopt.h>
#include <libutil.h> #include <libutil.h>
#include <limits.h> #include <limits.h>
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -170,13 +171,14 @@ usage(const char *why)
print_schemes(1); print_schemes(1);
fputc('\n', stderr); fputc('\n', stderr);
fprintf(stderr, " partition specification:\n"); fprintf(stderr, " partition specification:\n");
fprintf(stderr, "\t<t>[/<l>]::<size>\t- empty partition of given " fprintf(stderr, "\t<t>[/<l>]::<size>[:[+]<offset>]\t- "
"size\n"); "empty partition of given size and\n\t\t\t\t\t"
fprintf(stderr, "\t<t>[/<l>]:=<file>\t- partition content and size " " optional relative or absolute offset\n");
"are determined\n\t\t\t\t by the named file\n"); fprintf(stderr, "\t<t>[/<l>]:=<file>\t\t- partition content and size "
fprintf(stderr, "\t<t>[/<l>]:-<cmd>\t- partition content and size " "are\n\t\t\t\t\t determined by the named file\n");
"are taken from\n\t\t\t\t the output of the command to run\n"); fprintf(stderr, "\t<t>[/<l>]:-<cmd>\t\t- partition content and size "
fprintf(stderr, "\t-\t\t\t- unused partition entry\n"); "are taken\n\t\t\t\t\t from the output of the command to run\n");
fprintf(stderr, "\t-\t\t\t\t- unused partition entry\n");
fprintf(stderr, "\t where:\n"); fprintf(stderr, "\t where:\n");
fprintf(stderr, "\t\t<t>\t- scheme neutral partition type\n"); fprintf(stderr, "\t\t<t>\t- scheme neutral partition type\n");
fprintf(stderr, "\t\t<l>\t- optional scheme-dependent partition " fprintf(stderr, "\t\t<l>\t- optional scheme-dependent partition "
@ -396,13 +398,49 @@ capacity_resize(lba_t end)
return (image_set_size(min_capsz)); return (image_set_size(min_capsz));
} }
static void
mkimg_validate(void)
{
struct part *part, *part2;
lba_t start, end, start2, end2;
int i, j;
i = 0;
TAILQ_FOREACH(part, &partlist, link) {
start = part->block;
end = part->block + part->size;
j = i + 1;
part2 = TAILQ_NEXT(part, link);
if (part2 == NULL)
break;
TAILQ_FOREACH_FROM(part2, &partlist, link) {
start2 = part2->block;
end2 = part2->block + part2->size;
if ((start >= start2 && start < end2) ||
(end > start2 && end <= end2)) {
errx(1, "partition %d overlaps partition %d",
i, j);
}
j++;
}
i++;
}
}
static void static void
mkimg(void) mkimg(void)
{ {
FILE *fp; FILE *fp;
struct part *part; struct part *part;
lba_t block; lba_t block, blkoffset;
off_t bytesize; off_t bytesize, byteoffset;
char *size, *offset;
bool abs_offset;
int error, fd; int error, fd;
/* First check partition information */ /* First check partition information */
@ -413,17 +451,46 @@ mkimg(void)
} }
block = scheme_metadata(SCHEME_META_IMG_START, 0); block = scheme_metadata(SCHEME_META_IMG_START, 0);
abs_offset = false;
TAILQ_FOREACH(part, &partlist, link) { TAILQ_FOREACH(part, &partlist, link) {
block = scheme_metadata(SCHEME_META_PART_BEFORE, block); byteoffset = blkoffset = 0;
if (verbose) abs_offset = false;
fprintf(stderr, "partition %d: starting block %llu "
"... ", part->index + 1, (long long)block); /* Look for an offset. Set size too if we can. */
part->block = block;
switch (part->kind) { switch (part->kind) {
case PART_KIND_SIZE: case PART_KIND_SIZE:
if (expand_number(part->contents, &bytesize) == -1) offset = part->contents;
size = strsep(&offset, ":");
if (expand_number(size, &bytesize) == -1)
error = errno; error = errno;
if (offset != NULL) {
if (*offset != '+') {
abs_offset = true;
offset++;
}
if (expand_number(offset, &byteoffset) == -1)
error = errno;
}
break; break;
}
/* Work out exactly where the partition starts. */
blkoffset = (byteoffset + secsz - 1) / secsz;
if (abs_offset) {
part->block = scheme_metadata(SCHEME_META_PART_ABSOLUTE,
blkoffset);
} else {
block = scheme_metadata(SCHEME_META_PART_BEFORE,
block + blkoffset);
part->block = block;
}
if (verbose)
fprintf(stderr, "partition %d: starting block %llu "
"... ", part->index + 1, (long long)part->block);
/* Pull in partition contents, set size if we haven't yet. */
switch (part->kind) {
case PART_KIND_FILE: case PART_KIND_FILE:
fd = open(part->contents, O_RDONLY, 0); fd = open(part->contents, O_RDONLY, 0);
if (fd != -1) { if (fd != -1) {
@ -449,11 +516,26 @@ mkimg(void)
bytesize = part->size * secsz; bytesize = part->size * secsz;
fprintf(stderr, "size %llu bytes (%llu blocks)\n", fprintf(stderr, "size %llu bytes (%llu blocks)\n",
(long long)bytesize, (long long)part->size); (long long)bytesize, (long long)part->size);
if (abs_offset) {
fprintf(stderr,
" location %llu bytes (%llu blocks)\n",
(long long)byteoffset,
(long long)blkoffset);
} else if (blkoffset > 0) {
fprintf(stderr,
" offset %llu bytes (%llu blocks)\n",
(long long)byteoffset,
(long long)blkoffset);
}
}
if (!abs_offset) {
block = scheme_metadata(SCHEME_META_PART_AFTER,
part->block + part->size);
} }
block = scheme_metadata(SCHEME_META_PART_AFTER,
part->block + part->size);
} }
mkimg_validate();
block = scheme_metadata(SCHEME_META_IMG_END, block); block = scheme_metadata(SCHEME_META_IMG_END, block);
error = image_set_size(block); error = image_set_size(block);
if (!error) { if (!error) {

View File

@ -65,10 +65,11 @@ struct mkimg_scheme {
const char *description; const char *description;
struct mkimg_alias *aliases; struct mkimg_alias *aliases;
lba_t (*metadata)(u_int, lba_t); lba_t (*metadata)(u_int, lba_t);
#define SCHEME_META_IMG_START 1 #define SCHEME_META_IMG_START 1
#define SCHEME_META_IMG_END 2 #define SCHEME_META_IMG_END 2
#define SCHEME_META_PART_BEFORE 3 #define SCHEME_META_PART_BEFORE 3
#define SCHEME_META_PART_AFTER 4 #define SCHEME_META_PART_AFTER 4
#define SCHEME_META_PART_ABSOLUTE 5
int (*write)(lba_t, void *); int (*write)(lba_t, void *);
u_int nparts; u_int nparts;
u_int labellen; u_int labellen;