summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Olbrich <m.olbrich@pengutronix.de>2019-09-22 14:24:14 +0000
committerGitHub <noreply@github.com>2019-09-22 14:24:14 +0000
commitf69e15de765e48869fa26f9a9920557b6a9d2732 (patch)
tree007529e5ed970a560d3ad9945e4af8f03579ea3f
parent1b98d6fadfca76cc0202a2df3debc67a8fe0ee1a (diff)
parent3300b46aeb61d8eb0a723b7a3947ae4d95ba3666 (diff)
downloadgenimage-f69e15de765e48869fa26f9a9920557b6a9d2732.tar.gz
genimage-f69e15de765e48869fa26f9a9920557b6a9d2732.tar.xz
Merge branch 'master' into sparse
-rw-r--r--.travis.yml2
-rw-r--r--Makefile.am2
-rw-r--r--README.rst27
-rw-r--r--config.c17
-rw-r--r--configure.ac2
-rw-r--r--genimage.c18
-rw-r--r--genimage.h9
-rw-r--r--image-hd.c113
-rw-r--r--image-rauc.c31
-rwxr-xr-xtest/basic-images.test17
-rw-r--r--test/ext2percent.config7
-rw-r--r--test/ext2test-percent.dump40
-rw-r--r--test/hdimage.config4
-rw-r--r--util.c109
14 files changed, 335 insertions, 63 deletions
diff --git a/.travis.yml b/.travis.yml
index 395937e..187a7f5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,4 +23,4 @@ script:
- ./configure
- make distcheck
after_failure:
- - cat genimage-*/_build/test-suite.log
+ - find -name test-suite.log -print0 | xargs -0 cat
diff --git a/Makefile.am b/Makefile.am
index 3c96229..d283212 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -51,6 +51,8 @@ EXTRA_DIST += \
test/cramfs.config \
test/ext2.config \
test/ext2test.dump \
+ test/ext2percent.config \
+ test/ext2test-percent.dump \
test/ext3.config \
test/ext3test.dump \
test/ext4.config \
diff --git a/README.rst b/README.rst
index 67a648a..2f62e85 100644
--- a/README.rst
+++ b/README.rst
@@ -68,7 +68,11 @@ Here are all options for images:
:name: The name of this image. This is used for some image types
to set the name of the image.
-:size: Size of this image in bytes
+:size: Size of this image in bytes. 'k', 'M' or 'G' can be used as suffix to
+ specify the size in multiple of 1024 etc. If the image if filled from
+ a mountpoint then '%' as suffix indicates a percentage. '200%' means
+ the resulting filesystem should be about 50% filled. Note that is is
+ only a rough estimate based on the original size of the content.
:mountpoint: mountpoint if image refers to a filesystem image. The
default is "/". The content of "${rootpath}${mountpoint}"
will be used used fill the filesystem.
@@ -89,12 +93,16 @@ Partition options:
:offset: The offset of this partition as a total offset to the beginning
of the device.
-:size: The size of this partition in bytes. The last partition may have
- size 0 to make this partition use the rest of the available space
- on the device.
+:size: The size of this partition in bytes. If the size and
+ autoresize are both not set then the size of the partition
+ image is used.
:partition-type: Used by dos partition tables to specify the partition type.
:image: The image file this partition shall be filled with
-:autoresize: used by ubi (FIXME: do we need this? Isn't size = 0 enough)
+:autoresize: Boolean specifying that the partition should be resized
+ automatically. For UBI volumes this means that the
+ ``autoresize`` flag is set. Only one volume can have this flag.
+ For hd images this can be used for the last partition. If set
+ the partition will fill the remaining space of the image.
:bootable: Boolean specifying whether to set the bootable flag.
:in-partition-table: Boolean specifying whether to include this partition in
the partition table.
@@ -181,9 +189,16 @@ Options:
:extended-partition: Number of the extended partition. Contains the number of the
extended partition between 1 and 4 or 0 for automatic. Defaults
to 0.
-:disk-signature: 32 bit integer used as disk signature (offset 440 in the MBR)
+:disk-signature: 32 bit integer used as disk signature (offset 440 in the
+ MBR). Using a special value ``random`` will result in
+ using random 32 bit number.
:gpt: Boolean. If true, a GPT type partion table is written. If false
a DOS type partition table is written. Defaults to false.
+:gpt-location: Location of the GPT table. Occasionally useful for moving the GPT
+ table away from where a bootloader is placed due to hardware
+ requirements. All partitions in the table must begin after this
+ table. Regardless of this setting, the GPT header will still be
+ placed at 512 bytes (sector 1). Defaults to 1024 bytes (sector 2).
:disk-uuid: UUID string used as disk id in GPT partitioning. Defaults to a
random value.
diff --git a/config.c b/config.c
index 3e5ab80..b0dd721 100644
--- a/config.c
+++ b/config.c
@@ -152,7 +152,22 @@ unsigned long long cfg_getint_suffix(cfg_t *sec, const char *name)
unsigned long long val = 0;
if (str)
- val = strtoul_suffix(str, NULL, 0);
+ val = strtoul_suffix(str, NULL, NULL);
+
+ return val;
+}
+
+/*
+ * Like cfg_getint_suffix() but allow '%' as suffix as well
+ */
+unsigned long long cfg_getint_suffix_percent(cfg_t *sec, const char *name,
+ cfg_bool_t *percent)
+{
+ const char *str = cfg_getstr(sec, name);
+ unsigned long long val = 0;
+
+ if (str)
+ val = strtoul_suffix(str, NULL, percent);
return val;
}
diff --git a/configure.ac b/configure.ac
index 563b969..95e902d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ(2.60)
AC_INIT([genimage],
- [10],
+ [11],
[oss-tools@pengutronix.de],
[genimage],
[http://www.pengutronix.de/genimage/])
diff --git a/genimage.c b/genimage.c
index 64a7b2e..aafd3b7 100644
--- a/genimage.c
+++ b/genimage.c
@@ -157,6 +157,11 @@ static int image_setup(struct image *image)
image->seen = -1;
+ if (image->size_is_percent) {
+ image->size = image_dir_size(image) * image->size / 100;
+ image->size_is_percent = cfg_false;
+ }
+
list_for_each_entry(part, &image->partitions, list) {
struct image *child;
if (!part->image)
@@ -387,7 +392,7 @@ static struct mountpoint *add_mountpoint(const char *path)
path_sanitized = sanitize_path(path);
mp = xzalloc(sizeof(*mp));
mp->path = strdup(path);
- xasprintf(&mp->mountpath, "%s/%s", tmppath(), path_sanitized);
+ xasprintf(&mp->mountpath, "%s/mp-%s", tmppath(), path_sanitized);
list_add_tail(&mp->list, &mountpoints);
free(path_sanitized);
@@ -664,7 +669,8 @@ int main(int argc, char *argv[])
list_add_tail(&image->list, &images);
image->file = cfg_title(imagesec);
image->name = cfg_getstr(imagesec, "name");
- image->size = cfg_getint_suffix(imagesec, "size");
+ image->size = cfg_getint_suffix_percent(imagesec, "size",
+ &image->size_is_percent);
image->mountpoint = cfg_getstr(imagesec, "mountpoint");
image->exec_pre = cfg_getstr(imagesec, "exec-pre");
image->exec_post = cfg_getstr(imagesec, "exec-post");
@@ -717,6 +723,10 @@ int main(int argc, char *argv[])
if (ret)
goto cleanup;
+ ret = collect_mountpoints();
+ if (ret)
+ goto cleanup;
+
list_for_each_entry(image, &images, list) {
ret = image_setup(image);
if (ret)
@@ -731,10 +741,6 @@ int main(int argc, char *argv[])
if (ret)
goto cleanup;
- ret = collect_mountpoints();
- if (ret)
- goto cleanup;
-
list_for_each_entry(image, &images, list) {
ret = setenv_image(image);
if (ret)
diff --git a/genimage.h b/genimage.h
index e339d1d..eabcc46 100644
--- a/genimage.h
+++ b/genimage.h
@@ -51,6 +51,7 @@ struct image {
const char *name;
const char *file;
unsigned long long size;
+ cfg_bool_t size_is_percent;
const char *mountpoint;
const char *exec_pre;
const char *exec_post;
@@ -124,7 +125,8 @@ extern struct image_handler fit_handler;
(type *)( (char *)__mptr - offsetof(type,member) );})
void *xzalloc(size_t n);
-unsigned long long strtoul_suffix(const char *str, char **endp, int base);
+unsigned long long strtoul_suffix(const char *str, char **endp,
+ cfg_bool_t *percent);
int init_config(void);
cfg_opt_t *get_confuse_opts(void);
@@ -141,9 +143,12 @@ int pad_file(struct image *image, const char *infile,
size_t size, unsigned char fillpattern, enum pad_mode mode);
int insert_data(struct image *image, const char *data, const char *outfile,
size_t size, long offset);
+int extend_file(struct image *image, size_t size);
int reload_partitions(struct image *image);
unsigned long long cfg_getint_suffix(cfg_t *sec, const char *name);
+unsigned long long cfg_getint_suffix_percent(cfg_t *sec, const char *name,
+ cfg_bool_t *percent);
static inline const char *imageoutfile(const struct image *image)
{
@@ -154,6 +159,8 @@ int uuid_validate(const char *str);
void uuid_parse(const char *str, unsigned char *uuid);
char *uuid_random(void);
+unsigned long long image_dir_size(struct image *image);
+
uint32_t crc32(const void *data, size_t len);
#endif /* __PTX_IMAGE_H */
diff --git a/image-hd.c b/image-hd.c
index 2c2860c..fcb05d3 100644
--- a/image-hd.c
+++ b/image-hd.c
@@ -33,6 +33,8 @@ struct hdimage {
uint32_t disksig;
const char *disk_uuid;
cfg_bool_t gpt;
+ unsigned long long gpt_location;
+ cfg_bool_t fill;
};
struct mbr_partition_entry {
@@ -78,6 +80,8 @@ struct gpt_partition_entry {
#define GPT_SECTORS (1 + GPT_ENTRIES * sizeof(struct gpt_partition_entry) / 512)
#define GPT_REVISION_1_0 0x00010000
+#define GPT_PE_FLAG_BOOTABLE (1 << 2)
+
static void hdimage_setup_chs(unsigned int lba, unsigned char *chs)
{
const unsigned int hpc = 255;
@@ -258,14 +262,14 @@ static int hdimage_insert_gpt(struct image *image, struct list_head *partitions)
header.backup_lba = htole64(image->size/512 - 1);
header.last_usable_lba = htole64(image->size/512 - 1 - GPT_SECTORS);
uuid_parse(hd->disk_uuid, header.disk_uuid);
- header.starting_lba = htole64(2);
+ header.starting_lba = htole64(hd->gpt_location/512);
header.number_entries = htole32(GPT_ENTRIES);
header.entry_size = htole32(sizeof(struct gpt_partition_entry));
i = 0;
memset(&table, 0, sizeof(table));
list_for_each_entry(part, partitions, list) {
- if (header.first_usable_lba == 0)
+ if (header.first_usable_lba == 0 && part->in_partition_table)
header.first_usable_lba = htole64(part->offset / 512);
if (!part->in_partition_table)
@@ -275,6 +279,7 @@ static int hdimage_insert_gpt(struct image *image, struct list_head *partitions)
uuid_parse(part->partition_uuid, table[i].uuid);
table[i].first_lba = htole64(part->offset/512);
table[i].last_lba = htole64((part->offset + part->size)/512 - 1);
+ table[i].flags = part->bootable ? GPT_PE_FLAG_BOOTABLE : 0;
for (j = 0; j < strlen(part->name) && j < 36; j++)
table[i].name[j] = htole16(part->name[j]);
i++;
@@ -287,7 +292,7 @@ static int hdimage_insert_gpt(struct image *image, struct list_head *partitions)
image_error(image, "failed to write GPT\n");
return ret;
}
- ret = insert_data(image, (char *)&table, outfile, sizeof(table), 2*512);
+ ret = insert_data(image, (char *)&table, outfile, sizeof(table), hd->gpt_location);
if (ret) {
image_error(image, "failed to write GPT table\n");
return ret;
@@ -303,6 +308,7 @@ static int hdimage_insert_gpt(struct image *image, struct list_head *partitions)
header.header_crc = 0;
header.current_lba = htole64(image->size/512 - 1);
header.backup_lba = htole64(1);
+ header.starting_lba = htole64(image->size/512 - GPT_SECTORS);
header.header_crc = htole32(crc32(&header, sizeof(header)));
ret = insert_data(image, (char *)&table, outfile, sizeof(table),
image->size - GPT_SECTORS*512);
@@ -376,6 +382,14 @@ static int hdimage_generate(struct image *image)
}
}
+ if (hd->fill) {
+ ret = extend_file(image, image->size);
+ if (ret) {
+ image_error(image, "failed to fill the image.\n");
+ return ret;
+ }
+ }
+
if (hd->partition_table) {
if (hd->gpt) {
ret = hdimage_insert_gpt(image, &image->partitions);
@@ -401,16 +415,19 @@ static unsigned long long roundup(unsigned long long value, unsigned long long a
static int hdimage_setup(struct image *image, cfg_t *cfg)
{
struct partition *part;
- int has_extended;
+ int has_extended, autoresize = 0;
unsigned int partition_table_entries = 0;
unsigned long long now = 0;
+ const char *disk_signature;
struct hdimage *hd = xzalloc(sizeof(*hd));
hd->align = cfg_getint_suffix(cfg, "align");
hd->partition_table = cfg_getbool(cfg, "partition-table");
hd->extended_partition = cfg_getint(cfg, "extended-partition");
- hd->disksig = strtoul(cfg_getstr(cfg, "disk-signature"), NULL, 0);
+ disk_signature = cfg_getstr(cfg, "disk-signature");
hd->gpt = cfg_getbool(cfg, "gpt");
+ hd->gpt_location = cfg_getint_suffix(cfg, "gpt-location");
+ hd->fill = cfg_getbool(cfg, "fill");
hd->disk_uuid = cfg_getstr(cfg, "disk-uuid");
if (hd->extended_partition > 4) {
@@ -443,35 +460,30 @@ static int hdimage_setup(struct image *image, cfg_t *cfg)
hd->disk_uuid = uuid_random();
}
+ if (!strcmp(disk_signature, "random"))
+ hd->disksig = random();
+ else
+ hd->disksig = strtoul(disk_signature, NULL, 0);
+
+ if (hd->gpt_location == 0) {
+ hd->gpt_location = 2*512;
+ }
+ else if (hd->gpt_location % 512) {
+ image_error(image, "GPT table location (%lld) must be a "
+ "multiple of 1 sector (512 bytes)", hd->gpt_location);
+ }
+
partition_table_entries = 0;
list_for_each_entry(part, &image->partitions, list) {
- if (part->image) {
- struct image *child = image_get(part->image);
- if (!child) {
- image_error(image, "could not find %s\n",
- part->image);
- return -EINVAL;
- }
- if (!part->size) {
- if (part->in_partition_table)
- part->size = roundup(child->size, hd->align);
- else
- part->size = child->size;
- } else if (child->size > part->size) {
- image_error(image, "part %s size (%lld) too small for %s (%lld)\n",
- part->name, part->size, child->file, child->size);
- return -EINVAL;
- }
- }
- if (!part->size) {
- image_error(image, "part %s size must not be zero\n",
- part->name);
+ if (autoresize) {
+ image_error(image, "'autoresize' is only supported "
+ "for the last partition\n");
return -EINVAL;
}
- if (part->in_partition_table && (part->size % 512)) {
- image_error(image, "part %s size (%lld) must be a "
- "multiple of 1 sector (512 bytes)\n",
- part->name, part->size);
+ autoresize = part->autoresize;
+ if (autoresize && image->size == 0) {
+ image_error(image, "the images size must be specified "
+ "when using a 'autoresize' partition\n");
return -EINVAL;
}
if (hd->gpt) {
@@ -535,6 +547,45 @@ static int hdimage_setup(struct image *image, cfg_t *cfg)
}
part->offset = roundup(now, hd->align);
}
+ if (autoresize) {
+ long long partsize = image->size - now;
+ if (hd->gpt)
+ partsize -= GPT_SECTORS * 512;
+ if (partsize < 0) {
+ image_error(image, "partitions exceed device size\n");
+ return -EINVAL;
+ }
+ part->size = partsize;
+ }
+ if (part->image) {
+ struct image *child = image_get(part->image);
+ if (!child) {
+ image_error(image, "could not find %s\n",
+ part->image);
+ return -EINVAL;
+ }
+ if (!part->size) {
+ if (part->in_partition_table)
+ part->size = roundup(child->size, hd->align);
+ else
+ part->size = child->size;
+ } else if (child->size > part->size) {
+ image_error(image, "part %s size (%lld) too small for %s (%lld)\n",
+ part->name, part->size, child->file, child->size);
+ return -EINVAL;
+ }
+ }
+ if (!part->size) {
+ image_error(image, "part %s size must not be zero\n",
+ part->name);
+ return -EINVAL;
+ }
+ if (part->in_partition_table && (part->size % 512)) {
+ image_error(image, "part %s size (%lld) must be a "
+ "multiple of 1 sector (512 bytes)\n",
+ part->name, part->size);
+ return -EINVAL;
+ }
now = part->offset + part->size;
}
@@ -561,6 +612,8 @@ cfg_opt_t hdimage_opts[] = {
CFG_BOOL("partition-table", cfg_true, CFGF_NONE),
CFG_INT("extended-partition", 0, CFGF_NONE),
CFG_BOOL("gpt", cfg_false, CFGF_NONE),
+ CFG_STR("gpt-location", NULL, CFGF_NONE),
+ CFG_BOOL("fill", cfg_false, CFGF_NONE),
CFG_END()
};
diff --git a/image-rauc.c b/image-rauc.c
index 79aab10..c4195a3 100644
--- a/image-rauc.c
+++ b/image-rauc.c
@@ -91,29 +91,36 @@ static int rauc_generate(struct image *image)
static int rauc_parse(struct image *image, cfg_t *cfg)
{
+ const char *pkcs11_prefix = "pkcs11:";
unsigned int i;
unsigned int num_files;
struct partition *part;
+ char *part_image_key;
+ char *part_image_cert;
- part = xzalloc(sizeof *part);
- part->image = cfg_getstr(image->imagesec, "key");
- if (!part->image) {
+ part_image_key = cfg_getstr(image->imagesec, "key");
+ if (!part_image_key) {
image_error(image, "Mandatory 'key' option is missing!\n");
- free(part);
return -EINVAL;
}
- part->partition_type = RAUC_KEY;
- list_add_tail(&part->list, &image->partitions);
+ if (strncmp(pkcs11_prefix, part_image_key, strlen(pkcs11_prefix))) {
+ part = xzalloc(sizeof *part);
+ part->image = part_image_key;
+ part->partition_type = RAUC_KEY;
+ list_add_tail(&part->list, &image->partitions);
+ }
- part = xzalloc(sizeof *part);
- part->image = cfg_getstr(image->imagesec, "cert");
- if (!part->image) {
+ part_image_cert = cfg_getstr(image->imagesec, "cert");
+ if (!part_image_cert) {
image_error(image, "Mandatory 'cert' option is missing!\n");
- free(part);
return -EINVAL;
}
- part->partition_type = RAUC_CERT;
- list_add_tail(&part->list, &image->partitions);
+ if (strncmp(pkcs11_prefix, part_image_cert, strlen(pkcs11_prefix))) {
+ part = xzalloc(sizeof *part);
+ part->image = part_image_cert;
+ part->partition_type = RAUC_CERT;
+ list_add_tail(&part->list, &image->partitions);
+ }
num_files = cfg_size(cfg, "file");
for (i = 0; i < num_files; i++) {
diff --git a/test/basic-images.test b/test/basic-images.test
index e1cd784..d35898f 100755
--- a/test/basic-images.test
+++ b/test/basic-images.test
@@ -89,6 +89,14 @@ check_size() {
fi
}
+sfdisk_validate() {
+ if [ -n "$(sfdisk -q -V "${1}" 2>&1 | grep -v unallocated)" ]; then
+ echo "'sfdisk -V' failed with:"
+ sfdisk -V "${1}" 2>&1
+ return 1
+ fi
+}
+
get_disk_usage() {
local file="${1}"
if [ ! -f "${file}" ]; then
@@ -176,6 +184,11 @@ test_expect_success genext2fs,e2fsck "ext2" "
check_ext images/test.ext2 ext2test 4194304
"
+test_expect_success genext2fs,e2fsck "ext2percent" "
+ run_genimage ext2percent.config test.ext2 &&
+ check_ext images/test.ext2 ext2test-percent 69632
+"
+
test_expect_success genext2fs,e2fsck "ext3" "
run_genimage ext3.config test.ext3 &&
check_ext images/test.ext3 ext3test 4194304
@@ -212,7 +225,8 @@ exec_test_set_prereq sfdisk
test_expect_success fdisk,sfdisk "hdimage" "
setup_test_images &&
run_genimage hdimage.config test.hdimage &&
- check_size images/test.hdimage 9442816 &&
+ check_size images/test.hdimage 10485760 &&
+ sfdisk_validate images/test.hdimage &&
check_disk_usage_range images/test.hdimage 40960 57344 &&
# check the this identifier
fdisk -l images/test.hdimage | grep identifier: > hdimage.fdisk &&
@@ -240,6 +254,7 @@ test_expect_success fdisk-gpt,sfdisk-gpt "hdimage4" "
setup_test_images &&
run_genimage hdimage4.config test.hdimage &&
check_size images/test.hdimage 7356928 &&
+ sfdisk_validate images/test.hdimage &&
# check the this identifier
fdisk -l images/test.hdimage | grep identifier: > hdimage4.fdisk &&
# check partitions; filter output to handle different sfdisk versions
diff --git a/test/ext2percent.config b/test/ext2percent.config
new file mode 100644
index 0000000..f9cd848
--- /dev/null
+++ b/test/ext2percent.config
@@ -0,0 +1,7 @@
+image test.ext2 {
+ ext2 {
+ label = "ext2test"
+ fs-timestamp = "20000101000000"
+ }
+ size = 100%
+}
diff --git a/test/ext2test-percent.dump b/test/ext2test-percent.dump
new file mode 100644
index 0000000..f771eb4
--- /dev/null
+++ b/test/ext2test-percent.dump
@@ -0,0 +1,40 @@
+Filesystem volume name: ext2test
+Last mounted on: <not available>
+Filesystem magic number: 0xEF53
+Filesystem revision #: 0 (original)
+Filesystem features: (none)
+Default mount options: (none)
+Filesystem state: clean
+Errors behavior: Unknown (continue)
+Filesystem OS type: Linux
+Inode count: 56
+Block count: 68
+Reserved block count: 3
+Free blocks: 36
+Free inodes: 5
+First block: 1
+Block size: 1024
+Fragment size: 1024
+Blocks per group: 72
+Fragments per group: 72
+Inodes per group: 56
+Inode blocks per group: 7
+Filesystem created: Sat Jan 1 00:00:00 2000
+Last mount time: n/a
+Last write time: Sat Jan 1 00:00:00 2000
+Mount count: 0
+Maximum mount count: 20
+Last checked: Sat Jan 1 00:00:00 2000
+Check interval: 0 (<none>)
+Reserved blocks uid: 0 (user root)
+Reserved blocks gid: 0 (group root)
+
+
+Group 0: (Blocks 1-67)
+ Primary superblock at 1, Group descriptors at 2-2
+ Block bitmap at 3 (+2)
+ Inode bitmap at 4 (+3)
+ Inode table at 5-11 (+4)
+ 36 free blocks, 5 free inodes, 18 directories
+ Free blocks: 32-67
+ Free inodes: 52-56
diff --git a/test/hdimage.config b/test/hdimage.config
index 7287b6d..09978c4 100644
--- a/test/hdimage.config
+++ b/test/hdimage.config
@@ -1,6 +1,7 @@
image test.hdimage {
hdimage {
align = 1M
+ fill = true
disk-signature = 0x12345678
}
partition part1 {
@@ -68,7 +69,8 @@ image test.hdimage-2 {
}
partition part6 {
image = "part2.img"
- size = 1M
+ autoresize = true
partition-type = 0x83
}
+ size = 12M
}
diff --git a/util.c b/util.c
index 2310c90..39c3ba2 100644
--- a/util.c
+++ b/util.c
@@ -29,6 +29,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
+#include <dirent.h>
#include "genimage.h"
@@ -252,12 +253,16 @@ void *xzalloc(size_t n)
* Like simple_strtoul() but handles an optional G, M, K or k
* suffix for Gigabyte, Megabyte or Kilobyte
*/
-unsigned long long strtoul_suffix(const char *str, char **endp, int base)
+unsigned long long strtoul_suffix(const char *str, char **endp,
+ cfg_bool_t *percent)
{
unsigned long long val;
char *end;
- val = strtoull(str, &end, base);
+ val = strtoull(str, &end, 0);
+
+ if (percent)
+ *percent = cfg_false;
switch (*end) {
case 'G':
@@ -272,6 +277,12 @@ unsigned long long strtoul_suffix(const char *str, char **endp, int base)
end++;
case '\0':
break;
+ case '%':
+ if (percent) {
+ *percent = cfg_true;
+ break;
+ }
+ /* fall-through */
default:
error("Invalid size suffix '%s' in '%s'\n", end, str);
exit(1);
@@ -449,7 +460,7 @@ int pad_file(struct image *image, const char *infile,
if (!infile) {
if ((unsigned long long)s.st_size > size) {
- image_error(image, "input file '%s' too large\n", outfile);
+ image_error(image, "output file '%s' too large\n", outfile);
ret = -EINVAL;
goto err_out;
}
@@ -566,6 +577,49 @@ err_out:
return ret;
}
+int extend_file(struct image *image, size_t size)
+{
+ const char *outfile = imageoutfile(image);
+ char buf = '\0';
+ int f;
+ off_t offset;
+ int ret = 0;
+
+ f = open_file(image, outfile, 0);
+ if (f < 0)
+ return f;
+
+ offset = lseek(f, 0, SEEK_END);
+ if (offset < 0) {
+ ret = -errno;
+ image_error(image, "seek: %s\n", strerror(errno));
+ goto out;
+ }
+ if ((size_t)offset > size) {
+ ret = -EINVAL;
+ image_error(image, "output file is larger than requested size\n");
+ goto out;
+ }
+ if ((size_t)offset == size)
+ goto out;
+
+ if (lseek(f, size - 1, SEEK_SET) < 0) {
+ ret = -errno;
+ image_error(image, "seek %s: %s\n", outfile, strerror(errno));
+ goto out;
+ }
+ ret = write(f, &buf, 1);
+ if (ret < 1) {
+ ret = -errno;
+ image_error(image, "write %s: %s\n", outfile, strerror(errno));
+ goto out;
+ }
+ ret = 0;
+out:
+ close(f);
+ return ret;
+}
+
int uuid_validate(const char *str)
{
int i;
@@ -654,3 +708,52 @@ int reload_partitions(struct image *image)
close(fd);
return 0;
}
+
+#define ROUND_UP(num,align) ((((num) + ((align) - 1)) & ~((align) - 1)))
+
+static unsigned long long dir_size(struct image *image, int dirfd,
+ const char *subdir, size_t blocksize)
+{
+ struct dirent *d;
+ DIR *dir;
+ int fd;
+ unsigned long long size = 0;
+ struct stat st;
+
+ fd = openat(dirfd, subdir, O_RDONLY);
+ if (fd < 0) {
+ image_error(image, "failed to open '%s': %s", subdir,
+ strerror(errno));
+ return 0;
+ }
+
+ dir = fdopendir(dup(fd));
+ if (dir == NULL) {
+ image_error(image, "failed to opendir '%s': %s", subdir,
+ strerror(errno));
+ return 0;
+ }
+ while ((d = readdir(dir)) != NULL) {
+ if (d->d_type == DT_DIR) {
+ if (d->d_name[0] == '.' && (d->d_name[1] == '\0' ||
+ (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+ continue;
+ size += dir_size(image, fd, d->d_name, blocksize);
+ continue;
+ }
+ if (d->d_type != DT_REG)
+ continue;
+ if (fstatat(fd, d->d_name, &st, AT_NO_AUTOMOUNT) < 0) {
+ image_error(image, "failed to stat '%s': %s",
+ d->d_name, strerror(errno));
+ continue;
+ }
+ size += ROUND_UP(st.st_size, blocksize);
+ }
+ return size + blocksize;
+}
+
+unsigned long long image_dir_size(struct image *image)
+{
+ return dir_size(image, AT_FDCWD, mountpath(image), 4096);
+}