Changeset View
Standalone View
usr.bin/mkimg/mkimg.c
| Show All 29 Lines | |||||
| #include <sys/param.h> | #include <sys/param.h> | ||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||
| #include <errno.h> | #include <errno.h> | ||||
| #include <err.h> | #include <err.h> | ||||
| #include <fcntl.h> | #include <fcntl.h> | ||||
| #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> | ||||
| #include <string.h> | #include <string.h> | ||||
| #include <sysexits.h> | #include <sysexits.h> | ||||
| #include <unistd.h> | #include <unistd.h> | ||||
| #include "image.h" | #include "image.h" | ||||
| ▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | usage(const char *why) | ||||
| fprintf(stderr, "\t-S <num>\t- logical sector size\n"); | fprintf(stderr, "\t-S <num>\t- logical sector size\n"); | ||||
| fprintf(stderr, "\t-T <num>\t- number of tracks to simulate\n"); | fprintf(stderr, "\t-T <num>\t- number of tracks to simulate\n"); | ||||
| fputc('\n', stderr); | fputc('\n', stderr); | ||||
| print_formats(1); | print_formats(1); | ||||
| fputc('\n', stderr); | fputc('\n', stderr); | ||||
| 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 " | ||||
| "label\n"); | "label\n"); | ||||
| exit(EX_USAGE); | exit(EX_USAGE); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 204 Lines • ▼ Show 20 Lines | if (max_capsz != 0 && end > max_capsz) | ||||
| return (ENOSPC); | return (ENOSPC); | ||||
| if (end >= min_capsz) | if (end >= min_capsz) | ||||
| return (0); | return (0); | ||||
| return (image_set_size(min_capsz)); | return (image_set_size(min_capsz)); | ||||
| } | } | ||||
| static void | 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 | |||||
| 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 */ | ||||
| TAILQ_FOREACH(part, &partlist, link) { | TAILQ_FOREACH(part, &partlist, link) { | ||||
| error = scheme_check_part(part); | error = scheme_check_part(part); | ||||
| if (error) | if (error) | ||||
| errc(EX_DATAERR, error, "partition %d", part->index+1); | errc(EX_DATAERR, error, "partition %d", part->index+1); | ||||
| } | } | ||||
| 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) { | ||||
| error = image_copyin(block, fd, &bytesize); | error = image_copyin(block, fd, &bytesize); | ||||
| close(fd); | close(fd); | ||||
| } else | } else | ||||
| error = errno; | error = errno; | ||||
| break; | break; | ||||
| case PART_KIND_PIPE: | case PART_KIND_PIPE: | ||||
| fp = popen(part->contents, "r"); | fp = popen(part->contents, "r"); | ||||
| if (fp != NULL) { | if (fp != NULL) { | ||||
| fd = fileno(fp); | fd = fileno(fp); | ||||
| error = image_copyin(block, fd, &bytesize); | error = image_copyin(block, fd, &bytesize); | ||||
| pclose(fp); | pclose(fp); | ||||
| } else | } else | ||||
| error = errno; | error = errno; | ||||
| break; | break; | ||||
| } | } | ||||
| if (error) | if (error) | ||||
| errc(EX_IOERR, error, "partition %d", part->index + 1); | errc(EX_IOERR, error, "partition %d", part->index + 1); | ||||
| part->size = (bytesize + secsz - 1) / secsz; | part->size = (bytesize + secsz - 1) / secsz; | ||||
| if (verbose) { | if (verbose) { | ||||
| bytesize = part->size * secsz; | bytesize = part->size * secsz; | ||||
imp: I almost wonder if we need to have an adjustment here to make sure that the partition starts at… | |||||
Done Inline ActionsWould that be the track size? I'm happy to work that in. Or should that be in the scheme-specific code? benno: Would that be the track size? I'm happy to work that in. Or should that be in the scheme… | |||||
Done Inline ActionsI think it is one of the block scheme metadata callbacks. imp: I think it is one of the block scheme metadata callbacks. | |||||
| 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); | ||||
Not Done Inline ActionsWhy isn't this done at the top of loop? imp: Why isn't this done at the top of loop? | |||||
Not Done Inline ActionsBecause we don't know the value of abs_offset until the switch statement. benno: Because we don't know the value of abs_offset until the switch statement. | |||||
| 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) { | |||||
Done Inline Actionsthis should be always. the additional padding needs to be adjusted. imp: this should be always. the additional padding needs to be adjusted.
| |||||
Done Inline ActionsExcept that if I do this the next partition is placed after the absolutely-located one I just placed which throws a whole bunch of things off. If we're going to do this I'd probably prefer to come up with a whole new format for -p which specifically indicates a synthetic partition that we're not actually feeding anything in to and for which all placement rules are relaxed. i.e. we'll create the entry and it's up to you to provide the "truth" of it in some other way. benno: Except that if I do this the next partition is placed after the absolutely-located one I just… | |||||
Done Inline Actionsthen that next one needs to have its start adjusted as well, or rejected as not possible. But we have to have the proper structure even when specifying things at offsets. imp: then that next one needs to have its start adjusted as well, or rejected as not possible. But… | |||||
| block = scheme_metadata(SCHEME_META_PART_AFTER, | block = scheme_metadata(SCHEME_META_PART_AFTER, | ||||
| part->block + part->size); | 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) { | ||||
| error = capacity_resize(block); | error = capacity_resize(block); | ||||
| block = image_get_size(); | block = image_get_size(); | ||||
| } | } | ||||
| if (!error) { | if (!error) { | ||||
| ▲ Show 20 Lines • Show All 189 Lines • Show Last 20 Lines | |||||
I almost wonder if we need to have an adjustment here to make sure that the partition starts at an acceptable location. Some partitioning scheme get fussy if you don't do things on a cylinder boundary.