pax_global_header00006660000000000000000000000064146415262300014515gustar00rootroot0000000000000052 comment=00009af6e29cfd46909bc8b4180147dda9f82ba8 genimage-18/000077500000000000000000000000001464152623000130635ustar00rootroot00000000000000genimage-18/.github/000077500000000000000000000000001464152623000144235ustar00rootroot00000000000000genimage-18/.github/workflows/000077500000000000000000000000001464152623000164605ustar00rootroot00000000000000genimage-18/.github/workflows/tests.yml000066400000000000000000000024441464152623000203510ustar00rootroot00000000000000name: tests on: [push, pull_request] jobs: build: runs-on: ${{ matrix.os }} strategy: matrix: include: - os: ubuntu-22.04 pkgs: device-tree-compiler rauc simg2img u-boot-tools f2fs-tools arm-trusted-firmware-tools - os: ubuntu-22.04 pkgs: device-tree-compiler rauc simg2img u-boot-tools f2fs-tools arm-trusted-firmware-tools fake: sudo rm /usr/include/linux/fiemap.h /usr/include/linux/fs.h env: ac_cv_func_fallocate=no - os: ubuntu-20.04 pkgs: device-tree-compiler rauc simg2img u-boot-tools f2fs-tools steps: - name: Inspect environment run: | whoami lsb_release -a gcc --version - uses: actions/checkout@v3 - name: Install required packages run: | sudo apt-get update sudo apt-get install dosfstools fakeroot genext2fs genisoimage libconfuse-dev mtd-utils mtools qemu-utils qemu-utils squashfs-tools ${{ matrix.pkgs }} ${{ matrix.fake }} - name: Build & Test (with ${{ matrix.options }}) run: | ./autogen.sh ./configure ${{ matrix.env }} M_COLOR_TESTS=always make distcheck - name: Dump test log if: ${{ failure() }} run: | find -name test-suite.log -print0 | xargs -0 cat genimage-18/.gitignore000066400000000000000000000002601464152623000150510ustar00rootroot00000000000000*.o .deps/ Makefile Makefile.in aclocal.m4 autom4te.cache/ build-aux/ config.h config.h.in config.log config.status configure genimage libtool stamp-h1 /test/*.log /test/*.trs genimage-18/COPYING000066400000000000000000000432541464152623000141260ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. genimage-18/Makefile.am000066400000000000000000000100011464152623000151070ustar00rootroot00000000000000if BUILD_SILENTLY AM_MAKEFLAGS = --no-print-directory endif EXTRA_DIST = \ README.rst \ test.config \ flash.conf ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} AM_CPPFLAGS = \ -include $(top_builddir)/config.h bin_PROGRAMS = genimage genimage_SOURCES = \ genimage.c \ config.c \ util.c \ crc32.c \ image-android-sparse.c \ image-cpio.c \ image-cramfs.c \ image-ext2.c \ image-f2fs.c \ image-file.c \ image-fip.c \ image-fit.c \ image-flash.c \ image-hd.c \ image-iso.c \ image-jffs2.c \ image-qemu.c \ image-rauc.c \ image-squashfs.c \ image-tar.c \ image-ubi.c \ image-ubifs.c \ image-vfat.c genimage_CFLAGS = \ $(AM_CFLAGS) \ $(CONFUSE_CFLAGS) genimage_LDADD = \ $(CONFUSE_LIBS) noinst_HEADERS = \ genimage.h \ list.h EXTRA_DIST += \ $(TESTS) \ test/test-setup.sh \ test/cpio.config \ test/cramfs.config \ test/exec-check.sh \ test/exec-fail.config \ test/exec.config \ test/ext2.config \ test/ext2test.0.dump \ test/ext2test.1.dump \ test/ext2test.2.dump \ test/ext2percent.config \ test/ext2test-percent.0.dump \ test/ext2test-percent.1.dump \ test/ext2test-percent.2.dump \ test/ext3.config \ test/ext3test.0.dump \ test/ext3test.1.dump \ test/ext3test.2.dump \ test/ext4.config \ test/ext4test.0.dump \ test/ext4test.1.dump \ test/ext4test.2.dump \ test/f2fs.config \ test/fip.config \ test/fit.its \ test/fit.config \ test/flash-types.config \ test/flash.config \ test/flash.md5 \ test/gpt-overlap1.config \ test/gpt-overlap2.config \ test/gpt-overlap3.config \ test/gpt-partition-types.config \ test/gpt-partition-types.fdisk \ test/gpt-invalid-partition-type1.config \ test/gpt-invalid-partition-type2.config \ test/hdimage.config \ test/hdimage2.config \ test/hdimage.fdisk \ test/hdimage.fdisk-2 \ test/hdimage4.config \ test/hdimage4.fdisk \ test/hdimage5.config \ test/hdimage5.fdisk \ test/hdimage6.config \ test/hdimage6.fdisk \ test/hdimage7.config \ test/hdimage7.fdisk \ test/hole.config \ test/hdimage-hybrid.config \ test/hdimage-hybrid.fdisk \ test/hdimage-fail1.config \ test/hdimage-fail2.config \ test/hdimage-fail3.config \ test/hdimage-fail4.config \ test/hdimage-fail5.config \ test/hdimage-fail6.config \ test/hdimage-fail7.config \ test/hdimage-fail8.config \ test/hdimage-fail9.config \ test/hdimage-fail10.config \ test/hdimage-fail11.config \ test/hdimage-nopart.config \ test/hdimage-nopart.hexdump \ test/hdimage-forced-primary.config \ test/hdimage-forced-primary.fdisk \ test/include-aaa.fdisk \ test/include-bbb.fdisk \ test/include-ccc.fdisk \ test/include-test.config \ test/include.config \ test/include/aaa/include-test.config \ test/include/bbb/include-test.config \ test/iso.config \ test/jffs2.config \ test/jffs2.md5 \ test/mke2fs.conf \ test/mke2fs.config \ test/mke2fs.0.dump \ test/mke2fs.1.dump \ test/mke2fs.2.dump \ test/mke2fs.3.dump \ test/qemu.config \ test/qemu.qcow.gz \ test/rauc-openssl-ca/ca.cert.pem \ test/rauc-openssl-ca/rauc.cert.pem \ test/rauc-openssl-ca/rauc.key.pem \ test/rauc.config \ test/sharness.sh \ test/sparse.config \ test/squashfs.config \ test/tar.config \ test/test.raucb.info.1 \ test/test.raucb.info.2 \ test/test.raucb.info.3 \ test/test.raucb.info.4 \ test/test2.raucb.info.1 \ test/test2.raucb.info.2 \ test/test2.raucb.info.3 \ test/test2.raucb.info.4 \ test/ubi.config \ test/ubifs.config \ test/vfat.config TEST_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \ $(top_srcdir)/build-aux/tap-driver.sh TEST_LOG_COMPILER = fakeroot TESTS = \ test/genimage.test \ test/ext.test \ test/filesystem.test \ test/flash.test \ test/hdimage.test \ test/misc.test # when "make clean" runs CLEANFILES = \ test-results/*.test*.counts # when "make distclean" runs DISTCLEAN = \ Makefile # when "make maintainer-clean" runs MAINTAINERCLEANFILES = \ configure \ autoscan.log \ config.h.in~ \ config.h.in \ configure.scan \ configure.ac~ \ aclocal.m4 \ Makefile.in \ build-aux/depcomp \ build-aux/install-sh \ build-aux/missing \ $(DIST_ARCHIVES) genimage-18/README.rst000066400000000000000000000670171464152623000145650ustar00rootroot00000000000000================================== Genimage - The Image Creation Tool ================================== genimage is a tool to generate multiple filesystem and flash/disk images from a given root filesystem tree. genimage is intended to be run in a fakeroot environment. It also supports creating flash/disk images out of different file-system images and files. Configuration is done in a config file parsed by libconfuse. Options like the path to tools can be given via environment variables, the config file or from commandline switches. The Configuration File ====================== The config file of genimage uses a simple configuration language, provided by `libconfuse`_. This supports nested sections, as well as simple key-value pairs. .. _libconfuse: https://github.com/libconfuse/libconfuse Single-line comments can be introduced with ``#`` or ``//``, multi-line comments look like ``/* … */`` (as in C). The config file is separated into the main sections ``image``, ``flash`` and ``config``, and provides an ``include`` primitive. The image section ----------------- An image section describes a single filesystem or disk image to be built. It can be given multiple times to generate multiple images. An image can also have multiple partitions which refer to images themselves. Each image must have a type which can have different suboptions depending on the type. Let's have a look at an example:: image nand-pcm038.img { flash { } flashtype = "nand-64M-512" partition barebox { image = "barebox-pcm038.bin" size = 512K } partition root { image = "root-nand.jffs2" size = 24M } } This would generate a nand-pcm038.img which is a flash of type "nand-64M-512" The image contains two partitions, "barebox-pcm038.bin" and "root-nand.jffs2" which must refer to images described elsewhere in the config file. For example "root-nand.jffs2" partition could be described like this:: image root-nand.jffs2 { name = "root" jffs2 {} size = 24M mountpoint = "/" } In this case a single jffs2 image is generated from the root mountpoint. 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. 'k', 'M' or 'G' can be used as suffix to specify the size in multiple of 1024 etc. The suffix 's' specifies a multiple of the (traditional) sector size of 512. 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 to fill the filesystem. :srcpath: If this is set, specified path will be directly used to fill the filesystem. Ignoring rootpath/mountpoint logic. Path might be absolute or relative to current working directory. :empty: If this is set to true, then the specified rootpath and mountpoint are ignored for this image and an empty filesystem is created. This option is only used for writeable filesystem types, such as extX, vfat, ubifs and jffs2. This defaults to false. :temporary: If this is set to true, the image is created in ``tmppath`` rather than ``outputpath``. This can be useful for intermediate images defined in the configuration file which are not needed by themselves after the main image is created. This defaults to false. :exec-pre: Custom command to run before generating the image. :exec-post: Custom command to run after generating the image. :flashtype: refers to a flash section. Optional for non flash like images like hd images :partition: can be given multiple times and refers to a partition described below Additionally each image can have one of the following sections describing the type of the image: cpio, cramfs, ext2, ext3, ext4, file, flash, hdimage, iso, jffs2, qemu, squashfs, tar, ubi, ubifs, vfat. 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. If the size and autoresize are both not set then the size of the partition image is used. :align: Alignment value to use for automatic computation of ``offset`` and ``size``. Defaults to 1 for partitions not in the partition table, otherwise to the image's ``align`` value. :partition-type: Used by dos partition tables to specify the partition type. :image: The image file this partition shall be filled with :fill: Boolean specifying that all bytes of the partition should be explicitly initialized. Any bytes beyond the size of the specified image will be set to 0. :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. Defaults to true. :forced-primary: Force this partition to be a primary partition in the MBR partition table, useful when the extended partition should be followed by primary partitions. If there are more partitions defined after the first forced-primary, they must be also defined as forced-primary. Defaults to false. :partition-uuid: UUID string used by GPT partition tables to specify the partition id. Defaults to a random value. :partition-type-uuid: String used by GPT partition tables to specify the partition type. Either a UUID or a shortcut: * ``L``, ``linux``, ``linux-generic``: Linux filesystem (0fc63daf-8483-4772-8e79-3d69d8477de4) * ``S``, ``swap``: Swap (0657fd6d-a4ab-43c4-84e5-0933c84b4f4f) * ``H``, ``home``: Home (933ac7e1-2eb4-4f13-b844-0e14e2aef915) * ``U``, ``esp``, ``uefi``: EFI System Partition (c12a7328-f81f-11d2-ba4b-00a0c93ec93b) * ``R``, ``raid``: Linux RAID (a19d880f-05fc-4d3b-a006-743f0f84911e) * ``V``, ``lvm``: Linux LVM (e6d6d379-f507-44c2-a23c-238f2a3df928) * ``F``, ``fat32``: FAT32 / Basic Data Partition (ebd0a0a2-b9e5-4433-87c0-68b6b72699c7) * ``barebox-state`` (previously ``B``): Barebox State (4778ed65-bf42-45fa-9c5b-287a1dc4aab1) * ``barebox-env``: Barebox Environment (6c3737f2-07f8-45d1-ad45-15d260aab24d) Furthermore, for ``{arch}`` being one of ``alpha``, ``arc``, ``arm``, ``arm64``, ``ia64``, ``loongarch64``, ``mips``, ``mips64``, ``mips-le``, ``mips64-le``, ``parisc``, ``ppc``, ``ppc64``, ``ppc64-le``, ``riscv32``, ``riscv64``, ``s390``, ``s390x``, ``tilegx``, ``x86``, ``x86-64``, the following shortcuts from the `Discoverable Partitions Specification `_ are accepted (see the spec for the respective UUIDs): * ``root-{arch}``: Root Partition * ``usr-{arch}``: /usr Partition * ``root-{arch}-verity``: Root Verity Partition * ``usr-{arch}-verity``: /usr Verity Partition * ``root-{arch}-verity-sig``: Root Verity Signature Partition * ``usr-{arch}-verity-sig``: /usr Verity Signature Partition * ``xbootldr``: Extended Boot Loader Partition * ``srv``: Server Data Partition * ``var``: Variable Data Partition * ``tmp``: Temporary Data Partition * ``user-home``: Per-user Home Partition Defaults to ``L``. .. _dps-spec: https://uapi-group.org/specifications/specs/discoverable_partitions_specification/ For each partition, its final alignment, offset and size are determined as follows: * If the ``align`` option is not present, it defaults to the value of the image's ``align`` option if the partition is in the partition table, otherwise to 1. * If the ``offset`` option is absent or zero, and ``in-partition-table`` is true, the partition is placed after the end of all previously defined partitions, with the final offset rounded up to the partition's ``align`` value. * Otherwise, the ``offset`` option is used as-is. Note that if absent, that option defaults to 0, so in practice one must specify an ``offset`` for any partition that is not in the partition table (with at most one exception, e.g. a bootloader). * If the partition has the ``autoresize`` flag set, its size is computed as the space remaining in the image from its offset (for a GPT image, space is reserved at the end for the backup GPT table), rounded down to the partition's ``align`` value. If the partition also has a ``size`` option, it is ensured that the computed value is not less than that size. * Otherwise, if the ``size`` option is present and non-zero, its value is used as-is. * Otherwise, if the partition has an ``image`` option, the size of that image, rounded up to the partition's ``align`` value, is used to determine the size of the partition. The following sanity checks are done on these final values (in many cases, these will automatically be satisfied when the value has been determined via one of the above rules rather than given explicitly): * For a partition in the partition table, the partition's ``align`` value must be greater than or equal to the image's ``align`` value. * The partition's ``offset`` and ``size`` must both be multiples of its ``align``. * The size must not be 0. * The partition must not overlap any other partition, or the areas occupied by the partition table. The image configuration options ------------------------------- android-sparse ************** Generate android sparse images. They are typically used by fastboot. Sparse images encode "don't care" areas and areas that are filled with a single 32 bit value. As a result, they are often much smaller than raw disk images. Genimage assumes that all 'holes' in the input file are "don't care" areas. This is a reasonable assumption: Tools to generate filesystems typically operate on devices. So they only create holes in areas they don't care about. Genimage itself operates the same way when generating HD images. Options: :image: The source image that will be converted. :block-size: The granularity that the sparse image uses to find "don't care" or "fill" blocks. The supported block sizes depend on the user. The default is 4k. cpio **** Generates cpio images. Options: :format: archive format. Passed to the ``-H`` option to the cpio command. Valid options are ``bin``, ``odc``, ``newc``, ``crc``, ``tar``, ``ustar``, ``hpbin`` and ``hpodc`` :extraargs: Extra arguments passed to the cpio tool :compress: If given, pipe image through compression tool. Valid options are for example ``gzip``, ``lzop`` or any other tool that compresses from stdin to stdout. cramfs ****** Generates cramfs images. Options: :extraargs: Extra arguments passed to mkcramfs ext2, ext3, ext4 **************** Generates ext* images. Options: :use-mke2fs: If set to true, then mke2fs is used to create the image. Otherwise, genext2fs is used. Defaults to false. :mke2fs-conf: mke2fs.conf that should be used. If unspecified, the system default is used. :extraargs: Extra arguments passed to genext2fs or mke2fs. :features: Filesystem features. Passed to the ``-O`` option of tune2fs. This is a comma separated list of enabled or disabled features. See ``man ext4`` for features. For genext2fs all feature are specified. Default for ext3 images is ``has_journal``. Default for ext4 images is ``extents,uninit_bg,dir_index,has_journal``. For mke2fs these features are added in addition to the default features of the ext type. Already enabled features can be disabled by prefixing the feature with ``^``. :label: Specify the volume-label. Passed to the ``-L`` option of tune2fs :fs-timestamp: Sets different timestamps in the image. Sets the given timestamp using the debugfs commands ``set_current_time``, ``set_super_value mkfs_time`` and ``set_super_value lastcheck`` :root-owner: User and group IDs for the root directory. Defaults to ``0:0``. Only valid with mke2fs. :usage-type: Specify the usage type for the filesystem. Only valid with mke2fs. More details can be found in the mke2fs man-page. file **** This represents a pre-existing image which will be used as-is. When a partition section references an image that is not defined elsewhere in the configuration file, a ``file`` rule is implicitly generated. It is up to the user to ensure that the image exists in the input directory, or to use an absolute path to the image. It is possible to add a ``file`` image explicitly, which allows one to provide ``genimage`` with some information about the image which can not be deduced automatically. Currently, one such option exists: :holes: A list of ``"(;)"`` pairs specifying ranges of the file that do not contain meaningful data, and which can therefore be allowed to overlap other partitions or image metadata. For example:: image foo { hdimage { partition-table-type = "gpt" gpt-location = 64K } partition bootloader { in-partition-table = false offset = 0 image = "/path/to/bootloader.img" } partition rootfs { offset = 1M image = "rootfs.ext4" } } image /path/to/bootloader.img { file { holes = {"(440; 1K)", "(64K; 80K)"} } } This tells ``genimage`` that despite the ``bootloader`` partition overlapping both the last 72 bytes of the MBR (where the DOS partition table is located) and the GPT header occupying the sector starting at offset 512, this is all OK because ``bootloader.img`` does not contain useful data in that range. Further, in this example, the bootloader image has been carefully crafted to also allow placing the GPT array at offset 64K (the GPT header is always at offset 512). If the bootloader image is not declared explicitly and only used once then the holes can also be configured in the partition. This simplifies the config file for simple use-cases. For example:: image bar { hdimage {} partition bootloader { in-partition-table = false offset = 0 image = "/path/to/bootloader.img" holes = {"(440; 512)"} } partition rootfs { offset = 1M image = "rootfs.ext4" } } FIT *** Generates U-Boot FIT images. Options: :its: String option holding the path of the input its file :keydir: String option holding the directory containing the keys used for signing. flash ***** Generates flash images. These are basically the partition contents padded to the partition sizes concatenated together. There is no partition table. Needs a valid flashtype where the flash parameters are read from. hdimage ******* Generates DOS partition images. Options: :align: Partition alignment. Defaults to 512 bytes :partition-table: Boolean. If true, writes a partition table. If false, no partition table is generated. Defaults to true. Deprecated: use ``partition-table-type`` instead. :partition-table-type: Define what kind of partition table should be used. Valid options are: * ``none``: No partition table at all. In this case, the ``in-partition-table`` option for each partition is ignored. * ``mbr``: Legacy DOS/MBR partition table * ``gpt``: GUID Partition Table * ``hybrid``: A hybrid MBR/GPT partition table. Partitions with an explicit `partition-type` will be placed in in the MBR table. At most 3 such partitions are allowed. This limit does not effect the maximum number of GPT partition entries in the same image. :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). Using a special value ``random`` will result in using random 32 bit number. :gpt: Boolean. If true, a GPT type partition table is written. If false a DOS type partition table is written. Defaults to false. Deprecated: use ``partition-table-type`` instead. :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). :gpt-no-backup: Boolean. If true, then the backup partition table at the end of the image is not written. :disk-uuid: UUID string used as disk id in GPT partitioning. Defaults to a random value. :fill: If this is set to true, then the image file will be filled up to the end of the last partition. This might make the file bigger. This is necessary if the image will be processed by such tools as libvirt, libguestfs or parted. iso *** Generates an ISO image. Options: :boot-image: Path to the El Torito boot image. Passed to the ``-b`` option of genisofs :bootargs: Bootargs for the El Torito boot image. Defaults to ``-no-emul-boot -boot-load-size 4 -boot-info-table -c boot.cat -hide boot.cat`` :extraargs: Extra arguments passed to genisofs :input-charset: The input charset. Passed to the -input-charset option of genisofs. Defaults to ``default`` :volume-id: Volume ID. Passed to the ``-V`` option of genisofs jffs2 ***** Generates a JFFS image. Needs a valid flashtype where the flash parameters are read from. Options: :extraargs: Extra arguments passed to mkfs.jffs2 qemu **** Generates a QEMU image. Needs at least one valid partition. Options: :format: A valid ``qemu-img`` like ``qcow``, ``qcow2``, ``parallels``, ``vdi``, ``vhdx`` or ``vmdk``. Check ``qemu-img convert --help`` for the complete list of possible values. Defaults to ``qcow2``. :extraargs: Extra arguments passed to ``qemu-img convert`` squashfs ******** Generates a squashfs image. Options: :extraargs: Extra arguments passed to mksquashfs :compression: compression type for the image. Possible values are ``gzip`` (default), ``lzo``, ``xz`` or ``none`` :block-size: Block size. Passed to the ``-b`` option of mksquashfs. Defaults to 4096. rauc **** Generates a RAUC update bundle. Options: :extraargs: Extra arguments passed to RAUC :file: Specify a file to be added into the RAUC bundle. Usage is: ``file foo { image = "bar" }`` which adds a file "foo" in the RAUC bundle from then input file "bar" :files: A list of filenames added into the RAUC bundle. Like **file** above, but without the ability to add the files under different name. :key: Path to the key file or PKCS#11 URI. Passed to the ``--key`` option of RAUC :cert: Path to the certificate file or PKCS#11 URI. Passed to the ``--cert`` option of RAUC :keyring: Optional path to the keyring file. Passed to the ``--keyring`` option of RAUC :manifest: content of the manifest file tar *** Generates a tar image. The image will be compressed as defined by the filename suffix. ubi *** Generates an UBI image. Needs a valid flashtype where the flash parameters are read from. Options: :extraargs: Extra arguments passed to ubinize ubifs ***** Generates a UBIFS image. Needs a valid flashtype where the flash parameters are read from. Options: :extraargs: Extra arguments passed to mkubifs :max-size: Maximum size of the UBIFS image :space-fixup: Instructs the file-system free space to be freed up on first mount. vfat **** Generates a VFAT image. Options: :extraargs: Extra arguments passed to mkdosfs :label: Specify the volume-label. Passed to the ``-n`` option of mkdosfs :file: Specify a file to be added into the filesystem image. Usage is: ``file foo { image = "bar" }`` which adds a file "foo" in the filesystem image from the input file "bar" :files: A list of filenames added into the filesystem image. Like **file** above, but without the ability to add the files under different name. Note: If no content is specified with ``file`` or ``files`` then ``rootpath`` and ``mountpoint`` are used to provide the content. fip *** Generates a Firmware Image Package (FIP). A format used to bundle firmware to be loaded by ARM Trusted Firmware. Options: :extraargs: Extra arguments passed to fiptool :fw-config: Firmware Configuration (device tree), usually provided by BL2 (Trusted Firmware) :nt-fw: Non-Trusted Firmware (BL33) :hw-config: Hardware Configuration (device tree), passed to BL33 :tos-fw: Trusted OS (BL32) binaries. Second and third binary are used as extra1 and extra2 binaries if specified. Example: ``tos-fw = {"tee-header_v2.bin", "tee-pager_v2.bin", "tee-pageable_v2.bin"}`` :scp-fwu-cfg: SCP Firmware Updater Configuration FWU SCP_BL2U :ap-fwu-cfg: AP Firmware Updater Configuration BL2U :fwu: Firmware Updater NS_BL2U :fwu-cert: Non-Trusted Firmware Updater certificate :tb-fw: Trusted Boot Firmware BL2 :scp-fw: SCP Firmware SCP_BL2 :soc-fw: EL3 Runtime Firmware BL31 :tb-fw-config: TB_FW_CONFIG :soc-fw-config: SOC_FW_CONFIG :tos-fw-config: TOS_FW_CONFIG :nt-fw-config: NT_FW_CONFIG :rot-cert: Root Of Trust key certificate :trusted-key-cert: Trusted key certificate :scp-fw-key-cert: SCP Firmware key certificate :soc-fw-key-cert: SoC Firmware key certificate :tos-fw-key-cert: Trusted OS Firmware key certificate :nt-fw-key-cert: Non-Trusted Firmware key certificate :tb-fw-cert: Trusted Boot Firmware BL2 certificate :scp-fw-cert: SCP Firmware content certificate :soc-fw-cert: SoC Firmware content certificate :tos-fw-cert: Trusted OS Firmware content certificate :nt-fw-cert: Non-Trusted Firmware content certificate :sip-sp-cert: SiP owned Secure Partition content certificate :plat-sp-cert: Platform owned Secure Partition content certificate The Flash Section ----------------- The flash section can be given multiple times and each section describes a flash chip. The option names are mostly derived from the UBI terminology. There are the following options: :pebsize: The size of a physical eraseblock in bytes :lebsize: The size of a logical eraseblock in bytes (for ubifs) :numpebs: Number of physical eraseblocks on this device. The total size of the device is determined by pebsize * numpebs :minimum-io-unit-size: The minimum size in bytes accessible on this device :vid-header-offset: offset of the volume identifier header :sub-page-size: The size of a sub page in bytes. Several flash related image types need a valid flash section. From the image types the flash type section is referred to using the ``flashtype`` option which contains the name of the flash type to be used. For more information of the meaning of these values see the ubi(fs) and mtd FAQs: http://www.linux-mtd.infradead.org/faq/general.html Example flash section:: flash nand-64M-512 { pebsize = 16384 lebsize = 15360 numpebs = 4096 minimum-io-unit-size = 512 vid-header-offset = 512 sub-page-size = 512 } ... image jffs2 { flashtype = "nand-64M-512" } The config section ------------------ In this section the global behaviour of the program is described. Except as noted below, all options here can be given from either environment variables, the config file or command line switches. For instance, a config option ``foo`` can be passed as a ``--foo`` command line switch or as a GENIMAGE_FOO environment variable. :config: default: ``genimage.cfg`` Path to the genimage config file. :loglevel: default: 1 genimage log level. :outputpath: default: images Mandatory path where all images are written to (must exist). :inputpath: default: input This mandatory path is searched for input images, for example bootloader binaries, kernel images (must exist). :rootpath: default: root Mandatory path to the root filesystem (must exist). :tmppath: default: tmp Optional path to a temporary directory. There must be enough space available here to hold a copy of the root filesystem. :includepath: Colon-separated list of directories to search for files included via the ``include`` function. The current directory is searched after these. Thus, if this option is not given, only the current directory is searched. This has no effect when given in the config file. :configdump: File to write the final configuration to. This includes the results of all ``include`` directives, expansions of environment variables and application of default values - think ``gcc -E``. Use ``-`` for stdout. :cpio: path to the cpio program (default cpio) :dd: path to the dd program (default dd) :e2fsck: path to the e2fsck program (default e2fsck) :genext2fs: path to the genext2fs program (default genext2fs) :genisoimage: path to the genisoimage program (default genisoimage) :mcopy: path to the mcopy program (default mcopy) :mmd: path to the mmd program (default mmd) :mkcramfs: path to the mkcramfs program (default mkcramfs) :mkdosfs: path to the mkdosfs program (default mkdosfs) :mkfsjffs2: path to the mkfs.jffs2 program (default mkfs.jffs2) :mkfsubifs: path to the mkfs.ubifs program (default mkfs.ubifs) :mksquashfs: path to the mksquashfs program (default mksquashfs) :qemu-img: path to the qemu-img program (default qemu-img) :tar: path to the tar program (default tar) :tune2fs: path to the tune2fs program (default tune2fs) :ubinize: path to the ubinize program (default ubinize) :fiptool: path to the fiptool utility (default fiptool) Include Configurations Fragments -------------------------------- To include a ``"foo.cfg"`` config file, use the following statement:: include("foo.cfg") This allows to re-use, for example flash configuration files, across different image configurations. License and Developing ====================== To contribute to genimage please prepare a pull request on Github. To make it possible to include your modifications it's required that your code additions are licensed under the same terms as genimage itself. So you are required to agree to the following document: Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. Your agreement is expressed by adding a sign-off line to each of your commits (e.g. using ``git commit -s``) looking as follows: Signed-off-by: Random J Developer with your identity and email address matching the commit meta data. genimage-18/autogen.sh000077500000000000000000000011001464152623000150540ustar00rootroot00000000000000#!/bin/sh -e if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \ chmod +x .git/hooks/pre-commit && \ echo "Activated pre-commit hook." fi autoreconf --install --symlink args="--prefix=/usr" echo echo "----------------------------------------------------------------" echo "Initialized build system. For a common configuration please run:" echo "----------------------------------------------------------------" echo echo "./configure CFLAGS='-g -O0' $args" echo genimage-18/config.c000066400000000000000000000234231464152623000145000ustar00rootroot00000000000000/* * Copyright (c) 2011 Sascha Hauer , Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include "genimage.h" static LIST_HEAD(optlist); struct config { const char *name; cfg_opt_t opt; const char *env; struct list_head list; char *value; char *def; int hidden; }; static void show_help(const char *cmd) { struct config *c; printf("Usage %s [options]\n" "Generate filesystem, disk and flash images defined in the\n" "configuration file.\n\n" "Valid options: [ default value ] (environment variable)\n" " -h, --help\n" " -v, --version\n", cmd); list_for_each_entry(c, &optlist, list) { char opt[20], def[20]; if (c->hidden) continue; snprintf(opt, 20, "%s ", c->name); snprintf(def, 20, "[ %s ]", c->def); printf(" --%-20s %-20s (%s)\n", opt, c->def ? def : "", c->env); } printf("\n"); } static void show_version(void) { printf(PACKAGE_VERSION "\n"); } /* * get the value of an option */ const char *get_opt(const char *name) { struct config *c; list_for_each_entry(c, &optlist, list) { if (!strcmp(c->name, name)) return c->value; } return NULL; } /* * set option 'name' to 'value' */ static int set_opt(const char *name, const char *value) { struct config *c; list_for_each_entry(c, &optlist, list) { if (!strcmp(c->name, name)) { free(c->value); c->value = strdup(value); return 0; } } return -EINVAL; } /* * convert all options from the options list to a cfg_opt_t * array suitable for confuse */ cfg_opt_t *get_confuse_opts(void) { struct config *c; int num_opts = 0; cfg_opt_t *options; int i = 0; cfg_opt_t cfg_end[] = { CFG_END() }; list_for_each_entry(c, &optlist, list) { if (c->opt.name) num_opts++; } options = xzalloc(sizeof(cfg_opt_t) * (num_opts + 1)); list_for_each_entry(c, &optlist, list) { if (c->opt.name) { memcpy(&options[i], &c->opt, sizeof(cfg_opt_t)); i++; } } memcpy(&options[i], cfg_end, sizeof(cfg_opt_t)); return options; } /* * Get an integer type option from confuse, but with an optional * 'k', 'M', 'G' suffix */ unsigned long long cfg_getint_suffix(cfg_t *sec, const char *name) { const char *str = cfg_getstr(sec, name); unsigned long long val = 0; if (str) 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; } /* * Initialize all options in the following order: * * 1) default value * 2) from environment * 3) from config file * 4) from command line switch * * may be called multiple times with cfg == NULL when * config file is not yet available. */ int set_config_opts(int argc, char *argv[], cfg_t *cfg) { struct config *c; cfg_t *cfgsec = NULL; int num_opts = 0, n, i; static struct option *long_options = NULL; int ret = 0; if (cfg && (cfg_size(cfg, "config") > 0)) cfgsec = cfg_getsec(cfg, "config"); list_for_each_entry(c, &optlist, list) { char *str; num_opts++; /* set from option default value */ if (c->def) set_opt(c->name, c->def); /* set from environment */ str = getenv(c->env); if (str) set_opt(c->name, str); /* set from config file (if already available) */ if (cfgsec && c->opt.name) { str = cfg_getstr(cfgsec, c->opt.name); if (str) set_opt(c->name, str); } } /* and last but not least from command line switches */ long_options = xzalloc(sizeof(struct option) * (num_opts + 3)); i = 0; list_for_each_entry(c, &optlist, list) { struct option *o = &long_options[i]; o->name = c->name; o->has_arg = 1; i++; } long_options[i].name = "help"; long_options[i].val = 'h'; long_options[i+1].name = "version"; long_options[i+1].val = 'v'; optind = 1; while (1) { int option_index = 0; n = getopt_long(argc, argv, "hv", long_options, &option_index); if (n == -1) break; switch (n) { case 0: ret = set_opt(long_options[option_index].name, optarg); if (ret) goto err_out; break; case 'h': show_help(argv[0]); exit(0); break; case 'v': show_version(); exit(0); break; default: ret = -EINVAL; goto err_out; } } err_out: free(long_options); return ret; } static char *abspath(const char *path) { char *p; if (*path == '/') return strdup(path); xasprintf(&p, "%s/%s", get_current_dir_name(), path); return p; } const char *imagepath(void) { static const char *outputpath; if (!outputpath) outputpath = abspath(get_opt("outputpath")); return outputpath; } const char *inputpath(void) { static const char *inputpath; if (!inputpath) inputpath = abspath(get_opt("inputpath")); return inputpath; } static const char *cached_rootpath; void disable_rootpath(void) { cached_rootpath = ""; } const char *rootpath(void) { if (!cached_rootpath) cached_rootpath = abspath(get_opt("rootpath")); return cached_rootpath; } const char *tmppath(void) { static const char *tmppath; if (!tmppath) tmppath = abspath(get_opt("tmppath")); return tmppath; } static struct config opts[] = { { .name = "loglevel", .opt = CFG_STR("loglevel", NULL, CFGF_NONE), .env = "GENIMAGE_LOGLEVEL", .def = "1", }, { .name = "rootpath", .opt = CFG_STR("rootpath", NULL, CFGF_NONE), .env = "GENIMAGE_ROOTPATH", .def = "root", }, { .name = "tmppath", .opt = CFG_STR("tmppath", NULL, CFGF_NONE), .env = "GENIMAGE_TMPPATH", .def = "tmp", }, { .name = "inputpath", .opt = CFG_STR("inputpath", NULL, CFGF_NONE), .env = "GENIMAGE_INPUTPATH", .def = "input", }, { .name = "outputpath", .opt = CFG_STR("outputpath", NULL, CFGF_NONE), .env = "GENIMAGE_OUTPUTPATH", .def = "images", }, { .name = "includepath", .opt = CFG_STR("includepath", NULL, CFGF_NONE), .env = "GENIMAGE_INCLUDEPATH", .def = NULL, #ifndef HAVE_SEARCHPATH .hidden = 1, #endif }, { .name = "cpio", .opt = CFG_STR("cpio", NULL, CFGF_NONE), .env = "GENIMAGE_CPIO", .def = "cpio", }, { .name = "dd", .opt = CFG_STR("dd", NULL, CFGF_NONE), .env = "GENIMAGE_DD", .def = "dd", }, { .name = "debugfs", .opt = CFG_STR("debugfs", NULL, CFGF_NONE), .env = "GENIMAGE_DEBUGFS", .def = "debugfs", }, { .name = "e2fsck", .opt = CFG_STR("e2fsck", NULL, CFGF_NONE), .env = "GENIMAGE_E2FSCK", .def = "e2fsck", }, { .name = "genext2fs", .opt = CFG_STR("genext2fs", NULL, CFGF_NONE), .env = "GENIMAGE_GENEXT2FS", .def = "genext2fs", }, { .name = "genisoimage", .opt = CFG_STR("genisoimage", NULL, CFGF_NONE), .env = "GENIMAGE_GENISOIMAGE", .def = "genisoimage", }, { .name = "mcopy", .opt = CFG_STR("mcopy", NULL, CFGF_NONE), .env = "GENIMAGE_MCOPY", .def = "mcopy", }, { .name = "mmd", .opt = CFG_STR("mmd", NULL, CFGF_NONE), .env = "GENIMAGE_MMD", .def = "mmd", }, { .name = "mkcramfs", .opt = CFG_STR("mkcramfs", NULL, CFGF_NONE), .env = "GENIMAGE_MKCRAMFS", .def = "mkcramfs", }, { .name = "mkdosfs", .opt = CFG_STR("mkdosfs", NULL, CFGF_NONE), .env = "GENIMAGE_MKDOSFS", .def = "mkdosfs", }, { .name = "mke2fs", .opt = CFG_STR("mke2fs", NULL, CFGF_NONE), .env = "GENIMAGE_MKE2FS", .def = "mke2fs", }, { .name = "mkfsjffs2", .opt = CFG_STR("mkfsjffs2", NULL, CFGF_NONE), .env = "GENIMAGE_MKFJFFS2", .def = "mkfs.jffs2", }, { .name = "mkfsf2fs", .opt = CFG_STR("mkfsf2fs", NULL, CFGF_NONE), .env = "GENIMAGE_MKFSF2FS", .def = "mkfs.f2fs", }, { .name = "sloadf2fs", .opt = CFG_STR("sloadf2fs", NULL, CFGF_NONE), .env = "GENIMAGE_SLOADF2FS", .def = "sload.f2fs", }, { .name = "mkfsubifs", .opt = CFG_STR("mkfsubifs", NULL, CFGF_NONE), .env = "GENIMAGE_MKFSUBIFS", .def = "mkfs.ubifs", }, { .name = "mksquashfs", .opt = CFG_STR("mksquashfs", NULL, CFGF_NONE), .env = "GENIMAGE_MKSQUASHFS", .def = "mksquashfs", }, { .name = "qemu-img", .opt = CFG_STR("qemu-img", NULL, CFGF_NONE), .env = "GENIMAGE_QEMU", .def = "qemu-img", }, { .name = "rauc", .opt = CFG_STR("rauc", NULL, CFGF_NONE), .env = "GENIMAGE_RAUC", .def = "rauc", }, { .name = "tar", .opt = CFG_STR("tar", NULL, CFGF_NONE), .env = "GENIMAGE_TAR", .def = "tar", }, { .name = "tune2fs", .opt = CFG_STR("tune2fs", NULL, CFGF_NONE), .env = "GENIMAGE_TUNE2FS", .def = "tune2fs", }, { .name = "ubinize", .opt = CFG_STR("ubinize", NULL, CFGF_NONE), .env = "GENIMAGE_UBINIZE", .def = "ubinize", }, { .name = "mkimage", .opt = CFG_STR("mkimage", NULL, CFGF_NONE), .env = "GENIMAGE_MKIMAGE", .def = "mkimage", }, { .name = "fiptool", .opt = CFG_STR("fiptool", NULL, CFGF_NONE), .env = "GENIMAGE_FIPTOOL", .def = "fiptool", }, { .name = "config", .env = "GENIMAGE_CONFIG", .def = "genimage.cfg", }, { .name = "configdump", .env = "GENIMAGE_CONFIGDUMP", .def = NULL, }, }; /* * early setup: add all options from the array above to the * list of options */ int init_config(void) { unsigned int i; for (i = 0; i < ARRAY_SIZE(opts); i++) { struct config *c = &opts[i]; list_add_tail(&c->list, &optlist); } return 0; } genimage-18/configure.ac000066400000000000000000000126271464152623000153610ustar00rootroot00000000000000AC_PREREQ(2.60) AC_INIT([genimage], [18], [oss-tools@pengutronix.de], [genimage], [http://www.pengutronix.de/genimage/]) AC_CONFIG_SRCDIR([genimage.c]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects]) AC_PROG_CC # If possible, enable extensions to Posix AC_USE_SYSTEM_EXTENSIONS AC_SYS_LARGEFILE # where to put extension macros AC_CONFIG_MACRO_DIR([m4]) # default is less output while building the package AM_SILENT_RULES([yes]) # Help the generated libtool script understand the characteristics of the host LT_INIT # change if 'usr/local' as the default install path isn't a good choice #AC_PREFIX_DEFAULT([/usr/local]) AC_CHECK_FUNCS([memset setenv strdup strcasecmp strerror strstr strtoull]) AC_C_INLINE AC_FUNC_ERROR_AT_LINE AC_FUNC_MALLOC AC_TYPE_SIZE_T AC_TYPE_UINT32_T AC_CACHE_CHECK([whether linux/fs.h is available], [genimage_cv_header_linux_fs_h], AC_CHECK_HEADERS([linux/fs.h], [genimage_cv_header_linux_fs_h=yes], [genimage_cv_header_linux_fs_h=no])) AC_CACHE_CHECK([whether linux/fiemap.h is available], [genimage_cv_header_fiemap_h], AC_CHECK_HEADERS([linux/fiemap.h], [genimage_cv_header_fiemap_h=yes], [genimage_cv_header_fiemap_h=no])) if test "x$genimage_cv_header_linux_fs_h" = "xyes"; then AC_DEFINE([HAVE_LINUX_FS_H], [1], [Define if linux/fs.h is available]) fi if test "x$genimage_cv_header_fiemap_h" = "xyes" -a "x$genimage_cv_header_linux_fs_h" = "xyes"; then AC_DEFINE([HAVE_FIEMAP], [1], [Define if fiemap can be used]) fi AC_CHECK_FUNCS(fallocate) # ----------- query user's settings ---------------------- AC_MSG_CHECKING([whether to enable debugging]) AC_ARG_ENABLE([debug], AS_HELP_STRING([--enable-debug], [enable debug messages @<:@default=disabled@:>@]), [], [enable_debug=no]) AC_MSG_RESULT([${enable_debug}]) # should the executable export all symbols? AC_MSG_CHECKING([whether to hide internal symbols]) AC_ARG_ENABLE([hide], [AS_HELP_STRING([--disable-hide], [do not hide all internal symbols @<:@default=enabled@:>@])], [], [enable_hide=yes]) # for debugging purposes we must disable the hiding feature AS_IF([test "x${enable_debug}" = "xyes"], [AC_MSG_RESULT([no (due to debug enabled)]) enable_hide=no], [AC_MSG_RESULT([${enable_hide}])]) # ----------- autodetect some settings ------------------- # add as much warnings and features as possible, but check what the compiler # is able to understand and use it only if possible CC_CHECK_CFLAGS_SILENT([-pipe],[AM_CFLAGS="${AM_CFLAGS} -pipe"]) CC_CHECK_CFLAGS_SILENT([-Wall],[AM_CFLAGS="${AM_CFLAGS} -Wall"]) CC_CHECK_CFLAGS_SILENT([-Wextra],[AM_CFLAGS="${AM_CFLAGS} -Wextra"]) CC_CHECK_CFLAGS_SILENT([-Wmissing-declarations],[AM_CFLAGS="${AM_CFLAGS} -Wmissing-declarations"]) CC_CHECK_CFLAGS_SILENT([-Wmissing-prototypes],[AM_CFLAGS="${AM_CFLAGS} -Wmissing-prototypes"]) CC_CHECK_CFLAGS_SILENT([-Wnested-externs],[AM_CFLAGS="${AM_CFLAGS} -Wnested-externs"]) CC_CHECK_CFLAGS_SILENT([-Wpointer-arith],[AM_CFLAGS="${AM_CFLAGS} -Wpointer-arith"]) CC_CHECK_CFLAGS_SILENT([-Wsign-compare],[AM_CFLAGS="${AM_CFLAGS} -Wsign-compare"]) CC_CHECK_CFLAGS_SILENT([-Wchar-subscripts],[AM_CFLAGS="${AM_CFLAGS} -Wchar-subscripts"]) CC_CHECK_CFLAGS_SILENT([-Wstrict-prototypes],[AM_CFLAGS="${AM_CFLAGS} -Wstrict-prototypes"]) CC_CHECK_CFLAGS_SILENT([-Wshadow],[AM_CFLAGS="${AM_CFLAGS} -Wshadow"]) CC_CHECK_CFLAGS_SILENT([-Wformat-security],[AM_CFLAGS="${AM_CFLAGS} -Wformat-security"]) CC_CHECK_CFLAGS_SILENT([-Wtype-limits],[AM_CFLAGS="${AM_CFLAGS} -Wtype-limits"]) CC_CHECK_CFLAGS_SILENT([-Wunused-parameter],[AM_CFLAGS="${AM_CFLAGS} -Wno-unused-parameter"]) CC_CHECK_CFLAGS_SILENT([-ffunction-sections],[AM_CFLAGS="${AM_CFLAGS} -ffunction-sections"]) CC_CHECK_CFLAGS_SILENT([-fdata-sections],[AM_CFLAGS="${AM_CFLAGS} -fdata-sections"]) # Add only those libraries which are really used CC_CHECK_LDFLAGS([-Wl,--as-needed], [AM_LDFLAGS="${AM_LDFLAGS} -Wl,--as-needed"],[]) CC_CHECK_LDFLAGS([-Wl,--gc-sections], [AM_LDFLAGS="${AM_LDFLAGS} -Wl,--gc-sections"],[]) PKG_CHECK_MODULES(CONFUSE, libconfuse >= 2.8, [AC_DEFINE([HAVE_SEARCHPATH], [1], [Define if cfg_add_searchpath() is available])], [PKG_CHECK_MODULES(CONFUSE, libconfuse)]) # ------- use all the settings ---------------------- AS_IF([test "x$enable_debug" = "xyes"], [ AC_DEFINE(ENABLE_DEBUG, [1], [Debug messages.]) ]) # Enable "-fvisibility=hidden" only if the used gcc supports it AS_IF([test "${enable_hide}" = "yes"], [AC_MSG_CHECKING([whether the compiler supports -fvisibility=hidden]) CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], [], [enable_hide=no]) # still enabled? if test "x${enable_hide}" = "xyes"; then AC_DEFINE(DSO_HIDDEN, 1, [hide internal library symbols]) AM_CFLAGS="${AM_CFLAGS} -fvisibility=hidden" fi AC_MSG_RESULT([${enable_hide}])]) AC_SUBST(AM_CFLAGS) # be very silent on request AM_CONDITIONAL(BUILD_SILENTLY, test "x$AM_DEFAULT_VERBOSITY" = x0) AC_CONFIG_HEADERS(config.h) AC_CONFIG_FILES([ Makefile ]) AC_REQUIRE_AUX_FILE([tap-driver.sh]) AC_OUTPUT AC_MSG_RESULT([ $PACKAGE $VERSION ===== prefix: ${prefix} compiler: ${CC} cflags: ${CFLAGS} ${AM_CFLAGS} ldflags: ${LDFLAGS} ${AM_LDFLAGS} debug: ${enable_debug} hide symbols: ${enable_hide} libconfuse: ${CONFUSE_LIBS} ]) genimage-18/crc32.c000066400000000000000000000073421464152623000141510ustar00rootroot00000000000000#include #include #include "genimage.h" static const uint32_t crc32_tab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; uint32_t crc32_next(const void *data, size_t len, uint32_t last_crc) { uint32_t crc = ~last_crc; const char *p = data; while(len--) crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8); return ~crc; } uint32_t crc32(const void *data, size_t len) { return crc32_next(data, len, 0); } genimage-18/flash.conf000066400000000000000000000004441464152623000150310ustar00rootroot00000000000000flash nand-64M-512 { pebsize = 16384 lebsize = 15360 numpebs = 4096 minimum-io-unit-size = 512 vid-header-offset = 512 sub-page-size = 512 } flash nor-64M-128k { pebsize = 131072 lebsize = 130944 numpebs = 256 minimum-io-unit-size = 1 vid-header-offset = 64 sub-page-size = 1 } genimage-18/genimage.c000066400000000000000000000474171464152623000150200ustar00rootroot00000000000000/* * Copyright (c) 2011 Sascha Hauer , Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "genimage.h" /* * TODO: * * - add documentation * - implement missing image types (cpio, iso) * - free memory after usage * - make more failsafe (does flashtype exist where necessary) * - implement command line switches (--verbose, --dry-run, --config=) * */ static struct image_handler *handlers[] = { &android_sparse_handler, &cpio_handler, &cramfs_handler, &ext2_handler, &ext3_handler, &ext4_handler, &f2fs_handler, &file_handler, &fit_handler, &fip_handler, &flash_handler, &hdimage_handler, &iso_handler, &jffs2_handler, &qemu_handler, &rauc_handler, &squashfs_handler, &tar_handler, &ubi_handler, &ubifs_handler, &vfat_handler, }; static int image_set_handler(struct image *image, cfg_t *cfg) { unsigned int i; int num = 0, x; for (i = 0; i < ARRAY_SIZE(handlers); i++) { struct image_handler *handler = handlers[i]; x = cfg_size(cfg, handler->type); if (x) image->handler = handler; num += x; } if (num > 1) { image_error(image, "multiple image types given\n"); exit (1); } if (num < 1) { image_error(image, "no image type given\n"); exit (1); } image->imagesec = cfg_getsec(cfg, image->handler->type); return 0; } static cfg_opt_t partition_opts[] = { CFG_STR("offset", NULL, CFGF_NONE), CFG_STR("size", NULL, CFGF_NONE), CFG_STR("align", NULL, CFGF_NONE), CFG_INT("partition-type", 0, CFGF_NONE), CFG_BOOL("bootable", cfg_false, CFGF_NONE), CFG_BOOL("forced-primary", cfg_false, CFGF_NONE), CFG_BOOL("read-only", cfg_false, CFGF_NONE), CFG_BOOL("hidden", cfg_false, CFGF_NONE), CFG_BOOL("no-automount", cfg_false, CFGF_NONE), CFG_BOOL("fill", cfg_false, CFGF_NONE), CFG_STR("image", NULL, CFGF_NONE), CFG_STR_LIST("holes", NULL, CFGF_NONE), CFG_BOOL("autoresize", 0, CFGF_NONE), CFG_BOOL("in-partition-table", cfg_true, CFGF_NONE), CFG_STR("partition-uuid", NULL, CFGF_NONE), CFG_STR("partition-type-uuid", NULL, CFGF_NONE), CFG_END() }; static cfg_opt_t image_common_opts[] = { CFG_STR("name", NULL, CFGF_NONE), CFG_STR("size", NULL, CFGF_NONE), CFG_STR("mountpoint", NULL, CFGF_NONE), CFG_STR("srcpath", NULL, CFGF_NONE), CFG_BOOL("empty", cfg_false, CFGF_NONE), CFG_BOOL("temporary", cfg_false, CFGF_NONE), CFG_STR("exec-pre", NULL, CFGF_NONE), CFG_STR("exec-post", NULL, CFGF_NONE), CFG_STR("flashtype", NULL, CFGF_NONE), CFG_SEC("partition", partition_opts, CFGF_MULTI | CFGF_TITLE), CFG_FUNC("include", &cfg_include), }; static cfg_opt_t flashchip_opts[] = { CFG_STR("pebsize", "", CFGF_NONE), CFG_STR("lebsize", "", CFGF_NONE), CFG_STR("numpebs", "", CFGF_NONE), CFG_STR("minimum-io-unit-size", "", CFGF_NONE), CFG_STR("vid-header-offset", "", CFGF_NONE), CFG_STR("sub-page-size", "", CFGF_NONE), CFG_END() }; static LIST_HEAD(images); /* * find an image corresponding to a filename */ struct image *image_get(const char *filename) { struct image *image; list_for_each_entry(image, &images, list) { if (!strcmp(image->file, filename)) return image; } return NULL; } /* * setup the images. Calls ->setup function for each * image, recursively calls itself for resolving dependencies */ static int image_setup(struct image *image) { int ret = 0; struct partition *part; if (image->done < 0) return 0; if (image->seen < 0) { image_error(image, "recursive dependency detected\n"); return -EINVAL; } 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) continue; child = image_get(part->image); if (!child) { image_error(image, "could not find %s\n", part->image); return -EINVAL; } ret = image_setup(child); if (ret) { image_error(image, "could not setup %s\n", child->file); return ret; } } if (image->handler->setup) ret = image->handler->setup(image, image->imagesec); if (ret) return ret; image->done = -1; return 0; } static int overwriteenv(const char *name, const char *value) { int ret; ret = setenv(name, value ? : "", 1); if (ret) return -errno; return 0; } static int setenv_paths(void) { int ret; ret = overwriteenv("OUTPUTPATH", imagepath()); if (ret) return ret; ret = overwriteenv("INPUTPATH", inputpath()); if (ret) return ret; ret = overwriteenv("ROOTPATH", rootpath()); if (ret) return ret; ret = overwriteenv("TMPPATH", tmppath()); if (ret) return ret; return 0; } static int setenv_image(const struct image *image) { int ret; char sizestr[20]; snprintf(sizestr, sizeof(sizestr), "%llu", image->size); ret = overwriteenv("IMAGE", image->file); if (ret) return ret; ret = overwriteenv("IMAGEOUTFILE", imageoutfile(image)); if (ret) return ret; ret = overwriteenv("IMAGENAME", image->name); if (ret) return ret; ret = overwriteenv("IMAGESIZE", sizestr); if (ret) return ret; ret = overwriteenv("IMAGEMOUNTPOINT", image->mountpoint); if (ret) return ret; ret = overwriteenv("IMAGEMOUNTPATH", image->empty ? NULL : mountpath(image)); if (ret) return ret; return 0; } /* * generate the images. Calls ->generate function for each * image, recursively calls itself for resolving dependencies */ static int image_generate(struct image *image) { int ret; struct partition *part; if (image->done > 0) return 0; if (image->seen > 0) { image_error(image, "recursive dependency detected\n"); return -EINVAL; } image->seen = 1; list_for_each_entry(part, &image->partitions, list) { struct image *child; if (!part->image) continue; child = image_get(part->image); if (!child) { image_error(image, "could not find %s\n", part->image); return -EINVAL; } ret = image_generate(child); if (ret) { image_error(image, "could not generate %s\n", child->file); return ret; } } ret = setenv_image(image); if (ret) return ret; if (image->exec_pre) { ret = systemp(image, "%s", image->exec_pre); if (ret) return ret; } if (image->handler->generate) { ret = image->handler->generate(image); } else { image_error(image, "no generate function for %s\n", image->file); return -EINVAL; } if (ret) { struct stat s; if (lstat(imageoutfile(image), &s) != 0 || ((s.st_mode & S_IFMT) == S_IFREG) || ((s.st_mode & S_IFMT) == S_IFLNK)) systemp(image, "rm -f \"%s\"", imageoutfile(image)); return ret; } if (image->exec_post) { ret = systemp(image, "%s", image->exec_post); if (ret) return ret; } image->done = 1; return 0; } static LIST_HEAD(flashlist); static int parse_flashes(cfg_t *cfg) { int num_flashes; int i; num_flashes = cfg_size(cfg, "flash"); for (i = 0; i < num_flashes; i++) { cfg_t *flashsec = cfg_getnsec(cfg, "flash", i); struct flash_type *flash = xzalloc(sizeof *flash); flash->name = cfg_title(flashsec); flash->pebsize = cfg_getint_suffix(flashsec, "pebsize"); flash->lebsize = cfg_getint_suffix(flashsec, "lebsize"); flash->numpebs = cfg_getint_suffix(flashsec, "numpebs"); flash->minimum_io_unit_size = cfg_getint_suffix(flashsec, "minimum-io-unit-size"); flash->vid_header_offset = cfg_getint_suffix(flashsec, "vid-header-offset"); flash->sub_page_size = cfg_getint_suffix(flashsec, "sub-page-size"); list_add_tail(&flash->list, &flashlist); } return 0; } struct flash_type *flash_type_get(const char *name) { struct flash_type *flash; list_for_each_entry(flash, &flashlist, list) { if (!strcmp(flash->name, name)) return flash; } return NULL; } static int parse_partitions(struct image *image, cfg_t *imagesec) { struct partition *part; int num_partitions; int i; num_partitions = cfg_size(imagesec, "partition"); for (i = 0; i < num_partitions; i++) { cfg_t *partsec = cfg_getnsec(imagesec, "partition", i); part = xzalloc(sizeof *part); part->cfg = partsec; part->name = cfg_title(partsec); list_add_tail(&part->list, &image->partitions); part->size = cfg_getint_suffix(partsec, "size"); part->offset = cfg_getint_suffix(partsec, "offset"); part->align = cfg_getint_suffix(partsec, "align"); part->partition_type = cfg_getint(partsec, "partition-type"); part->bootable = cfg_getbool(partsec, "bootable"); part->forced_primary = cfg_getbool(partsec, "forced-primary"); part->read_only = cfg_getbool(partsec, "read-only"); part->hidden = cfg_getbool(partsec, "hidden"); part->no_automount = cfg_getbool(partsec, "no-automount"); part->fill = cfg_getbool(partsec, "fill"); part->image = cfg_getstr(partsec, "image"); part->autoresize = cfg_getbool(partsec, "autoresize"); part->in_partition_table = cfg_getbool(partsec, "in-partition-table"); part->partition_type_uuid = cfg_getstr(partsec, "partition-type-uuid"); part->partition_uuid = cfg_getstr(partsec, "partition-uuid"); } return 0; } static int set_flash_type(void) { struct image *image; list_for_each_entry(image, &images, list) { struct partition *part; if (!image->flash_type) continue; list_for_each_entry(part, &image->partitions, list) { struct image *i; if (!part->image) continue; i = image_get(part->image); if (!i) return -EINVAL; if (i->flash_type) { if (i->flash_type != image->flash_type) { image_error(i, "conflicting flash types: %s has flashtype %s whereas %s has flashtype %s\n", i->file, i->flash_type->name, image->file, image->flash_type->name); return -EINVAL; } } else { i->flash_type = image->flash_type; } } } return 0; } static LIST_HEAD(mountpoints); static struct mountpoint *get_mountpoint(const char *path) { struct mountpoint *mp; list_for_each_entry(mp, &mountpoints, list) { if (!strcmp(mp->path, path)) return mp; } return NULL; } char *sanitize_path(const char *path) { char *path_sanitized; char *c; path_sanitized = strdup(path); c = path_sanitized; while ((c = strchr(c, '/'))) { *c = '-'; c++; } return path_sanitized; } static struct mountpoint *add_mountpoint(const char *path) { struct mountpoint *mp; char *path_sanitized; mp = get_mountpoint(path); if (mp) return mp; path_sanitized = sanitize_path(path); mp = xzalloc(sizeof(*mp)); mp->path = strdup(path); xasprintf(&mp->mountpath, "%s/mp-%s", tmppath(), path_sanitized); list_add_tail(&mp->list, &mountpoints); free(path_sanitized); return mp; } static void add_root_mountpoint(void) { struct mountpoint *mp; mp = xzalloc(sizeof(*mp)); mp->path = strdup(""); xasprintf(&mp->mountpath, "%s/root", tmppath()); list_add_tail(&mp->list, &mountpoints); } static int collect_mountpoints(void) { struct image *image; struct mountpoint *mp; int ret, need_mtime_fixup = 0, need_root = 0; list_for_each_entry(image, &images, list) { if (!(image->empty || image->handler->no_rootpath || image->srcpath)) { need_root = 1; break; } } if (!need_root) { disable_rootpath(); return 0; } add_root_mountpoint(); ret = systemp(NULL, "mkdir -p \"%s\"", tmppath()); if (ret) return ret; ret = systemp(NULL, "cp -a \"%s\" \"%s/root\"", rootpath(), tmppath()); if (ret) return ret; list_for_each_entry(image, &images, list) { if (image->mountpoint) image->mp = add_mountpoint(image->mountpoint); } list_for_each_entry(mp, &mountpoints, list) { if (!strlen(mp->path)) continue; ret = systemp(NULL, "mv \"%s/root/%s\" \"%s\"", tmppath(), mp->path, mp->mountpath); if (ret) return ret; ret = systemp(NULL, "mkdir \"%s/root/%s\"", tmppath(), mp->path); if (ret) return ret; ret = systemp(NULL, "chmod --reference=\"%s\" \"%s/root/%s\"", mp->mountpath, tmppath(), mp->path); if (ret) return ret; ret = systemp(NULL, "chown --reference=\"%s\" \"%s/root/%s\"", mp->mountpath, tmppath(), mp->path); if (ret) return ret; need_mtime_fixup = 1; } /* * After the mv/mkdir of the mountpoints the timestamps of the * mountpoint and all parent dirs are changed. Fix that here. */ if (need_mtime_fixup) ret = systemp(NULL, "find '%s/root' -depth -type d -printf '%%P\\0' | xargs -0 -I {} touch -r '%s/{}' '%s/root/{}'", tmppath(), rootpath(), tmppath()); return ret; } const char *mountpath(const struct image *image) { if(image->srcpath) return image->srcpath; struct mountpoint *mp; if (image->empty || image->handler->no_rootpath) return ""; mp = image->mp; if (!mp) mp = get_mountpoint(""); return mp->mountpath; } static enum { TMPPATH_NONE, TMPPATH_CHECKED, TMPPATH_CREATED } tmppath_generated; static void check_tmp_path(void) { const char *tmp = tmppath(); int ret; DIR *dir; int i = 0; if (!tmp) { error("tmppath not set. aborting\n"); exit(1); } dir = opendir(tmp); if (!dir) { ret = systemp(NULL, "mkdir -p \"%s\"", tmppath()); if (ret) exit(1); tmppath_generated = TMPPATH_CREATED; return; } while (1) { if (!readdir(dir)) break; i++; if (i > 2) { error("tmppath '%s' exists and is not empty\n", tmp); exit(1); } } tmppath_generated = TMPPATH_CHECKED; closedir(dir); } static void cleanup(void) { switch (tmppath_generated) { case TMPPATH_CREATED: systemp(NULL, "rm -rf \"%s/\"", tmppath()); break; case TMPPATH_CHECKED: systemp(NULL, "rm -rf \"%s\"/*", tmppath()); break; default: break; } } static cfg_opt_t top_opts[] = { CFG_SEC("image", NULL, CFGF_MULTI | CFGF_TITLE), CFG_SEC("flash", flashchip_opts, CFGF_MULTI | CFGF_TITLE), CFG_SEC("config", NULL, CFGF_MULTI), CFG_FUNC("include", &cfg_include), CFG_END() }; #ifdef HAVE_SEARCHPATH static int add_searchpath(cfg_t *cfg, const char *dir) { if (cfg_add_searchpath(cfg, dir)) { error("error adding %s to include search path", dir); return -1; } return 0; } static int set_include_path(cfg_t *cfg, const char *path) { char *dup, *s, *e; int ret; e = dup = strdup(path); do { s = e; e = strchr(s, ':'); if (e) *e++ = '\0'; ret = add_searchpath(cfg, s); if (ret) goto out; } while (e); /* Make sure current directory is always searched. */ ret = add_searchpath(cfg, "."); out: free(dup); return ret; } #endif int main(int argc, char *argv[]) { unsigned int i; unsigned int num_images; int ret; cfg_opt_t *imageopts = xzalloc((ARRAY_SIZE(image_common_opts) + ARRAY_SIZE(handlers) + 1) * sizeof(cfg_opt_t)); int start; struct image *image; const char *str; cfg_t *cfg; struct partition *part; cfg_opt_t image_end[] = { CFG_END() }; struct timeval tv; /* Seed the rng */ gettimeofday(&tv, NULL); srandom(tv.tv_usec); memcpy(imageopts, image_common_opts, sizeof(image_common_opts)); start = ARRAY_SIZE(image_common_opts); for (i = 0; i < ARRAY_SIZE(handlers); i++) { struct image_handler *handler = handlers[i]; cfg_opt_t image_tmp[] = { CFG_SEC("dummy", NULL, CFGF_MULTI), }; image_tmp[0].name = handler->type; image_tmp[0].subopts = handler->opts; memcpy(&imageopts[start + i], image_tmp, sizeof(cfg_opt_t)); } memcpy(&imageopts[start + i], &image_end[0], sizeof(cfg_opt_t)); top_opts[0].subopts = imageopts; init_config(); top_opts[2].subopts = get_confuse_opts(); /* call set_config_opts to make get_opt("config") work */ set_config_opts(argc, argv, NULL); cfg = cfg_init(top_opts, CFGF_NONE); str = get_opt("includepath"); if (str) { #ifdef HAVE_SEARCHPATH ret = set_include_path(cfg, str); if (ret) goto cleanup; #else error("--includepath used, but genimage built with too old libconfuse\n"); ret = -1; goto cleanup; #endif } ret = cfg_parse(cfg, get_opt("config")); switch (ret) { case 0: break; case CFG_PARSE_ERROR: goto cleanup; case CFG_FILE_ERROR: error("could not open config file '%s'\n", get_opt("config")); goto cleanup; } /* again, with config file this time */ set_config_opts(argc, argv, cfg); str = get_opt("configdump"); if (str) { FILE *dump; dump = (strcmp(str, "-")) ? fopen(str, "w") : stdout; if (!dump) { error("could not open dump file %s: %s", str, strerror(errno)); ret = -1; goto cleanup; } cfg_print(cfg, dump); if (dump != stdout) fclose(dump); } check_tmp_path(); ret = systemp(NULL, "rm -rf \"%s\"/*", tmppath()); if (ret) goto cleanup; parse_flashes(cfg); num_images = cfg_size(cfg, "image"); for (i = 0; i < num_images; i++) { cfg_t *imagesec = cfg_getnsec(cfg, "image", i); image = xzalloc(sizeof *image); INIT_LIST_HEAD(&image->partitions); list_add_tail(&image->list, &images); image->file = cfg_title(imagesec); image->name = cfg_getstr(imagesec, "name"); image->size = cfg_getint_suffix_percent(imagesec, "size", &image->size_is_percent); image->srcpath = cfg_getstr(imagesec, "srcpath"); image->mountpoint = cfg_getstr(imagesec, "mountpoint"); image->empty = cfg_getbool(imagesec, "empty"); image->temporary = cfg_getbool(imagesec, "temporary"); image->exec_pre = cfg_getstr(imagesec, "exec-pre"); image->exec_post = cfg_getstr(imagesec, "exec-post"); if (image->file[0] == '/') image->outfile = strdup(image->file); else xasprintf(&image->outfile, "%s/%s", image->temporary ? tmppath() : imagepath(), image->file); if (image->mountpoint && *image->mountpoint == '/') image->mountpoint++; if (image->srcpath && image->mountpoint && (strlen(image->mountpoint) > 0)) { image_error(image, "Cannot specify both srcpath and mountpoint at the same time."); goto cleanup; } str = cfg_getstr(imagesec, "flashtype"); if (str) image->flash_type = flash_type_get(str); image_set_handler(image, imagesec); parse_partitions(image, imagesec); if (image->handler->parse) { ret = image->handler->parse(image, image->imagesec); if (ret) goto cleanup; } } /* check if each partition has a corresponding image */ list_for_each_entry(image, &images, list) { list_for_each_entry(part, &image->partitions, list) { struct image *child; if (!part->image) { if (part->in_partition_table) continue; image_error(image, "no input file given\n"); ret = -EINVAL; goto cleanup; } child = image_get(part->image); if (child) { if (cfg_size(part->cfg, "holes") > 0) { image_error(image, "holes in partitions are only valid for implicit child images!\n"); ret = -EINVAL; goto cleanup; } continue; } image_debug(image, "adding implicit file rule for '%s'\n", part->image); child = xzalloc(sizeof *image); INIT_LIST_HEAD(&child->partitions); list_add_tail(&child->list, &images); child->file = part->image; child->handler = &file_handler; if (child->handler->parse) { ret = child->handler->parse(child, child->imagesec); if (ret) goto cleanup; } parse_holes(child, part->cfg); } } /* propagate flash types to partitions */ ret = set_flash_type(); if (ret) goto cleanup; ret = collect_mountpoints(); if (ret) goto cleanup; list_for_each_entry(image, &images, list) { ret = image_setup(image); if (ret) goto cleanup; } ret = setenv_paths(); if (ret) goto cleanup; ret = systemp(NULL, "mkdir -p \"%s\"", imagepath()); if (ret) goto cleanup; list_for_each_entry(image, &images, list) { ret = image_generate(image); if (ret) { image_error(image, "failed to generate %s\n", image->file); goto cleanup; } } cleanup: cleanup(); return ret ? 1 : 0; } genimage-18/genimage.h000066400000000000000000000137751464152623000150250ustar00rootroot00000000000000#ifndef __PTX_IMAGE_H #define __PTX_IMAGE_H #include #include #include "list.h" struct image_handler; struct image *image_get(const char *filename); int systemp(struct image *image, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); void error(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); void info(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); void debug(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); void image_error(struct image *image, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); void image_info(struct image *image, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); void image_debug(struct image *image, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); void xasprintf(char **strp, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); void xstrcatf(char **strp, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); void disable_rootpath(void); const char *imagepath(void); const char *inputpath(void); const char *rootpath(void); const char *tmppath(void); const char *mountpath(const struct image *); struct flash_type; struct mountpoint { char *path; struct list_head list; char *mountpath; }; struct partition { unsigned long long offset; unsigned long long size; unsigned long long align; unsigned char partition_type; cfg_bool_t bootable; cfg_bool_t logical; cfg_bool_t forced_primary; cfg_bool_t read_only; cfg_bool_t hidden; cfg_bool_t no_automount; cfg_bool_t fill; const char *image; off_t imageoffset; struct list_head list; int autoresize; int in_partition_table; const char *name; const char *partition_type_uuid; const char *partition_uuid; cfg_t *cfg; }; struct image { const char *name; const char *file; unsigned long long size; struct extent *holes; int n_holes; cfg_bool_t size_is_percent; const char *mountpoint; const char *srcpath; cfg_bool_t empty; cfg_bool_t temporary; const char *exec_pre; const char *exec_post; unsigned char partition_type; void *handler_priv; struct image_handler *handler; struct list_head list; int done; struct flash_type *flash_type; cfg_t *imagesec; struct list_head partitions; struct mountpoint *mp; char *outfile; int seen; off_t last_offset; }; struct image_handler { char *type; cfg_bool_t no_rootpath; int (*parse)(struct image *i, cfg_t *cfg); int (*setup)(struct image *i, cfg_t *cfg); int (*generate)(struct image *i); cfg_opt_t *opts; }; struct flash_type { const char *name; int pebsize; int lebsize; int numpebs; int minimum_io_unit_size; int vid_header_offset; int sub_page_size; struct list_head list; }; struct flash_type *flash_type_get(const char *name); extern struct image_handler android_sparse_handler; extern struct image_handler cpio_handler; extern struct image_handler cramfs_handler; extern struct image_handler ext2_handler; extern struct image_handler ext3_handler; extern struct image_handler ext4_handler; extern struct image_handler f2fs_handler; extern struct image_handler file_handler; extern struct image_handler flash_handler; extern struct image_handler hdimage_handler; extern struct image_handler iso_handler; extern struct image_handler jffs2_handler; extern struct image_handler qemu_handler; extern struct image_handler rauc_handler; extern struct image_handler squashfs_handler; extern struct image_handler tar_handler; extern struct image_handler ubi_handler; extern struct image_handler ubifs_handler; extern struct image_handler vfat_handler; extern struct image_handler fit_handler; extern struct image_handler fip_handler; #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) /** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) void *xzalloc(size_t n); void *xrealloc(void *ptr, size_t size); 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); const char *get_opt(const char *name); int set_config_opts(int argc, char *argv[], cfg_t *cfg); static inline size_t min(size_t a, size_t b) { return a < b ? a : b; } enum pad_mode { MODE_APPEND, MODE_OVERWRITE, }; struct extent { unsigned long long start, end; }; int open_file(struct image *image, const char *filename, int extra_flags); int map_file_extents(struct image *image, const char *filename, int fd, size_t size, struct extent **extents, size_t *extent_count); int is_block_device(const char *filename); int block_device_size(struct image *image, const char *blkdev, unsigned long long *size); int prepare_image(struct image *image, unsigned long long size); int insert_image(struct image *image, struct image *sub, unsigned long long size, unsigned long long offset, unsigned char byte); int insert_data(struct image *image, const void *data, const char *outfile, size_t size, unsigned long long offset); int extend_file(struct image *image, size_t size); int reload_partitions(struct image *image); int parse_holes(struct image *image, cfg_t *cfg); 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) { return image->outfile; } char *sanitize_path(const char *path); 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); uint32_t crc32_next(const void *data, size_t len, uint32_t last_crc); #define ct_assert(e) _Static_assert(e, #e) #endif /* __PTX_IMAGE_H */ genimage-18/image-android-sparse.c000066400000000000000000000256341464152623000172340ustar00rootroot00000000000000/* * Copyright (c) 2021 Michael Olbrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include "genimage.h" struct sparse { uint32_t block_size; }; struct sparse_header { uint32_t magic; uint16_t major_version; uint16_t minor_version; uint16_t header_size; uint16_t chunk_header_size; uint32_t block_size; uint32_t output_blocks; uint32_t input_chunks; uint32_t crc32; } __attribute__((packed)); #define SPARSE_RAW htole16(0xCAC1) #define SPARSE_FILL htole16(0xCAC2) #define SPARSE_DONT_CARE htole16(0xCAC3) #define SPARSE_CRC32 htole16(0xCAC4) struct sparse_chunk_header { uint16_t chunk_type; uint16_t reserved; uint32_t blocks; uint32_t size; } __attribute__((packed)); static int write_data(struct image *image, int fd, const void *data, size_t size) { int ret = 0; ssize_t written = write(fd, data, size); if (written < 0) { ret = -errno; image_error(image, "write %s: %s\n", imageoutfile(image), strerror(errno)); } else if ((size_t)written != size) { image_error(image, "only %llu bytes written instead of %llu\n", (unsigned long long)written, (unsigned long long)size); ret = -EINVAL; } return ret; } static int flush_header(struct image *image, int fd, struct sparse_chunk_header *header, ssize_t offset) { int ret; if (header->chunk_type == 0) return 0; if (offset >= 0) { if (lseek(fd, offset, SEEK_SET) < 0) { ret = -errno; image_error(image, "seek %s: %s\n", imageoutfile(image), strerror(errno)); return ret; } } ret = write_data(image, fd, header, sizeof(*header)); if (ret < 0) return ret; if (offset >= 0) { if (lseek(fd, 0, SEEK_END) < 0) { ret = -errno; image_error(image, "seek %s: %s\n", imageoutfile(image), strerror(errno)); return ret; } } if (header->blocks > 0 || header->chunk_type == SPARSE_CRC32) image_debug(image, "chunk(0x%04x): blocks =%7u size =%10u bytes\n", header->chunk_type, header->blocks, header->size); return 0; } static int android_sparse_generate(struct image *image) { struct sparse *sparse = image->handler_priv; struct image *inimage; const char *infile; struct sparse_header header; struct sparse_chunk_header chunk_header = {}; struct extent *extents = NULL; size_t extent_count, extent, block_count, block; int in_fd = -1, out_fd = -1, ret; off_t offset; unsigned int i; uint32_t *buf, *zeros, crc32 = 0; struct stat s; memset(&header, 0, sizeof(header)); header.magic = htole32(0xed26ff3a); header.major_version = htole16(0x1); header.minor_version = htole16(0x0); header.header_size = htole16(sizeof(struct sparse_header)); header.chunk_header_size = htole16(sizeof(struct sparse_chunk_header)); header.block_size = sparse->block_size; inimage = image_get(list_first_entry(&image->partitions, struct partition, list)->image); infile = imageoutfile(inimage); in_fd = open(infile, O_RDONLY); if (in_fd < 0) { ret = -errno; image_error(image, "open %s: %s\n", infile, strerror(errno)); return ret; } ret = fstat(in_fd, &s); if (ret) { ret = -errno; image_error(image, "stat %s: %s\n", infile, strerror(errno)); goto out; } block_count = (s.st_size - 1 + sparse->block_size) / sparse->block_size; header.output_blocks = block_count; ret = map_file_extents(inimage, infile, in_fd, s.st_size, &extents, &extent_count); if (ret < 0) goto out; /* The extents may have a different granularity than the chosen block size. So all start and end of all extents must be aligned accordingly. The extents may overlap now, so merge them if necessary. */ for (extent = 0; extent < extent_count; ++extent) { size_t size, max; int j; extents[extent].start = extents[extent].start / sparse->block_size * sparse->block_size; extents[extent].end = (extents[extent].end - 1 + sparse->block_size) / sparse->block_size * sparse->block_size; extents[extent].end = min(extents[extent].end, s.st_size); for (j = extent - 1; j > 0; --j) if (extents[j].end != 0) break; if (j >= 0 && extents[extent].start <= extents[j].end) { extents[j].end = extents[extent].end; extents[extent].start = 0; extents[extent].end = 0; } /* TODO: split extents that are too big */ max = (~(uint32_t)0) - sizeof(struct sparse_chunk_header); size = extents[extent].end - extents[extent].start; if (size > max) { image_error(image, "extents size %llu larger and supported maximum %llu.\n", (unsigned long long)size, (unsigned long long)max); ret = -EINVAL; goto out; } } out_fd = open_file(image, imageoutfile(image), O_TRUNC); if (out_fd < 0) { ret = out_fd; goto out; } ret = write_data(image, out_fd, &header, sizeof(header)); if (ret < 0) goto out; block = 0; buf = xzalloc(sparse->block_size); zeros = xzalloc(sparse->block_size); memset(zeros, 0, sparse->block_size); for (extent = 0; extent < extent_count; ++extent) { uint32_t start_block = extents[extent].start / sparse->block_size; size_t size = extents[extent].end - extents[extent].start; uint32_t fill_value = 0; size_t pos; /* skip removed extents */ if (size == 0) continue; if (block < start_block) { header.input_chunks++; chunk_header.chunk_type = SPARSE_DONT_CARE; chunk_header.blocks = start_block - block; chunk_header.size = sizeof(chunk_header); ret = flush_header(image, out_fd, &chunk_header, -1); if (ret < 0) return ret; block = start_block; for (i = 0; i < chunk_header.blocks; ++i) crc32 = crc32_next(zeros, sparse->block_size, crc32); } offset = lseek(in_fd, extents[extent].start, SEEK_SET); if (offset < 0) { ret = -errno; image_error(image, "seek %s: %s\n", infile, strerror(errno)); goto out; } chunk_header.chunk_type = 0; chunk_header.blocks = 0; pos = lseek(out_fd, 0, SEEK_CUR); while (size > 0) { ssize_t now = min(size, sparse->block_size); int fill = 1; ssize_t r = read(in_fd, buf, now); if (r < 0) { ret = -errno; image_error(image, "read %s: %s\n", infile, strerror(errno)); goto out; } else if (r != now) { ret = -EINVAL; image_error(image, "short read %s %lld != %lld\n", infile, (long long)r, (long long)now); goto out; } /* The sparse format only allows image sizes that are a multiple of the block size. Pad the last block as needed. */ if ((uint32_t)r < sparse->block_size) { memset(((char*)buf)+ r, 0, sparse->block_size - r); now = sparse->block_size; } crc32 = crc32_next(buf, sparse->block_size, crc32); for (i = 1; i < sparse->block_size/4; ++i) { if (buf[0] != buf[i]) { fill = 0; break; } } if (fill) { if (chunk_header.chunk_type != SPARSE_FILL || fill_value != buf[0]) { header.input_chunks++; ret = flush_header(image, out_fd, &chunk_header, pos); if (ret < 0) return ret; pos = lseek(out_fd, 0, SEEK_CUR); chunk_header.chunk_type = SPARSE_FILL; chunk_header.size = sizeof(chunk_header) + sizeof(buf[0]); chunk_header.blocks = 0; fill_value = buf[0]; ret = flush_header(image, out_fd, &chunk_header, -1); if (ret < 0) return ret; ret = write_data(image, out_fd, buf, sizeof(buf[0])); if (ret < 0) goto out; } chunk_header.blocks++; } else { if (chunk_header.chunk_type != SPARSE_RAW) { header.input_chunks++; ret = flush_header(image, out_fd, &chunk_header, pos); if (ret < 0) return ret; pos = lseek(out_fd, 0, SEEK_CUR); chunk_header.chunk_type = SPARSE_RAW; chunk_header.size = sizeof(chunk_header); chunk_header.blocks = 0; ret = flush_header(image, out_fd, &chunk_header, -1); if (ret < 0) return ret; } chunk_header.blocks++; chunk_header.size += now; ret = write_data(image, out_fd, buf, now); if (ret < 0) goto out; } size -= r; } ret = flush_header(image, out_fd, &chunk_header, pos); if (ret < 0) return ret; block = (extents[extent].end - 1 + sparse->block_size) / sparse->block_size; } if (block < block_count) { header.input_chunks++; chunk_header.chunk_type = SPARSE_DONT_CARE; chunk_header.blocks = block_count - block; chunk_header.size = sizeof(chunk_header); ret = flush_header(image, out_fd, &chunk_header, -1); if (ret < 0) return ret; for (i = 0; i < chunk_header.blocks; ++i) crc32 = crc32_next(zeros, sparse->block_size, crc32); } header.input_chunks++; chunk_header.chunk_type = SPARSE_CRC32; chunk_header.blocks = 0; chunk_header.size = sizeof(chunk_header) + sizeof(crc32); ret = flush_header(image, out_fd, &chunk_header, -1); if (ret < 0) return ret; ret = write_data(image, out_fd, &crc32, sizeof(crc32)); if (ret < 0) goto out; offset = lseek(out_fd, 0, SEEK_SET); if (offset < 0) { ret = -errno; image_error(image, "seek %s: %s\n", infile, strerror(errno)); goto out; } ret = write_data(image, out_fd, &header, sizeof(header)); if (ret < 0) goto out; image_info(image, "sparse image with %u chunks and %u blocks\n", header.input_chunks, header.output_blocks); out: close(in_fd); if (out_fd >= 0) close(out_fd); if (extents) free(extents); return ret; } static int android_sparse_parse(struct image *image, cfg_t *cfg) { struct partition *part; char *src; src = cfg_getstr(image->imagesec, "image"); if (!src) { image_error(image, "Mandatory 'image' option is missing!\n"); return -EINVAL; } image_info(image, "input image: %s\n", src); part = xzalloc(sizeof *part); part->image = src; list_add_tail(&part->list, &image->partitions); return 0; } static int android_sparse_setup(struct image *image, cfg_t *cfg) { struct sparse *sparse = xzalloc(sizeof(*sparse)); sparse->block_size = cfg_getint_suffix(cfg, "block-size"); if (sparse->block_size % 512) { image_error(image, "block-size %u invalid. It must be a multiple of 512!\n", sparse->block_size); return -EINVAL; } image->handler_priv = sparse; return 0; } static cfg_opt_t android_sparse_opts[] = { CFG_STR("image", NULL, CFGF_NONE), CFG_STR("block-size", "4k", CFGF_NONE), CFG_END() }; struct image_handler android_sparse_handler = { .type = "android-sparse", .no_rootpath = cfg_true, .generate = android_sparse_generate, .parse = android_sparse_parse, .setup = android_sparse_setup, .opts = android_sparse_opts, }; genimage-18/image-cpio.c000066400000000000000000000027371464152623000152520ustar00rootroot00000000000000/* * Copyright (c) 2011 Sascha Hauer , Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "genimage.h" static int cpio_generate(struct image *image) { int ret; char *format = cfg_getstr(image->imagesec, "format"); char *extraargs = cfg_getstr(image->imagesec, "extraargs"); char *comp = cfg_getstr(image->imagesec, "compress"); ret = systemp(image, "(cd '%s' && find . | %s -H '%s' %s -o %s %s) > '%s'", mountpath(image), get_opt("cpio"), format, extraargs, comp[0] != '\0' ? "|" : "", comp, imageoutfile(image)); return ret; } static cfg_opt_t cpio_opts[] = { CFG_STR("format", "newc", CFGF_NONE), CFG_STR("extraargs", "", CFGF_NONE), CFG_STR("compress", "", CFGF_NONE), CFG_END() }; struct image_handler cpio_handler = { .type = "cpio", .generate = cpio_generate, .opts = cpio_opts, }; genimage-18/image-cramfs.c000066400000000000000000000025101464152623000155600ustar00rootroot00000000000000/* * Copyright (c) 2016 Julien Viard de Galbert * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "genimage.h" static int cram_generate(struct image *image) { char *extraargs = cfg_getstr(image->imagesec, "extraargs"); return systemp(image, "%s%s%s %s '%s' '%s'", get_opt("mkcramfs"), image->name ? " -n " : "", image->name ? image->name : "", /* name */ extraargs, mountpath(image), /* source dir */ imageoutfile(image)); /* destination file */ } static cfg_opt_t cram_opts[] = { CFG_STR("extraargs", "", CFGF_NONE), CFG_END() }; struct image_handler cramfs_handler = { .type = "cramfs", .generate = cram_generate, .opts = cram_opts, }; genimage-18/image-ext2.c000066400000000000000000000144371464152623000152020ustar00rootroot00000000000000/* * Copyright (c) 2011 Sascha Hauer , Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "genimage.h" struct ext { int use_mke2fs; const char *features; char *usage_type_args; char *conf_env; char *size_features; }; static int ext2_generate_genext2fs(struct image *image) { int ret; struct ext *ext = image->handler_priv; const char *extraargs = cfg_getstr(image->imagesec, "extraargs"); const char *label = cfg_getstr(image->imagesec, "label"); ret = systemp(image, "%s %s%s%s --size-in-blocks=%lld -i 16384 '%s' %s", get_opt("genext2fs"), image->empty ? "" : "-d '", image->empty ? "" : mountpath(image), image->empty ? "" : "'", image->size / 1024, imageoutfile(image), extraargs); if (ret) return ret; if (ext->features && ext->features[0] != '\0') { ret = systemp(image, "%s -O '%s' '%s'", get_opt("tune2fs"), ext->features, imageoutfile(image)); if (ret) return ret; } if (label && label[0] != '\0') { ret = systemp(image, "%s -L '%s' '%s'", get_opt("tune2fs"), label, imageoutfile(image)); if (ret) return ret; } return 0; } static int ext2_generate_mke2fs(struct image *image) { struct ext *ext = image->handler_priv; const char *extraargs = cfg_getstr(image->imagesec, "extraargs"); const char *label = cfg_getstr(image->imagesec, "label"); const char *root_owner = cfg_getstr(image->imagesec, "root-owner"); const char *options = "lazy_itable_init=0,lazy_journal_init=0"; const char *features = ext->features; int ret; if (features && features[0] == '\0') features = NULL; if (label && label[0] == '\0') label = NULL; ret = prepare_image(image, image->size); if (ret < 0) return ret; return systemp(image, "%s%s -t %s%s -I 256 -E 'root_owner=%s,%s'%s %s%s%s %s %s%s%s %s%s%s '%s' %lldk", ext->conf_env, get_opt("mke2fs"), image->handler->type, ext->usage_type_args, root_owner, options, ext->size_features, image->empty ? "" : "-d '", image->empty ? "" : mountpath(image), image->empty ? "" : "'", extraargs, label ? "-L '" : "", label ? label : "", label ? "'" : "", features ? "-O '" : "", features ? features : "", features ? "'" : "", imageoutfile(image), image->size / 1024); } static int ext2_generate(struct image *image) { struct ext *ext = image->handler_priv; const char *fs_timestamp = cfg_getstr(image->imagesec, "fs-timestamp"); int ret; if (ext->use_mke2fs) ret = ext2_generate_mke2fs(image); else ret = ext2_generate_genext2fs(image); if (ret) return ret; ret = systemp(image, "%s -pvfD '%s'", get_opt("e2fsck"), imageoutfile(image)); /* e2fsck return 1 when the filesystem was successfully modified */ if (ret > 2) return ret; if (fs_timestamp) { ret = systemp(image, "echo '" "set_current_time %s\n" "set_super_value mkfs_time %s\n" "set_super_value lastcheck %s\n" "set_super_value mtime 00000000' | %s -w '%s'", fs_timestamp, fs_timestamp, fs_timestamp, get_opt("debugfs"), imageoutfile(image)); if (ret) return ret; } return 0; } static int ext2_setup(struct image *image, cfg_t *cfg) { struct ext *ext = xzalloc(sizeof(*ext)); const char *conf = cfg_getstr(image->imagesec, "mke2fs-conf"); const char *usage_type = cfg_getstr(image->imagesec, "usage-type"); if (!conf) { conf = cfg_getstr(image->imagesec, "mke2fs_conf"); if (conf) image_info(image, "option 'mke2fs_conf' is deprecated, use mke2fs-conf instead.\n"); } if (!image->size) { image_error(image, "no size given or must not be zero\n"); return -EINVAL; } ext->use_mke2fs = cfg_getbool(cfg, "use-mke2fs"); ext->features = cfg_getstr(image->imagesec, "features"); if (!ext->features) { if (!ext->use_mke2fs) { if (!strcmp(image->handler->type, "ext3")) ext->features = "has_journal"; else if (!strcmp(image->handler->type, "ext4")) ext->features = "extents,uninit_bg,dir_index,has_journal"; } } if (ext->use_mke2fs) { int is_large = image->size >= 4ll * 1024 * 1024 * 1024; int is_huge = image->size >= 2048ll * 1024 * 1024 * 1024; struct stat s; int ret; if (conf) { /* mke2fs ignores a missing config file, so make sure it exists. */ ret = stat(conf, &s); if (ret) { image_error(image, "mke2fs.conf(%s) does not exist: %s\n", conf, strerror(errno)); return -errno; } xasprintf(&ext->conf_env,"MKE2FS_CONFIG=\"%s\" ", conf); } else ext->conf_env = ""; if (usage_type) xasprintf(&ext->usage_type_args, " -T '%s'", usage_type); else ext->usage_type_args = ""; xasprintf(&ext->size_features, "%s%s", is_large ? "" : " -O '^large_file'", is_huge ? "" : " -O '^huge_file'"); } else { if (conf) { image_error(image, "'mke2fs.conf' is only used for 'mke2fs'\n"); return -EINVAL; } if (usage_type) { image_error(image, "'usage_type' is only used for 'mke2fs'\n"); return -EINVAL; } } image->handler_priv = ext; return 0; } static cfg_opt_t ext_opts[] = { CFG_STR("root-owner", "0:0", CFGF_NONE), CFG_STR("extraargs", "", CFGF_NONE), CFG_STR("features", NULL, CFGF_NONE), CFG_STR("label", NULL, CFGF_NONE), CFG_STR("fs-timestamp", NULL, CFGF_NONE), CFG_BOOL("use-mke2fs", cfg_true, CFGF_NONE), CFG_STR("usage-type", NULL, CFGF_NONE), CFG_STR("mke2fs-conf", NULL, CFGF_NONE), CFG_STR("mke2fs_conf", NULL, CFGF_NONE), CFG_END() }; struct image_handler ext2_handler = { .type = "ext2", .generate = ext2_generate, .setup = ext2_setup, .opts = ext_opts, }; struct image_handler ext3_handler = { .type = "ext3", .generate = ext2_generate, .setup = ext2_setup, .opts = ext_opts, }; struct image_handler ext4_handler = { .type = "ext4", .generate = ext2_generate, .setup = ext2_setup, .opts = ext_opts, }; genimage-18/image-f2fs.c000066400000000000000000000032001464152623000151420ustar00rootroot00000000000000/* * Copyright (c) 2022 Tomas Mudrunka * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "genimage.h" static int f2fs_generate(struct image *image) { int ret; char *extraargs = cfg_getstr(image->imagesec, "extraargs"); char *label = cfg_getstr(image->imagesec, "label"); extraargs = cfg_getstr(image->imagesec, "extraargs"); ret = prepare_image(image, image->size); if(ret) return ret; ret = systemp(image, "%s %s %s%s%s %s '%s'", get_opt("mkfsf2fs"), label ? "-l" : "", label ? "'" : "", label ? label : "", label ? "'" : "", extraargs, imageoutfile(image)); if(ret || image->empty) return ret; ret = systemp(image, "%s -f '%s' '%s'", get_opt("sloadf2fs"), mountpath(image), imageoutfile(image)); return ret; } static cfg_opt_t f2fs_opts[] = { CFG_STR("extraargs", "", CFGF_NONE), CFG_STR("label", NULL, CFGF_NONE), CFG_END() }; struct image_handler f2fs_handler = { .type = "f2fs", .generate = f2fs_generate, .opts = f2fs_opts, }; genimage-18/image-file.c000066400000000000000000000047351464152623000152370ustar00rootroot00000000000000/* * Copyright (c) 2011 Sascha Hauer , Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "genimage.h" struct file { char *name; char *infile; cfg_bool_t copy; }; static int file_generate(struct image *image) { struct file *f = image->handler_priv; int ret; if (!f->copy) return 0; if (!strcmp(f->infile, imageoutfile(image))) return 0; ret = systemp(image, "cp '%s' '%s'", f->infile, imageoutfile(image)); return ret; } static int file_setup(struct image *image, cfg_t *cfg) { struct file *f = xzalloc(sizeof(*f)); struct stat s; int ret; if (cfg) f->name = cfg_getstr(cfg, "name"); if (!f->name) f->name = strdup(image->file); if (f->name[0] == '/') f->infile = strdup(f->name); else xasprintf(&f->infile, "%s/%s", inputpath(), f->name); ret = stat(f->infile, &s); if (ret) { ret = -errno; image_error(image, "stat(%s) failed: %s\n", f->infile, strerror(errno)); return ret; } if (!image->size) image->size = s.st_size; if (cfg) f->copy = cfg_getbool(cfg, "copy"); else f->copy = cfg_false; if (!f->copy) { free(image->outfile); image->outfile = strdup(f->infile); } ret = parse_holes(image, cfg); if (ret) return ret; image->handler_priv = f; return 0; } static int file_parse(struct image *image, cfg_t *cfg) { /* File type images are used for custom types so assume that the * rootpath is need when a pre/post command is defined */ if (!image->exec_pre && !image->exec_post) image->empty = cfg_true; return 0; } static cfg_opt_t file_opts[] = { CFG_STR("name", NULL, CFGF_NONE), CFG_BOOL("copy", cfg_true, CFGF_NONE), CFG_STR_LIST("holes", NULL, CFGF_NONE), CFG_END() }; struct image_handler file_handler = { .type = "file", .generate = file_generate, .setup = file_setup, .parse = file_parse, .opts = file_opts, }; genimage-18/image-fip.c000066400000000000000000000114471464152623000150740ustar00rootroot00000000000000/* * Copyright (c) 2022 Ahmad Fatoum * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "genimage.h" static int fip_generate(struct image *image) { struct partition *part; char *args = strdup(""); const char *extraargs = cfg_getstr(image->imagesec, "extraargs"); int ret; list_for_each_entry(part, &image->partitions, list) { struct image *child = image_get(part->image); char *oldargs; oldargs = args; xasprintf(&args, "%s --%s '%s'", args, part->name, imageoutfile(child)); free(oldargs); } ret = systemp(image, "%s create %s %s '%s'", get_opt("fiptool"), args, extraargs, imageoutfile(image)); free(args); return ret; } static void fip_add_part(struct image *image, const char *name, const char *path) { struct partition *part; part = xzalloc(sizeof *part); part->image = path; part->name = name; list_add_tail(&part->list, &image->partitions); } static cfg_opt_t fip_opts[] = { CFG_STR("extraargs", "", CFGF_NONE), CFG_STR_LIST("tos-fw", NULL, CFGF_NONE), /* Secure Payload BL32 (Trusted OS, Extra1, Extra 2) */ /* CFGF_NODEFAULT marks options passed as-is */ CFG_STR("scp-fwu-cfg", NULL, CFGF_NODEFAULT), /* SCP Firmware Updater Configuration FWU SCP_BL2U */ CFG_STR("ap-fwu-cfg", NULL, CFGF_NODEFAULT), /* AP Firmware Updater Configuration BL2U */ CFG_STR("fwu", NULL, CFGF_NODEFAULT), /* Firmware Updater NS_BL2U */ CFG_STR("fwu-cert", NULL, CFGF_NODEFAULT), /* Non-Trusted Firmware Updater certificate */ CFG_STR("tb-fw", NULL, CFGF_NODEFAULT), /* Trusted Boot Firmware BL2 */ CFG_STR("scp-fw", NULL, CFGF_NODEFAULT), /* SCP Firmware SCP_BL2 */ CFG_STR("soc-fw", NULL, CFGF_NODEFAULT), /* EL3 Runtime Firmware BL31 */ CFG_STR("nt-fw", NULL, CFGF_NODEFAULT), /* Non-Trusted Firmware BL33 */ CFG_STR("fw-config", NULL, CFGF_NODEFAULT), /* FW_CONFIG */ CFG_STR("hw-config", NULL, CFGF_NODEFAULT), /* HW_CONFIG */ CFG_STR("tb-fw-config", NULL, CFGF_NODEFAULT), /* TB_FW_CONFIG */ CFG_STR("soc-fw-config", NULL, CFGF_NODEFAULT), /* SOC_FW_CONFIG */ CFG_STR("tos-fw-config", NULL, CFGF_NODEFAULT), /* TOS_FW_CONFIG */ CFG_STR("nt-fw-config", NULL, CFGF_NODEFAULT), /* NT_FW_CONFIG */ CFG_STR("rot-cert", NULL, CFGF_NODEFAULT), /* Root Of Trust key certificate */ CFG_STR("trusted-key-cert", NULL, CFGF_NODEFAULT), /* Trusted key certificate */ CFG_STR("scp-fw-key-cert", NULL, CFGF_NODEFAULT), /* SCP Firmware key certificate */ CFG_STR("soc-fw-key-cert", NULL, CFGF_NODEFAULT), /* SoC Firmware key certificate */ CFG_STR("tos-fw-key-cert", NULL, CFGF_NODEFAULT), /* Trusted OS Firmware key certificate */ CFG_STR("nt-fw-key-cert", NULL, CFGF_NODEFAULT), /* Non-Trusted Firmware key certificate */ CFG_STR("tb-fw-cert", NULL, CFGF_NODEFAULT), /* Trusted Boot Firmware BL2 certificate */ CFG_STR("scp-fw-cert", NULL, CFGF_NODEFAULT), /* SCP Firmware content certificate */ CFG_STR("soc-fw-cert", NULL, CFGF_NODEFAULT), /* SoC Firmware content certificate */ CFG_STR("tos-fw-cert", NULL, CFGF_NODEFAULT), /* Trusted OS Firmware content certificate */ CFG_STR("nt-fw-cert", NULL, CFGF_NODEFAULT), /* Non-Trusted Firmware content certificate */ CFG_STR("sip-sp-cert", NULL, CFGF_NODEFAULT), /* SiP owned Secure Partition content certificate */ CFG_STR("plat-sp-cert", NULL, CFGF_NODEFAULT), /* Platform owned Secure Partition content certificate */ CFG_END() }; static const char *tos_fw[] = { "tos-fw", "tos-fw-extra1", "tos-fw-extra2" }; static int fip_parse(struct image *image, cfg_t *cfg) { unsigned int i, num_tos_fw; cfg_opt_t *opt; num_tos_fw = cfg_size(cfg, "tos-fw"); if (num_tos_fw > ARRAY_SIZE(tos_fw)) { image_error(image, "%u tos-fw binaries given, but maximum is %zu\n", num_tos_fw, ARRAY_SIZE(tos_fw)); return -EINVAL; } for (i = 0; i < num_tos_fw; i++) fip_add_part(image, tos_fw[i], cfg_getnstr(cfg, "tos-fw", i)); for (opt = fip_opts; opt->type; opt++) { const char *file; if (opt->flags != CFGF_NODEFAULT) continue; file = cfg_getstr(cfg, opt->name); if (file) fip_add_part(image, opt->name, file); } return 0; } struct image_handler fip_handler = { .type = "fip", .no_rootpath = cfg_true, .generate = fip_generate, .parse = fip_parse, .opts = fip_opts, }; genimage-18/image-fit.c000066400000000000000000000060101464152623000150660ustar00rootroot00000000000000/* * Copyright (c) 2018 Sascha Hauer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include "genimage.h" static struct partition *partition_by_name(struct image *image, const char *name) { struct partition *part; list_for_each_entry(part, &image->partitions, list) if (!strcmp(part->name, name)) return part; return NULL; } static int fit_generate(struct image *image) { int ret; struct partition *part, *its; char *itspath; int itsfd; char *keydir = cfg_getstr(image->imagesec, "keydir"); char *keyopt = NULL; its = partition_by_name(image, "its"); if (!its) return -EINVAL; struct image *itsimg = image_get(its->image); xasprintf(&itspath, "%s/fit.its", tmppath()); /* Copy input its file to temporary path. Use 'cat' to ignore permissions */ ret = systemp(image, "cat '%s' > '%s'", imageoutfile(itsimg), itspath); if (ret) return ret; itsfd = open(itspath, O_WRONLY | O_APPEND); if (itsfd < 0) { printf("Cannot open %s: %s\n", itspath, strerror(errno)); return -errno; } dprintf(itsfd, "\n"); /* Add /incbin/ to each /images// node */ list_for_each_entry(part, &image->partitions, list) { struct image *child = image_get(part->image); const char *file = imageoutfile(child); const char *target = part->name; if (part == its) continue; dprintf(itsfd, "/ { images { %s { data = /incbin/(\"%s\"); };};};\n", target, file); } close(itsfd); if (keydir && *keydir) { if (*keydir != '/') { image_error(image, "'keydir' must be an absolute path\n"); return -EINVAL; } xasprintf(&keyopt, "-k '%s'", keydir); } ret = systemp(image, "%s -r %s -f '%s' '%s'", get_opt("mkimage"), keyopt ? keyopt : "", itspath, imageoutfile(image)); if (ret) image_error(image, "Failed to create FIT image\n"); return ret; } static int fit_parse(struct image *image, cfg_t *cfg) { struct partition *part; char *its = cfg_getstr(image->imagesec, "its"); part = xzalloc(sizeof *part); part->name = "its"; part->image = its; list_add_tail(&part->list, &image->partitions); return 0; } static cfg_opt_t fit_opts[] = { CFG_STR("keydir", "", CFGF_NONE), CFG_STR("its", "", CFGF_NONE), CFG_END() }; struct image_handler fit_handler = { .type = "fit", .no_rootpath = cfg_true, .generate = fit_generate, .parse = fit_parse, .opts = fit_opts, }; genimage-18/image-flash.c000066400000000000000000000076531464152623000154170ustar00rootroot00000000000000/* * Copyright (c) 2011 Sascha Hauer , Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include "list.h" #include "genimage.h" struct flash_image { }; static int flash_generate(struct image *image) { struct partition *part; unsigned long long end = 0; int ret; ret = prepare_image(image, image->size); if (ret < 0) return ret; list_for_each_entry(part, &image->partitions, list) { struct image *child = NULL; image_info(image, "writing image partition '%s' (0x%llx@0x%llx)\n", part->name, part->size, part->offset); if (part->offset > end) { ret = insert_image(image, NULL, part->offset - end, end, 0xFF); if (ret) { image_error(image, "failed to pad image to size %lld\n", part->offset); return ret; } } if (part->image) child = image_get(part->image); ret = insert_image(image, child, part->size, part->offset, 0xFF); if (ret) { image_error(image, "failed to write image partition '%s'\n", part->name); return ret; } end = part->offset + part->size; } return 0; } static int flash_setup(struct image *image, cfg_t *cfg) { struct flash_image *f = xzalloc(sizeof(*f)); struct partition *part; int last = 0; unsigned long long partsize = 0, flashsize; image->handler_priv = f; if (!image->flash_type) { image_error(image, "no flash type given\n"); return -EINVAL; } flashsize = (unsigned long long)image->flash_type->pebsize * image->flash_type->numpebs; list_for_each_entry(part, &image->partitions, list) { if (last) { image_error(image, "only last partition may have size 0\n"); return -EINVAL; } if (!part->size) { last = 1; if (partsize > flashsize) goto err_exceed; part->size = flashsize - partsize; } if (part->size % image->flash_type->pebsize) { image_error(image, "part %s size (%lld) must be a " "multiple of erase block size (%i bytes)\n", part->name, part->size, image->flash_type->pebsize); return -EINVAL; } if (part->offset % image->flash_type->pebsize) { image_error(image, "part %s offset (%lld) must be a" "multiple of erase block size (%i bytes)\n", part->name, part->offset, image->flash_type->pebsize); return -EINVAL; } if (part->offset) { if (partsize > part->offset) { image_error(image, "part %s overlaps with previous partition\n", part->name); return -EINVAL; } } else { part->offset = 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 (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; } } partsize = part->offset + part->size; } if (partsize > flashsize) { err_exceed: image_error(image, "size of partitions (%lld) exceeds flash size (%lld)\n", partsize, flashsize); return -EINVAL; } if (!image->size) image->size = partsize; return 0; } static cfg_opt_t flash_opts[] = { CFG_END() }; struct image_handler flash_handler = { .type = "flash", .no_rootpath = cfg_true, .generate = flash_generate, .setup = flash_setup, .opts = flash_opts, }; genimage-18/image-hd.c000066400000000000000000001204021464152623000147010ustar00rootroot00000000000000/* * Copyright (c) 2011 Sascha Hauer , Pengutronix * (c) 2011 Michael Olbrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include "genimage.h" #define TYPE_NONE 0 #define TYPE_MBR 1 #define TYPE_GPT 2 #define TYPE_HYBRID (TYPE_MBR|TYPE_GPT) #define PARTITION_TYPE_EXTENDED 0x0F struct hdimage { unsigned int extended_partition_index; struct partition *extended_partition; unsigned long long align; uint32_t disksig; const char *disk_uuid; int table_type; unsigned long long gpt_location; cfg_bool_t gpt_no_backup; cfg_bool_t fill; unsigned long long file_size; }; struct mbr_partition_entry { unsigned char boot; unsigned char first_chs[3]; unsigned char partition_type; unsigned char last_chs[3]; uint32_t relative_sectors; uint32_t total_sectors; } __attribute__((packed)); ct_assert(sizeof(struct mbr_partition_entry) == 16); struct mbr_tail { uint32_t disk_signature; uint16_t copy_protect; struct mbr_partition_entry part_entry[4]; uint16_t boot_signature; } __attribute__((packed)); ct_assert(sizeof(struct mbr_tail) == 72); struct gpt_header { unsigned char signature[8]; uint32_t revision; uint32_t header_size; uint32_t header_crc; uint32_t reserved; uint64_t current_lba; uint64_t backup_lba; uint64_t first_usable_lba; uint64_t last_usable_lba; unsigned char disk_uuid[16]; uint64_t starting_lba; uint32_t number_entries; uint32_t entry_size; uint32_t table_crc; } __attribute__((packed)); ct_assert(sizeof(struct gpt_header) == 92); struct gpt_partition_entry { unsigned char type_uuid[16]; unsigned char uuid[16]; uint64_t first_lba; uint64_t last_lba; uint64_t flags; uint16_t name[36]; } __attribute__((packed)); ct_assert(sizeof(struct gpt_partition_entry) == 128); #define GPT_ENTRIES 128 #define GPT_SECTORS (1 + GPT_ENTRIES * sizeof(struct gpt_partition_entry) / 512) #define GPT_REVISION_1_0 0x00010000 #define GPT_PE_FLAG_BOOTABLE (1ULL << 2) #define GPT_PE_FLAG_READ_ONLY (1ULL << 60) #define GPT_PE_FLAG_HIDDEN (1ULL << 62) #define GPT_PE_FLAG_NO_AUTO (1ULL << 63) static unsigned long long partition_end(const struct partition *part) { return part->offset + part->size; } static void lba_to_chs(unsigned int lba, unsigned char *chs) { const unsigned int hpc = 255; const unsigned int spt = 63; unsigned int s, c; chs[0] = (lba/spt)%hpc; c = (lba/(spt * hpc)); s = (lba > 0) ?(lba%spt + 1) : 0; chs[1] = ((c & 0x300) >> 2) | (s & 0xff); chs[2] = (c & 0xff); } static void hdimage_setup_chs(struct mbr_partition_entry *entry, unsigned long long offset_sectors) { lba_to_chs(entry->relative_sectors + offset_sectors, entry->first_chs); lba_to_chs(entry->relative_sectors + entry->total_sectors - 1 + offset_sectors, entry->last_chs); } static int hdimage_insert_mbr(struct image *image, struct list_head *partitions) { struct hdimage *hd = image->handler_priv; struct mbr_tail mbr; struct partition *part; int ret, i = 0; if (hd->table_type == TYPE_HYBRID) { image_info(image, "writing hybrid MBR\n"); } else { image_info(image, "writing MBR\n"); } memset(&mbr, 0, sizeof(mbr)); memcpy(&mbr.disk_signature, &hd->disksig, sizeof(hd->disksig)); list_for_each_entry(part, partitions, list) { struct mbr_partition_entry *entry; if (!part->in_partition_table || part->logical) continue; if (hd->table_type == TYPE_HYBRID && !part->partition_type) continue; entry = &mbr.part_entry[i]; entry->boot = part->bootable ? 0x80 : 0x00; entry->partition_type = part->partition_type; entry->relative_sectors = part->offset/512; entry->total_sectors = part->size/512; hdimage_setup_chs(entry, 0); image_debug(image, "[MBR entry %d]: type=%x start=%d size=%d\n", i, entry->partition_type, entry->relative_sectors, entry->total_sectors); i++; } if (hd->table_type == TYPE_HYBRID) { struct mbr_partition_entry *entry; entry = &mbr.part_entry[i]; entry->boot = 0x00; entry->partition_type = 0xee; entry->relative_sectors = 1; entry->total_sectors = hd->gpt_location / 512 + GPT_SECTORS - 2; hdimage_setup_chs(entry, 0); } mbr.boot_signature = htole16(0xaa55); ret = insert_data(image, &mbr, imageoutfile(image), sizeof(mbr), 440); if (ret) { if (hd->table_type == TYPE_HYBRID) { image_error(image, "failed to write hybrid MBR\n"); } else { image_error(image, "failed to write MBR\n"); } return ret; } return 0; } static int hdimage_insert_ebr(struct image *image, struct partition *part) { struct hdimage *hd = image->handler_priv; struct mbr_partition_entry *entry; char ebr[4*sizeof(struct mbr_partition_entry)+2], *part_table; int ret; unsigned long long ebr_offset = part->offset - hd->align + 446; image_debug(image, "writing EBR to sector %llu\n", ebr_offset / 512); memset(ebr, 0, sizeof(ebr)); part_table = ebr; entry = (struct mbr_partition_entry *)part_table; entry->boot = 0x00; entry->partition_type = part->partition_type; entry->relative_sectors = hd->align/512; entry->total_sectors = part->size/512; // absolute CHS address of the logical partition // equals to absolute partition offset hdimage_setup_chs(entry, (part->offset - hd->align) / 512); struct partition *p = part; list_for_each_entry_continue(p, &image->partitions, list) { if (!p->logical) continue; ++entry; entry->boot = 0x00; entry->partition_type = PARTITION_TYPE_EXTENDED; entry->relative_sectors = (p->offset - hd->align - hd->extended_partition->offset)/512; entry->total_sectors = (p->size + hd->align)/512; // absolute CHS address of the next EBR // equals to relative address within extended partition + partition start hdimage_setup_chs(entry, hd->extended_partition->offset / 512); break; } part_table += 4 * sizeof(struct mbr_partition_entry); part_table[0] = 0x55; part_table[1] = 0xaa; ret = insert_data(image, ebr, imageoutfile(image), sizeof(ebr), ebr_offset); if (ret) { image_error(image, "failed to write EBR\n"); return ret; } return 0; } struct gpt_partition_type_shortcut_t { const char * shortcut; const char * guid; }; static const struct gpt_partition_type_shortcut_t gpt_partition_type_shortcuts[] = { { "L" , "0fc63daf-8483-4772-8e79-3d69d8477de4" }, { "linux" , "0fc63daf-8483-4772-8e79-3d69d8477de4" }, { "S" , "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f" }, { "swap" , "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f" }, { "H" , "933ac7e1-2eb4-4f13-b844-0e14e2aef915" }, { "home" , "933ac7e1-2eb4-4f13-b844-0e14e2aef915" }, { "U" , "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" }, { "uefi" , "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" }, { "R" , "a19d880f-05fc-4d3b-a006-743f0f84911e" }, { "raid" , "a19d880f-05fc-4d3b-a006-743f0f84911e" }, { "V" , "e6d6d379-f507-44c2-a23c-238f2a3df928" }, { "lvm" , "e6d6d379-f507-44c2-a23c-238f2a3df928" }, { "F" , "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, { "fat32" , "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, { "barebox-state" , "4778ed65-bf42-45fa-9c5b-287a1dc4aab1" }, { "barebox-env" , "6c3737f2-07f8-45d1-ad45-15d260aab24d" }, /* Discoverable Partitions Specification GUID, see * https://uapi-group.org/specifications/specs/discoverable_partitions_specification/ */ { "root-alpha" , "6523f8ae-3eb1-4e2a-a05a-18b695ae656f" }, { "root-arc" , "d27f46ed-2919-4cb8-bd25-9531f3c16534" }, { "root-arm" , "69dad710-2ce4-4e3c-b16c-21a1d49abed3" }, { "root-arm64" , "b921b045-1df0-41c3-af44-4c6f280d3fae" }, { "root-ia64" , "993d8d3d-f80e-4225-855a-9daf8ed7ea97" }, { "root-loongarch64" , "77055800-792c-4f94-b39a-98c91b762bb6" }, { "root-mips" , "e9434544-6e2c-47cc-bae2-12d6deafb44c" }, { "root-mips64" , "d113af76-80ef-41b4-bdb6-0cff4d3d4a25" }, { "root-mips-le" , "37c58c8a-d913-4156-a25f-48b1b64e07f0" }, { "root-mips64-le" , "700bda43-7a34-4507-b179-eeb93d7a7ca3" }, { "root-parisc" , "1aacdb3b-5444-4138-bd9e-e5c2239b2346" }, { "root-ppc" , "1de3f1ef-fa98-47b5-8dcd-4a860a654d78" }, { "root-ppc64" , "912ade1d-a839-4913-8964-a10eee08fbd2" }, { "root-ppc64-le" , "c31c45e6-3f39-412e-80fb-4809c4980599" }, { "root-riscv32" , "60d5a7fe-8e7d-435c-b714-3dd8162144e1" }, { "root-riscv64" , "72ec70a6-cf74-40e6-bd49-4bda08e8f224" }, { "root-s390" , "08a7acea-624c-4a20-91e8-6e0fa67d23f9" }, { "root-s390x" , "5eead9a9-fe09-4a1e-a1d7-520d00531306" }, { "root-tilegx" , "c50cdd70-3862-4cc3-90e1-809a8c93ee2c" }, { "root-x86" , "44479540-f297-41b2-9af7-d131d5f0458a" }, { "root-x86-64" , "4f68bce3-e8cd-4db1-96e7-fbcaf984b709" }, { "usr-alpha" , "e18cf08c-33ec-4c0d-8246-c6c6fb3da024" }, { "usr-arc" , "7978a683-6316-4922-bbee-38bff5a2fecc" }, { "usr-arm" , "7d0359a3-02b3-4f0a-865c-654403e70625" }, { "usr-arm64" , "b0e01050-ee5f-4390-949a-9101b17104e9" }, { "usr-ia64" , "4301d2a6-4e3b-4b2a-bb94-9e0b2c4225ea" }, { "usr-loongarch64" , "e611c702-575c-4cbe-9a46-434fa0bf7e3f" }, { "usr-mips" , "773b2abc-2a99-4398-8bf5-03baac40d02b" }, { "usr-mips64" , "57e13958-7331-4365-8e6e-35eeee17c61b" }, { "usr-mips-le" , "0f4868e9-9952-4706-979f-3ed3a473e947" }, { "usr-mips64-le" , "c97c1f32-ba06-40b4-9f22-236061b08aa8" }, { "usr-parisc" , "dc4a4480-6917-4262-a4ec-db9384949f25" }, { "usr-ppc" , "7d14fec5-cc71-415d-9d6c-06bf0b3c3eaf" }, { "usr-ppc64" , "2c9739e2-f068-46b3-9fd0-01c5a9afbcca" }, { "usr-ppc64-le" , "15bb03af-77e7-4d4a-b12b-c0d084f7491c" }, { "usr-riscv32" , "b933fb22-5c3f-4f91-af90-e2bb0fa50702" }, { "usr-riscv64" , "beaec34b-8442-439b-a40b-984381ed097d" }, { "usr-s390" , "cd0f869b-d0fb-4ca0-b141-9ea87cc78d66" }, { "usr-s390x" , "8a4f5770-50aa-4ed3-874a-99b710db6fea" }, { "usr-tilegx" , "55497029-c7c1-44cc-aa39-815ed1558630" }, { "usr-x86" , "75250d76-8cc6-458e-bd66-bd47cc81a812" }, { "usr-x86-64" , "8484680c-9521-48c6-9c11-b0720656f69e" }, { "root-alpha-verity" , "fc56d9e9-e6e5-4c06-be32-e74407ce09a5" }, { "root-arc-verity" , "24b2d975-0f97-4521-afa1-cd531e421b8d" }, { "root-arm-verity" , "7386cdf2-203c-47a9-a498-f2ecce45a2d6" }, { "root-arm64-verity" , "df3300ce-d69f-4c92-978c-9bfb0f38d820" }, { "root-ia64-verity" , "86ed10d5-b607-45bb-8957-d350f23d0571" }, { "root-loongarch64-verity" , "f3393b22-e9af-4613-a948-9d3bfbd0c535" }, { "root-mips-verity" , "7a430799-f711-4c7e-8e5b-1d685bd48607" }, { "root-mips64-verity" , "579536f8-6a33-4055-a95a-df2d5e2c42a8" }, { "root-mips-le-verity" , "d7d150d2-2a04-4a33-8f12-16651205ff7b" }, { "root-mips64-le-verity" , "16b417f8-3e06-4f57-8dd2-9b5232f41aa6" }, { "root-parisc-verity" , "d212a430-fbc5-49f9-a983-a7feef2b8d0e" }, { "root-ppc64-le-verity" , "906bd944-4589-4aae-a4e4-dd983917446a" }, { "root-ppc64-verity" , "9225a9a3-3c19-4d89-b4f6-eeff88f17631" }, { "root-ppc-verity" , "98cfe649-1588-46dc-b2f0-add147424925" }, { "root-riscv32-verity" , "ae0253be-1167-4007-ac68-43926c14c5de" }, { "root-riscv64-verity" , "b6ed5582-440b-4209-b8da-5ff7c419ea3d" }, { "root-s390-verity" , "7ac63b47-b25c-463b-8df8-b4a94e6c90e1" }, { "root-s390x-verity" , "b325bfbe-c7be-4ab8-8357-139e652d2f6b" }, { "root-tilegx-verity" , "966061ec-28e4-4b2e-b4a5-1f0a825a1d84" }, { "root-x86-64-verity" , "2c7357ed-ebd2-46d9-aec1-23d437ec2bf5" }, { "root-x86-verity" , "d13c5d3b-b5d1-422a-b29f-9454fdc89d76" }, { "usr-alpha-verity" , "8cce0d25-c0d0-4a44-bd87-46331bf1df67" }, { "usr-arc-verity" , "fca0598c-d880-4591-8c16-4eda05c7347c" }, { "usr-arm-verity" , "c215d751-7bcd-4649-be90-6627490a4c05" }, { "usr-arm64-verity" , "6e11a4e7-fbca-4ded-b9e9-e1a512bb664e" }, { "usr-ia64-verity" , "6a491e03-3be7-4545-8e38-83320e0ea880" }, { "usr-loongarch64-verity" , "f46b2c26-59ae-48f0-9106-c50ed47f673d" }, { "usr-mips-verity" , "6e5a1bc8-d223-49b7-bca8-37a5fcceb996" }, { "usr-mips64-verity" , "81cf9d90-7458-4df4-8dcf-c8a3a404f09b" }, { "usr-mips-le-verity" , "46b98d8d-b55c-4e8f-aab3-37fca7f80752" }, { "usr-mips64-le-verity" , "3c3d61fe-b5f3-414d-bb71-8739a694a4ef" }, { "usr-parisc-verity" , "5843d618-ec37-48d7-9f12-cea8e08768b2" }, { "usr-ppc64-le-verity" , "ee2b9983-21e8-4153-86d9-b6901a54d1ce" }, { "usr-ppc64-verity" , "bdb528a5-a259-475f-a87d-da53fa736a07" }, { "usr-ppc-verity" , "df765d00-270e-49e5-bc75-f47bb2118b09" }, { "usr-riscv32-verity" , "cb1ee4e3-8cd0-4136-a0a4-aa61a32e8730" }, { "usr-riscv64-verity" , "8f1056be-9b05-47c4-81d6-be53128e5b54" }, { "usr-s390-verity" , "b663c618-e7bc-4d6d-90aa-11b756bb1797" }, { "usr-s390x-verity" , "31741cc4-1a2a-4111-a581-e00b447d2d06" }, { "usr-tilegx-verity" , "2fb4bf56-07fa-42da-8132-6b139f2026ae" }, { "usr-x86-64-verity" , "77ff5f63-e7b6-4633-acf4-1565b864c0e6" }, { "usr-x86-verity" , "8f461b0d-14ee-4e81-9aa9-049b6fb97abd" }, { "root-alpha-verity-sig" , "d46495b7-a053-414f-80f7-700c99921ef8" }, { "root-arc-verity-sig" , "143a70ba-cbd3-4f06-919f-6c05683a78bc" }, { "root-arm-verity-sig" , "42b0455f-eb11-491d-98d3-56145ba9d037" }, { "root-arm64-verity-sig" , "6db69de6-29f4-4758-a7a5-962190f00ce3" }, { "root-ia64-verity-sig" , "e98b36ee-32ba-4882-9b12-0ce14655f46a" }, { "root-loongarch64-verity-sig" , "5afb67eb-ecc8-4f85-ae8e-ac1e7c50e7d0" }, { "root-mips-verity-sig" , "bba210a2-9c5d-45ee-9e87-ff2ccbd002d0" }, { "root-mips64-verity-sig" , "43ce94d4-0f3d-4999-8250-b9deafd98e6e" }, { "root-mips-le-verity-sig" , "c919cc1f-4456-4eff-918c-f75e94525ca5" }, { "root-mips64-le-verity-sig" , "904e58ef-5c65-4a31-9c57-6af5fc7c5de7" }, { "root-parisc-verity-sig" , "15de6170-65d3-431c-916e-b0dcd8393f25" }, { "root-ppc64-le-verity-sig" , "d4a236e7-e873-4c07-bf1d-bf6cf7f1c3c6" }, { "root-ppc64-verity-sig" , "f5e2c20c-45b2-4ffa-bce9-2a60737e1aaf" }, { "root-ppc-verity-sig" , "1b31b5aa-add9-463a-b2ed-bd467fc857e7" }, { "root-riscv32-verity-sig" , "3a112a75-8729-4380-b4cf-764d79934448" }, { "root-riscv64-verity-sig" , "efe0f087-ea8d-4469-821a-4c2a96a8386a" }, { "root-s390-verity-sig" , "3482388e-4254-435a-a241-766a065f9960" }, { "root-s390x-verity-sig" , "c80187a5-73a3-491a-901a-017c3fa953e9" }, { "root-tilegx-verity-sig" , "b3671439-97b0-4a53-90f7-2d5a8f3ad47b" }, { "root-x86-64-verity-sig" , "41092b05-9fc8-4523-994f-2def0408b176" }, { "root-x86-verity-sig" , "5996fc05-109c-48de-808b-23fa0830b676" }, { "usr-alpha-verity-sig" , "5c6e1c76-076a-457a-a0fe-f3b4cd21ce6e" }, { "usr-arc-verity-sig" , "94f9a9a1-9971-427a-a400-50cb297f0f35" }, { "usr-arm-verity-sig" , "d7ff812f-37d1-4902-a810-d76ba57b975a" }, { "usr-arm64-verity-sig" , "c23ce4ff-44bd-4b00-b2d4-b41b3419e02a" }, { "usr-ia64-verity-sig" , "8de58bc2-2a43-460d-b14e-a76e4a17b47f" }, { "usr-loongarch64-verity-sig" , "b024f315-d330-444c-8461-44bbde524e99" }, { "usr-mips-verity-sig" , "97ae158d-f216-497b-8057-f7f905770f54" }, { "usr-mips64-verity-sig" , "05816ce2-dd40-4ac6-a61d-37d32dc1ba7d" }, { "usr-mips-le-verity-sig" , "3e23ca0b-a4bc-4b4e-8087-5ab6a26aa8a9" }, { "usr-mips64-le-verity-sig" , "f2c2c7ee-adcc-4351-b5c6-ee9816b66e16" }, { "usr-parisc-verity-sig" , "450dd7d1-3224-45ec-9cf2-a43a346d71ee" }, { "usr-ppc64-le-verity-sig" , "c8bfbd1e-268e-4521-8bba-bf314c399557" }, { "usr-ppc64-verity-sig" , "0b888863-d7f8-4d9e-9766-239fce4d58af" }, { "usr-ppc-verity-sig" , "7007891d-d371-4a80-86a4-5cb875b9302e" }, { "usr-riscv32-verity-sig" , "c3836a13-3137-45ba-b583-b16c50fe5eb4" }, { "usr-riscv64-verity-sig" , "d2f9000a-7a18-453f-b5cd-4d32f77a7b32" }, { "usr-s390-verity-sig" , "17440e4f-a8d0-467f-a46e-3912ae6ef2c5" }, { "usr-s390x-verity-sig" , "3f324816-667b-46ae-86ee-9b0c0c6c11b4" }, { "usr-tilegx-verity-sig" , "4ede75e2-6ccc-4cc8-b9c7-70334b087510" }, { "usr-x86-64-verity-sig" , "e7bb33fb-06cf-4e81-8273-e543b413e2e2" }, { "usr-x86-verity-sig" , "974a71c0-de41-43c3-be5d-5c5ccd1ad2c0" }, { "esp" , "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" }, { "xbootldr" , "bc13c2ff-59e6-4262-a352-b275fd6f7172" }, { "srv" , "3b8f8425-20e0-4f3b-907f-1a25a76f98e8" }, { "var" , "4d21b016-b534-45c2-a9fb-5c16e091fd2d" }, { "tmp" , "7ec6f557-3bc5-4aca-b293-16ef5df639d1" }, { "user-home" , "773f91ef-66d4-49b5-bd83-d683bf40ad16" }, { "linux-generic" , "0fc63daf-8483-4772-8e79-3d69d8477de4" }, { 0, 0 } /* sentinel */ }; static const char * gpt_partition_type_lookup(const char * shortcut) { const struct gpt_partition_type_shortcut_t * s; for(s = gpt_partition_type_shortcuts; s->shortcut; s++) { if(strcasecmp(s->shortcut, shortcut) == 0) { return s->guid; } } return NULL; } static int hdimage_insert_protective_mbr(struct image *image) { struct partition mbr; struct list_head mbr_list = LIST_HEAD_INIT(mbr_list); int ret = 0; image_info(image, "writing protective MBR\n"); memset(&mbr, 0, sizeof(struct partition)); mbr.offset = 512; mbr.size = image->size - 512; mbr.in_partition_table = 1; mbr.partition_type = 0xee; list_add_tail(&mbr.list, &mbr_list); ret = hdimage_insert_mbr(image, &mbr_list); if (ret) { image_error(image,"failed to write protective MBR\n"); return ret; } return 0; } static int hdimage_insert_gpt(struct image *image, struct list_head *partitions) { struct hdimage *hd = image->handler_priv; const char *outfile = imageoutfile(image); struct gpt_header header; struct gpt_partition_entry table[GPT_ENTRIES]; unsigned long long smallest_offset = ~0ULL; struct partition *part; unsigned i, j; int ret; image_info(image, "writing GPT\n"); memset(&header, 0, sizeof(struct gpt_header)); memcpy(header.signature, "EFI PART", 8); header.revision = htole32(GPT_REVISION_1_0); header.header_size = htole32(sizeof(struct gpt_header)); header.current_lba = htole64(1); header.backup_lba = htole64(hd->gpt_no_backup ? 1 :image->size/512 - 1); header.first_usable_lba = htole64(~0ULL); header.last_usable_lba = htole64(image->size/512 - 1 - GPT_SECTORS); uuid_parse(hd->disk_uuid, header.disk_uuid); 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 (!part->in_partition_table) continue; if (part->offset < smallest_offset) smallest_offset = part->offset; uuid_parse(part->partition_type_uuid, table[i].type_uuid); 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) | (part->read_only ? GPT_PE_FLAG_READ_ONLY : 0) | (part->hidden ? GPT_PE_FLAG_HIDDEN : 0) | (part->no_automount ? GPT_PE_FLAG_NO_AUTO : 0); for (j = 0; j < strlen(part->name) && j < 36; j++) table[i].name[j] = htole16(part->name[j]); i++; } if (smallest_offset == ~0ULL) smallest_offset = hd->gpt_location + (GPT_SECTORS - 1)*512; header.first_usable_lba = htole64(smallest_offset / 512); header.table_crc = htole32(crc32(table, sizeof(table))); header.header_crc = htole32(crc32(&header, sizeof(header))); ret = insert_data(image, &header, outfile, sizeof(header), 512); if (ret) { image_error(image, "failed to write GPT\n"); return ret; } ret = insert_data(image, &table, outfile, sizeof(table), hd->gpt_location); if (ret) { image_error(image, "failed to write GPT table\n"); return ret; } if (!hd->gpt_no_backup) { ret = extend_file(image, image->size); if (ret) { image_error(image, "failed to pad image to size %lld\n", image->size); return ret; } 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, &table, outfile, sizeof(table), image->size - GPT_SECTORS*512); if (ret) { image_error(image, "failed to write backup GPT table\n"); return ret; } ret = insert_data(image, &header, outfile, sizeof(header), image->size - 512); if (ret) { image_error(image, "failed to write backup GPT\n"); return ret; } } if (hd->table_type == TYPE_HYBRID) { ret = hdimage_insert_mbr(image, partitions); } else { ret = hdimage_insert_protective_mbr(image); } if (ret) { return ret; } return 0; } static int hdimage_generate(struct image *image) { struct partition *part; struct hdimage *hd = image->handler_priv; struct stat s; int ret; ret = prepare_image(image, hd->file_size); if (ret < 0) return ret; list_for_each_entry(part, &image->partitions, list) { struct image *child; image_info(image, "adding %s partition '%s'%s%s%s%s ...\n", part->logical ? "logical" : "primary", part->name, part->in_partition_table ? " (in MBR)" : "", part->image ? " from '": "", part->image ? part->image : "", part->image ? "'" : ""); if (part->logical) { ret = hdimage_insert_ebr(image, part); if (ret) { image_error(image, "failed to write EBR\n"); return ret; } } if (!part->image) continue; child = image_get(part->image); if (child->size == 0 && !part->fill) continue; 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 -E2BIG; } ret = insert_image(image, child, part->fill ? part->size : child->size, part->offset, 0); if (ret) { image_error(image, "failed to write image partition '%s'\n", part->name); return ret; } } if (hd->table_type != TYPE_NONE) { if (hd->table_type & TYPE_GPT) { ret = hdimage_insert_gpt(image, &image->partitions); if (ret) return ret; } else { ret = hdimage_insert_mbr(image, &image->partitions); if (ret) return ret; } } if (hd->fill) { ret = extend_file(image, image->size); if (ret) { image_error(image, "failed to fill the image.\n"); return ret; } } if (!is_block_device(imageoutfile(image))) { ret = stat(imageoutfile(image), &s); if (ret) { ret = -errno; image_error(image, "stat(%s) failed: %s\n", imageoutfile(image), strerror(errno)); return ret; } if (hd->file_size != (unsigned long long)s.st_size) { image_error(image, "unexpected output file size: %llu != %llu\n", hd->file_size, (unsigned long long)s.st_size); return -EINVAL; } } if (hd->table_type != TYPE_NONE) return reload_partitions(image); return 0; } static unsigned long long roundup(unsigned long long value, unsigned long long align) { return ((value - 1)/align + 1) * align; } static unsigned long long rounddown(unsigned long long value, unsigned long long align) { return value - (value % align); } static unsigned long long min_ull(unsigned long long x, unsigned long long y) { return x < y ? x : y; } static unsigned long long max_ull(unsigned long long x, unsigned long long y) { return x > y ? x : y; } static bool image_has_hole_covering(const char *image, unsigned long long start, unsigned long long end) { struct image *child; int i; if (!image) return false; child = image_get(image); for (i = 0; i < child->n_holes; ++i) { const struct extent *e = &child->holes[i]; if (e->start <= start && end <= e->end) return true; } return false; } static int check_overlap(struct image *image, struct partition *p) { unsigned long long start, end; struct partition *q; list_for_each_entry(q, &image->partitions, list) { /* Stop iterating when we reach p. */ if (p == q) return 0; /* We must have that p starts beyond where q ends... */ if (p->offset >= q->offset + q->size) continue; /* ...or vice versa. */ if (q->offset >= p->offset + p->size) continue; /* * Or maybe the image occupying the q partition has an * area which it is ok to overwrite. We do not do the * "vice versa" check, since images are written to the * output file in the order the partitions are * specified. */ start = max_ull(p->offset, q->offset); end = min_ull(p->offset + p->size, q->offset + q->size); if (image_has_hole_covering(q->image, start - q->offset, end - q->offset)) continue; image_error(image, "partition %s (offset 0x%llx, size 0x%llx) overlaps previous " "partition %s (offset 0x%llx, size 0x%llx)\n", p->name, p->offset, p->size, q->name, q->offset, q->size); if (!q->in_partition_table && (!strcmp(p->name, "[MBR]") || !strncmp(p->name, "[GPT", 4))) image_error(image, "bootloaders, etc. that overlap with the " "partition table must declare the overlapping " "area as a hole.\n"); return -EINVAL; } /* This should not be reached. */ image_error(image, "linked list corruption???\n"); return -EIO; } static struct partition * fake_partition(const char *name, unsigned long long offset, unsigned long long size) { struct partition *p = xzalloc(sizeof(*p)); p->name = name; p->offset = offset; p->size = size; p->align = 1; return p; } static void ensure_extended_partition_index(struct image *image) { struct hdimage *hd = image->handler_priv; struct partition *part; int count = 0; if (hd->extended_partition_index) return; list_for_each_entry(part, &image->partitions, list) { if (!part->in_partition_table) continue; if (++count > 4) { hd->extended_partition_index = 4; return; } } } static int setup_logical_partitions(struct image *image) { struct hdimage *hd = image->handler_priv; struct partition *part; bool in_extended = false, found_extended = false; unsigned int count = 0, mbr_entries = 0; if (hd->extended_partition_index > 4) { image_error(image, "invalid extended partition index (%i). must be " "less or equal to 4 (0 for automatic)\n", hd->extended_partition_index); return -EINVAL; } if (hd->table_type != TYPE_MBR) return 0; ensure_extended_partition_index(image); if (!hd->extended_partition_index) return 0; list_for_each_entry(part, &image->partitions, list) { if (!part->in_partition_table) continue; ++count; if (hd->extended_partition_index == count) { size_t offset = part->offset ? part->offset - hd->align : 0; struct partition *p = fake_partition("[Extended]", offset, 0); p->in_partition_table = true; p->partition_type = PARTITION_TYPE_EXTENDED; p->align = hd->align; hd->extended_partition = p; /* insert before the first logical partition */ list_add_tail(&p->list, &part->list); in_extended = found_extended = true; ++mbr_entries; } if (part->forced_primary) in_extended = false; if (in_extended && !part->forced_primary) part->logical = true; else ++mbr_entries; if (part->forced_primary) { if (!found_extended) { image_error(image, "partition %s: forced-primary can only be used for " "partitions following the extended partition\n", part->name); return -EINVAL; } } else if (!in_extended && found_extended) { image_error(image, "cannot create non-primary partition %s after forced-primary partition\n", part->name); return -EINVAL; } if (mbr_entries > 4) { image_error(image, "too many primary partitions\n"); return -EINVAL; } } return 0; } static int setup_uuid(struct image *image, cfg_t *cfg) { struct hdimage *hd = image->handler_priv; const char *disk_signature = cfg_getstr(cfg, "disk-signature"); hd->disk_uuid = cfg_getstr(cfg, "disk-uuid"); if (hd->disk_uuid) { if (!(hd->table_type & TYPE_GPT)) { image_error(image, "'disk-uuid' is only valid for gpt and hybrid partition-table-type\n"); return -EINVAL; } if (uuid_validate(hd->disk_uuid) == -1) { image_error(image, "invalid disk UUID: %s\n", hd->disk_uuid); return -EINVAL; } } else { hd->disk_uuid = uuid_random(); } if (!disk_signature) hd->disksig = 0; else if (!strcmp(disk_signature, "random")) hd->disksig = random(); else { if (!(hd->table_type & TYPE_MBR)) { image_error(image, "'disk-signature' is only valid for mbr and hybrid partition-table-type\n"); return -EINVAL; } hd->disksig = strtoul(disk_signature, NULL, 0); } return 0; } static int setup_part_autoresize(struct image *image, struct partition *part, bool *resized) { struct hdimage *hd = image->handler_priv; long long partsize; if (!part->autoresize) return 0; if (*resized) { image_error(image, "'autoresize' is only supported " "for one partition\n"); return -EINVAL; } if (image->size == 0) { image_error(image, "the image size must be specified " "when using an 'autoresize' partition\n"); return -EINVAL; } partsize = image->size - part->offset; if (hd->table_type & TYPE_GPT) partsize -= GPT_SECTORS * 512; partsize = rounddown(partsize, part->align); if (partsize <= 0) { image_error(image, "partitions exceed device size\n"); return -EINVAL; } if (partsize < (long long)part->size) { image_error(image, "auto-resize partition %s ends up with a size %lld" " smaller than minimum %lld\n", part->name, partsize, part->size); return -EINVAL; } part->size = partsize; *resized = true; return 0; } static int setup_part_image(struct image *image, struct partition *part) { struct hdimage *hd = image->handler_priv; struct image *child; if (!part->image) return 0; 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, part->align); else part->size = child->size; } 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->offset + child->size > hd->file_size) { size_t file_size = part->offset + child->size; if (file_size > hd->file_size) hd->file_size = file_size; } return 0; } static int hdimage_setup(struct image *image, cfg_t *cfg) { struct partition *part; unsigned int partition_table_entries = 0, hybrid_entries = 0; unsigned long long now = 0; const char *table_type; struct hdimage *hd = xzalloc(sizeof(*hd)); struct partition *gpt_backup = NULL; bool partition_resized = false; int ret; image->handler_priv = hd; hd->align = cfg_getint_suffix(cfg, "align"); hd->extended_partition_index = cfg_getint(cfg, "extended-partition"); table_type = cfg_getstr(cfg, "partition-table-type"); hd->gpt_location = cfg_getint_suffix(cfg, "gpt-location"); hd->gpt_no_backup = cfg_getbool(cfg, "gpt-no-backup"); hd->fill = cfg_getbool(cfg, "fill"); if (is_block_device(imageoutfile(image))) { if (image->size) { image_error(image, "image size must not be specified for a block device target\n"); return -EINVAL; } ret = block_device_size(image, imageoutfile(image), &image->size); if (ret) return ret; image_info(image, "determined size of block device %s to be %llu\n", imageoutfile(image), image->size); } if (!strcmp(table_type, "none")) hd->table_type = TYPE_NONE; else if (!strcmp(table_type, "mbr") || !strcmp(table_type, "dos")) hd->table_type = TYPE_MBR; else if (!strcmp(table_type, "gpt")) hd->table_type = TYPE_GPT; else if (!strcmp(table_type, "hybrid")) hd->table_type = TYPE_HYBRID; else { image_error(image, "'%s' is not a valid partition-table-type\n", table_type); return -EINVAL; } if (cfg_size(cfg, "partition-table") > 0) { hd->table_type = cfg_getbool(cfg, "partition-table") ? TYPE_MBR : TYPE_NONE; image_info(image, "The option 'partition-table' is deprecated. Use 'partition-table-type' instead\n"); } if (cfg_size(cfg, "gpt") > 0) { hd->table_type = cfg_getbool(cfg, "gpt") ? TYPE_GPT : TYPE_MBR; image_info(image, "The option 'gpt' is deprecated. Use 'partition-table-type' instead\n"); } if (!hd->align) hd->align = hd->table_type == TYPE_NONE ? 1 : 512; if ((hd->table_type != TYPE_NONE) && ((hd->align % 512) || (hd->align == 0))) { image_error(image, "partition alignment (%lld) must be a " "multiple of 1 sector (512 bytes)\n", hd->align); return -EINVAL; } ret = setup_logical_partitions(image); if (ret < 0) return ret; ret = setup_uuid(image, cfg); if (ret < 0) return ret; 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)\n", hd->gpt_location); } if (hd->table_type != TYPE_NONE) { struct partition *mbr = fake_partition("[MBR]", 512 - sizeof(struct mbr_tail), sizeof(struct mbr_tail)); list_add_tail(&mbr->list, &image->partitions); now = partition_end(mbr); if (hd->table_type & TYPE_GPT) { struct partition *gpt_header, *gpt_array; unsigned long long backup_offset, backup_size; gpt_header = fake_partition("[GPT header]", 512, 512); gpt_array = fake_partition("[GPT array]", hd->gpt_location, (GPT_SECTORS - 1) * 512); list_add_tail(&gpt_header->list, &image->partitions); list_add_tail(&gpt_array->list, &image->partitions); now = partition_end(gpt_array); /* Includes both the backup header and array. */ backup_size = GPT_SECTORS * 512; backup_offset = image->size ? image->size - backup_size : 0; gpt_backup = fake_partition("[GPT backup]", backup_offset, backup_size); list_add_tail(&gpt_backup->list, &image->partitions); } } partition_table_entries = 0; list_for_each_entry(part, &image->partitions, list) { if (hd->table_type == TYPE_NONE) part->in_partition_table = false; if (!part->align) part->align = (part->in_partition_table || hd->table_type == TYPE_NONE) ? hd->align : 1; if (part->in_partition_table && part->align % hd->align) { image_error(image, "partition alignment (%lld) of partition %s " "must be multiple of image alignment (%lld)", part->align, part->name, hd->align); } if (part->partition_type_uuid && !(hd->table_type & TYPE_GPT)) { image_error(image, "part %s: 'partition-type-uuid' is only valid for gpt and hybrid partition-table-type\n", part->name); return -EINVAL; } if (part->partition_type && !(hd->table_type & TYPE_MBR)) { image_error(image, "part %s: 'partition-type' is only valid for mbr and hybrid partition-table-type\n", part->name); return -EINVAL; } if ((hd->table_type & TYPE_GPT) && part->in_partition_table) { if (!part->partition_type_uuid) part->partition_type_uuid = "L"; if (strlen(part->partition_type_uuid) > 0 && uuid_validate(part->partition_type_uuid) != 0) { const char *uuid; uuid = gpt_partition_type_lookup(part->partition_type_uuid); if (!uuid) { image_error(image, "part %s has invalid type shortcut: %s\n", part->name, part->partition_type_uuid); return -EINVAL; } part->partition_type_uuid = uuid; } if (uuid_validate(part->partition_type_uuid) == -1) { image_error(image, "part %s has invalid partition type UUID: %s\n", part->name, part->partition_type_uuid); return -EINVAL; } if (part->partition_uuid) { if (uuid_validate(part->partition_uuid) == -1) { image_error(image, "part %s has invalid partition UUID: %s\n", part->name, part->partition_uuid); return -EINVAL; } } else { part->partition_uuid = uuid_random(); } if (part->partition_type) ++hybrid_entries; } if (part->in_partition_table) ++partition_table_entries; if (part->logical) { /* reserve space for extended boot record */ now += hd->align; now = roundup(now, part->align); } if (part == gpt_backup && !part->offset) { /* * Make sure the backup, and hence the whole * image, ends at a 4K boundary. */ now += part->size; part->offset = roundup(now, 4096) - part->size; } if (!part->offset && (part->in_partition_table || hd->table_type == TYPE_NONE)) { part->offset = roundup(now, part->align); } if (part->offset % part->align) { image_error(image, "part %s offset (%lld) must be a" "multiple of %lld bytes\n", part->name, part->offset, part->align); return -EINVAL; } ret = setup_part_autoresize(image, part, &partition_resized); if (ret < 0) return ret; ret = setup_part_image(image, part); if (ret < 0) return ret; /* the size of the extended partition will be filled in later */ if (!part->size && part != hd->extended_partition) { image_error(image, "part %s size must not be zero\n", part->name); return -EINVAL; } if (!part->logical) { ret = check_overlap(image, part); if (ret) return ret; } else if (now > part->offset) { image_error(image, "part %s overlaps with previous partition\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; } if (part->offset + part->size > now) now = part->offset + part->size; if (part->logical) { size_t file_size = part->offset - hd->align + 512; if (file_size > hd->file_size) hd->file_size = file_size; } if (part->logical) { hd->extended_partition->size = now - hd->extended_partition->offset; } } if (hybrid_entries > 3) { image_error(image, "hybrid MBR partitions (%i) exceeds maximum of 3\n", hybrid_entries); return -EINVAL; } if (hd->table_type == TYPE_HYBRID && hybrid_entries == 0) { image_error(image, "no partition with partition-type but hybrid partition-table-type selected\n"); return -EINVAL; } if (image->size > 0 && now > image->size) { image_error(image, "partitions exceed device size\n"); return -EINVAL; } if (image->size == 0) { image->size = now; } if (hd->fill || ((hd->table_type & TYPE_GPT) && !hd->gpt_no_backup)) hd->file_size = image->size; return 0; } static cfg_opt_t hdimage_opts[] = { CFG_STR("align", NULL, CFGF_NONE), CFG_STR("disk-signature", NULL, CFGF_NONE), CFG_STR("disk-uuid", NULL, CFGF_NONE), CFG_BOOL("partition-table", cfg_false, CFGF_NODEFAULT), CFG_INT("extended-partition", 0, CFGF_NONE), CFG_STR("partition-table-type", "mbr", CFGF_NONE), CFG_BOOL("gpt", cfg_false, CFGF_NODEFAULT), CFG_STR("gpt-location", NULL, CFGF_NONE), CFG_BOOL("gpt-no-backup", cfg_false, CFGF_NONE), CFG_BOOL("fill", cfg_false, CFGF_NONE), CFG_END() }; struct image_handler hdimage_handler = { .type = "hdimage", .no_rootpath = cfg_true, .generate = hdimage_generate, .setup = hdimage_setup, .opts = hdimage_opts, }; genimage-18/image-iso.c000066400000000000000000000035771464152623000151150ustar00rootroot00000000000000/* * Copyright (c) 2012 Michael Olbrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "genimage.h" static int iso_generate(struct image *image) { int ret; char *boot; char *boot_image = cfg_getstr(image->imagesec, "boot-image"); char *bootargs = cfg_getstr(image->imagesec, "bootargs"); char *extraargs = cfg_getstr(image->imagesec, "extraargs"); char *input_charset = cfg_getstr(image->imagesec, "input-charset"); char *volume_id = cfg_getstr(image->imagesec, "volume-id"); if (boot_image) xasprintf(&boot, "-b '%s' %s", boot_image, bootargs); else boot = ""; ret = systemp(image, "%s -input-charset %s -R -hide-rr-moved %s -V '%s' %s -o '%s' '%s'", get_opt("genisoimage"), input_charset, boot, volume_id, extraargs, imageoutfile(image), mountpath(image)); return ret; } static cfg_opt_t iso_opts[] = { CFG_STR("boot-image", NULL, CFGF_NONE), CFG_STR("bootargs", "-no-emul-boot -boot-load-size 4 -boot-info-table -c boot.cat -hide boot.cat", CFGF_NONE), CFG_STR("extraargs", "", CFGF_NONE), CFG_STR("input-charset", "default", CFGF_NONE), CFG_STR("volume-id", "", CFGF_NONE), CFG_END() }; struct image_handler iso_handler = { .type = "iso", .generate = iso_generate, .opts = iso_opts, }; genimage-18/image-jffs2.c000066400000000000000000000030561464152623000153250ustar00rootroot00000000000000/* * Copyright (c) 2011 Sascha Hauer , Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "genimage.h" static int jffs2_generate(struct image *image) { int ret; char *extraargs; extraargs = cfg_getstr(image->imagesec, "extraargs"); ret = systemp(image, "%s --eraseblock=%d %s%s%s -o '%s' %s", get_opt("mkfsjffs2"), image->flash_type->pebsize, image->empty ? "" : "-d '", image->empty ? "" : mountpath(image), image->empty ? "" : "'", imageoutfile(image), extraargs); return ret; } static int jffs2_setup(struct image *image, cfg_t *cfg) { if (!image->flash_type) { image_error(image, "no flash type given\n"); return -EINVAL; } return 0; } static cfg_opt_t jffs2_opts[] = { CFG_STR("extraargs", "", CFGF_NONE), CFG_END() }; struct image_handler jffs2_handler = { .type = "jffs2", .generate = jffs2_generate, .setup = jffs2_setup, .opts = jffs2_opts, }; genimage-18/image-qemu.c000066400000000000000000000045741464152623000152700ustar00rootroot00000000000000/* * Copyright (c) 2018 Alexandre Fournier , Kiplink * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "genimage.h" struct qemu { const char *format; const char *extraargs; }; static int qemu_generate(struct image *image) { struct partition *part; struct qemu *qemu = image->handler_priv; char *partitions = NULL; int ret; list_for_each_entry(part, &image->partitions, list) { struct image *child; const char *infile; if (!part->image) { image_debug(image, "skipping partition %s\n", part->name); continue; } image_info(image, "adding partition %s from %s ...\n", part->name, part->image); child = image_get(part->image); infile = imageoutfile(child); if (!partitions) xasprintf(&partitions, "'%s'", infile); else xasprintf(&partitions, "%s '%s'", partitions, infile); } ret = systemp(image, "qemu-img convert %s -O %s %s '%s'", qemu->extraargs, qemu->format, partitions, imageoutfile(image)); return ret; } static int qemu_setup(struct image *image, cfg_t *cfg) { struct qemu *qemu = xzalloc(sizeof(*qemu)); struct partition *part; int partitions_count = 0; list_for_each_entry(part, &image->partitions, list) { if (part->image) partitions_count++; } if (partitions_count == 0) { image_error(image, "no partition given\n"); return -EINVAL; } qemu->format = cfg_getstr(cfg, "format"); qemu->extraargs = cfg_getstr(cfg, "extraargs"); image->handler_priv = qemu; return 0; } static cfg_opt_t qemu_opts[] = { CFG_STR("format", "qcow2", CFGF_NONE), CFG_STR("extraargs", "", CFGF_NONE), CFG_END() }; struct image_handler qemu_handler = { .type = "qemu", .no_rootpath = cfg_true, .generate = qemu_generate, .setup = qemu_setup, .opts = qemu_opts, }; genimage-18/image-rauc.c000066400000000000000000000167051464152623000152520ustar00rootroot00000000000000/* * Copyright (c) 2016 Michael Olbrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "genimage.h" #define RAUC_CONTENT 0 #define RAUC_KEY 1 #define RAUC_CERT 2 #define RAUC_KEYRING 3 #define RAUC_INTERMEDIATE 4 static const char *pkcs11_prefix = "pkcs11:"; static int rauc_generate(struct image *image) { int ret; struct partition *part; const char *extraargs = cfg_getstr(image->imagesec, "extraargs"); const char *manifest = cfg_getstr(image->imagesec, "manifest"); const char *cert = cfg_getstr(image->imagesec, "cert"); const char *key = cfg_getstr(image->imagesec, "key"); const char *keyring = cfg_getstr(image->imagesec, "keyring"); char *keyringarg = NULL; char *manifest_file = NULL; char *tmpdir = NULL; char *intermediatearg = NULL; unsigned int i; image_debug(image, "manifest = '%s'\n", manifest); xasprintf(&tmpdir, "%s/rauc-%s", tmppath(), sanitize_path(image->file)); ret = systemp(image, "mkdir -p '%s'", tmpdir); if (ret) goto out; xasprintf(&manifest_file, "%s/manifest.raucm", tmpdir); ret = insert_data(image, manifest, manifest_file, strlen(manifest), 0); if (ret) goto out; for (i = 0; i < cfg_size(image->imagesec, "intermediate"); i++) { const char *uri; uri = cfg_getnstr(image->imagesec, "intermediate", i); if (!strncmp(pkcs11_prefix, uri, strlen(pkcs11_prefix))) xstrcatf(&intermediatearg, " --intermediate='%s'", uri); } list_for_each_entry(part, &image->partitions, list) { struct image *child = image_get(part->image); const char *file = imageoutfile(child); const char *target = part->name; char *tmptarget; char *path, *tmp; if (part->partition_type == RAUC_CERT) cert = file; if (part->partition_type == RAUC_KEY) key = file; if (part->partition_type == RAUC_KEYRING) keyring = file; if (part->partition_type == RAUC_INTERMEDIATE) xstrcatf(&intermediatearg, " --intermediate='%s'", file); if (part->partition_type != RAUC_CONTENT) continue; if (!target) { /* use basename from source as target name */ tmp = strrchr(child->file, '/'); if (tmp) target = tmp + 1; else target = child->file; } /* create parent directories if target needs it */ path = strdupa(target); tmp = strrchr(path, '/'); if (tmp) { *tmp = '\0'; ret = systemp(image, "mkdir -p '%s/%s'", tmpdir, path); if (ret) goto out; } xasprintf(&tmptarget, "%s/%s", tmpdir, target); image_info(image, "adding file '%s' as '%s' (offset=%lld)...\n", child->file, target, (long long)part->imageoffset); if (part->imageoffset) { unlink(tmptarget); /* * Starting with coreutils 9.1 you can use a 'B' suffix for * skip=N instead of iflag=skip_bytes to have N count bytes, not * (input) blocks. * * Note that dd doesn't behave as optimal as cp in the * else branch below because it doesn't preserve holes. * To improve here insert_image() should be extended to * support part->imageoffset != 0 and then it can * replace both commands. */ ret = systemp(image, "dd if='%s' of='%s' iflag=skip_bytes skip=%lld", file, tmptarget, (long long)part->imageoffset); } else { ret = systemp(image, "cp --remove-destination '%s' '%s'", file, tmptarget); } free(tmptarget); if (ret) goto out; } if (keyring) xasprintf(&keyringarg, "--keyring='%s'", keyring); systemp(image, "rm -f '%s'", imageoutfile(image)); ret = systemp(image, "%s bundle '%s' --cert='%s' --key='%s' %s %s %s '%s'", get_opt("rauc"), tmpdir, cert, key, (keyringarg ? keyringarg : ""), (intermediatearg ? intermediatearg : ""), extraargs, imageoutfile(image)); out: free(keyringarg); free(tmpdir); free(manifest_file); free(intermediatearg); return ret; } static int rauc_parse(struct image *image, cfg_t *cfg) { unsigned int i; unsigned int num_files; struct partition *part; char *part_image_key; char *part_image_cert; char *part_image_keyring; part_image_key = cfg_getstr(image->imagesec, "key"); if (!part_image_key) { image_error(image, "Mandatory 'key' option is missing!\n"); return -EINVAL; } 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_image_cert = cfg_getstr(image->imagesec, "cert"); if (!part_image_cert) { image_error(image, "Mandatory 'cert' option is missing!\n"); return -EINVAL; } 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); } part_image_keyring = cfg_getstr(image->imagesec, "keyring"); if (part_image_keyring) { part = xzalloc(sizeof *part); part->image = part_image_keyring; part->partition_type = RAUC_KEYRING; list_add_tail(&part->list, &image->partitions); } for (i = 0; i < cfg_size(cfg, "intermediate"); i++) { char *part_image_intermediate; part_image_intermediate = cfg_getnstr(cfg, "intermediate", i); if (strncmp(pkcs11_prefix, part_image_intermediate, strlen(pkcs11_prefix))) { part = xzalloc(sizeof *part); part->image = part_image_intermediate; part->partition_type = RAUC_INTERMEDIATE; list_add_tail(&part->list, &image->partitions); } } num_files = cfg_size(cfg, "file"); for (i = 0; i < num_files; i++) { cfg_t *filesec = cfg_getnsec(cfg, "file", i); part = xzalloc(sizeof *part); part->name = cfg_title(filesec); part->image = cfg_getstr(filesec, "image"); part->imageoffset = cfg_getint_suffix(filesec, "offset"); part->partition_type = RAUC_CONTENT; list_add_tail(&part->list, &image->partitions); } for(i = 0; i < cfg_size(cfg, "files"); i++) { part = xzalloc(sizeof *part); part->image = cfg_getnstr(cfg, "files", i); part->partition_type = RAUC_CONTENT; list_add_tail(&part->list, &image->partitions); } return 0; } static int rauc_setup(struct image *image, cfg_t *cfg) { char *manifest = cfg_getstr(image->imagesec, "manifest"); if (!manifest) { image_error(image, "Mandatory 'manifest' option is missing!\n"); return -EINVAL; } return 0; } static cfg_opt_t file_opts[] = { CFG_STR("image", NULL, CFGF_NONE), CFG_STR("offset", "0", CFGF_NONE), CFG_END() }; static cfg_opt_t rauc_opts[] = { CFG_STR("extraargs", "", CFGF_NONE), CFG_STR_LIST("files", NULL, CFGF_NONE), CFG_SEC("file", file_opts, CFGF_MULTI | CFGF_TITLE), CFG_STR("key", NULL, CFGF_NONE), CFG_STR("cert", NULL, CFGF_NONE), CFG_STR("keyring", NULL, CFGF_NONE), CFG_STR_LIST("intermediate", 0, CFGF_NONE), CFG_STR("manifest", NULL, CFGF_NONE), CFG_END() }; struct image_handler rauc_handler = { .type = "rauc", .no_rootpath = cfg_true, .generate = rauc_generate, .parse = rauc_parse, .setup = rauc_setup, .opts = rauc_opts, }; genimage-18/image-squashfs.c000066400000000000000000000056451464152623000161560ustar00rootroot00000000000000/* * Copyright (c) 2014 Juergen Beisert * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include "genimage.h" static int squash_generate(struct image *image) { char *extraargs = cfg_getstr(image->imagesec, "extraargs"); char compression[128]; char *comp_setup = cfg_getstr(image->imagesec, "compression"); unsigned block_size = cfg_getint_suffix(image->imagesec, "block-size"); unsigned long long file_size; struct stat sb; int ret; /* * 'mksquashfs' currently defaults to 'gzip' compression. Provide a shortcut * to be able to disable all kind of compression and force the current * default behaviour for the future. Disabling compression is very useful * to handle binary diffs. */ if (!strcasecmp(comp_setup, "none")) strncpy(compression, "-comp gzip -noInodeCompression -noDataCompression -noFragmentCompression -noXattrCompression", sizeof(compression)); else snprintf(compression, sizeof(compression), "-comp %s", comp_setup); ret = systemp(image, "%s '%s' '%s' -b %u -noappend %s %s", get_opt("mksquashfs"), mountpath(image), /* source dir */ imageoutfile(image), /* destination file */ block_size, compression, extraargs); if (ret) return ret; ret = stat(imageoutfile(image), &sb); if (ret) { ret = -errno; image_error(image, "stat(%s) failed: %s\n", imageoutfile(image), strerror(errno)); return ret; } file_size = sb.st_size; if (image->size && file_size > image->size) { image_error(image, "generated image %s is larger than given image size (%llu v %llu)\n", imageoutfile(image), file_size, image->size); return -E2BIG; } image_debug(image, "setting image size to %llu bytes\n", file_size); image->size = file_size; return 0; } /** * 'compression' can be 'gzip' (the current default), 'lzo', 'xz' or 'none' * @note 'none' is a special keyword to add the parameters '-noInodeCompression -noDataCompression -noFragmentCompression -noXattrCompression' */ static cfg_opt_t squash_opts[] = { CFG_STR("extraargs", "", CFGF_NONE), CFG_STR("compression", "gzip", CFGF_NONE), CFG_STR("block-size", "4096", CFGF_NONE), CFG_END() }; struct image_handler squashfs_handler = { .type = "squashfs", .generate = squash_generate, .opts = squash_opts, }; genimage-18/image-tar.c000066400000000000000000000024071464152623000151000ustar00rootroot00000000000000/* * Copyright (c) 2011 Sascha Hauer , Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "genimage.h" static int tar_generate(struct image *image) { int ret; char *comp = "a"; if (strstr(image->file, ".tar.gz") || strstr(image->file, "tgz")) comp = "z"; if (strstr(image->file, ".tar.bz2")) comp = "j"; ret = systemp(image, "%s c%s -f '%s' -C '%s' .", get_opt("tar"), comp, imageoutfile(image), mountpath(image)); return ret; } static cfg_opt_t tar_opts[] = { CFG_END() }; struct image_handler tar_handler = { .type = "tar", .generate = tar_generate, .opts = tar_opts, }; genimage-18/image-ubi.c000066400000000000000000000060641464152623000150740ustar00rootroot00000000000000/* * Copyright (c) 2011 Sascha Hauer , Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "genimage.h" struct ubi { }; static int ubi_generate(struct image *image) { int ret; FILE *fini; char *tempfile; int i = 0; struct partition *part; char *extraargs = cfg_getstr(image->imagesec, "extraargs"); xasprintf(&tempfile, "%s/ubi.ini", tmppath()); if (!tempfile) return -ENOMEM; fini = fopen(tempfile, "w"); if (!fini) { ret = -errno; image_error(image, "creating temp file failed: %s\n", strerror(errno)); goto err_free; } list_for_each_entry(part, &image->partitions, list) { struct image *child = NULL; unsigned long long size = part->size; if (part->image) child = image_get(part->image); if (!size) { if (!child) { image_error(image, "could not find %s\n", part->image); fclose(fini); ret = -EINVAL; goto err_free; } size = child->size; } fprintf(fini, "[%s]\n", part->name); fprintf(fini, "mode=ubi\n"); if (child) fprintf(fini, "image=%s\n", imageoutfile(child)); fprintf(fini, "vol_id=%d\n", i); fprintf(fini, "vol_size=%lld\n", size); fprintf(fini, "vol_type=%s\n", part->read_only ? "static" : "dynamic"); fprintf(fini, "vol_name=%s\n", part->name); if (part->autoresize) fprintf(fini, "vol_flags=autoresize\n"); fprintf(fini, "vol_alignment=1\n"); i++; } fclose(fini); ret = systemp(image, "%s -s %d -O %d -p %d -m %d -o '%s' '%s' %s", get_opt("ubinize"), image->flash_type->sub_page_size, image->flash_type->vid_header_offset, image->flash_type->pebsize, image->flash_type->minimum_io_unit_size, imageoutfile(image), tempfile, extraargs); err_free: free(tempfile); return ret; } static int ubi_setup(struct image *image, cfg_t *cfg) { struct ubi *ubi = xzalloc(sizeof(*ubi)); int autoresize = 0; struct partition *part; if (!image->flash_type) { image_error(image, "no flash type given\n"); return -EINVAL; } image->handler_priv = ubi; list_for_each_entry(part, &image->partitions, list) autoresize += part->autoresize; if (autoresize > 1) { image_error(image, "more than one volume has the autoresize flag set\n"); return -EINVAL; } return 0; } static cfg_opt_t ubi_opts[] = { CFG_STR("extraargs", "", CFGF_NONE), CFG_END() }; struct image_handler ubi_handler = { .type = "ubi", .no_rootpath = cfg_true, .generate = ubi_generate, .setup = ubi_setup, .opts = ubi_opts, }; genimage-18/image-ubifs.c000066400000000000000000000042521464152623000154220ustar00rootroot00000000000000/* * Copyright (c) 2011 Sascha Hauer , Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "genimage.h" static int ubifs_generate(struct image *image) { int max_leb_cnt; int ret; char *extraargs = cfg_getstr(image->imagesec, "extraargs"); unsigned long long max_size = cfg_getint_suffix(image->imagesec, "max-size"); cfg_bool_t space_fixup = cfg_getbool(image->imagesec, "space-fixup"); if (max_size) max_leb_cnt = max_size / image->flash_type->lebsize; else max_leb_cnt = image->size / image->flash_type->lebsize; ret = systemp(image, "%s %s%s%s %s -e %d -m %d -c %d -o '%s' %s", get_opt("mkfsubifs"), image->empty ? "" : "-d '", image->empty ? "" : mountpath(image), image->empty ? "" : "'", space_fixup ? "-F" : "", image->flash_type->lebsize, image->flash_type->minimum_io_unit_size, max_leb_cnt, imageoutfile(image), extraargs); return ret; } static int ubifs_setup(struct image *image, cfg_t *cfg) { if (!image->flash_type) { image_error(image, "no flash type given\n"); return -EINVAL; } if (image->flash_type->lebsize <= 0) { image_error(image, "invalid lebsize (%d) in %s\n", image->flash_type->lebsize, image->flash_type->name); return -EINVAL; } return 0; } static cfg_opt_t ubifs_opts[] = { CFG_STR("extraargs", "", CFGF_NONE), CFG_STR("max-size", NULL, CFGF_NONE), CFG_BOOL("space-fixup", 0, CFGF_NONE), CFG_END() }; struct image_handler ubifs_handler = { .type = "ubifs", .generate = ubifs_generate, .setup = ubifs_setup, .opts = ubifs_opts, }; genimage-18/image-vfat.c000066400000000000000000000071521464152623000152540ustar00rootroot00000000000000/* * Copyright (c) 2012 Michael Olbrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "genimage.h" static int vfat_generate(struct image *image) { int ret; struct partition *part; char *extraargs = cfg_getstr(image->imagesec, "extraargs"); char *label = cfg_getstr(image->imagesec, "label"); if (label && label[0] != '\0') xasprintf(&label, "-n '%s'", label); else label = ""; ret = prepare_image(image, image->size); if (ret) return ret; ret = systemp(image, "%s %s %s '%s'", get_opt("mkdosfs"), extraargs, label, imageoutfile(image)); if (ret) return ret; list_for_each_entry(part, &image->partitions, list) { struct image *child = image_get(part->image); const char *file = imageoutfile(child); const char *target = part->name; char *path = strdupa(target); char *next = path; while ((next = strchr(next, '/')) != NULL) { *next = '\0'; /* ignore the error: mdd fails if the target exists. */ systemp(image, "MTOOLS_SKIP_CHECK=1 %s -DsS -i %s '::%s'", get_opt("mmd"), imageoutfile(image), path); *next = '/'; ++next; } image_info(image, "adding file '%s' as '%s' ...\n", child->file, *target ? target : child->file); ret = systemp(image, "MTOOLS_SKIP_CHECK=1 %s -sp -i '%s' '%s' '::%s'", get_opt("mcopy"), imageoutfile(image), file, target); if (ret) return ret; } if (!list_empty(&image->partitions)) return 0; if (!image->empty) ret = systemp(image, "MTOOLS_SKIP_CHECK=1 %s -sp -i '%s' '%s'/* ::", get_opt("mcopy"), imageoutfile(image), mountpath(image)); return ret; } static int vfat_setup(struct image *image, cfg_t *cfg) { char *label = cfg_getstr(image->imagesec, "label"); if (!image->size) { image_error(image, "no size given or must not be zero\n"); return -EINVAL; } if (label && strlen(label) > 11) { image_error(image, "vfat volume name cannot be longer than 11 characters\n"); return -EINVAL; } return 0; } static int vfat_parse(struct image *image, cfg_t *cfg) { unsigned int i; unsigned int num_files; struct partition *part; num_files = cfg_size(cfg, "file"); for (i = 0; i < num_files; i++) { cfg_t *filesec = cfg_getnsec(cfg, "file", i); part = xzalloc(sizeof *part); part->name = cfg_title(filesec); part->image = cfg_getstr(filesec, "image"); list_add_tail(&part->list, &image->partitions); } for(i = 0; i < cfg_size(cfg, "files"); i++) { part = xzalloc(sizeof *part); part->image = cfg_getnstr(cfg, "files", i); part->name = ""; list_add_tail(&part->list, &image->partitions); } return 0; } static cfg_opt_t file_opts[] = { CFG_STR("image", NULL, CFGF_NONE), CFG_END() }; static cfg_opt_t vfat_opts[] = { CFG_STR("extraargs", "", CFGF_NONE), CFG_STR("label", "", CFGF_NONE), CFG_STR_LIST("files", NULL, CFGF_NONE), CFG_SEC("file", file_opts, CFGF_MULTI | CFGF_TITLE), CFG_END() }; struct image_handler vfat_handler = { .type = "vfat", .generate = vfat_generate, .setup = vfat_setup, .parse = vfat_parse, .opts = vfat_opts, }; genimage-18/list.h000066400000000000000000000410301464152623000142050ustar00rootroot00000000000000#ifndef _LINUX_LIST_H #define _LINUX_LIST_H /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ #define LIST_POISON1 ((void *) 0x00100100) #define LIST_POISON2 ((void *) 0x00200200) struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ #ifndef CONFIG_DEBUG_LIST static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } #else extern void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next); #endif /** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ #ifndef CONFIG_DEBUG_LIST static inline void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } #else extern void list_add(struct list_head *new, struct list_head *head); #endif /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty() on entry does not return true after this, the entry is * in an undefined state. */ #ifndef CONFIG_DEBUG_LIST static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = LIST_POISON1; entry->prev = LIST_POISON2; } #else extern void list_del(struct list_head *entry); #endif /** * list_replace - replace old entry by new one * @old : the element to be replaced * @new : the new element to insert * * If @old was empty, it will be overwritten. */ static inline void list_replace(struct list_head *old, struct list_head *new) { new->next = old->next; new->next->prev = new; new->prev = old->prev; new->prev->next = new; } static inline void list_replace_init(struct list_head *old, struct list_head *new) { list_replace(old, new); INIT_LIST_HEAD(old); } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static inline void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } /** * list_move - delete from one list and add as another's head * @list: the entry to move * @head: the head that will precede our entry */ static inline void list_move(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add(list, head); } /** * list_move_tail - delete from one list and add as another's tail * @list: the entry to move * @head: the head that will follow our entry */ static inline void list_move_tail(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add_tail(list, head); } /** * list_is_last - tests whether @list is the last entry in list @head * @list: the entry to test * @head: the head of the list */ static inline int list_is_last(const struct list_head *list, const struct list_head *head) { return list->next == head; } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty(const struct list_head *head) { return head->next == head; } /** * list_empty_careful - tests whether a list is empty and not being modified * @head: the list to test * * Description: * tests whether a list is empty _and_ checks that no other CPU might be * in the process of modifying either member (next or prev) * * NOTE: using list_empty_careful() without synchronization * can only be safe if the only activity that can happen * to the list entry is list_del_init(). Eg. it cannot be used * if another CPU could re-list_add() it. */ static inline int list_empty_careful(const struct list_head *head) { struct list_head *next = head->next; return (next == head) && (next == head->prev); } static inline void __list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } /** * list_splice - join two lists * @list: the new list to add. * @head: the place to add it in the first list. */ static inline void list_splice(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head); } /** * list_splice_init - join two lists and reinitialise the emptied list. * @list: the new list to add. * @head: the place to add it in the first list. * * The list at @list is reinitialised */ static inline void list_splice_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head); INIT_LIST_HEAD(list); } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ container_of(ptr, type, member) /** * list_first_entry - get the first element from a list * @ptr: the list head to take the element from. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. * * Note, that list is expected to be not empty. */ #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); \ pos = pos->next) /** * list_for_each_prev - iterate over a list backwards * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); \ pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop cursor. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_reverse - iterate backwards over list of given type. * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_reverse(pos, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.prev, typeof(*pos), member)) /** * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() * @pos: the type * to use as a start point * @head: the head of the list * @member: the name of the list_struct within the struct. * * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). */ #define list_prepare_entry(pos, head, member) \ ((pos) ? : list_entry(head, typeof(*pos), member)) /** * list_for_each_entry_continue - continue iteration over list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Continue to iterate over list of given type, continuing after * the current position. */ #define list_for_each_entry_continue(pos, head, member) \ for (pos = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_from - iterate over list of given type from the current point * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing from current position. */ #define list_for_each_entry_from(pos, head, member) \ for (; &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_continue * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing after current point, * safe against removal of list entry. */ #define list_for_each_entry_safe_continue(pos, n, head, member) \ for (pos = list_entry(pos->member.next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_from * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type from current point, safe against * removal of list entry. */ #define list_for_each_entry_safe_from(pos, n, head, member) \ for (n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_reverse * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate backwards over list of given type, safe against removal * of list entry. */ #define list_for_each_entry_safe_reverse(pos, n, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member), \ n = list_entry(pos->member.prev, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.prev, typeof(*n), member)) /** * list_add_sort - add a new entry to a sorted list * @new: new entry to be added * @head: list head to add it in * @compare: Compare function to compare two list entries * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_sort(struct list_head *new, struct list_head *head, int (*compare)(struct list_head *a, struct list_head *b)) { struct list_head *pos, *insert = head; list_for_each(pos, head) { if (compare(pos, new) < 0) continue; insert = pos; break; } list_add_tail(new, insert); } /* * Double linked lists with a single pointer list head. * Mostly useful for hash tables where the two pointer list head is * too wasteful. * You lose the ability to access the tail in O(1). */ struct hlist_head { struct hlist_node *first; }; struct hlist_node { struct hlist_node *next, **pprev; }; #define HLIST_HEAD_INIT { .first = NULL } #define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) static inline void INIT_HLIST_NODE(struct hlist_node *h) { h->next = NULL; h->pprev = NULL; } static inline int hlist_unhashed(const struct hlist_node *h) { return !h->pprev; } static inline int hlist_empty(const struct hlist_head *h) { return !h->first; } static inline void __hlist_del(struct hlist_node *n) { struct hlist_node *next = n->next; struct hlist_node **pprev = n->pprev; *pprev = next; if (next) next->pprev = pprev; } static inline void hlist_del(struct hlist_node *n) { __hlist_del(n); n->next = LIST_POISON1; n->pprev = LIST_POISON2; } static inline void hlist_del_init(struct hlist_node *n) { if (!hlist_unhashed(n)) { __hlist_del(n); INIT_HLIST_NODE(n); } } static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { struct hlist_node *first = h->first; n->next = first; if (first) first->pprev = &n->next; h->first = n; n->pprev = &h->first; } /* next must be != NULL */ static inline void hlist_add_before(struct hlist_node *n, struct hlist_node *next) { n->pprev = next->pprev; n->next = next; next->pprev = &n->next; *(n->pprev) = n; } static inline void hlist_add_after(struct hlist_node *n, struct hlist_node *next) { next->next = n->next; n->next = next; next->pprev = &n->next; if(next->next) next->next->pprev = &next->next; } #define hlist_entry(ptr, type, member) container_of(ptr,type,member) #define hlist_for_each(pos, head) \ for (pos = (head)->first; pos; \ pos = pos->next) #define hlist_for_each_safe(pos, n, head) \ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ pos = n) /** * hlist_for_each_entry - iterate over list of given type * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @head: the head for your list. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry(tpos, pos, head, member) \ for (pos = (head)->first; \ pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) /** * hlist_for_each_entry_continue - iterate over a hlist continuing after current point * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_continue(tpos, pos, member) \ for (pos = (pos)->next; \ pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) /** * hlist_for_each_entry_from - iterate over a hlist continuing from current point * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_from(tpos, pos, member) \ for (; pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) /** * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @n: another &struct hlist_node to use as temporary storage * @head: the head for your list. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ for (pos = (head)->first; \ pos && ({ n = pos->next; 1; }) && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = n) #endif genimage-18/m4/000077500000000000000000000000001464152623000134035ustar00rootroot00000000000000genimage-18/m4/.gitignore000066400000000000000000000001001464152623000153620ustar00rootroot00000000000000libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 lt~obsolete.m4 genimage-18/m4/attributes.m4000066400000000000000000000242741464152623000160440ustar00rootroot00000000000000dnl Macros to check the presence of generic (non-typed) symbols. dnl Copyright (c) 2006-2008 Diego Pettenò dnl Copyright (c) 2006-2008 xine project dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2, or (at your option) dnl any later version. dnl dnl This program is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the dnl GNU General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA dnl 02110-1301, USA. dnl dnl As a special exception, the copyright owners of the dnl macro gives unlimited permission to copy, distribute and modify the dnl configure scripts that are the output of Autoconf when processing the dnl Macro. You need not follow the terms of the GNU General Public dnl License when using or distributing such scripts, even though portions dnl of the text of the Macro appear in them. The GNU General Public dnl License (GPL) does govern all other use of the material that dnl constitutes the Autoconf Macro. dnl dnl This special exception to the GPL applies to versions of the dnl Autoconf Macro released by this project. When you make and dnl distribute a modified version of the Autoconf Macro, you may extend dnl this special exception to the GPL to apply to your modified version as dnl well. dnl Check if the flag is supported by compiler dnl CC_CHECK_CFLAGS_SILENT([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [ AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]), [ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $1" AC_COMPILE_IFELSE([AC_LANG_SOURCE([int a;])], [eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"], [eval "AS_TR_SH([cc_cv_cflags_$1])='no'"]) CFLAGS="$ac_save_CFLAGS" ]) AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], [$2], [$3]) ]) dnl Check if the flag is supported by compiler (cacheable) dnl CC_CHECK_CFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) AC_DEFUN([CC_CHECK_CFLAGS], [ AC_CACHE_CHECK([if $CC supports $1 flag], AS_TR_SH([cc_cv_cflags_$1]), CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! ) AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], [$2], [$3]) ]) dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found]) dnl Check for CFLAG and appends them to CFLAGS if supported AC_DEFUN([CC_CHECK_CFLAG_APPEND], [ AC_CACHE_CHECK([if $CC supports $1 flag], AS_TR_SH([cc_cv_cflags_$1]), CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! ) AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], [CFLAGS="$CFLAGS $1"; DEBUG_CFLAGS="$DEBUG_CFLAGS $1"; $2], [$3]) ]) dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not]) AC_DEFUN([CC_CHECK_CFLAGS_APPEND], [ for flag in $1; do CC_CHECK_CFLAG_APPEND($flag, [$2], [$3]) done ]) dnl Check if the flag is supported by linker (cacheable) dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) AC_DEFUN([CC_CHECK_LDFLAGS], [ AC_CACHE_CHECK([if $CC supports $1 flag], AS_TR_SH([cc_cv_ldflags_$1]), [ac_save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $1" AC_LINK_IFELSE([AC_LANG_SOURCE([int main() { return 1; }])], [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) LDFLAGS="$ac_save_LDFLAGS" ]) AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], [$2], [$3]) ]) dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for dnl the current linker to avoid undefined references in a shared object. AC_DEFUN([CC_NOUNDEFINED], [ dnl We check $host for which systems to enable this for. AC_REQUIRE([AC_CANONICAL_HOST]) case $host in dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads dnl are requested, as different implementations are present; to avoid problems dnl use -Wl,-z,defs only for those platform not behaving this way. *-freebsd* | *-openbsd*) ;; *) dnl First of all check for the --no-undefined variant of GNU ld. This allows dnl for a much more readable commandline, so that people can understand what dnl it does without going to look for what the heck -z defs does. for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) break done ;; esac AC_SUBST([LDFLAGS_NOUNDEFINED]) ]) dnl Check for a -Werror flag or equivalent. -Werror is the GCC dnl and ICC flag that tells the compiler to treat all the warnings dnl as fatal. We usually need this option to make sure that some dnl constructs (like attributes) are not simply ignored. dnl dnl Other compilers don't support -Werror per se, but they support dnl an equivalent flag: dnl - Sun Studio compiler supports -errwarn=%all AC_DEFUN([CC_CHECK_WERROR], [ AC_CACHE_CHECK( [for $CC way to treat warnings as errors], [cc_cv_werror], [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror], [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])]) ]) ]) AC_DEFUN([CC_CHECK_ATTRIBUTE], [ AC_REQUIRE([CC_CHECK_WERROR]) AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], AS_TR_SH([cc_cv_attribute_$1]), [ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $cc_cv_werror" AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])], [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) CFLAGS="$ac_save_CFLAGS" ]) AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], [AC_DEFINE( AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] ) $4], [$5]) ]) AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ CC_CHECK_ATTRIBUTE( [constructor],, [void __attribute__((constructor)) ctor() { int a; }], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ CC_CHECK_ATTRIBUTE( [format], [format(printf, n, n)], [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ CC_CHECK_ATTRIBUTE( [format_arg], [format_arg(printf)], [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ CC_CHECK_ATTRIBUTE( [visibility_$1], [visibility("$1")], [void __attribute__((visibility("$1"))) $1_function() { }], [$2], [$3]) ]) AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ CC_CHECK_ATTRIBUTE( [nonnull], [nonnull()], [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ CC_CHECK_ATTRIBUTE( [unused], , [void some_function(void *foo, __attribute__((unused)) void *bar);], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ CC_CHECK_ATTRIBUTE( [sentinel], , [void some_function(void *foo, ...) __attribute__((sentinel));], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ CC_CHECK_ATTRIBUTE( [deprecated], , [void some_function(void *foo, ...) __attribute__((deprecated));], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ CC_CHECK_ATTRIBUTE( [alias], [weak, alias], [void other_function(void *foo) { } void some_function(void *foo) __attribute__((weak, alias("other_function")));], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ CC_CHECK_ATTRIBUTE( [malloc], , [void * __attribute__((malloc)) my_alloc(int n);], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_PACKED], [ CC_CHECK_ATTRIBUTE( [packed], , [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_CONST], [ CC_CHECK_ATTRIBUTE( [const], , [int __attribute__((const)) twopow(int n) { return 1 << n; } ], [$1], [$2]) ]) AC_DEFUN([CC_FLAG_VISIBILITY], [ AC_REQUIRE([CC_CHECK_WERROR]) AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], [cc_cv_flag_visibility], [cc_flag_visibility_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $cc_cv_werror" CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], cc_cv_flag_visibility='yes', cc_cv_flag_visibility='no') CFLAGS="$cc_flag_visibility_save_CFLAGS"]) AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, [Define this if the compiler supports the -fvisibility flag]) $1], [$2]) ]) AC_DEFUN([CC_FUNC_EXPECT], [ AC_REQUIRE([CC_CHECK_WERROR]) AC_CACHE_CHECK([if compiler has __builtin_expect function], [cc_cv_func_expect], [ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $cc_cv_werror" AC_COMPILE_IFELSE([AC_LANG_SOURCE( [int some_function() { int a = 3; return (int)__builtin_expect(a, 3); }])], [cc_cv_func_expect=yes], [cc_cv_func_expect=no]) CFLAGS="$ac_save_CFLAGS" ]) AS_IF([test "x$cc_cv_func_expect" = "xyes"], [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, [Define this if the compiler supports __builtin_expect() function]) $1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ AC_REQUIRE([CC_CHECK_WERROR]) AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], [cc_cv_attribute_aligned], [ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $cc_cv_werror" for cc_attribute_align_try in 64 32 16 8 4 2; do AC_COMPILE_IFELSE([AC_LANG_SOURCE([ int main() { static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; return c; }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) done CFLAGS="$ac_save_CFLAGS" ]) if test "x$cc_cv_attribute_aligned" != "x"; then AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], [Define the highest alignment supported]) fi ]) genimage-18/test.config000066400000000000000000000044311464152623000152330ustar00rootroot00000000000000 include("flash.conf") #----------------------------------- image data.tgz { tar {} mountpoint = "/data" } image nand-pcm038.img { flash { } flashtype = "nand-64M-512" partition barebox { image = "barebox-pcm038.bin" size = 512K } partition bareboxenv { image = "bareboxenv-pcm038.bin" size = 512K } partition kernel { image = "kernel-imx.bin" size = 4M } partition root { image = "root-nand.ubi" size = 20M } partition data { image = "data-nand.ubi" size = 0 } } image root-nor-32M-64k.jffs2 { name = "root" flashtype = "nor-64M-128k" jffs2 {} size = 24M mountpoint = "/" } image data-nor-32M-64k.jffs2 { name = "data" flashtype = "nor-64M-128k" size = 0 jffs2 { extraargs = "-l" } mountpoint = "/data" } image nand-pcm037.img { flash { } flashtype = "nand-64M-512" partition barebox { image = "barebox-pcm037.bin" size = 512K } partition bareboxenv { image = "bareboxenv-pcm037.bin" size = 512K } partition kernel { image = "kernel-imx.bin" size = 4M } partition root { image = "root-nand.ubi" size = 20M } partition data { image = "data-nand.ubi" size = 0 } } image data-nand.ubi { ubi {} partition data { autoresize = true image = "data-nand.ubifs" } partition root { image = "data-nand.ubifs" } } image data-nand.ubifs { ubifs {} name = "data" size = 128M mountpoint = "/data" } image barebox-pcm038.bin { name = "barebox" file {} } image bareboxenv-pcm038.bin { name = "bareboxenv" file {} } image barebox-pcm037.bin { name = "barebox" file {} } image bareboxenv-pcm037.bin { name = "bareboxenv" file {} } image kernel-imx.bin { name = "kernel" file { name = "zImage-linux-2.6.39-imx" } } image root-nand.ubi { name = "root" ubi {} partition root { image = "root-nand.ubifs" } } image root-nand.ubifs { name = "root" size = 128M ubifs {} mountpoint = "/" } image hdimg.img { hdimage {} partition root { offset = 2M size = 128M partition-type = 0x78 image = "root.ext2" } partition data { size = 20M partition-type = 0x1a image = "data.ext2" } size = 2G } image root.ext2 { ext2 {} size = 128M mountpoint = "/" } image data.ext2 { ext2 {} size = 20M mountpoint = "/data" } config { outputpath = images inputpath = input rootpath = root tmppath = tmp } genimage-18/test/000077500000000000000000000000001464152623000140425ustar00rootroot00000000000000genimage-18/test/cpio.config000066400000000000000000000001051464152623000161570ustar00rootroot00000000000000image test.cpio { cpio { format = "newc" compress = "gzip" } } genimage-18/test/cramfs.config000066400000000000000000000000431464152623000165010ustar00rootroot00000000000000image test.cramfs { cramfs { } } genimage-18/test/exec-check.sh000077500000000000000000000011611464152623000163770ustar00rootroot00000000000000#!/bin/bash exec >&2 name="${1}" empty="${2}" set -ex : OUTPUTPATH test "${OUTPUTPATH}" = "${PWD}/images" : INPUTPATH test "${INPUTPATH}" = "${PWD}/input" : ROOTPATH test "${ROOTPATH}" = "${PWD}/root.orig" : TMPPATH test "${TMPPATH}" = "${PWD}/tmp" : IMAGE test "${IMAGE}" = "${name}" : IMAGEOUTFILE test "${IMAGEOUTFILE}" = "${PWD}/images/${name}" : IMAGENAME test "${IMAGENAME}" = "exec-test" : IMAGESIZE test "${IMAGESIZE}" = "3584" : IMAGEMOUNTPOINT test "${IMAGEMOUNTPOINT}" = "" : IMAGEMOUNTPATH if [ "${empty}" = "empty" ]; then test "${IMAGEMOUNTPATH}" = "" else test "${IMAGEMOUNTPATH}" = "${PWD}/tmp/root" fi genimage-18/test/exec-fail.config000066400000000000000000000000611464152623000170630ustar00rootroot00000000000000image file1.img { file {} exec-pre = "false" } genimage-18/test/exec.config000066400000000000000000000006651464152623000161640ustar00rootroot00000000000000image file1.img { file {} name = "exec-test" exec-pre = "./exec-check.sh file1.img" } image file2.img { file {} name = "exec-test" mountpoint = "/" exec-post = "./exec-check.sh file2.img" } image file3.img { file {} name = "exec-test" empty = true exec-pre = "./exec-check.sh file3.img empty" } image file4.img { file {} name = "exec-test" empty = true mountpoint = "/" exec-post = "./exec-check.sh file4.img empty" } genimage-18/test/ext.test000077500000000000000000000061441464152623000155530ustar00rootroot00000000000000#!/bin/bash test_description="extX Image Tests" . "$(dirname "${0}")/test-setup.sh" check_root() { diff -ru "${root_orig}" "${root_test}" } func_check() { local ret="$?" set +x if [ "${ret}" != 0 ]; then echo "Failed to execute '${FUNCNAME[1]}'!" >&2 return "${ret}" fi } compare_label() { if [ "${1}" != "${2}" ]; then echo "Filesystem Label does not match: exprected: '${2}' found '${1}'" return 1 fi } version_leq() { first="$(printf "${1}\n${2}" | sort -V | head -n1)" test "${first}" == "${1}" } check_ext() { [ "$verbose" = "t" ] && set -x # UUID is randomly generated uuid="Filesystem UUID" # Hash Seed is randomly generated seed="Directory Hash Seed:" # checksum depends on random data csum1="Checksum: \|Group 0: (Blocks 1-4095) csum" # format change csum2="Group 0: (Blocks 1-4095) \\[ITABLE_ZEROED\\]\| Checksum .*, unused inodes 205" dumpe2fs "${1}" | grep -v "^\($uuid\|$seed\|$csum1\|$csum2\)" > "dump" && # some architectures (including arm64) use unsigned char sed -i 's/un\(signed_directory_hash\)/\1/' "dump" && if [ "${4}" = "genext2fs" ]; then if [ "$(genext2fs --version)" = "genext2fs 1.4.1" ]; then version=0 else dumpe2fs_version="$(dumpe2fs -V |& sed -n 's/^dumpe2fs \([^ ]*\) .*/\1/p')" if version_leq "${dumpe2fs_version}" "1.46.2"; then # Debian Bullseye version=1 else version=2 fi fi else mke2fs_version="$(mke2fs -V |& sed -n 's/^mke2fs \([^ ]*\) .*/\1/p')" if version_leq "${mke2fs_version}" "1.45.5"; then # Ubuntu 20.04 version=0 elif version_leq "${mke2fs_version}" "1.46.5"; then # Ubuntu 22.04 version=1 elif version_leq "${mke2fs_version}" "1.47.0"; then # Ubuntu 24.04 version=2 else # at least 1.47.0 version=3 fi fi export TEST_CMP="diff --ignore-space-change -u" && test_cmp "${testdir}/${2}.${version}.dump" "dump" && e2fsck -nf "${1}" && # old versions of debugfs cannot dump '/' debugfs -R "ls -p" "${1}" | ( IFS=/ while read a b c d e x f; do case "${x}" in .|..|lost+found|"") continue ;; esac debugfs -R "rdump \"${x}\" \"${root_test}\"" "${1}" || break done ) && check_size "${1}" "${3}" && check_root func_check } exec_test_set_prereq genext2fs exec_test_set_prereq e2fsck test_expect_success genext2fs,e2fsck "ext2" " run_genimage_root ext2.config test.ext2 && check_ext images/test.ext2 ext2test 4194304 genext2fs " test_expect_success genext2fs,e2fsck "ext2percent" " run_genimage_root ext2percent.config test.ext2 && check_ext images/test.ext2 ext2test-percent 69632 genext2fs " test_expect_success genext2fs,e2fsck "ext3" " run_genimage_root ext3.config test.ext3 && check_ext images/test.ext3 ext3test 4194304 genext2fs " test_expect_success genext2fs,e2fsck "ext4" " run_genimage ext4.config test.ext4 && check_ext images/test.ext4 ext4test 4194304 genext2fs " # make sure mke2fs supports '-d root-directory' [ "$(mke2fs |& sed -n 's/.*\(-d \).*/\1/p')" = "-d " ] && test_set_prereq mke2fs test_expect_success mke2fs,e2fsck "mke2fs" " run_genimage_root mke2fs.config mke2fs.ext4 && check_ext images/mke2fs.ext4 mke2fs 33554432 mke2fs " test_done # vim: syntax=sh genimage-18/test/ext2.config000066400000000000000000000001661464152623000161160ustar00rootroot00000000000000image test.ext2 { ext2 { label = "ext2test" use-mke2fs = false fs-timestamp = "20000101000000" } size = 4M } genimage-18/test/ext2percent.config000066400000000000000000000001701464152623000174720ustar00rootroot00000000000000image test.ext2 { ext2 { label = "ext2test" use-mke2fs = false fs-timestamp = "20000101000000" } size = 100% } genimage-18/test/ext2test-percent.0.dump000066400000000000000000000023721464152623000203130ustar00rootroot00000000000000Filesystem volume name: ext2test Last mounted on: 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 () 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 genimage-18/test/ext2test-percent.1.dump000066400000000000000000000024601464152623000203120ustar00rootroot00000000000000Filesystem volume name: ext2test Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) 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: 22 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 () Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 128 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) 22 free blocks, 5 free inodes, 18 directories Free blocks: 46-67 Free inodes: 52-56 genimage-18/test/ext2test-percent.2.dump000066400000000000000000000024641464152623000203170ustar00rootroot00000000000000Filesystem volume name: ext2test Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) 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: 22 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 () Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 128 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) 22 free blocks, 5 free inodes, 18 directories Free blocks: 46-67 Free inodes: 52-56 genimage-18/test/ext2test.0.dump000066400000000000000000000024231464152623000166520ustar00rootroot00000000000000Filesystem volume name: ext2test Last mounted on: 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: 256 Block count: 4096 Reserved block count: 204 Free blocks: 3837 Free inodes: 205 First block: 1 Block size: 1024 Fragment size: 1024 Blocks per group: 4096 Fragments per group: 4096 Inodes per group: 256 Inode blocks per group: 32 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 () Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) Group 0: (Blocks 1-4095) Primary superblock at 1, Group descriptors at 2-2 Block bitmap at 3 (+2) Inode bitmap at 4 (+3) Inode table at 5-36 (+4) 3837 free blocks, 205 free inodes, 18 directories Free blocks: 259-4095 Free inodes: 52-256 genimage-18/test/ext2test.1.dump000066400000000000000000000025101464152623000166500ustar00rootroot00000000000000Filesystem volume name: ext2test Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: (none) Default mount options: (none) Filesystem state: clean Errors behavior: Unknown (continue) Filesystem OS type: Linux Inode count: 256 Block count: 4096 Reserved block count: 204 Free blocks: 4025 Free inodes: 205 First block: 1 Block size: 1024 Fragment size: 1024 Blocks per group: 4096 Fragments per group: 4096 Inodes per group: 256 Inode blocks per group: 32 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 () Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 128 Group 0: (Blocks 1-4095) Primary superblock at 1, Group descriptors at 2-2 Block bitmap at 3 (+2) Inode bitmap at 4 (+3) Inode table at 5-36 (+4) 4025 free blocks, 205 free inodes, 18 directories Free blocks: 71-4095 Free inodes: 52-256 genimage-18/test/ext2test.2.dump000066400000000000000000000025141464152623000166550ustar00rootroot00000000000000Filesystem volume name: ext2test Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: (none) Default mount options: (none) Filesystem state: clean Errors behavior: Unknown (continue) Filesystem OS type: Linux Inode count: 256 Block count: 4096 Reserved block count: 204 Free blocks: 4025 Free inodes: 205 First block: 1 Block size: 1024 Fragment size: 1024 Blocks per group: 4096 Fragments per group: 4096 Inodes per group: 256 Inode blocks per group: 32 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 () Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 128 Group 0: (Blocks 1-4095) Primary superblock at 1, Group descriptors at 2-2 Block bitmap at 3 (+2) Inode bitmap at 4 (+3) Inode table at 5-36 (+4) 4025 free blocks, 205 free inodes, 18 directories Free blocks: 71-4095 Free inodes: 52-256 genimage-18/test/ext3.config000066400000000000000000000001661464152623000161170ustar00rootroot00000000000000image test.ext3 { ext3 { label = "ext3test" use-mke2fs = false fs-timestamp = "20000101000000" } size = 4M } genimage-18/test/ext3test.0.dump000066400000000000000000000030631464152623000166540ustar00rootroot00000000000000Filesystem volume name: ext3test Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: has_journal Default mount options: (none) Filesystem state: clean Errors behavior: Unknown (continue) Filesystem OS type: Linux Inode count: 256 Block count: 4096 Reserved block count: 204 Free blocks: 2808 Free inodes: 205 First block: 1 Block size: 1024 Fragment size: 1024 Blocks per group: 4096 Fragments per group: 4096 Inodes per group: 256 Inode blocks per group: 32 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 () Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 128 Journal inode: 8 Journal backup: inode blocks Journal features: (none) Journal size: 1024k Journal length: 1024 Journal sequence: 0x00000001 Journal start: 0 Group 0: (Blocks 1-4095) Primary superblock at 1, Group descriptors at 2-2 Block bitmap at 3 (+2) Inode bitmap at 4 (+3) Inode table at 5-36 (+4) 2808 free blocks, 205 free inodes, 18 directories Free blocks: 1288-4095 Free inodes: 52-256 genimage-18/test/ext3test.1.dump000066400000000000000000000031561464152623000166600ustar00rootroot00000000000000Filesystem volume name: ext3test Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: has_journal Default mount options: (none) Filesystem state: clean Errors behavior: Unknown (continue) Filesystem OS type: Linux Inode count: 256 Block count: 4096 Reserved block count: 204 Free blocks: 2996 Free inodes: 205 First block: 1 Block size: 1024 Fragment size: 1024 Blocks per group: 4096 Fragments per group: 4096 Inodes per group: 256 Inode blocks per group: 32 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 () Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 128 Journal inode: 8 Journal backup: inode blocks Journal features: (none) Total journal size: 1024k Total journal blocks: 1024 Max transaction length: 1024 Fast commit length: 0 Journal sequence: 0x00000001 Journal start: 0 Group 0: (Blocks 1-4095) Primary superblock at 1, Group descriptors at 2-2 Block bitmap at 3 (+2) Inode bitmap at 4 (+3) Inode table at 5-36 (+4) 2996 free blocks, 205 free inodes, 18 directories Free blocks: 1100-4095 Free inodes: 52-256 genimage-18/test/ext3test.2.dump000066400000000000000000000032211464152623000166520ustar00rootroot00000000000000Filesystem volume name: ext3test Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: has_journal Default mount options: (none) Filesystem state: clean Errors behavior: Unknown (continue) Filesystem OS type: Linux Inode count: 256 Block count: 4096 Reserved block count: 204 Overhead clusters: 1024 Free blocks: 2996 Free inodes: 205 First block: 1 Block size: 1024 Fragment size: 1024 Blocks per group: 4096 Fragments per group: 4096 Inodes per group: 256 Inode blocks per group: 32 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 () Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 128 Journal inode: 8 Journal backup: inode blocks Journal features: (none) Total journal size: 1024k Total journal blocks: 1024 Max transaction length: 1024 Fast commit length: 0 Journal sequence: 0x00000001 Journal start: 0 Group 0: (Blocks 1-4095) Primary superblock at 1, Group descriptors at 2-2 Block bitmap at 3 (+2) Inode bitmap at 4 (+3) Inode table at 5-36 (+4) 2996 free blocks, 205 free inodes, 18 directories Free blocks: 1100-4095 Free inodes: 52-256 genimage-18/test/ext4.config000066400000000000000000000002151464152623000161130ustar00rootroot00000000000000image test.ext4 { ext4 { label = "ext4test" fs-timestamp = "20000101000000" use-mke2fs = false } srcpath = "root.orig" size = 4M } genimage-18/test/ext4test.0.dump000066400000000000000000000032341464152623000166550ustar00rootroot00000000000000Filesystem volume name: ext4test Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: has_journal dir_index extent uninit_bg Filesystem flags: signed_directory_hash Default mount options: (none) Filesystem state: clean Errors behavior: Unknown (continue) Filesystem OS type: Linux Inode count: 256 Block count: 4096 Reserved block count: 204 Free blocks: 2813 Free inodes: 205 First block: 1 Block size: 1024 Fragment size: 1024 Blocks per group: 4096 Fragments per group: 4096 Inodes per group: 256 Inode blocks per group: 32 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 () Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 128 Journal inode: 8 Default directory hash: half_md4 Journal backup: inode blocks Journal features: (none) Journal size: 1024k Journal length: 1024 Journal sequence: 0x00000001 Journal start: 0 Primary superblock at 1, Group descriptors at 2-2 Block bitmap at 3 (+2) Inode bitmap at 4 (+3) Inode table at 5-36 (+4) 2813 free blocks, 205 free inodes, 18 directories, 205 unused inodes Free blocks: 1283-4095 Free inodes: 52-256 genimage-18/test/ext4test.1.dump000066400000000000000000000033271464152623000166610ustar00rootroot00000000000000Filesystem volume name: ext4test Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: has_journal dir_index extent uninit_bg Filesystem flags: signed_directory_hash Default mount options: (none) Filesystem state: clean Errors behavior: Unknown (continue) Filesystem OS type: Linux Inode count: 256 Block count: 4096 Reserved block count: 204 Free blocks: 3001 Free inodes: 205 First block: 1 Block size: 1024 Fragment size: 1024 Blocks per group: 4096 Fragments per group: 4096 Inodes per group: 256 Inode blocks per group: 32 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 () Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 128 Journal inode: 8 Default directory hash: half_md4 Journal backup: inode blocks Journal features: (none) Total journal size: 1024k Total journal blocks: 1024 Max transaction length: 1024 Fast commit length: 0 Journal sequence: 0x00000001 Journal start: 0 Primary superblock at 1, Group descriptors at 2-2 Block bitmap at 3 (+2) Inode bitmap at 4 (+3) Inode table at 5-36 (+4) 3001 free blocks, 205 free inodes, 18 directories, 205 unused inodes Free blocks: 1095-4095 Free inodes: 52-256 genimage-18/test/ext4test.2.dump000066400000000000000000000033721464152623000166620ustar00rootroot00000000000000Filesystem volume name: ext4test Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: has_journal dir_index extent uninit_bg Filesystem flags: signed_directory_hash Default mount options: (none) Filesystem state: clean Errors behavior: Unknown (continue) Filesystem OS type: Linux Inode count: 256 Block count: 4096 Reserved block count: 204 Overhead clusters: 1024 Free blocks: 3001 Free inodes: 205 First block: 1 Block size: 1024 Fragment size: 1024 Blocks per group: 4096 Fragments per group: 4096 Inodes per group: 256 Inode blocks per group: 32 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 () Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 128 Journal inode: 8 Default directory hash: half_md4 Journal backup: inode blocks Journal features: (none) Total journal size: 1024k Total journal blocks: 1024 Max transaction length: 1024 Fast commit length: 0 Journal sequence: 0x00000001 Journal start: 0 Primary superblock at 1, Group descriptors at 2-2 Block bitmap at 3 (+2) Inode bitmap at 4 (+3) Inode table at 5-36 (+4) 3001 free blocks, 205 free inodes, 18 directories, 205 unused inodes Free blocks: 1095-4095 Free inodes: 52-256 genimage-18/test/f2fs.config000066400000000000000000000001001464152623000160600ustar00rootroot00000000000000image test.f2fs { f2fs { label = "f2fstest" } size = 64M } genimage-18/test/filesystem.test000077500000000000000000000040071464152623000171330ustar00rootroot00000000000000#!/bin/bash test_description="Filesystem Image Tests" . "$(dirname "${0}")/test-setup.sh" check_filelist() { test_cmp "${filelist_orig}" "${filelist_test}" } exec_test_set_prereq cpio test_expect_success cpio "cpio" " run_genimage_root cpio.config test.cpio && zcat images/test.cpio | cpio --extract -t | grep -v '^\.$' | sort > '${filelist_test}' && check_size_range images/test.cpio 400 550 && check_filelist " exec_test_set_prereq mkcramfs test_expect_success mkcramfs "cramfs" " run_genimage_root cramfs.config test.cramfs && check_size images/test.cramfs 4096 " exec_test_set_prereq genisoimage test_expect_success genisoimage "iso" " run_genimage_root iso.config test.iso && check_size_range images/test.iso 300000 400000 " exec_test_set_prereq mkfs.f2fs exec_test_set_prereq sload.f2fs exec_test_set_prereq fsck.f2fs test_expect_success mkfs_f2fs,sload_f2fs,fsck_f2fs "f2fs" " run_genimage_root f2fs.config test.f2fs && fsck.f2fs images/test.f2fs " exec_test_set_prereq mksquashfs test_expect_success mksquashfs "squashfs" " run_genimage_root squashfs.config test.squashfs && check_size_range images/test.squashfs 4000 4100 && unsquashfs -ls images/test.squashfs | sed -n '/squashfs-root/s;squashfs-root/;;p' | sort > '${filelist_test}' && check_filelist " exec_test_set_prereq tar test_expect_success tar "tar" " run_genimage_root tar.config test.tar.gz && check_size_range images/test.tar.gz 500 600 && zcat images/test.tar.gz | tar -t | sed -n -e 's;/$;;' -e 's;^\./\(..*\)$;\1;p' | sort > '${filelist_test}' && check_filelist " exec_test_set_prereq dd exec_test_set_prereq mkdosfs exec_test_set_prereq mcopy test_expect_success dd,mkdosfs,mcopy "vfat" " run_genimage_root vfat.config test.vfat && fsck.fat -p images/test.vfat | tee fsck.log && test_must_fail grep -q 'Filesystem was changed' fsck.log && check_size images/test.vfat 4193280 && MTOOLS_SKIP_CHECK=1 mdir -/ -f -b -i images/test.vfat / | sed -e 's;^::/;;' -e 's;/$;;' | sort > '${filelist_test}' && check_filelist " test_done # vim: syntax=sh genimage-18/test/fip.config000066400000000000000000000001721464152623000160070ustar00rootroot00000000000000image test.fip { fip { extraargs = "--align 64" fw-config = "part1.img" tos-fw = { "part2.img", "part1.img" } } } genimage-18/test/fit.config000066400000000000000000000002141464152623000160100ustar00rootroot00000000000000image test.fit { fit { its = "fit.its" } partition kernel { image = "part1.img" } partition ramdisk { image = "part2.img" } } genimage-18/test/fit.its000066400000000000000000000007361464152623000153530ustar00rootroot00000000000000/dts-v1/; / { description = "Test FIT image"; #address-cells = <1>; images { kernel { description = "kernel"; type = "kernel"; arch = "arm"; os = "linux"; compression = "none"; }; ramdisk { description = "ramdisk"; type = "ramdisk"; arch = "arm"; os = "linux"; compression = "none"; }; }; configurations { default = "conf"; conf { description = "test dummy config"; kernel = "kernel"; ramdisk = "ramdisk"; }; }; }; genimage-18/test/flash-types.config000066400000000000000000000004451464152623000174730ustar00rootroot00000000000000flash nand-64M-512 { pebsize = 16384 lebsize = 15360 numpebs = 4096 minimum-io-unit-size = 512 vid-header-offset = 512 sub-page-size = 512 } flash nor-64M-128k { pebsize = 131072 lebsize = 130944 numpebs = 256 minimum-io-unit-size = 1 vid-header-offset = 64 sub-page-size = 1 } genimage-18/test/flash.config000066400000000000000000000003141464152623000163240ustar00rootroot00000000000000include("flash-types.config") image test.flash { flash { } flashtype = "nand-64M-512" partition part1 { image = "part1.img" size = 1M } partition part2 { image = "part2.img" size = 1M } } genimage-18/test/flash.md5000066400000000000000000000000641464152623000155460ustar00rootroot000000000000003ac27658859853c3c49b1c8f4524e9cc images/test.flash genimage-18/test/flash.test000077500000000000000000000015311464152623000160430ustar00rootroot00000000000000#!/bin/bash test_description="Flash Image Tests" . "$(dirname "${0}")/test-setup.sh" exec_test_set_prereq dd test_expect_success "flash" " setup_test_images && run_genimage flash.config test.flash && md5sum -c '${testdir}/flash.md5' " exec_test_set_prereq mkfs.jffs2 test_expect_success mkfs_jffs2 "jffs2" " run_genimage_root jffs2.config test.jffs2 && md5sum -c '${testdir}/jffs2.md5' " exec_test_set_prereq mkfs.ubifs test_expect_success mkfs_ubifs "ubifs" " run_genimage_root ubifs.config test.ubifs && check_size_range images/test.ubifs 200000 300000 " setup_ubi_images() { rm -rf input && mkdir input && cp images/test.ubifs input/ } exec_test_set_prereq ubinize test_expect_success ubinize "ubi" " setup_ubi_images && run_genimage ubi.config test.ubi && check_size_range images/test.ubi 550000 600000 " test_done # vim: syntax=sh genimage-18/test/genimage.test000077500000000000000000000035461464152623000165320ustar00rootroot00000000000000#!/bin/bash test_description="Genimage Basic Functionality Tests" . "$(dirname "${0}")/test-setup.sh" setup_exec_files() { rm -rf input && mkdir input && dd if=/dev/zero of=input/file1.img bs=512 count=7 && dd if=/dev/zero of=input/file2.img bs=512 count=7 && dd if=/dev/zero of=input/file3.img bs=512 count=7 && dd if=/dev/zero of=input/file4.img bs=512 count=7 } test_expect_success "exec" " setup_exec_files && run_genimage_root exec.config" test_expect_success "exec-fail" " setup_exec_files && test_must_fail run_genimage_root exec-fail.config" "$genimage" --help | grep -q 'GENIMAGE_INCLUDEPATH' && test_set_prereq "includepath" test_expect_success fdisk-gpt,sfdisk-gpt "includepath1" " run_genimage include.config && sanitized_fdisk_sfdisk images/include.hdimage > include.fdisk && test_cmp '${testdir}/include-ccc.fdisk' include.fdisk " test_expect_success fdisk-gpt,sfdisk-gpt,includepath "includepath2" " extra_opts='--includepath=${testdir}/include/aaa' run_genimage include.config && sanitized_fdisk_sfdisk images/include.hdimage > include.fdisk && test_cmp '${testdir}/include-aaa.fdisk' include.fdisk " test_expect_success fdisk-gpt,sfdisk-gpt,includepath "includepath3" " extra_opts='--includepath=${testdir}/include/bbb:${testdir}/include/aaa' run_genimage include.config && sanitized_fdisk_sfdisk images/include.hdimage > include.fdisk && test_cmp '${testdir}/include-bbb.fdisk' include.fdisk " test_expect_success fdisk-gpt,sfdisk-gpt,includepath "includepath4" " extra_opts='--includepath=.:${testdir}/include/bbb' run_genimage include.config && sanitized_fdisk_sfdisk images/include.hdimage > include.fdisk && test_cmp '${testdir}/include-ccc.fdisk' include.fdisk " test_expect_success !includepath "includepath5" " extra_opts='--includepath=${testdir}/include/aaa' test_must_fail run_genimage include.config " test_done # vim: syntax=sh genimage-18/test/gpt-invalid-partition-type1.config000066400000000000000000000002411464152623000225130ustar00rootroot00000000000000image gpt-partition-types-fail.img { hdimage { partition-table-type = "gpt" } partition part1 { partition-type-uuid = "unknown-shortcut" size = 1M } } genimage-18/test/gpt-invalid-partition-type2.config000066400000000000000000000002651464152623000225220ustar00rootroot00000000000000image gpt-partition-types-fail.img { hdimage { partition-table-type = "gpt" } partition part1 { partition-type-uuid = "30f239f3-275c-4e0d-9b61-Ka385b7b80f9" size = 1M } } genimage-18/test/gpt-overlap1.config000066400000000000000000000005041464152623000175510ustar00rootroot00000000000000image test.gpt-overlap1 { hdimage { partition-table-type = "gpt" } partition SPL { # This should fail due to placing something on top of the GPT array. offset = 1K size = 24K in-partition-table = false image = "3K.img" } partition aaa { in-partition-table = true offset = 1M image = "70K.img" } } genimage-18/test/gpt-overlap2.config000066400000000000000000000004221464152623000175510ustar00rootroot00000000000000image test.gpt-overlap2 { hdimage { partition-table-type = "gpt" gpt-location = 32K } partition SPL { offset = 1K size = 24K in-partition-table = false image = "3K.img" } partition aaa { in-partition-table = true offset = 1M image = "70K.img" } } genimage-18/test/gpt-overlap3.config000066400000000000000000000005441464152623000175570ustar00rootroot00000000000000image test.gpt-overlap3 { hdimage { partition-table-type = "gpt" gpt-location = 30K } partition SPL { offset = 1K size = 24K in-partition-table = false image = "3K.img" } partition aaa { # The GPT partition table array occupies 16K, so this should fail. in-partition-table = true offset = 32K image = "70K.img" size = 1M } } genimage-18/test/gpt-partition-types.config000066400000000000000000000015301464152623000211730ustar00rootroot00000000000000image gpt-partition-types.img { /* note: set non-random disk-uuid and partition-uuid */ hdimage { partition-table-type = "gpt" disk-uuid = "b0326371-955b-42e3-ad81-ad0151d813ec" } partition part1 { partition-type-uuid = "linux" partition-uuid = "3c1e674d-4bfd-4347-a1ab-4bb5d258b361" size = 1M } partition part2 { partition-type-uuid = "U" partition-uuid = "6a879323-b5f9-4275-9bb0-1c881048cba2" size = 1M } partition part3 { partition-type-uuid = "swap" partition-uuid = "9ea7f2d5-ea3f-431a-a9a5-16cabbca7f1b" size = 1M } partition part4 { partition-type-uuid = "3df8f8b0-4464-4fe6-8df4-2a5e2f6c4949" partition-uuid = "7dd9bebe-1c35-4886-a26c-2b784f172d89" size = 1M } partition part5 { partition-type-uuid = "usr-loongarch64-verity-sig" partition-uuid = "ae7784a0-a0b7-4ef4-94c4-c3ef78b00176" size = 1M } } genimage-18/test/gpt-partition-types.fdisk000066400000000000000000000014421464152623000210300ustar00rootroot00000000000000Disk identifier: B0326371-955B-42E3-AD81-AD0151D813EC images/gpt-partition-types.img1:start=34,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=3C1E674D-4BFD-4347-A1AB-4BB5D258B361,name="part1" images/gpt-partition-types.img2:start=2082,size=2048,type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B,uuid=6A879323-B5F9-4275-9BB0-1C881048CBA2,name="part2" images/gpt-partition-types.img3:start=4130,size=2048,type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F,uuid=9EA7F2D5-EA3F-431A-A9A5-16CABBCA7F1B,name="part3" images/gpt-partition-types.img4:start=6178,size=2048,type=3DF8F8B0-4464-4FE6-8DF4-2A5E2F6C4949,uuid=7DD9BEBE-1C35-4886-A26C-2B784F172D89,name="part4" images/gpt-partition-types.img5:start=8226,size=2048,type=B024F315-D330-444C-8461-44BBDE524E99,uuid=AE7784A0-A0B7-4EF4-94C4-C3EF78B00176,name="part5" genimage-18/test/hdimage-fail1.config000066400000000000000000000002441464152623000176210ustar00rootroot00000000000000image test.hdimage { hdimage { partition-table-type = "mbr" } partition part1 { /* partition-type-uuid not valid for mbr */ partition-type-uuid = "L" } } genimage-18/test/hdimage-fail10.config000066400000000000000000000011201464152623000176730ustar00rootroot00000000000000image test.hdimage { hdimage { align = 1M extended-partition = 3 } partition primary1 { image = "part1.img" partition-type = 0x83 } partition primary2 { image = "part1.img" partition-type = 0x83 } partition extended1 { image = "part1.img" partition-type = 0x83 } partition extended2 { image = "part1.img" partition-type = 0x83 } partition primary3 { image = "part1.img" partition-type = 0x83 forced-primary = "yes" } partition primary4 { image = "part1.img" partition-type = 0x83 /* would be 5th primary partition */ forced-primary = "yes" } } genimage-18/test/hdimage-fail11.config000066400000000000000000000011231464152623000176770ustar00rootroot00000000000000image test.hdimage { hdimage { align = 1M extended-partition = 1 } partition extended1 { image = "part1.img" partition-type = 0x83 } partition extended2 { image = "part1.img" partition-type = 0x83 } partition extended3 { image = "part1.img" partition-type = 0x83 } partition extended4 { image = "part1.img" partition-type = 0x83 } partition primary2 { image = "part1.img" partition-type = 0x83 forced-primary = "yes" } partition extended5 { image = "part1.img" partition-type = 0x83 /* extended partition would overlap the forced-primary one */ } } genimage-18/test/hdimage-fail2.config000066400000000000000000000002331464152623000176200ustar00rootroot00000000000000image test.hdimage { hdimage { partition-table-type = "gpt" } partition part1 { /* partition-type not valid for gpt */ partition-type = 0x83 } } genimage-18/test/hdimage-fail3.config000066400000000000000000000002301464152623000176160ustar00rootroot00000000000000image test.hdimage { hdimage { partition-table-type = "hybrid" } partition part1 { /* missing partition-type */ partition-type-uuid = "L" } } genimage-18/test/hdimage-fail4.config000066400000000000000000000002411464152623000176210ustar00rootroot00000000000000image test.hdimage { hdimage { partition-table-type = "mbr" /* disk-uuid is only valid for gpt */ disk-uuid = "afcfea87-e41a-40e0-85ae-295c60773c7a" } } genimage-18/test/hdimage-fail5.config000066400000000000000000000002171464152623000176250ustar00rootroot00000000000000image test.hdimage { hdimage { partition-table-type = "gpt" /* disk-signature is only valid for mbr */ disk-signature = 0x12345678 } } genimage-18/test/hdimage-fail6.config000066400000000000000000000007221464152623000176270ustar00rootroot00000000000000image test.hdimage { hdimage { disk-signature = 0x12345678 } partition part1 { offset = 1M size = 1M partition-type = 0x83 } partition part2 { offset = 2M size = 1M partition-type = 0x83 } partition part3 { offset = 3M size = 1M partition-type = 0x83 } partition part4 { /* this will overlap with the EBR */ offset = 4M size = 1M partition-type = 0x83 } partition part5 { offset = 5M size = 1M partition-type = 0x83 } } genimage-18/test/hdimage-fail7.config000066400000000000000000000007051464152623000176310ustar00rootroot00000000000000image test.hdimage { hdimage { partition-table-type = "hybrid" disk-signature = 0x12345678 } partition part1 { size = 1M partition-type-uuid = L } partition part2 { size = 1M partition-type = 0x83 } partition part3 { size = 1M partition-type = 0x83 } partition part4 { size = 1M partition-type = 0x83 } partition part5 { size = 1M /* at most 3 MBR partitions are allowed in hybrid mode */ partition-type = 0x83 } } genimage-18/test/hdimage-fail8.config000066400000000000000000000010241464152623000176250ustar00rootroot00000000000000image test.hdimage { hdimage { align = 1M extended-partition = 1 } partition part1 { image = "part1.img" partition-type = 0x83 forced-primary = "yes" /* forced-primary can be only used for partitions defined after the extended partition */ } partition part2 { image = "part1.img" partition-type = 0x83 } partition part3 { image = "part1.img" partition-type = 0x83 } partition part4 { image = "part1.img" partition-type = 0x83 } partition part5 { image = "part1.img" partition-type = 0x83 } } genimage-18/test/hdimage-fail9.config000066400000000000000000000007571464152623000176420ustar00rootroot00000000000000image test.hdimage { hdimage { align = 1M } partition primary1 { image = "part1.img" partition-type = 0x83 } partition primary2 { image = "part1.img" partition-type = 0x83 } partition primary3 { image = "part1.img" partition-type = 0x83 } partition primary4 { image = "part1.img" partition-type = 0x83 } partition primary5 { image = "part1.img" partition-type = 0x83 /* part4 is implicitly extended -> too many primary entries */ forced-primary = "yes" } } genimage-18/test/hdimage-forced-primary.config000066400000000000000000000016551464152623000215570ustar00rootroot00000000000000image test.hdimage { hdimage { align = 1M disk-signature = 0x12345678 extended-partition = 2 } partition part1 { image = "part1.img" partition-type = 0xc bootable = "yes" } /* * partition 2 will be the extended partition entry * partitions 3-4 will be primary partitions at the end * partition 5 is first logical partition of the extended partition */ partition part5-logical { image = "part1.img" partition-type = 0x83 } partition part6-logical { image = "part2.img" partition-type = 0x83 } partition part7-logical { image = "part1.img" partition-type = 0x83 } partition part8-logical { image = "part2.img" partition-type = 0x83 } partition part9-logical { image = "part1.img" partition-type = 0x83 } partition part3 { image = "part1.img" partition-type = 0x83 forced-primary = "yes" } partition part4 { image = "part2.img" partition-type = 0x82 forced-primary = "yes" } } genimage-18/test/hdimage-forced-primary.fdisk000066400000000000000000000007541464152623000214110ustar00rootroot00000000000000Disk identifier: 0x12345678 images/test.hdimage1:start=2048,size=2048,type=c,bootable images/test.hdimage2:start=4096,size=20480,type=f images/test.hdimage3:start=24576,size=2048,type=83 images/test.hdimage4:start=26624,size=2048,type=82 images/test.hdimage5:start=6144,size=2048,type=83 images/test.hdimage6:start=10240,size=2048,type=83 images/test.hdimage7:start=14336,size=2048,type=83 images/test.hdimage8:start=18432,size=2048,type=83 images/test.hdimage9:start=22528,size=2048,type=83 genimage-18/test/hdimage-hybrid.config000066400000000000000000000027471464152623000201200ustar00rootroot00000000000000image hybrid.hdimage { hdimage { partition-table-type = "hybrid" fill = "true" disk-uuid = "afcfea87-e41a-40e0-85ae-295c60773c7a" } partition part1 { align = 1M image = "part1.img" size = 1M partition-uuid = "92762261-e854-45c1-b4c9-fc5e752034ab" partition-type = 0x83 } partition part2 { image = "part2.img" size = 1M partition-type-uuid = "L" partition-uuid = "41061242-1d5a-4657-892d-fcc1fdb11a6c" partition-type = 0x83 } partition part3 { image = "part1.img" size = 1M partition-type-uuid = "S" partition-uuid = "954532ea-bd86-4992-a1ed-2cdb2c18581a" partition-type = 0x83 } partition part4 { image = "part2.img" size = 1M partition-type-uuid = "F" partition-uuid = "6d04bf47-3ddf-4a75-919b-c7bf46f2ef92" } partition part5 { image = "part1.img" size = 1M partition-uuid = "92762261-e854-45c1-b4c9-fc5e752034ab" } partition part6 { image = "part2.img" size = 1M partition-uuid = "c9460c06-fbc0-48ae-b4f3-3e897d3ebe71" } } image mbr.hdimage { hdimage { partition-table-type = "mbr" fill = "true" } partition part1 { align = 1M image = "part1.img" size = 1M partition-type = 0x83 } partition part2 { image = "part2.img" size = 1M partition-type = 0x83 } partition part3 { image = "part1.img" size = 1M partition-type = 0x83 } partition fake-gpt { /* position of the GPT */ offset = 1s /* size of the GPT header + table */ size = 33s /* type of the protective enty */ partition-type = 0xEE } } genimage-18/test/hdimage-hybrid.fdisk000066400000000000000000000016061464152623000177440ustar00rootroot00000000000000Disk identifier: AFCFEA87-E41A-40E0-85AE-295C60773C7A images/hybrid.hdimage1:start=2048,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=92762261-E854-45C1-B4C9-FC5E752034AB,name="part1" images/hybrid.hdimage2:start=4096,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=41061242-1D5A-4657-892D-FCC1FDB11A6C,name="part2" images/hybrid.hdimage3:start=6144,size=2048,type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F,uuid=954532EA-BD86-4992-A1ED-2CDB2C18581A,name="part3" images/hybrid.hdimage4:start=8192,size=2048,type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7,uuid=6D04BF47-3DDF-4A75-919B-C7BF46F2EF92,name="part4" images/hybrid.hdimage5:start=10240,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=92762261-E854-45C1-B4C9-FC5E752034AB,name="part5" images/hybrid.hdimage6:start=12288,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=C9460C06-FBC0-48AE-B4F3-3E897D3EBE71,name="part6" genimage-18/test/hdimage-nopart.config000066400000000000000000000003761464152623000201360ustar00rootroot00000000000000image test.hdimage { hdimage { partition-table-type = none align = 128 fill = true } size = 512 partition part1 { image = "block1.img" } partition part2 { image = "block2.img" align = 8 } partition part3 { image = "block3.img" } } genimage-18/test/hdimage-nopart.hexdump000066400000000000000000000012131464152623000203320ustar00rootroot0000000000000000000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| * 00000060 ff ff ff ff 00 00 00 00 aa aa aa aa aa aa aa aa |................| 00000070 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa |................| * 00000090 aa aa aa aa aa aa aa aa aa aa 00 00 00 00 00 00 |................| 000000a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000100 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 77 |wwwwwwwwwwwwwwww| * 00000140 77 77 77 77 77 77 77 77 77 77 77 00 00 00 00 00 |wwwwwwwwwww.....| 00000150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000200 genimage-18/test/hdimage.config000066400000000000000000000022361464152623000166320ustar00rootroot00000000000000image test.hdimage { hdimage { align = 1M fill = true disk-signature = 0x12345678 } partition part1 { image = "part1.img" size = 1M partition-type = 0x83 } partition part2 { image = "part3.img" size = 1M partition-type = 0x83 } partition part3 { image = "part1.img" size = 1M partition-type = 0x83 } partition part4 { image = "part2.img" size = 1M partition-type = 0x83 } partition part5 { image = "part1.img" size = 1M partition-type = 0x83 } partition part6 { image = "part2.img" size = 1M partition-type = 0x83 } } image test.hdimage-2 { hdimage { align = 1M disk-signature = 0x12345678 extended-partition = 2 } partition part1 { image = "part1.img" size = 1M partition-type = 0x83 } partition part2 { image = "part2.img" size = 1M partition-type = 0x83 } partition part3 { image = "part1.img" size = 1M partition-type = 0x83 } partition part4 { image = "part2.img" size = 1M partition-type = 0x83 } partition part5 { image = "part1.img" size = 1M partition-type = 0x83 } partition part6 { image = "part2.img" autoresize = true partition-type = 0x83 } size = 12M } genimage-18/test/hdimage.fdisk000066400000000000000000000005751464152623000164710ustar00rootroot00000000000000Disk identifier: 0x12345678 images/test.hdimage1:start=2048,size=2048,type=83 images/test.hdimage2:start=4096,size=2048,type=83 images/test.hdimage3:start=6144,size=2048,type=83 images/test.hdimage4:start=8192,size=12288,type=f images/test.hdimage5:start=10240,size=2048,type=83 images/test.hdimage6:start=14336,size=2048,type=83 images/test.hdimage7:start=18432,size=2048,type=83 genimage-18/test/hdimage.fdisk-2000066400000000000000000000006231464152623000166220ustar00rootroot00000000000000Disk identifier: 0x12345678 images/test.hdimage-2p1:start=2048,size=2048,type=83 images/test.hdimage-2p2:start=4096,size=20480,type=f images/test.hdimage-2p5:start=6144,size=2048,type=83 images/test.hdimage-2p6:start=10240,size=2048,type=83 images/test.hdimage-2p7:start=14336,size=2048,type=83 images/test.hdimage-2p8:start=18432,size=2048,type=83 images/test.hdimage-2p9:start=22528,size=2048,type=83 genimage-18/test/hdimage.test000077500000000000000000000142241464152623000163470ustar00rootroot00000000000000#!/bin/bash test_description="hdimage Image Tests" . "$(dirname "${0}")/test-setup.sh" get_disk_usage() { local file="${1}" if [ ! -f "${file}" ]; then echo "Failed to check file disk usage: '${file}' does not exist!" return 1 fi set -- $(du -B 1 "${file}") usage="${1}" } check_disk_usage_range() { local usage get_disk_usage "${1}" || return if [ "${usage}" -lt "${2}" -o "${usage}" -gt "${3}" ]; then echo "Incorrect file disk usage for '${1}': expected min: ${2} max: ${3} found: ${usage}" return 1 fi } exec_test_set_prereq fdisk 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 10485760 && sfdisk_validate images/test.hdimage && check_disk_usage_range images/test.hdimage 40960 57344 && sanitized_fdisk_sfdisk images/test.hdimage > hdimage.fdisk && test_cmp '${testdir}/hdimage.fdisk' hdimage.fdisk && check_size images/test.hdimage-2 11539968 && sfdisk_validate images/test.hdimage-2 && check_disk_usage_range images/test.hdimage-2 61290 65376 && sanitized_fdisk_sfdisk images/test.hdimage-2 > hdimage.fdisk-2 && test_cmp '${testdir}/hdimage.fdisk-2' hdimage.fdisk-2 " test_expect_success "hdimage2" " setup_test_images && test_must_fail run_genimage hdimage2.config test.hdimage " test_expect_success fdisk-gpt,sfdisk-gpt "hdimage4" " setup_test_images && run_genimage hdimage4.config test.hdimage && check_size images/test.hdimage 7360512 && sfdisk_validate images/test.hdimage && sanitized_fdisk_sfdisk images/test.hdimage > hdimage4.fdisk && test_cmp '${testdir}/hdimage4.fdisk' hdimage4.fdisk " test_expect_success fdisk-gpt,sfdisk-gpt "hdimage5" " setup_test_images && run_genimage hdimage5.config test.hdimage && check_size images/test.hdimage 7360512 && sanitized_fdisk_sfdisk images/test.hdimage > hdimage5.fdisk && test_cmp '${testdir}/hdimage5.fdisk' hdimage5.fdisk " test_expect_success fdisk,sfdisk "hdimage6" " setup_test_images && run_genimage hdimage6.config test.hdimage && check_size images/test.hdimage 28082176 && sanitized_fdisk_sfdisk images/test.hdimage > hdimage6.fdisk && test_cmp '${testdir}/hdimage6.fdisk' hdimage6.fdisk " test_expect_success fdisk-gpt,sfdisk-gpt "hdimage7" " setup_test_images && run_genimage hdimage7.config && sfdisk_validate images/test.hdimage && sanitized_fdisk_sfdisk images/test.hdimage > hdimage7.fdisk && test_cmp '${testdir}/hdimage7.fdisk' hdimage7.fdisk " exec_test_set_prereq hexdump test_expect_success fdisk-gpt,sfdisk-gpt,hexdump "hdimage-hybrid" " setup_test_images && run_genimage hdimage-hybrid.config && sfdisk_validate images/hybrid.hdimage && sanitized_fdisk_sfdisk images/hybrid.hdimage > hdimage-hybrid.fdisk && test_cmp '${testdir}/hdimage-hybrid.fdisk' hdimage-hybrid.fdisk && dd if=images/hybrid.hdimage count=1 | hexdump -C > hybrid.sector0 && dd if=images/mbr.hdimage count=1 | hexdump -C > mbr.sector0 && test_cmp hybrid.sector0 mbr.sector0 " test_expect_success "hdimage syntax" " setup_test_images && test_must_fail run_genimage hdimage-fail1.config && test_must_fail run_genimage hdimage-fail2.config && test_must_fail run_genimage hdimage-fail3.config && test_must_fail run_genimage hdimage-fail4.config && test_must_fail run_genimage hdimage-fail5.config && test_must_fail run_genimage hdimage-fail6.config && test_must_fail run_genimage hdimage-fail7.config && test_must_fail run_genimage hdimage-fail8.config && test_must_fail run_genimage hdimage-fail9.config && test_must_fail run_genimage hdimage-fail10.config && test_must_fail run_genimage hdimage-fail11.config " setup_gpt_files() { rm -rf input && mkdir input && truncate -s 3k input/3K.img && truncate -s 70k input/70K.img } test_expect_success "gpt-overlap1" " setup_gpt_files && test_must_fail run_genimage gpt-overlap1.config" test_expect_success "gpt-overlap2" " setup_gpt_files && run_genimage gpt-overlap2.config" test_expect_success "gpt-overlap3" " setup_gpt_files && test_must_fail run_genimage gpt-overlap3.config" test_expect_success fdisk,sfdisk "gpt-partition-types" " run_genimage gpt-partition-types.config && sfdisk_validate images/gpt-partition-types.img && sanitized_fdisk_sfdisk images/gpt-partition-types.img > gpt-partition-types.fdisk && test_cmp '${testdir}/gpt-partition-types.fdisk' gpt-partition-types.fdisk" test_expect_success "gpt-invalid-partition-types" " test_must_fail run_genimage gpt-invalid-partition-type1.config && test_must_fail run_genimage gpt-invalid-partition-type2.config" # A bootloader image with a don't-care region extending over MBR # table, GPT header and (usual) placement of GPT array. test_expect_success "bootloader-hole1" " setup_gpt_files && run_genimage hole.config" # Oops, if we move the GPT array we're no longer covered by the hole. test_expect_success "bootloader-hole2" " setup_gpt_files && GPT_LOCATION=64K test_must_fail run_genimage hole.config" # But it's ok if the array is moved beyond the bootloader. test_expect_success "bootloader-hole3" " setup_gpt_files && GPT_LOCATION=70K run_genimage hole.config" # If the 70K bootloader starts at 64K, it will overlap a partition at 129K. test_expect_success "bootloader-hole4" " setup_gpt_files && OFFSET=64K test_must_fail run_genimage hole.config" # But if it starts at 128K, its hole will cover the small 3K partition. test_expect_success "bootloader-hole5" " setup_gpt_files && OFFSET=128K run_genimage hole.config" test_expect_success hexdump "hdimage no-partition" " dd if=/dev/zero bs=1 count=100 | tr '\000' '\377' > input/block1.img && dd if=/dev/zero bs=1 count=50 | tr '\000' '\252' > input/block2.img && dd if=/dev/zero bs=1 count=75 | tr '\000' '\167' > input/block3.img && run_genimage hdimage-nopart.config && hexdump -C images/test.hdimage > 'hdimage-nopart.hexdump' && test_cmp 'hdimage-nopart.hexdump' '${testdir}/hdimage-nopart.hexdump' " test_expect_success sfdisk "hdimage forced-primary" " setup_test_images && run_genimage hdimage-forced-primary.config && sfdisk_validate images/test.hdimage && sanitized_fdisk_sfdisk images/test.hdimage > hdimage.fdisk && test_cmp '${testdir}/hdimage-forced-primary.fdisk' hdimage.fdisk " test_done # vim: syntax=sh genimage-18/test/hdimage2.config000066400000000000000000000002401464152623000167050ustar00rootroot00000000000000image test.hdimage { hdimage { align = 1M disk-signature = 0x12345678 } partition part1 { image = "part2.img" size = 5k partition-type = 0x83 } } genimage-18/test/hdimage4.config000066400000000000000000000016261464152623000167200ustar00rootroot00000000000000image test.hdimage { hdimage { align = 1M partition-table-type = "gpt" fill = "true" disk-uuid = "afcfea87-e41a-40e0-85ae-295c60773c7a" } partition part1 { image = "part1.img" size = 1M partition-uuid = "92762261-e854-45c1-b4c9-fc5e752034ab" } partition part2 { image = "part2.img" size = 1M partition-type-uuid = "L" partition-uuid = "41061242-1d5a-4657-892d-fcc1fdb11a6c" } partition part3 { image = "part1.img" size = 1M partition-type-uuid = "S" partition-uuid = "954532ea-bd86-4992-a1ed-2cdb2c18581a" } partition part4 { image = "part2.img" size = 1M partition-type-uuid = "F" partition-uuid = "6d04bf47-3ddf-4a75-919b-c7bf46f2ef92" } partition part5 { image = "part1.img" size = 1M partition-uuid = "92762261-e854-45c1-b4c9-fc5e752034ab" } partition part6 { image = "part2.img" size = 1M partition-uuid = "c9460c06-fbc0-48ae-b4f3-3e897d3ebe71" } } genimage-18/test/hdimage4.fdisk000066400000000000000000000015721464152623000165530ustar00rootroot00000000000000Disk identifier: AFCFEA87-E41A-40E0-85AE-295C60773C7A images/test.hdimage1:start=2048,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=92762261-E854-45C1-B4C9-FC5E752034AB,name="part1" images/test.hdimage2:start=4096,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=41061242-1D5A-4657-892D-FCC1FDB11A6C,name="part2" images/test.hdimage3:start=6144,size=2048,type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F,uuid=954532EA-BD86-4992-A1ED-2CDB2C18581A,name="part3" images/test.hdimage4:start=8192,size=2048,type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7,uuid=6D04BF47-3DDF-4A75-919B-C7BF46F2EF92,name="part4" images/test.hdimage5:start=10240,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=92762261-E854-45C1-B4C9-FC5E752034AB,name="part5" images/test.hdimage6:start=12288,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=C9460C06-FBC0-48AE-B4F3-3E897D3EBE71,name="part6" genimage-18/test/hdimage5.config000066400000000000000000000016571464152623000167250ustar00rootroot00000000000000image test.hdimage { hdimage { align = 1M partition-table-type = "gpt" gpt-no-backup = "true" fill = "true" disk-uuid = "afcfea87-e41a-40e0-85ae-295c60773c7a" } partition part1 { image = "part1.img" size = 1M partition-uuid = "92762261-e854-45c1-b4c9-fc5e752034ab" } partition part2 { image = "part2.img" size = 1M partition-type-uuid = "L" partition-uuid = "41061242-1d5a-4657-892d-fcc1fdb11a6c" } partition part3 { image = "part1.img" size = 1M partition-type-uuid = "S" partition-uuid = "954532ea-bd86-4992-a1ed-2cdb2c18581a" } partition part4 { image = "part2.img" size = 1M partition-type-uuid = "F" partition-uuid = "6d04bf47-3ddf-4a75-919b-c7bf46f2ef92" } partition part5 { image = "part1.img" size = 1M partition-uuid = "92762261-e854-45c1-b4c9-fc5e752034ab" } partition part6 { image = "part2.img" size = 1M partition-uuid = "c9460c06-fbc0-48ae-b4f3-3e897d3ebe71" } } genimage-18/test/hdimage5.fdisk000066400000000000000000000015721464152623000165540ustar00rootroot00000000000000Disk identifier: AFCFEA87-E41A-40E0-85AE-295C60773C7A images/test.hdimage1:start=2048,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=92762261-E854-45C1-B4C9-FC5E752034AB,name="part1" images/test.hdimage2:start=4096,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=41061242-1D5A-4657-892D-FCC1FDB11A6C,name="part2" images/test.hdimage3:start=6144,size=2048,type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F,uuid=954532EA-BD86-4992-A1ED-2CDB2C18581A,name="part3" images/test.hdimage4:start=8192,size=2048,type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7,uuid=6D04BF47-3DDF-4A75-919B-C7BF46F2EF92,name="part4" images/test.hdimage5:start=10240,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=92762261-E854-45C1-B4C9-FC5E752034AB,name="part5" images/test.hdimage6:start=12288,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=C9460C06-FBC0-48AE-B4F3-3E897D3EBE71,name="part6" genimage-18/test/hdimage6.config000066400000000000000000000007021464152623000167140ustar00rootroot00000000000000image test.hdimage { hdimage { extended-partition = 3 } partition part1 { offset = 128K size = 256K partition-type = 0x83 } partition part2 { size = 3072K partition-type = 0x83 } partition part3 { offset = 3686400 size = 8126464 partition-type = 0x83 } partition part4 { offset = 11821056 size = 16252928 partition-type = 0x83 } partition part5 { offset = 28082176 size = 16252928 partition-type = 0x83 } } genimage-18/test/hdimage6.fdisk000066400000000000000000000005121464152623000165460ustar00rootroot00000000000000Disk identifier: 0x00000000 images/test.hdimage1:start=256,size=512,type=83 images/test.hdimage2:start=768,size=6144,type=83 images/test.hdimage3:start=7199,size=79393,type=f images/test.hdimage5:start=7200,size=15872,type=83 images/test.hdimage6:start=23088,size=31744,type=83 images/test.hdimage7:start=54848,size=31744,type=83 genimage-18/test/hdimage7.config000066400000000000000000000032771464152623000167270ustar00rootroot00000000000000image test.hdimage { hdimage { partition-table-type = "gpt" gpt-location = 768K disk-uuid = "afcfea87-e41a-40e0-85ae-295c60773c7a" } partition rescue { image = "part1.img" offset = 2M size = 1M partition-uuid = "9f60b7f0-f4c8-42d4-8469-be6c19904994" } partition rootfs-A { image = "part2.img" align = 2M size = 8M partition-type-uuid = "L" partition-uuid = "0cfa71d4-3388-4f08-8fa0-f66e46ec5a0e" } partition rootfs-B { image = "part2.img" align = 2M size = 8M partition-type-uuid = "L" partition-uuid = "b9cc42b2-d030-4eca-9922-5f88e32c94bc" } partition reserved { image = "part1.img" size = 128K partition-uuid = "cb597eaf-5662-44d9-8127-dc5e8c1b830d" } partition sys { image = "part1.img" size = 4M partition-type-uuid = "L" partition-uuid = "c9d69b9a-a561-42ef-88df-2ba25328e6ef" } partition data { image = "part1.img" size = 4M partition-uuid = "b7104ed8-6ac9-4f80-96e2-9d57ff5f3453" } partition bootloader { image = "part2.img" size = 1M offset = 1M partition-uuid = "de9980f1-0449-4e83-84bd-98e4b1ca3fe3" } partition env-1 { image = "part1.img" offset = 800K size = 16K partition-uuid = "eb3b107b-ae9d-4c6b-994a-ec412d36959b" } partition env-2 { image = "part1.img" offset = 832K size = 16K partition-uuid = "6e7c8caa-c119-43b9-8031-fcdfa34c3fae" } partition ucode { image = "part1.img" offset = 960K size = 64K partition-uuid = "b1a7539f-8e86-4a31-94c6-090c08f5a3d3" } partition SPL { image = "part1.img" in-partition-table = false offset = 1K size = 512K } } genimage-18/test/hdimage7.fdisk000066400000000000000000000026611464152623000165560ustar00rootroot00000000000000Disk identifier: AFCFEA87-E41A-40E0-85AE-295C60773C7A images/test.hdimage1:start=4096,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=9F60B7F0-F4C8-42D4-8469-BE6C19904994,name="rescue" images/test.hdimage2:start=8192,size=16384,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=0CFA71D4-3388-4F08-8FA0-F66E46EC5A0E,name="rootfs-A" images/test.hdimage3:start=24576,size=16384,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=B9CC42B2-D030-4ECA-9922-5F88E32C94BC,name="rootfs-B" images/test.hdimage4:start=40960,size=256,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=CB597EAF-5662-44D9-8127-DC5E8C1B830D,name="reserved" images/test.hdimage5:start=41216,size=8192,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=C9D69B9A-A561-42EF-88DF-2BA25328E6EF,name="sys" images/test.hdimage6:start=49408,size=8192,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=B7104ED8-6AC9-4F80-96E2-9D57FF5F3453,name="data" images/test.hdimage7:start=2048,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=DE9980F1-0449-4E83-84BD-98E4B1CA3FE3,name="bootloader" images/test.hdimage8:start=1600,size=32,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=EB3B107B-AE9D-4C6B-994A-EC412D36959B,name="env-1" images/test.hdimage9:start=1664,size=32,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=6E7C8CAA-C119-43B9-8031-FCDFA34C3FAE,name="env-2" images/test.hdimage10:start=1920,size=128,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=B1A7539F-8E86-4A31-94C6-090C08F5A3D3,name="ucode" genimage-18/test/hole.config000066400000000000000000000004701464152623000161610ustar00rootroot00000000000000image test.hole { hdimage { partition-table-type = "gpt" gpt-location = ${GPT_LOCATION:-1K} } partition bootloader { in-partition-table = false offset = ${OFFSET:-0} image = "70K.img" } partition foo { offset = 129K image = "3K.img" } } image 70K.img { file { holes = "(440; 33K)" } } genimage-18/test/include-aaa.fdisk000066400000000000000000000003001464152623000172200ustar00rootroot00000000000000Disk identifier: 6A921DBB-823D-44C4-8EDC-ECB038E6D743 images/include.hdimage1:start=34,size=2048,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=59DA602D-C2EA-4F18-818F-CF7947BAD0CA,name="aaa" genimage-18/test/include-bbb.fdisk000066400000000000000000000003001464152623000172230ustar00rootroot00000000000000Disk identifier: 6A921DBB-823D-44C4-8EDC-ECB038E6D743 images/include.hdimage1:start=34,size=4096,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=284635E9-6B62-41CA-A02A-357C01517279,name="bbb" genimage-18/test/include-ccc.fdisk000066400000000000000000000003001464152623000172260ustar00rootroot00000000000000Disk identifier: 6A921DBB-823D-44C4-8EDC-ECB038E6D743 images/include.hdimage1:start=34,size=6144,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4,uuid=088813B5-7028-4540-99DA-B10015FD07DA,name="ccc" genimage-18/test/include-test.config000066400000000000000000000001611464152623000176270ustar00rootroot00000000000000partition ccc { size = 3M partition-type-uuid = "L" partition-uuid = "088813b5-7028-4540-99da-b10015fd07da" } genimage-18/test/include.config000066400000000000000000000002341464152623000166530ustar00rootroot00000000000000image include.hdimage { hdimage { partition-table-type = "gpt" disk-uuid = "6a921dbb-823d-44c4-8edc-ecb038e6d743" } include("include-test.config") } genimage-18/test/include/000077500000000000000000000000001464152623000154655ustar00rootroot00000000000000genimage-18/test/include/aaa/000077500000000000000000000000001464152623000162075ustar00rootroot00000000000000genimage-18/test/include/aaa/include-test.config000066400000000000000000000001611464152623000217740ustar00rootroot00000000000000partition aaa { size = 1M partition-type-uuid = "L" partition-uuid = "59da602d-c2ea-4f18-818f-cf7947bad0ca" } genimage-18/test/include/bbb/000077500000000000000000000000001464152623000162125ustar00rootroot00000000000000genimage-18/test/include/bbb/include-test.config000066400000000000000000000001611464152623000217770ustar00rootroot00000000000000partition bbb { size = 2M partition-type-uuid = "L" partition-uuid = "284635e9-6b62-41ca-a02a-357c01517279" } genimage-18/test/iso.config000066400000000000000000000000661464152623000160250ustar00rootroot00000000000000image test.iso { iso { volume-id = "iso-test" } } genimage-18/test/jffs2.config000066400000000000000000000001471464152623000162450ustar00rootroot00000000000000include("flash-types.config") image test.jffs2 { jffs2 { } flashtype = "nor-64M-128k" size = 4M } genimage-18/test/jffs2.md5000066400000000000000000000000641464152623000154630ustar00rootroot000000000000004c37f72de7a902286f0cfcbf13b4fde8 images/test.jffs2 genimage-18/test/misc.test000077500000000000000000000062501464152623000157040ustar00rootroot00000000000000#!/bin/bash test_description="Misc Image Tests" . "$(dirname "${0}")/test-setup.sh" exec_test_set_prereq dd exec_test_set_prereq diff exec_test_set_prereq qemu-img test_expect_success dd,diff,qemu-img "qemu" " setup_test_images && run_genimage qemu.config test.qcow && qemu-img check images/test.qcow && zcat '${testdir}/qemu.qcow.gz' > qemu.qcow && qemu-img compare images/test.qcow qemu.qcow " setup_fit_its() { setup_test_images && cp ${testdir}/fit.its input/ } exec_test_set_prereq mkimage exec_test_set_prereq dtc test_expect_success mkimage,dtc "fit" " setup_fit_its && run_genimage fit.config test.fit " setup_rauc() { rm -rf input && mkdir input && cp -r "${testdir}"/rauc-openssl-ca input/ && echo "test" > input/rauc.content && echo "xtest2" > input/rauc2.content } version_lt() { first="$(printf "${1}\n${2}" | sort -V | head -n1)" test "${first}" == "${1}" && test "${1}" != "${2}" } rauc_cmp() { if version_lt "${rauc_version}" "1.6"; then test_cmp "${testdir}/${1}.raucb.info.1" "${1}.raucb.info" elif version_lt "${rauc_version}" "1.9"; then test_cmp "${testdir}/${1}.raucb.info.2" "${1}.raucb.info" elif version_lt "${rauc_version}" "1.10"; then test_cmp "${testdir}/${1}.raucb.info.3" "${1}.raucb.info" else test_cmp "${testdir}/${1}.raucb.info.4" "${1}.raucb.info" fi } exec_test_set_prereq rauc test_expect_success rauc "rauc" " rauc_version="$(rauc --version | sed 's/rauc //')" setup_rauc && run_genimage rauc.config test.raucb && rauc info \ --keyring input/rauc-openssl-ca/ca.cert.pem \ --cert input/rauc-openssl-ca/ca.cert.pem \ images/test.raucb | grep -v cms_get_enveloped_type \ | sed -e 's;O = Test Org, CN = ;/O=Test Org/CN=;' \ -e '/Bundle Format:[ \t]*plain$/d' \ > test.raucb.info && rauc_cmp test rauc info \ --keyring input/rauc-openssl-ca/ca.cert.pem \ --cert input/rauc-openssl-ca/ca.cert.pem \ images/test2.raucb | grep -v cms_get_enveloped_type \ | sed -e 's;O = Test Org, CN = ;/O=Test Org/CN=;' \ -e '/Bundle Format:[ \t]*plain$/d' \ > test2.raucb.info && rauc_cmp test2 " exec_test_set_prereq simg2img test_expect_success simg2img "android-sparse" " setup_test_images && # make sure there is a 4*32k hole at the end i=16 truncate --size=\$[i*(i+1)*i*i*512+32768*4] input/interleaved for i in \`seq 16\`; do dd if=/dev/urandom of=input/interleaved conv=notrunc seek=\$[i*i] count=\$[i] bs=\$[i*i*512] || break done && dd if=/dev/urandom of=input/not-aligned count=9 bs=1024 run_genimage sparse.config && # simg2img will expand the partial block truncate --size=12k input/not-aligned md5sum images/test.hdimage input/interleaved input/not-aligned > md5sum && rm images/test.hdimage input/interleaved input/not-aligned && check_size_range images/interleaved.sparse 9732464 9732636 && simg2img images/test.sparse images/test.hdimage && simg2img images/interleaved.sparse input/interleaved && simg2img images/not-aligned.sparse input/not-aligned && md5sum -c md5sum " exec_test_set_prereq fiptool test_expect_success fiptool "fip" " setup_test_images && run_genimage fip.config test.fip && check_size_range images/test.fip 12804 13056 && fiptool info images/test.fip " test_done # vim: syntax=sh genimage-18/test/mke2fs.0.dump000066400000000000000000000061651464152623000162660ustar00rootroot00000000000000Filesystem volume name: mke2fs Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: has_journal ext_attr dir_index filetype extent 64bit flex_bg sparse_super dir_nlink extra_isize quota metadata_csum Filesystem flags: signed_directory_hash Default mount options: user_xattr acl Filesystem state: clean Errors behavior: Continue Filesystem OS type: Linux Inode count: 8192 Block count: 32768 Reserved block count: 1638 Free blocks: 26580 Free inodes: 8141 First block: 1 Block size: 1024 Fragment size: 1024 Group descriptor size: 64 Blocks per group: 8192 Fragments per group: 8192 Inodes per group: 2048 Inode blocks per group: 512 Flex block group size: 16 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: -1 Last checked: Sat Jan 1 00:00:00 2000 Check interval: 0 () Lifetime writes: 107 kB Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 256 Required extra isize: 32 Desired extra isize: 32 Journal inode: 8 Default directory hash: half_md4 Journal backup: inode blocks Checksum type: crc32c Journal features: (none) Journal size: 4096k Journal length: 4096 Journal sequence: 0x00000001 Journal start: 0 Group 0: (Blocks 1-8192) csum 0xd0bb [ITABLE_ZEROED] Primary superblock at 1, Group descriptors at 2-2 Block bitmap at 3 (+2), csum 0xde29f1cb Inode bitmap at 7 (+6), csum 0xb1052088 Inode table at 11-522 (+10) 6105 free blocks, 1997 free inodes, 18 directories, 1997 unused inodes Free blocks: 2088-8192 Free inodes: 52-2048 Group 1: (Blocks 8193-16384) csum 0x8fde [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED] Backup superblock at 8193, Group descriptors at 8194-8194 Block bitmap at 4 (bg #0 + 3), csum 0x00000000 Inode bitmap at 8 (bg #0 + 7), csum 0x00000000 Inode table at 523-1034 (bg #0 + 522) 8190 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes Free blocks: 8195-16384 Free inodes: 2049-4096 Group 2: (Blocks 16385-24576) csum 0x720f [INODE_UNINIT, ITABLE_ZEROED] Block bitmap at 5 (bg #0 + 4), csum 0x040008b2 Inode bitmap at 9 (bg #0 + 8), csum 0x00000000 Inode table at 1035-1546 (bg #0 + 1034) 4096 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes Free blocks: 20481-24576 Free inodes: 4097-6144 Group 3: (Blocks 24577-32767) csum 0xd0be [INODE_UNINIT, ITABLE_ZEROED] Backup superblock at 24577, Group descriptors at 24578-24578 Block bitmap at 6 (bg #0 + 5), csum 0x4327ef1c Inode bitmap at 10 (bg #0 + 9), csum 0x00000000 Inode table at 1547-2058 (bg #0 + 1546) 8189 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes Free blocks: 24579-32767 Free inodes: 6145-8192 genimage-18/test/mke2fs.1.dump000066400000000000000000000063171464152623000162660ustar00rootroot00000000000000Filesystem volume name: mke2fs Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: has_journal ext_attr dir_index filetype extent 64bit flex_bg sparse_super dir_nlink extra_isize quota metadata_csum Filesystem flags: signed_directory_hash Default mount options: user_xattr acl Filesystem state: clean Errors behavior: Continue Filesystem OS type: Linux Inode count: 8192 Block count: 32768 Reserved block count: 1638 Overhead clusters: 6159 Free blocks: 26580 Free inodes: 8141 First block: 1 Block size: 1024 Fragment size: 1024 Group descriptor size: 64 Blocks per group: 8192 Fragments per group: 8192 Inodes per group: 2048 Inode blocks per group: 512 Flex block group size: 16 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: -1 Last checked: Sat Jan 1 00:00:00 2000 Check interval: 0 () Lifetime writes: 107 kB Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 256 Required extra isize: 32 Desired extra isize: 32 Journal inode: 8 Default directory hash: half_md4 Journal backup: inode blocks Checksum type: crc32c Journal features: (none) Total journal size: 4096k Total journal blocks: 4096 Max transaction length: 4096 Fast commit length: 0 Journal sequence: 0x00000001 Journal start: 0 Group 0: (Blocks 1-8192) csum 0xd0bb [ITABLE_ZEROED] Primary superblock at 1, Group descriptors at 2-2 Block bitmap at 3 (+2), csum 0xde29f1cb Inode bitmap at 7 (+6), csum 0xb1052088 Inode table at 11-522 (+10) 6105 free blocks, 1997 free inodes, 18 directories, 1997 unused inodes Free blocks: 2088-8192 Free inodes: 52-2048 Group 1: (Blocks 8193-16384) csum 0x8fde [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED] Backup superblock at 8193, Group descriptors at 8194-8194 Block bitmap at 4 (bg #0 + 3), csum 0x00000000 Inode bitmap at 8 (bg #0 + 7), csum 0x00000000 Inode table at 523-1034 (bg #0 + 522) 8190 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes Free blocks: 8195-16384 Free inodes: 2049-4096 Group 2: (Blocks 16385-24576) csum 0x720f [INODE_UNINIT, ITABLE_ZEROED] Block bitmap at 5 (bg #0 + 4), csum 0x040008b2 Inode bitmap at 9 (bg #0 + 8), csum 0x00000000 Inode table at 1035-1546 (bg #0 + 1034) 4096 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes Free blocks: 20481-24576 Free inodes: 4097-6144 Group 3: (Blocks 24577-32767) csum 0xd0be [INODE_UNINIT, ITABLE_ZEROED] Backup superblock at 24577, Group descriptors at 24578-24578 Block bitmap at 6 (bg #0 + 5), csum 0x4327ef1c Inode bitmap at 10 (bg #0 + 9), csum 0x00000000 Inode table at 1547-2058 (bg #0 + 1546) 8189 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes Free blocks: 24579-32767 Free inodes: 6145-8192 genimage-18/test/mke2fs.2.dump000066400000000000000000000063171464152623000162670ustar00rootroot00000000000000Filesystem volume name: mke2fs Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: has_journal ext_attr dir_index filetype extent 64bit flex_bg sparse_super dir_nlink extra_isize quota metadata_csum Filesystem flags: signed_directory_hash Default mount options: user_xattr acl Filesystem state: clean Errors behavior: Continue Filesystem OS type: Linux Inode count: 8192 Block count: 32768 Reserved block count: 1638 Overhead clusters: 6159 Free blocks: 26580 Free inodes: 8141 First block: 1 Block size: 1024 Fragment size: 1024 Group descriptor size: 64 Blocks per group: 8192 Fragments per group: 8192 Inodes per group: 2048 Inode blocks per group: 512 Flex block group size: 16 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: -1 Last checked: Sat Jan 1 00:00:00 2000 Check interval: 0 () Lifetime writes: 107 kB Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 256 Required extra isize: 32 Desired extra isize: 32 Journal inode: 8 Default directory hash: half_md4 Journal backup: inode blocks Checksum type: crc32c Journal features: (none) Total journal size: 4096k Total journal blocks: 4096 Max transaction length: 4096 Fast commit length: 0 Journal sequence: 0x00000001 Journal start: 0 Group 0: (Blocks 1-8192) csum 0xd0bb [ITABLE_ZEROED] Primary superblock at 1, Group descriptors at 2-2 Block bitmap at 3 (+2), csum 0xde29f1cb Inode bitmap at 7 (+6), csum 0xb1052088 Inode table at 11-522 (+10) 6105 free blocks, 1997 free inodes, 18 directories, 1997 unused inodes Free blocks: 2088-8192 Free inodes: 52-2048 Group 1: (Blocks 8193-16384) csum 0x8fde [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED] Backup superblock at 8193, Group descriptors at 8194-8194 Block bitmap at 4 (bg #0 + 3), csum 0x00000000 Inode bitmap at 8 (bg #0 + 7), csum 0x00000000 Inode table at 523-1034 (bg #0 + 522) 8190 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes Free blocks: 8195-16384 Free inodes: 2049-4096 Group 2: (Blocks 16385-24576) csum 0x720f [INODE_UNINIT, ITABLE_ZEROED] Block bitmap at 5 (bg #0 + 4), csum 0x040008b2 Inode bitmap at 9 (bg #0 + 8), csum 0x00000000 Inode table at 1035-1546 (bg #0 + 1034) 4096 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes Free blocks: 20481-24576 Free inodes: 4097-6144 Group 3: (Blocks 24577-32767) csum 0xd0be [INODE_UNINIT, ITABLE_ZEROED] Backup superblock at 24577, Group descriptors at 24578-24578 Block bitmap at 6 (bg #0 + 5), csum 0x4327ef1c Inode bitmap at 10 (bg #0 + 9), csum 0x00000000 Inode table at 1547-2058 (bg #0 + 1546) 8189 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes Free blocks: 24579-32767 Free inodes: 6145-8192 genimage-18/test/mke2fs.3.dump000066400000000000000000000063051464152623000162650ustar00rootroot00000000000000Filesystem volume name: mke2fs Last mounted on: Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: has_journal ext_attr dir_index filetype extent 64bit flex_bg sparse_super dir_nlink extra_isize quota metadata_csum Filesystem flags: signed_directory_hash Default mount options: user_xattr acl Filesystem state: clean Errors behavior: Continue Filesystem OS type: Linux Inode count: 8192 Block count: 32768 Reserved block count: 1638 Overhead clusters: 6159 Free blocks: 26580 Free inodes: 8141 First block: 1 Block size: 1024 Fragment size: 1024 Group descriptor size: 64 Blocks per group: 8192 Fragments per group: 8192 Inodes per group: 2048 Inode blocks per group: 512 Flex block group size: 16 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: -1 Last checked: Sat Jan 1 00:00:00 2000 Check interval: 0 () Lifetime writes: 110 kB Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 256 Required extra isize: 32 Desired extra isize: 32 Journal inode: 8 Default directory hash: half_md4 Journal backup: inode blocks Checksum type: crc32c Journal features: (none) Total journal size: 4096k Total journal blocks: 4096 Max transaction length: 4096 Fast commit length: 0 Journal sequence: 0x00000001 Journal start: 0 Group 0: (Blocks 1-8192) csum 0xd0bb [ITABLE_ZEROED] Primary superblock at 1, Group descriptors at 2-2 Block bitmap at 3 (+2), csum 0xde29f1cb Inode bitmap at 7 (+6), csum 0xb1052088 Inode table at 11-522 (+10) 6105 free blocks, 1997 free inodes, 18 directories, 1997 unused inodes Free blocks: 2088-8192 Free inodes: 52-2048 Group 1: (Blocks 8193-16384) csum 0x1510 [INODE_UNINIT, ITABLE_ZEROED] Backup superblock at 8193, Group descriptors at 8194-8194 Block bitmap at 4 (bg #0 + 3), csum 0xc1d1d464 Inode bitmap at 8 (bg #0 + 7), csum 0x00000000 Inode table at 523-1034 (bg #0 + 522) 8190 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes Free blocks: 8195-16384 Free inodes: 2049-4096 Group 2: (Blocks 16385-24576) csum 0x720f [INODE_UNINIT, ITABLE_ZEROED] Block bitmap at 5 (bg #0 + 4), csum 0x040008b2 Inode bitmap at 9 (bg #0 + 8), csum 0x00000000 Inode table at 1035-1546 (bg #0 + 1034) 4096 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes Free blocks: 20481-24576 Free inodes: 4097-6144 Group 3: (Blocks 24577-32767) csum 0xd0be [INODE_UNINIT, ITABLE_ZEROED] Backup superblock at 24577, Group descriptors at 24578-24578 Block bitmap at 6 (bg #0 + 5), csum 0x4327ef1c Inode bitmap at 10 (bg #0 + 9), csum 0x00000000 Inode table at 1547-2058 (bg #0 + 1546) 8189 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes Free blocks: 24579-32767 Free inodes: 6145-8192 genimage-18/test/mke2fs.conf000066400000000000000000000014541464152623000161040ustar00rootroot00000000000000[defaults] base_features = sparse_super,large_file,filetype,resize_inode,dir_index,ext_attr default_mntopts = acl,user_xattr enable_periodic_fsck = 0 blocksize = 4096 inode_size = 256 inode_ratio = 16384 [fs_types] ext3 = { features = has_journal } ext4 = { features = has_journal,extent,huge_file,flex_bg,metadata_csum,64bit,dir_nlink,extra_isize inode_size = 256 } small = { blocksize = 1024 inode_size = 128 inode_ratio = 4096 } floppy = { blocksize = 1024 inode_size = 128 inode_ratio = 8192 } big = { inode_ratio = 32768 } huge = { inode_ratio = 65536 } news = { inode_ratio = 4096 } largefile = { inode_ratio = 1048576 blocksize = -1 } largefile4 = { inode_ratio = 4194304 blocksize = -1 } hurd = { blocksize = 4096 inode_size = 128 } genimage-18/test/mke2fs.config000066400000000000000000000003751464152623000164250ustar00rootroot00000000000000image mke2fs.ext4 { ext4 { label = "mke2fs" fs-timestamp = "20000101000000" use-mke2fs = true mke2fs-conf = "mke2fs.conf" extraargs = "-U 12345678-1234-1234-1234-1234567890ab -E quotatype=" features = "^resize_inode,quota" } size = 32M } genimage-18/test/qemu.config000066400000000000000000000002121464152623000161730ustar00rootroot00000000000000image test.qcow { qemu { format = "qcow2" } partition part1 { image = "part1.img" } partition part2 { image = "part2.img" } } genimage-18/test/qemu.qcow.gz000066400000000000000000000010341464152623000163210ustar00rootroot00000000000000 \test.qcowαAKETYd7d'\%FܗWNF[! 1|C;/:}KyYE 8|{htR [&Kܹ^O'6genimage-18/test/rauc-openssl-ca/000077500000000000000000000000001464152623000170365ustar00rootroot00000000000000genimage-18/test/rauc-openssl-ca/ca.cert.pem000066400000000000000000000104431464152623000210620ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: O=Test Org, CN=Test Org rauc CA Development Validity Not Before: Jan 1 00:00:00 1970 GMT Not After : Dec 31 23:59:59 9999 GMT Subject: O=Test Org, CN=Test Org rauc CA Development Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:e8:fd:f7:69:39:25:dd:9a:b8:c2:59:32:e6:49: 12:85:f3:c3:54:2e:ff:be:87:e8:5c:31:7e:c0:9c: 9f:67:a4:12:01:b2:e7:8e:23:c2:ae:ee:7d:d6:0c: 44:b2:38:60:2d:e7:14:6d:a2:56:63:03:55:f1:1f: 4b:27:9d:51:ac:e7:c4:bd:dd:b3:57:92:47:02:06: 9c:97:c1:2a:97:ac:de:0f:96:a2:6c:c0:bc:03:bd: 43:30:0d:c3:11:03:54:2b:16:4d:08:21:d3:15:9e: 9c:fb:64:a6:52:8b:34:eb:b4:60:21:d6:7b:e4:09: 17:75:2f:e9:61:9b:93:6e:f7:09:45:67:e6:50:9f: 31:86:e5:01:d3:14:c3:b2:16:18:fe:5a:78:b5:9f: aa:ee:d6:71:bb:92:c8:ac:e6:38:17:ef:3f:cc:ae: 92:e0:d6:fa:30:a9:82:db:dc:c2:e0:0a:c6:83:a5: 2a:f6:02:70:4c:f6:82:50:1b:e4:94:18:ae:0a:6b: 18:82:10:ab:7a:b4:11:33:0d:bc:4b:0c:36:24:fc: 6f:b7:09:c2:64:44:af:7f:24:d0:c3:ee:d1:03:c6: fa:4d:5c:67:83:75:ce:c7:b9:e5:d5:11:c7:23:f3: d1:f9:4d:98:27:a8:6a:bd:54:58:10:41:a9:44:94: 1c:1d Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: 9B:70:24:C6:A5:5A:39:78:0A:EB:25:27:13:D3:F1:C6:B4:52:76:79 X509v3 Authority Key Identifier: keyid:9B:70:24:C6:A5:5A:39:78:0A:EB:25:27:13:D3:F1:C6:B4:52:76:79 DirName:/O=Test Org/CN=Test Org rauc CA Development serial:01 X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha256WithRSAEncryption 75:1b:17:97:83:e6:37:52:c0:06:06:ff:04:92:4f:f1:7d:7f: 14:f5:3f:e2:12:c5:c9:ff:6f:51:f4:6e:85:21:0b:bf:2e:68: d0:31:8e:90:e9:f4:cd:bb:00:9f:c4:32:90:d3:c1:80:48:92: 5b:64:39:94:25:1f:23:a7:db:e1:42:51:50:6b:3e:2f:c3:bd: 0e:02:f3:a3:bb:03:9c:26:4d:58:82:dd:f1:53:e7:5b:8c:e3: 4b:23:75:5c:e1:e5:2b:03:41:1a:8a:00:81:ae:fb:b9:70:09: 9c:14:28:3e:2c:df:50:eb:cf:82:c1:4d:ca:f6:cc:a9:37:22: 77:36:0c:d6:c3:8a:85:64:25:c5:e3:05:41:05:1c:fe:4f:97: e3:dc:a4:16:b4:35:23:8a:43:64:64:9f:78:71:70:9a:6a:ed: e2:5e:08:65:07:f7:2e:d1:4a:59:fc:1c:52:7b:36:66:ae:ac: 0d:21:1c:0e:ae:8f:d0:d8:82:3f:b9:5a:d6:f7:6c:26:6f:f7: 61:20:99:99:ee:ec:c6:09:af:73:99:b1:d8:c5:45:1c:de:1e: 30:34:e5:f4:94:41:bd:3c:e5:34:c4:53:80:1f:43:62:28:a4: 6f:5d:67:c2:7d:ec:84:20:33:20:42:f6:60:d1:b9:cb:26:69: 9b:04:a6:f8 -----BEGIN CERTIFICATE----- MIIDhjCCAm6gAwIBAgIBATANBgkqhkiG9w0BAQsFADA6MREwDwYDVQQKDAhUZXN0 IE9yZzElMCMGA1UEAwwcVGVzdCBPcmcgcmF1YyBDQSBEZXZlbG9wbWVudDAgFw03 MDAxMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowOjERMA8GA1UECgwIVGVzdCBP cmcxJTAjBgNVBAMMHFRlc3QgT3JnIHJhdWMgQ0EgRGV2ZWxvcG1lbnQwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDo/fdpOSXdmrjCWTLmSRKF88NULv++ h+hcMX7AnJ9npBIBsueOI8Ku7n3WDESyOGAt5xRtolZjA1XxH0snnVGs58S93bNX kkcCBpyXwSqXrN4PlqJswLwDvUMwDcMRA1QrFk0IIdMVnpz7ZKZSizTrtGAh1nvk CRd1L+lhm5Nu9wlFZ+ZQnzGG5QHTFMOyFhj+Wni1n6ru1nG7ksis5jgX7z/MrpLg 1vowqYLb3MLgCsaDpSr2AnBM9oJQG+SUGK4KaxiCEKt6tBEzDbxLDDYk/G+3CcJk RK9/JNDD7tEDxvpNXGeDdc7HueXVEccj89H5TZgnqGq9VFgQQalElBwdAgMBAAGj gZQwgZEwHQYDVR0OBBYEFJtwJMalWjl4CuslJxPT8ca0UnZ5MGIGA1UdIwRbMFmA FJtwJMalWjl4CuslJxPT8ca0UnZ5oT6kPDA6MREwDwYDVQQKDAhUZXN0IE9yZzEl MCMGA1UEAwwcVGVzdCBPcmcgcmF1YyBDQSBEZXZlbG9wbWVudIIBATAMBgNVHRME BTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB1GxeXg+Y3UsAGBv8Ekk/xfX8U9T/i EsXJ/29R9G6FIQu/LmjQMY6Q6fTNuwCfxDKQ08GASJJbZDmUJR8jp9vhQlFQaz4v w70OAvOjuwOcJk1Ygt3xU+dbjONLI3Vc4eUrA0EaigCBrvu5cAmcFCg+LN9Q68+C wU3K9sypNyJ3NgzWw4qFZCXF4wVBBRz+T5fj3KQWtDUjikNkZJ94cXCaau3iXghl B/cu0UpZ/BxSezZmrqwNIRwOro/Q2II/uVrW92wmb/dhIJmZ7uzGCa9zmbHYxUUc 3h4wNOX0lEG9POU0xFOAH0NiKKRvXWfCfeyEIDMgQvZg0bnLJmmbBKb4 -----END CERTIFICATE----- genimage-18/test/rauc-openssl-ca/rauc.cert.pem000066400000000000000000000104221464152623000214260ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: sha256WithRSAEncryption Issuer: O=Test Org, CN=Test Org rauc CA Development Validity Not Before: Jan 1 00:00:00 1970 GMT Not After : Dec 31 23:59:59 9999 GMT Subject: O=Test Org, CN=Test Org Development-1 Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:ad:98:3e:f6:c6:6d:8c:23:b2:1c:7e:7a:6d:6e: b4:fd:be:31:77:c6:59:48:bd:f9:27:65:ec:35:74: cf:6f:2b:04:3f:0b:4b:e0:0e:6f:b2:92:2a:46:d8: 72:87:49:a8:22:5e:f8:6a:f3:50:68:35:3c:df:18: 5e:1b:9a:c3:c1:26:60:cb:fb:78:d1:8f:d8:74:32: ca:a3:34:13:f9:a5:7f:f6:cc:37:d6:b6:c9:16:f8: 66:d3:fb:01:94:d3:92:9d:43:bf:1f:fc:cd:5e:6a: 98:0a:e8:c1:b2:26:6e:43:4b:0b:2d:b2:47:87:dd: 54:a6:c3:74:94:38:10:12:cd:b0:bd:af:80:cc:d5: c2:2b:29:9c:55:45:95:50:8b:96:66:a3:4f:e6:54: 25:51:8f:c3:4c:e2:94:f3:cb:a0:b2:4b:6c:d3:5f: 36:66:39:4e:ee:fe:60:c9:f4:06:ae:7e:80:9a:4b: 08:7b:ce:93:23:e0:21:da:88:0e:2e:3d:42:33:20: bb:c2:25:ce:ee:68:2e:0c:72:0a:97:f8:8c:d4:01: 12:46:4d:08:fd:27:f4:e4:f7:af:e1:69:f1:19:c4: a1:76:02:8b:d8:45:e7:e7:31:5c:8f:f2:88:d5:55: 1a:31:30:34:72:89:b0:28:62:72:b2:03:d1:a0:1b: 70:47 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: 14:EB:9D:17:A0:17:50:60:D2:4E:52:9E:58:C4:0A:FA:00:66:13:73 X509v3 Authority Key Identifier: keyid:9B:70:24:C6:A5:5A:39:78:0A:EB:25:27:13:D3:F1:C6:B4:52:76:79 DirName:/O=Test Org/CN=Test Org rauc CA Development serial:01 X509v3 Basic Constraints: CA:FALSE Signature Algorithm: sha256WithRSAEncryption cf:5f:a1:98:7f:4a:39:c8:30:3e:77:f0:cb:5d:bd:9f:b8:a3: f3:f7:5a:2c:d7:ed:13:60:c8:09:b9:a5:67:7f:73:2d:94:27: ef:32:e7:8f:82:87:38:a6:c3:2b:7f:2b:d8:47:8c:cf:52:c3: 4e:8d:ed:38:b1:d6:26:b2:4d:b0:2c:d7:95:05:26:c8:17:78: 60:2e:01:91:75:44:d9:7b:f3:db:69:8e:b0:9c:ca:28:72:bf: 96:49:29:07:1c:98:4d:19:d7:50:0b:46:81:d5:fa:f3:2b:49: 59:f4:4d:b7:32:7e:8b:e4:b0:db:db:81:00:14:e8:b0:2f:69: f0:2c:1d:45:9e:9c:92:20:a9:2e:a7:e5:0e:39:94:66:f3:a7: 1b:9e:26:ad:09:76:16:5b:28:2f:a0:6f:97:de:32:e4:26:ee: 79:87:0e:a9:14:c7:a3:d7:cc:c2:05:93:b7:50:35:72:2d:87: c7:e3:23:3e:f6:8c:26:07:22:dd:b9:4f:4a:b9:de:bd:7f:16: 37:48:db:d1:d8:cd:35:0e:86:18:bb:5c:d4:e1:d6:23:d5:53: 15:56:2f:08:a1:bb:d1:3c:92:de:b3:1e:e0:e1:71:f7:bc:1e: 0f:47:67:c5:02:b7:ec:06:4a:28:02:c1:7b:58:95:10:09:e1: aa:07:9d:07 -----BEGIN CERTIFICATE----- MIIDfTCCAmWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADA6MREwDwYDVQQKDAhUZXN0 IE9yZzElMCMGA1UEAwwcVGVzdCBPcmcgcmF1YyBDQSBEZXZlbG9wbWVudDAgFw03 MDAxMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowNDERMA8GA1UECgwIVGVzdCBP cmcxHzAdBgNVBAMMFlRlc3QgT3JnIERldmVsb3BtZW50LTEwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCtmD72xm2MI7IcfnptbrT9vjF3xllIvfknZew1 dM9vKwQ/C0vgDm+ykipG2HKHSagiXvhq81BoNTzfGF4bmsPBJmDL+3jRj9h0Msqj NBP5pX/2zDfWtskW+GbT+wGU05KdQ78f/M1eapgK6MGyJm5DSwstskeH3VSmw3SU OBASzbC9r4DM1cIrKZxVRZVQi5Zmo0/mVCVRj8NM4pTzy6CyS2zTXzZmOU7u/mDJ 9AaufoCaSwh7zpMj4CHaiA4uPUIzILvCJc7uaC4McgqX+IzUARJGTQj9J/Tk96/h afEZxKF2AovYRefnMVyP8ojVVRoxMDRyibAoYnKyA9GgG3BHAgMBAAGjgZEwgY4w HQYDVR0OBBYEFBTrnRegF1Bg0k5SnljECvoAZhNzMGIGA1UdIwRbMFmAFJtwJMal Wjl4CuslJxPT8ca0UnZ5oT6kPDA6MREwDwYDVQQKDAhUZXN0IE9yZzElMCMGA1UE AwwcVGVzdCBPcmcgcmF1YyBDQSBEZXZlbG9wbWVudIIBATAJBgNVHRMEAjAAMA0G CSqGSIb3DQEBCwUAA4IBAQDPX6GYf0o5yDA+d/DLXb2fuKPz91os1+0TYMgJuaVn f3MtlCfvMuePgoc4psMrfyvYR4zPUsNOje04sdYmsk2wLNeVBSbIF3hgLgGRdUTZ e/PbaY6wnMoocr+WSSkHHJhNGddQC0aB1frzK0lZ9E23Mn6L5LDb24EAFOiwL2nw LB1FnpySIKkup+UOOZRm86cbniatCXYWWygvoG+X3jLkJu55hw6pFMej18zCBZO3 UDVyLYfH4yM+9owmByLduU9Kud69fxY3SNvR2M01DoYYu1zU4dYj1VMVVi8IobvR PJLesx7g4XH3vB4PR2fFArfsBkooAsF7WJUQCeGqB50H -----END CERTIFICATE----- genimage-18/test/rauc-openssl-ca/rauc.key.pem000066400000000000000000000032501464152623000212620ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCtmD72xm2MI7Ic fnptbrT9vjF3xllIvfknZew1dM9vKwQ/C0vgDm+ykipG2HKHSagiXvhq81BoNTzf GF4bmsPBJmDL+3jRj9h0MsqjNBP5pX/2zDfWtskW+GbT+wGU05KdQ78f/M1eapgK 6MGyJm5DSwstskeH3VSmw3SUOBASzbC9r4DM1cIrKZxVRZVQi5Zmo0/mVCVRj8NM 4pTzy6CyS2zTXzZmOU7u/mDJ9AaufoCaSwh7zpMj4CHaiA4uPUIzILvCJc7uaC4M cgqX+IzUARJGTQj9J/Tk96/hafEZxKF2AovYRefnMVyP8ojVVRoxMDRyibAoYnKy A9GgG3BHAgMBAAECggEBAIvaAa/RwGOMRmvKQVt0Ov/JgBTciQWfduCUri2Kw6rt 3ufjc+c3+ijEtKaKrgnr/zZhiISxLPAnI7kf6oEWt+odvxHWsEk0N8+1M6czx3vy Jxtu/vVOIMcOq9jPeUCrCo0EDS/5/IG6Im93gMTDTUWNaZ4Q6Ku+VfpbsMnQOLLM C0MBg3GG9OHFwAvmrkTA8fLsI9lsjh2euczD8Gnxy8gIkTGxd3/atzjJwfU7drTk +p5YrlAwswa/Or98OqYLoUUs3KlR3FZdhJdfLOBeCN7ycBoH/vrqUGCZxPf7hG1V WQ/MXIErEIThEVmPVpawN2uuaE2xr18aEDmCc8GkITECgYEA2/9emIs6b1ncXR9a bP+slWPlh6TmOc/r0f82QLPuHfegCJ9kIK1V3ad/rKE02MSVFukptEmE8/YvOrWz NVCNcZ5M2D3mgeIzQZnZz1JqZ3ooEnSfU+Dy1BgPCV2EFyn1NtoiZ4V8vpZKkXOO o9Du11KdqugG1Afv6veUYCTeV4UCgYEAygDdd80IeYkXoZd/1hNV60KeBQzgpsBe Tw9KnO579O9/t+ZF2HUuO5tfRWQxu/pcJ3PinO6TbB1v4nxV4RaFgjQdkeSqVQcJ 68YyT7JOdR3TEbLcJKKE4eikeHa5/P+KVyQJ5avRslH9WSoFdhHf9laqQcy3BsCe /G2XINt3RFsCgYBe2P+Qpt4fqc9e+qiCu8xNcA9CZu63WBQkqnJafPiZROxjK00A 5ZpSgOeDptDg8AgTI51OVDAU+jushS/pOXxx0rzwsedSchKFIu6L+s1TJZBnPI6A nEg09tZsxDuxvO4youMYXK3GgYdOpFKIAAkpHj5Js9VVzsI6PFllBiAx/QKBgDH1 7tCfjFYK2yZjQwHefGSYcF7NZY64i1rAbHLN5SiaR5tjP6keqlWhwvl1o3tbm4lC dyzbMOkPismYeOEX4eNnIl0gEiS/feurdGwTrKX4v2hkNWB2NaluEaedrbhuN3f/ +NauHUoeTyvLYdhm6V6S5r8pc6ce4vOJ41QEE8Z7AoGALDpRTNPk4GOjuXMwCJrO 3pNOjG4/VYT3uKl9m6XDT7/Xaut5mvVTg5ydHfLFx+wCnlpjDkB4hzlv/jLZoscd HAV700G8gIsDvIIVHn9XaGmb535C3NgKlU6k4zCxnv9rFX9whaesWTzGSA4i8RwA X+B3KymaDhAuzRpSfNO+sCY= -----END PRIVATE KEY----- genimage-18/test/rauc.config000066400000000000000000000012571464152623000161700ustar00rootroot00000000000000image test.raucb { rauc { file content { image = "rauc.content" } manifest = " [update] compatible=genimage-test version=42 build=23 description='genimage rauc test' [image.rootfs] filename=content " cert = "rauc-openssl-ca/rauc.cert.pem" key = "rauc-openssl-ca/rauc.key.pem" keyring = "rauc-openssl-ca/ca.cert.pem" } } image test2.raucb { rauc { file data { image = "rauc2.content" offset = 1 } manifest = " [update] compatible=genimage-test version=42 build=23 description='genimage rauc test' [image.rootfs] filename=data " cert = "rauc-openssl-ca/rauc.cert.pem" key = "rauc-openssl-ca/rauc.key.pem" } } genimage-18/test/sharness.sh000066400000000000000000000542241464152623000162330ustar00rootroot00000000000000#!/bin/sh # # Copyright (c) 2011-2012 Mathias Lafeldt # Copyright (c) 2005-2012 Git project # Copyright (c) 2005-2012 Junio C Hamano # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . # Public: Current version of Sharness. SHARNESS_VERSION="1.0.0" export SHARNESS_VERSION # Public: The file extension for tests. By default, it is set to "t". : ${SHARNESS_TEST_EXTENSION:=t} export SHARNESS_TEST_EXTENSION # Reset TERM to original terminal if found, otherwise save orignal TERM [ "x" = "x$SHARNESS_ORIG_TERM" ] && SHARNESS_ORIG_TERM="$TERM" || TERM="$SHARNESS_ORIG_TERM" # Public: The unsanitized TERM under which sharness is originally run export SHARNESS_ORIG_TERM # Export SHELL_PATH : ${SHELL_PATH:=$SHELL} export SHELL_PATH # For repeatability, reset the environment to a known state. # TERM is sanitized below, after saving color control sequences. LANG=C LC_ALL=C PAGER=cat TZ=UTC EDITOR=: export LANG LC_ALL PAGER TZ EDITOR unset VISUAL CDPATH GREP_OPTIONS # Line feed LF=' ' [ "x$TERM" != "xdumb" ] && ( [ -t 1 ] && tput bold >/dev/null 2>&1 && tput setaf 1 >/dev/null 2>&1 && tput sgr0 >/dev/null 2>&1 ) && color=t while test "$#" -ne 0; do case "$1" in -d|--d|--de|--deb|--debu|--debug) debug=t; shift ;; -i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate) immediate=t; shift ;; -l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests) TEST_LONG=t; export TEST_LONG; shift ;; --in|--int|--inte|--inter|--intera|--interac|--interact|--interacti|--interactiv|--interactive|--interactive-|--interactive-t|--interactive-te|--interactive-tes|--interactive-test|--interactive-tests): TEST_INTERACTIVE=t; export TEST_INTERACTIVE; verbose=t; shift ;; -h|--h|--he|--hel|--help) help=t; shift ;; -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose) verbose=t; shift ;; -q|--q|--qu|--qui|--quie|--quiet) # Ignore --quiet under a TAP::Harness. Saying how many tests # passed without the ok/not ok details is always an error. test -z "$HARNESS_ACTIVE" && quiet=t; shift ;; --chain-lint) chain_lint=t; shift ;; --no-chain-lint) chain_lint=; shift ;; --no-color) color=; shift ;; --root=*) root=$(expr "z$1" : 'z[^=]*=\(.*\)') shift ;; *) echo "error: unknown test option '$1'" >&2; exit 1 ;; esac done if test -n "$color"; then # Save the color control sequences now rather than run tput # each time say_color() is called. This is done for two # reasons: # * TERM will be changed to dumb # * HOME will be changed to a temporary directory and tput # might need to read ~/.terminfo from the original HOME # directory to get the control sequences # Note: This approach assumes the control sequences don't end # in a newline for any terminal of interest (command # substitutions strip trailing newlines). Given that most # (all?) terminals in common use are related to ECMA-48, this # shouldn't be a problem. say_color_error=$(tput bold; tput setaf 1) # bold red say_color_skip=$(tput setaf 4) # blue say_color_warn=$(tput setaf 3) # brown/yellow say_color_pass=$(tput setaf 2) # green say_color_info=$(tput setaf 6) # cyan say_color_reset=$(tput sgr0) say_color_="" # no formatting for normal text say_color() { test -z "$1" && test -n "$quiet" && return eval "say_color_color=\$say_color_$1" shift printf "%s\\n" "$say_color_color$*$say_color_reset" } else say_color() { test -z "$1" && test -n "$quiet" && return shift printf "%s\n" "$*" } fi TERM=dumb export TERM error() { say_color error "error: $*" EXIT_OK=t exit 1 } say() { say_color info "$*" } test -n "$test_description" || error "Test script did not set test_description." if test "$help" = "t"; then echo "$test_description" exit 0 fi exec 5>&1 exec 6<&0 if test "$verbose" = "t"; then exec 4>&2 3>&1 else exec 4>/dev/null 3>/dev/null fi test_failure=0 test_count=0 test_fixed=0 test_broken=0 test_success=0 die() { code=$? if test -n "$EXIT_OK"; then exit $code else echo >&5 "FATAL: Unexpected exit with code $code" exit 1 fi } EXIT_OK= trap 'die' EXIT # Public: Define that a test prerequisite is available. # # The prerequisite can later be checked explicitly using test_have_prereq or # implicitly by specifying the prerequisite name in calls to test_expect_success # or test_expect_failure. # # $1 - Name of prerequiste (a simple word, in all capital letters by convention) # # Examples # # # Set PYTHON prerequisite if interpreter is available. # command -v python >/dev/null && test_set_prereq PYTHON # # # Set prerequisite depending on some variable. # test -z "$NO_GETTEXT" && test_set_prereq GETTEXT # # Returns nothing. test_set_prereq() { satisfied_prereq="$satisfied_prereq$1 " } satisfied_prereq=" " # Public: Check if one or more test prerequisites are defined. # # The prerequisites must have previously been set with test_set_prereq. # The most common use of this is to skip all the tests if some essential # prerequisite is missing. # # $1 - Comma-separated list of test prerequisites. # # Examples # # # Skip all remaining tests if prerequisite is not set. # if ! test_have_prereq PERL; then # skip_all='skipping perl interface tests, perl not available' # test_done # fi # # Returns 0 if all prerequisites are defined or 1 otherwise. test_have_prereq() { # prerequisites can be concatenated with ',' save_IFS=$IFS IFS=, set -- $* IFS=$save_IFS total_prereq=0 ok_prereq=0 missing_prereq= for prerequisite; do case "$prerequisite" in !*) negative_prereq=t prerequisite=${prerequisite#!} ;; *) negative_prereq= esac total_prereq=$(($total_prereq + 1)) case "$satisfied_prereq" in *" $prerequisite "*) satisfied_this_prereq=t ;; *) satisfied_this_prereq= esac case "$satisfied_this_prereq,$negative_prereq" in t,|,t) ok_prereq=$(($ok_prereq + 1)) ;; *) # Keep a list of missing prerequisites; restore # the negative marker if necessary. prerequisite=${negative_prereq:+!}$prerequisite if test -z "$missing_prereq"; then missing_prereq=$prerequisite else missing_prereq="$prerequisite,$missing_prereq" fi esac done test $total_prereq = $ok_prereq } # You are not expected to call test_ok_ and test_failure_ directly, use # the text_expect_* functions instead. test_ok_() { test_success=$(($test_success + 1)) say_color "" "ok $test_count - $@" } test_failure_() { test_failure=$(($test_failure + 1)) say_color error "not ok $test_count - $1" shift echo "$@" | sed -e 's/^/# /' test "$immediate" = "" || { EXIT_OK=t; exit 1; } } test_known_broken_ok_() { test_fixed=$(($test_fixed + 1)) say_color error "ok $test_count - $@ # TODO known breakage vanished" } test_known_broken_failure_() { test_broken=$(($test_broken + 1)) say_color warn "not ok $test_count - $@ # TODO known breakage" } # Public: Execute commands in debug mode. # # Takes a single argument and evaluates it only when the test script is started # with --debug. This is primarily meant for use during the development of test # scripts. # # $1 - Commands to be executed. # # Examples # # test_debug "cat some_log_file" # # Returns the exit code of the last command executed in debug mode or 0 # otherwise. test_debug() { test "$debug" = "" || eval "$1" } # Public: Stop execution and start a shell. # # This is useful for debugging tests and only makes sense together with "-v". # Be sure to remove all invocations of this command before submitting. test_pause() { if test "$verbose" = t; then "$SHELL_PATH" <&6 >&3 2>&4 else error >&5 "test_pause requires --verbose" fi } test_eval_() { # This is a separate function because some tests use # "return" to end a test_expect_success block early. case ",$test_prereq," in *,INTERACTIVE,*) eval "$*" ;; *) eval &3 2>&4 "$*" ;; esac } test_run_() { test_cleanup=: expecting_failure=$2 test_eval_ "$1" eval_ret=$? if test "$chain_lint" = "t"; then test_eval_ "(exit 117) && $1" if test "$?" != 117; then error "bug in the test script: broken &&-chain: $1" fi fi if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"; then test_eval_ "$test_cleanup" fi if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then echo "" fi return "$eval_ret" } test_skip_() { test_count=$(($test_count + 1)) to_skip= for skp in $SKIP_TESTS; do case $this_test.$test_count in $skp) to_skip=t break esac done if test -z "$to_skip" && test -n "$test_prereq" && ! test_have_prereq "$test_prereq"; then to_skip=t fi case "$to_skip" in t) of_prereq= if test "$missing_prereq" != "$test_prereq"; then of_prereq=" of $test_prereq" fi say_color skip >&3 "skipping test: $@" say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})" : true ;; *) false ;; esac } # Public: Run test commands and expect them to succeed. # # When the test passed, an "ok" message is printed and the number of successful # tests is incremented. When it failed, a "not ok" message is printed and the # number of failed tests is incremented. # # With --immediate, exit test immediately upon the first failed test. # # Usually takes two arguments: # $1 - Test description # $2 - Commands to be executed. # # With three arguments, the first will be taken to be a prerequisite: # $1 - Comma-separated list of test prerequisites. The test will be skipped if # not all of the given prerequisites are set. To negate a prerequisite, # put a "!" in front of it. # $2 - Test description # $3 - Commands to be executed. # # Examples # # test_expect_success \ # 'git-write-tree should be able to write an empty tree.' \ # 'tree=$(git-write-tree)' # # # Test depending on one prerequisite. # test_expect_success TTY 'git --paginate rev-list uses a pager' \ # ' ... ' # # # Multiple prerequisites are separated by a comma. # test_expect_success PERL,PYTHON 'yo dawg' \ # ' test $(perl -E 'print eval "1 +" . qx[python -c "print 2"]') == "4" ' # # Returns nothing. test_expect_success() { test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_success" export test_prereq if ! test_skip_ "$@"; then say >&3 "expecting success: $2" if test_run_ "$2"; then test_ok_ "$1" else test_failure_ "$@" fi fi echo >&3 "" } # Public: Run test commands and expect them to fail. Used to demonstrate a known # breakage. # # This is NOT the opposite of test_expect_success, but rather used to mark a # test that demonstrates a known breakage. # # When the test passed, an "ok" message is printed and the number of fixed tests # is incremented. When it failed, a "not ok" message is printed and the number # of tests still broken is incremented. # # Failures from these tests won't cause --immediate to stop. # # Usually takes two arguments: # $1 - Test description # $2 - Commands to be executed. # # With three arguments, the first will be taken to be a prerequisite: # $1 - Comma-separated list of test prerequisites. The test will be skipped if # not all of the given prerequisites are set. To negate a prerequisite, # put a "!" in front of it. # $2 - Test description # $3 - Commands to be executed. # # Returns nothing. test_expect_failure() { test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_failure" export test_prereq if ! test_skip_ "$@"; then say >&3 "checking known breakage: $2" if test_run_ "$2" expecting_failure; then test_known_broken_ok_ "$1" else test_known_broken_failure_ "$1" fi fi echo >&3 "" } # Public: Run command and ensure that it fails in a controlled way. # # Use it instead of "! ". For example, when dies due to a # segfault, test_must_fail diagnoses it as an error, while "! " would # mistakenly be treated as just another expected failure. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1.. - Command to be executed. # # Examples # # test_expect_success 'complain and die' ' # do something && # do something else && # test_must_fail git checkout ../outerspace # ' # # Returns 1 if the command succeeded (exit code 0). # Returns 1 if the command died by signal (exit codes 130-192) # Returns 1 if the command could not be found (exit code 127). # Returns 0 otherwise. test_must_fail() { "$@" exit_code=$? if test $exit_code = 0; then echo >&2 "test_must_fail: command succeeded: $*" return 1 elif test $exit_code -gt 129 -a $exit_code -le 192; then echo >&2 "test_must_fail: died by signal: $*" return 1 elif test $exit_code = 127; then echo >&2 "test_must_fail: command not found: $*" return 1 fi return 0 } # Public: Run command and ensure that it succeeds or fails in a controlled way. # # Similar to test_must_fail, but tolerates success too. Use it instead of # " || :" to catch failures caused by a segfault, for instance. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1.. - Command to be executed. # # Examples # # test_expect_success 'some command works without configuration' ' # test_might_fail git config --unset all.configuration && # do something # ' # # Returns 1 if the command died by signal (exit codes 130-192) # Returns 1 if the command could not be found (exit code 127). # Returns 0 otherwise. test_might_fail() { "$@" exit_code=$? if test $exit_code -gt 129 -a $exit_code -le 192; then echo >&2 "test_might_fail: died by signal: $*" return 1 elif test $exit_code = 127; then echo >&2 "test_might_fail: command not found: $*" return 1 fi return 0 } # Public: Run command and ensure it exits with a given exit code. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1 - Expected exit code. # $2.. - Command to be executed. # # Examples # # test_expect_success 'Merge with d/f conflicts' ' # test_expect_code 1 git merge "merge msg" B master # ' # # Returns 0 if the expected exit code is returned or 1 otherwise. test_expect_code() { want_code=$1 shift "$@" exit_code=$? if test $exit_code = $want_code; then return 0 fi echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*" return 1 } # Public: Compare two files to see if expected output matches actual output. # # The TEST_CMP variable defines the command used for the comparision; it # defaults to "diff -u". Only when the test script was started with --verbose, # will the command's output, the diff, be printed to the standard output. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1 - Path to file with expected output. # $2 - Path to file with actual output. # # Examples # # test_expect_success 'foo works' ' # echo expected >expected && # foo >actual && # test_cmp expected actual # ' # # Returns the exit code of the command set by TEST_CMP. test_cmp() { ${TEST_CMP:-diff -u} "$@" } # Public: portably print a sequence of numbers. # # seq is not in POSIX and GNU seq might not be available everywhere, # so it is nice to have a seq implementation, even a very simple one. # # $1 - Starting number. # $2 - Ending number. # # Examples # # test_expect_success 'foo works 10 times' ' # for i in $(test_seq 1 10) # do # foo || return # done # ' # # Returns 0 if all the specified numbers can be displayed. test_seq() { i="$1" j="$2" while test "$i" -le "$j" do echo "$i" || return i=$(expr "$i" + 1) done } # Public: Check if the file expected to be empty is indeed empty, and barfs # otherwise. # # $1 - File to check for emptyness. # # Returns 0 if file is empty, 1 otherwise. test_must_be_empty() { if test -s "$1" then echo "'$1' is not empty, it contains:" cat "$1" return 1 fi } # Public: Schedule cleanup commands to be run unconditionally at the end of a # test. # # If some cleanup command fails, the test will not pass. With --immediate, no # cleanup is done to help diagnose what went wrong. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1.. - Commands to prepend to the list of cleanup commands. # # Examples # # test_expect_success 'test core.capslock' ' # git config core.capslock true && # test_when_finished "git config --unset core.capslock" && # do_something # ' # # Returns the exit code of the last cleanup command executed. test_when_finished() { test_cleanup="{ $* } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup" } # Public: Schedule cleanup commands to be run unconditionally when all tests # have run. # # This can be used to clean up things like test databases. It is not needed to # clean up temporary files, as test_done already does that. # # Examples: # # cleanup mysql -e "DROP DATABASE mytest" # # Returns the exit code of the last cleanup command executed. final_cleanup= cleanup() { final_cleanup="{ $* } && (exit \"\$eval_ret\"); eval_ret=\$?; $final_cleanup" } # Public: Summarize test results and exit with an appropriate error code. # # Must be called at the end of each test script. # # Can also be used to stop tests early and skip all remaining tests. For this, # set skip_all to a string explaining why the tests were skipped before calling # test_done. # # Examples # # # Each test script must call test_done at the end. # test_done # # # Skip all remaining tests if prerequisite is not set. # if ! test_have_prereq PERL; then # skip_all='skipping perl interface tests, perl not available' # test_done # fi # # Returns 0 if all tests passed or 1 if there was a failure. test_done() { EXIT_OK=t if test -z "$HARNESS_ACTIVE"; then test_results_dir="$SHARNESS_TEST_DIRECTORY/test-results" mkdir -p "$test_results_dir" test_results_path="$test_results_dir/$this_test.$$.counts" cat >>"$test_results_path" <<-EOF total $test_count success $test_success fixed $test_fixed broken $test_broken failed $test_failure EOF fi if test "$test_fixed" != 0; then say_color error "# $test_fixed known breakage(s) vanished; please update test(s)" fi if test "$test_broken" != 0; then say_color warn "# still have $test_broken known breakage(s)" fi if test "$test_broken" != 0 || test "$test_fixed" != 0; then test_remaining=$(( $test_count - $test_broken - $test_fixed )) msg="remaining $test_remaining test(s)" else test_remaining=$test_count msg="$test_count test(s)" fi case "$test_failure" in 0) # Maybe print SKIP message if test -n "$skip_all" && test $test_count -gt 0; then error "Can't use skip_all after running some tests" fi [ -z "$skip_all" ] || skip_all=" # SKIP $skip_all" if test $test_remaining -gt 0; then say_color pass "# passed all $msg" fi say "1..$test_count$skip_all" test_eval_ "$final_cleanup" test -d "$remove_trash" && cd "$(dirname "$remove_trash")" && rm -rf "$(basename "$remove_trash")" exit 0 ;; *) say_color error "# failed $test_failure among $msg" say "1..$test_count" exit 1 ;; esac } # Public: Root directory containing tests. Tests can override this variable, # e.g. for testing Sharness itself. : ${SHARNESS_TEST_DIRECTORY:=$(pwd)} export SHARNESS_TEST_DIRECTORY # Public: Source directory of test code and sharness library. # This directory may be different from the directory in which tests are # being run. : ${SHARNESS_TEST_SRCDIR:=$(cd $(dirname $0) && pwd)} export SHARNESS_TEST_SRCDIR # Public: Build directory that will be added to PATH. By default, it is set to # the parent directory of SHARNESS_TEST_DIRECTORY. : ${SHARNESS_BUILD_DIRECTORY:="$SHARNESS_TEST_DIRECTORY/.."} PATH="$SHARNESS_BUILD_DIRECTORY:$PATH" export PATH SHARNESS_BUILD_DIRECTORY # Public: Path to test script currently executed. SHARNESS_TEST_FILE="$0" export SHARNESS_TEST_FILE # Prepare test area. SHARNESS_TRASH_DIRECTORY="trash directory.$(basename "$SHARNESS_TEST_FILE" ".$SHARNESS_TEST_EXTENSION")" test -n "$root" && SHARNESS_TRASH_DIRECTORY="$root/$SHARNESS_TRASH_DIRECTORY" case "$SHARNESS_TRASH_DIRECTORY" in /*) ;; # absolute path is good *) SHARNESS_TRASH_DIRECTORY="$SHARNESS_TEST_DIRECTORY/$SHARNESS_TRASH_DIRECTORY" ;; esac test "$debug" = "t" || remove_trash="$SHARNESS_TRASH_DIRECTORY" rm -rf "$SHARNESS_TRASH_DIRECTORY" || { EXIT_OK=t echo >&5 "FATAL: Cannot prepare test area" exit 1 } # # Load any extensions in $srcdir/sharness.d/*.sh # if test -d "${SHARNESS_TEST_SRCDIR}/sharness.d" then for file in "${SHARNESS_TEST_SRCDIR}"/sharness.d/*.sh do # Ensure glob was not an empty match: test -e "${file}" || break if test -n "$debug" then echo >&5 "sharness: loading extensions from ${file}" fi . "${file}" if test $? != 0 then echo >&5 "sharness: Error loading ${file}. Aborting." exit 1 fi done fi # Public: Empty trash directory, the test area, provided for each test. The HOME # variable is set to that directory too. export SHARNESS_TRASH_DIRECTORY HOME="$SHARNESS_TRASH_DIRECTORY" export HOME mkdir -p "$SHARNESS_TRASH_DIRECTORY" || exit 1 # Use -P to resolve symlinks in our working directory so that the cwd # in subprocesses like git equals our $PWD (for pathname comparisons). cd -P "$SHARNESS_TRASH_DIRECTORY" || exit 1 this_test=${SHARNESS_TEST_FILE##*/} this_test=${this_test%.$SHARNESS_TEST_EXTENSION} for skp in $SKIP_TESTS; do case "$this_test" in $skp) say_color info >&3 "skipping test $this_test altogether" skip_all="skip all tests in $this_test" test_done esac done test -n "$TEST_LONG" && test_set_prereq EXPENSIVE test -n "$TEST_INTERACTIVE" && test_set_prereq INTERACTIVE # Make sure this script ends with code 0 : # vi: set ts=4 sw=4 noet : genimage-18/test/sparse.config000066400000000000000000000012161464152623000165260ustar00rootroot00000000000000image test.hdimage { hdimage { align = 1M partition-table-type = "gpt" disk-uuid = "afcfea87-e41a-40e0-85ae-295c60773c7a" } partition part1 { image = "part1.img" size = 10M partition-uuid = "92762261-e854-45c1-b4c9-fc5e752034ab" } partition part2 { image = "part2.img" size = 10M partition-type-uuid = "L" partition-uuid = "41061242-1d5a-4657-892d-fcc1fdb11a6c" } size = 22M } image test.sparse { android-sparse { image = test.hdimage } } image interleaved.sparse { android-sparse { image = interleaved block-size = 32k } } image not-aligned.sparse { android-sparse { image = not-aligned block-size = 4k } } genimage-18/test/squashfs.config000066400000000000000000000000751464152623000170700ustar00rootroot00000000000000image test.squashfs { squashfs { compression = "lzo" } } genimage-18/test/tar.config000066400000000000000000000000401464152623000160110ustar00rootroot00000000000000image test.tar.gz { tar { } } genimage-18/test/test-setup.sh000066400000000000000000000053221464152623000165150ustar00rootroot00000000000000#!/bin/bash testdir="$(readlink -f $(dirname "${0}"))" genimage="$(pwd)/genimage" PATH="$PATH:/sbin:/usr/sbin" set -- -v "$@" . "${testdir}/sharness.sh" filelist_orig="$(pwd)/file-list.orig" filelist_test="$(pwd)/file-list.test" root_orig="$(pwd)/root.orig" root_test="$(pwd)/root.test" setup_data() { umask 0022 mkdir -p "${root_orig}"/{foo,bar,baz,"with spaces"}/{1,2,3} touch "${root_orig}"/{foo,bar,baz,"with spaces"}/{1,2,3}/{one,two} find "${root_orig}" -print0 | xargs -0 touch -c -d "2011-11-11 UTC" find "${root_orig}"/ -mindepth 1 -printf "%P\n" | sort > "${filelist_orig}" cp "${testdir}"/*.conf* "${testdir}"/*.sh . } run_genimage_impl() { if [ ! -e "${1}" ]; then echo "ERROR: genimage config file '${1}' missing!" return 130 fi if [ "$verbose" = "t" ]; then vargs="--loglevel=3" fi rm -rf tmp images "${root_test}" mkdir "${root_test}" images if [ -n "${2}" ]; then # create a larger output image to make sure it is recreated properly dd if=/dev/zero of="images/${2}" bs=1M seek=30 count=1 fi "${genimage}" \ ${vargs} \ --outputpath=images \ --inputpath=input \ --rootpath="${root}" \ --tmppath=tmp \ ${extra_opts} \ --config "${1}" } run_genimage_root() { root="root.orig" run_genimage_impl "${@}" } run_genimage() { root="/this/directory/does/not/exist" run_genimage_impl "${@}" } get_size() { local file="${1}" if [ ! -f "${file}" ]; then echo "Failed to check file size: '${file}' does not exist!" return 1 fi set -- $(du -b "${file}") size="${1}" } check_size_range() { local size get_size "${1}" || return if [ "${size}" -lt "${2}" -o "${size}" -gt "${3}" ]; then echo "Incorrect file size for '${1}': expected min: ${2} max: ${3} found: ${size}" return 1 fi } check_size() { local size get_size "${1}" || return if [ "${size}" -ne "${2}" ]; then echo "Incorrect file size for '${1}': expected: ${2} found: ${size}" return 1 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 } setup_test_images() { rm -rf input && mkdir input && dd if=/dev/zero of=input/part1.img bs=512 count=7 && dd if=/dev/zero of=input/part2.img bs=512 count=11 && touch input/part3.img } sanitized_fdisk_sfdisk() { # check the disk identifier fdisk -l "${1}" | grep identifier: && # check partitions; filter output to handle different sfdisk versions sfdisk -d "${1}" 2>/dev/null | grep '^images/' | \ sed -e 's/ *//g' -e 's;Id=;type=;' } exec_test_set_prereq() { command -v "${1}" > /dev/null && test_set_prereq "${1/./_}" } set -o pipefail setup_data sfdisk -h | grep -q gpt && test_set_prereq sfdisk-gpt fdisk -h | grep -q gpt && test_set_prereq fdisk-gpt genimage-18/test/test.raucb.info.1000066400000000000000000000015721464152623000171350ustar00rootroot00000000000000Compatible: 'genimage-test' Version: '42' Description: ''genimage rauc test'' Build: '23' Hooks: '' 1 Image: (1) content Slotclass: rootfs Checksum: f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2 Size: 5 Hooks: 0 Files Certificate Chain: 0 Subject: /O=Test Org/CN=Test Org Development-1 Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 79:82:8B:11:2C:F2:78:06:60:4D:09:3B:55:3D:AF:D8:B4:B1:02:9A:D3:AC:40:57:77:1D:D0:AF:E8:B9:9E:90 Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT 1 Subject: /O=Test Org/CN=Test Org rauc CA Development Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 09:72:43:C2:97:DA:BB:C6:39:FE:41:84:10:2C:69:9C:6E:8D:AD:06:2F:62:66:A5:CB:15:44:77:E5:DB:BE:AD Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT genimage-18/test/test.raucb.info.2000066400000000000000000000015731464152623000171370ustar00rootroot00000000000000Compatible: 'genimage-test' Version: '42' Description: ''genimage rauc test'' Build: '23' Hooks: '' 1 Image: [rootfs] Filename: content Checksum: f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2 Size: 5 Hooks: Certificate Chain: 0 Subject: /O=Test Org/CN=Test Org Development-1 Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 79:82:8B:11:2C:F2:78:06:60:4D:09:3B:55:3D:AF:D8:B4:B1:02:9A:D3:AC:40:57:77:1D:D0:AF:E8:B9:9E:90 Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT 1 Subject: /O=Test Org/CN=Test Org rauc CA Development Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 09:72:43:C2:97:DA:BB:C6:39:FE:41:84:10:2C:69:9C:6E:8D:AD:06:2F:62:66:A5:CB:15:44:77:E5:DB:BE:AD Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT genimage-18/test/test.raucb.info.3000066400000000000000000000017161464152623000171370ustar00rootroot00000000000000Compatible: 'genimage-test' Version: '42' Description: ''genimage rauc test'' Build: '23' Hooks: '' Manifest Hash: '396427d8c699c8c1f1c89836dc9883448d1b176477848fff63cdd1bdae1cd1a0' 1 Image: [rootfs] Filename: content Checksum: f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2 Size: 5 Hooks: Certificate Chain: 0 Subject: /O=Test Org/CN=Test Org Development-1 Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 79:82:8B:11:2C:F2:78:06:60:4D:09:3B:55:3D:AF:D8:B4:B1:02:9A:D3:AC:40:57:77:1D:D0:AF:E8:B9:9E:90 Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT 1 Subject: /O=Test Org/CN=Test Org rauc CA Development Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 09:72:43:C2:97:DA:BB:C6:39:FE:41:84:10:2C:69:9C:6E:8D:AD:06:2F:62:66:A5:CB:15:44:77:E5:DB:BE:AD Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT genimage-18/test/test.raucb.info.4000066400000000000000000000017241464152623000171370ustar00rootroot00000000000000Compatible: 'genimage-test' Version: '42' Description: ''genimage rauc test'' Build: '23' Hooks: '' Manifest Hash: '396427d8c699c8c1f1c89836dc9883448d1b176477848fff63cdd1bdae1cd1a0' 1 Image: [rootfs] Filename: content Checksum: f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2 Size: 5 bytes Hooks: Certificate Chain: 0 Subject: /O=Test Org/CN=Test Org Development-1 Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 79:82:8B:11:2C:F2:78:06:60:4D:09:3B:55:3D:AF:D8:B4:B1:02:9A:D3:AC:40:57:77:1D:D0:AF:E8:B9:9E:90 Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT 1 Subject: /O=Test Org/CN=Test Org rauc CA Development Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 09:72:43:C2:97:DA:BB:C6:39:FE:41:84:10:2C:69:9C:6E:8D:AD:06:2F:62:66:A5:CB:15:44:77:E5:DB:BE:AD Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT genimage-18/test/test2.raucb.info.1000066400000000000000000000015671464152623000172230ustar00rootroot00000000000000Compatible: 'genimage-test' Version: '42' Description: ''genimage rauc test'' Build: '23' Hooks: '' 1 Image: (1) data Slotclass: rootfs Checksum: 7d6fd7774f0d87624da6dcf16d0d3d104c3191e771fbe2f39c86aed4b2bf1a0f Size: 6 Hooks: 0 Files Certificate Chain: 0 Subject: /O=Test Org/CN=Test Org Development-1 Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 79:82:8B:11:2C:F2:78:06:60:4D:09:3B:55:3D:AF:D8:B4:B1:02:9A:D3:AC:40:57:77:1D:D0:AF:E8:B9:9E:90 Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT 1 Subject: /O=Test Org/CN=Test Org rauc CA Development Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 09:72:43:C2:97:DA:BB:C6:39:FE:41:84:10:2C:69:9C:6E:8D:AD:06:2F:62:66:A5:CB:15:44:77:E5:DB:BE:AD Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT genimage-18/test/test2.raucb.info.2000066400000000000000000000015701464152623000172160ustar00rootroot00000000000000Compatible: 'genimage-test' Version: '42' Description: ''genimage rauc test'' Build: '23' Hooks: '' 1 Image: [rootfs] Filename: data Checksum: 7d6fd7774f0d87624da6dcf16d0d3d104c3191e771fbe2f39c86aed4b2bf1a0f Size: 6 Hooks: Certificate Chain: 0 Subject: /O=Test Org/CN=Test Org Development-1 Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 79:82:8B:11:2C:F2:78:06:60:4D:09:3B:55:3D:AF:D8:B4:B1:02:9A:D3:AC:40:57:77:1D:D0:AF:E8:B9:9E:90 Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT 1 Subject: /O=Test Org/CN=Test Org rauc CA Development Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 09:72:43:C2:97:DA:BB:C6:39:FE:41:84:10:2C:69:9C:6E:8D:AD:06:2F:62:66:A5:CB:15:44:77:E5:DB:BE:AD Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT genimage-18/test/test2.raucb.info.3000066400000000000000000000017131464152623000172160ustar00rootroot00000000000000Compatible: 'genimage-test' Version: '42' Description: ''genimage rauc test'' Build: '23' Hooks: '' Manifest Hash: 'ef0e93a54af2689a033ad524522c4b6b97115bad3ac0b907e01a41221f41e729' 1 Image: [rootfs] Filename: data Checksum: 7d6fd7774f0d87624da6dcf16d0d3d104c3191e771fbe2f39c86aed4b2bf1a0f Size: 6 Hooks: Certificate Chain: 0 Subject: /O=Test Org/CN=Test Org Development-1 Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 79:82:8B:11:2C:F2:78:06:60:4D:09:3B:55:3D:AF:D8:B4:B1:02:9A:D3:AC:40:57:77:1D:D0:AF:E8:B9:9E:90 Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT 1 Subject: /O=Test Org/CN=Test Org rauc CA Development Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 09:72:43:C2:97:DA:BB:C6:39:FE:41:84:10:2C:69:9C:6E:8D:AD:06:2F:62:66:A5:CB:15:44:77:E5:DB:BE:AD Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT genimage-18/test/test2.raucb.info.4000066400000000000000000000017211464152623000172160ustar00rootroot00000000000000Compatible: 'genimage-test' Version: '42' Description: ''genimage rauc test'' Build: '23' Hooks: '' Manifest Hash: 'ef0e93a54af2689a033ad524522c4b6b97115bad3ac0b907e01a41221f41e729' 1 Image: [rootfs] Filename: data Checksum: 7d6fd7774f0d87624da6dcf16d0d3d104c3191e771fbe2f39c86aed4b2bf1a0f Size: 6 bytes Hooks: Certificate Chain: 0 Subject: /O=Test Org/CN=Test Org Development-1 Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 79:82:8B:11:2C:F2:78:06:60:4D:09:3B:55:3D:AF:D8:B4:B1:02:9A:D3:AC:40:57:77:1D:D0:AF:E8:B9:9E:90 Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT 1 Subject: /O=Test Org/CN=Test Org rauc CA Development Issuer: /O=Test Org/CN=Test Org rauc CA Development SPKI sha256: 09:72:43:C2:97:DA:BB:C6:39:FE:41:84:10:2C:69:9C:6E:8D:AD:06:2F:62:66:A5:CB:15:44:77:E5:DB:BE:AD Not Before: Jan 1 00:00:00 1970 GMT Not After: Dec 31 23:59:59 9999 GMT genimage-18/test/ubi.config000066400000000000000000000003101464152623000160020ustar00rootroot00000000000000include("flash-types.config") image test.ubi { ubi { } partition ubifs1 { image = "test.ubifs" } partition ubifs2 { image = "test.ubifs" autoresize = true } flashtype = "nand-64M-512" } genimage-18/test/ubifs.config000066400000000000000000000001701464152623000163370ustar00rootroot00000000000000include("flash-types.config") image test.ubifs { ubifs { max-size = 16M } flashtype = "nand-64M-512" size = 4M } genimage-18/test/vfat.config000066400000000000000000000001141464152623000161650ustar00rootroot00000000000000image test.vfat { vfat { extraargs = "-n 'vfat-test'" } size = 4095K } genimage-18/util.c000066400000000000000000000457241464152623000142200ustar00rootroot00000000000000/* * Copyright (c) 2011 Sascha Hauer , Pengutronix * (c) 2011 Michael Olbrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #ifdef HAVE_LINUX_FS_H #include #endif #ifdef HAVE_FIEMAP #include #endif #include #include #include #include #include "genimage.h" #ifndef AT_NO_AUTOMOUNT #define AT_NO_AUTOMOUNT 0x800 #endif static int loglevel(void) { static int level = -1; if (level < 0) { const char *l = get_opt("loglevel"); if (l) level = atoi(l); else level = 1; } return level; } static int skip_log(int level) { return (level > loglevel()); } static void xvasprintf(char **strp, const char *fmt, va_list ap) { if (vasprintf(strp, fmt, ap) < 0) { error("out of memory\n"); exit(1); } } void xasprintf(char **strp, const char *fmt, ...) { va_list args; va_start (args, fmt); xvasprintf(strp, fmt, args); va_end (args); } void xstrcatf(char **strp, const char *fmt, ...) { char *tmp; va_list list; va_start(list, fmt); xvasprintf(&tmp, fmt, list); va_end(list); if (*strp) { *strp = xrealloc(*strp, strlen(*strp) + strlen(tmp) + 1); strcat(*strp, tmp); free(tmp); } else { *strp = tmp; } } static void image_log(struct image *image, int level, const char *fmt, va_list args) { char *buf; const char *p; if (skip_log(level)) return; xvasprintf(&buf, fmt, args); switch (level) { case 0: p = "ERROR"; break; case 1: p = "INFO"; break; case 2: p = "DEBUG"; break; case 3: default: p = "VDEBUG"; break; } if (image) fprintf(stderr, "%s: %s(%s): %s", p, image->handler ? image->handler->type : "unknown", image->file, buf); else fprintf(stderr, "%s: %s", p, buf); free(buf); } void image_error(struct image *image, const char *fmt, ...) { va_list args; va_start(args, fmt); image_log(image, 0, fmt, args); va_end(args); } void image_info(struct image *image, const char *fmt, ...) { va_list args; va_start(args, fmt); image_log(image, 1, fmt, args); va_end(args); } void image_debug(struct image *image, const char *fmt, ...) { va_list args; va_start(args, fmt); image_log(image, 2, fmt, args); va_end(args); } void error(const char *fmt, ...) { va_list args; va_start(args, fmt); image_log(NULL, 0, fmt, args); va_end(args); } void info(const char *fmt, ...) { va_list args; va_start(args, fmt); image_log(NULL, 1, fmt, args); va_end(args); } void debug(const char *fmt, ...) { va_list args; va_start(args, fmt); image_log(NULL, 2, fmt, args); va_end(args); } /* * printf wrapper around 'system' */ int systemp(struct image *image, const char *fmt, ...) { va_list args; char *buf; const char *o; int ret; int status; pid_t pid; va_start (args, fmt); xvasprintf(&buf, fmt, args); va_end (args); if (!buf) return -ENOMEM; if (loglevel() >= 3) o = " (stderr+stdout):"; else if (loglevel() >= 1) o = " (stderr):"; else o = ""; image_info(image, "cmd: \"%s\"%s\n", buf, o); pid = fork(); if (!pid) { const char *shell; int fd; if (loglevel() < 1) { fd = open("/dev/null", O_WRONLY); dup2(fd, STDERR_FILENO); } if (loglevel() < 3) { fd = open("/dev/null", O_WRONLY); dup2(fd, STDOUT_FILENO); } else { dup2(STDERR_FILENO, STDOUT_FILENO); } shell = getenv("GENIMAGE_SHELL"); if (!shell || shell[0] == 0x0) shell = "/bin/sh"; execl(shell, shell, "-c", buf, NULL); ret = -errno; error("Cannot execute %s: %s\n", buf, strerror(errno)); goto err_out; } else { ret = waitpid(pid, &status, 0); if (ret < 0) { ret = -errno; error("Failed to wait for command execution: %s\n", strerror(errno)); goto err_out; } } ret = WEXITSTATUS(status); err_out: free(buf); return ret; } /* * xzalloc - safely allocate zeroed memory */ void *xzalloc(size_t n) { void *m = malloc(n); if (!m) { error("out of memory\n"); exit(1); } memset(m, 0, n); return m; } void *xrealloc(void *ptr, size_t size) { void *m = realloc(ptr, size); if (!m) { error("out of memory\n"); exit(1); } return m; } /* * 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, cfg_bool_t *percent) { unsigned long long val; char *end; val = strtoull(str, &end, 0); if (percent) *percent = cfg_false; switch (*end) { case 'G': val *= 1024; /* fall-through */ case 'M': val *= 1024; /* fall-through */ case 'k': case 'K': val *= 1024; end++; break; case 's': val *= 512; end++; break; 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); } if (endp) *endp = (char *)end; return val; } int is_block_device(const char *filename) { struct stat s; return stat(filename, &s) == 0 && ((s.st_mode & S_IFMT) == S_IFBLK); } int open_file(struct image *image, const char *filename, int extra_flags) { int flags = O_WRONLY | extra_flags; int ret, fd; /* make sure block devices are unused before writing */ if (is_block_device(filename)) flags |= O_EXCL; else flags |= O_CREAT; fd = open(filename, flags, 0666); if (fd < 0) { ret = -errno; image_error(image, "open %s: %s\n", filename, strerror(errno)); return ret; } return fd; } /* Build a file extent covering the whole file */ static int whole_file_exent(size_t size, struct extent **extents, size_t *extent_count) { *extents = xzalloc(sizeof(struct extent)); (*extents)[0].start = 0; (*extents)[0].end = size; *extent_count = 1; return 0; } /* Build an file extent array for the file */ int map_file_extents(struct image *image, const char *filename, int f, size_t size, struct extent **extents, size_t *extent_count) { int ret; #ifdef HAVE_FIEMAP struct fiemap *fiemap; unsigned i; /* Get extent count */ fiemap = xzalloc(sizeof(struct fiemap)); fiemap->fm_length = size; ret = ioctl(f, FS_IOC_FIEMAP, fiemap); if (ret == -1) goto err_out; /* Get extents */ fiemap = xrealloc(fiemap, sizeof(struct fiemap) + fiemap->fm_mapped_extents * sizeof(struct fiemap_extent)); fiemap->fm_extent_count = fiemap->fm_mapped_extents; ret = ioctl(f, FS_IOC_FIEMAP, fiemap); if (ret == -1) goto err_out; /* Build extent array */ *extent_count = fiemap->fm_mapped_extents; *extents = xzalloc(*extent_count * sizeof(struct extent)); for (i = 0; i < *extent_count; i++) { (*extents)[i].start = fiemap->fm_extents[i].fe_logical; (*extents)[i].end = fiemap->fm_extents[i].fe_logical + fiemap->fm_extents[i].fe_length; } /* The last extent may extend beyond the end of file, limit it to the actual end */ if (*extent_count && (*extents)[i-1].end > size) (*extents)[i-1].end = size; free(fiemap); return 0; err_out: ret = -errno; free(fiemap); #else ret = -EOPNOTSUPP; #endif /* If failure is due to no filesystem support, return a single extent */ if (ret == -EOPNOTSUPP || ret == -ENOTTY) return whole_file_exent(size, extents, extent_count); image_error(image, "fiemap %s: %d %s\n", filename, errno, strerror(errno)); return ret; } /* * Write @size @byte bytes at the @offset in @fd. Roughly equivalent to * a single "pwrite(fd, big-buffer, size, offset)", except that we try to use * more efficient operations (ftruncate and fallocate) if @byte is zero. This * only uses methods that do not affect the offset of fd. */ static int write_bytes(int fd, size_t size, off_t offset, unsigned char byte) { struct stat st; char buf[4096]; if (!size) return 0; if (fstat(fd, &st) < 0) return -errno; if (S_ISREG(st.st_mode) && (byte == 0)) { if (offset + size > (size_t)st.st_size) { if (ftruncate(fd, offset + size) < 0) return -errno; /* * The area from st.st_size to offset+size is * zeroed by this operation. If offset was >= * st.st_size, we're done. */ if (offset >= st.st_size) return 0; /* * Otherwise, reduce size accordingly, we only * need to write bytes from offset until the * old end of the file. */ size = st.st_size - offset; } #ifdef HAVE_FALLOCATE /* * Use fallocate if it is available and FALLOC_FL_PUNCH_HOLE * is supported by the filesystem. If not, fall through to * the write loop. */ if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, offset, size) == 0) return 0; #endif } /* Not a regular file, non-zero pattern, or fallocate not applicable. */ memset(buf, byte, sizeof(buf)); while (size) { size_t now = min(size, sizeof(buf)); int r; r = pwrite(fd, buf, now, offset); if (r < 0) return -errno; size -= r; offset += r; } return 0; } /* * For regular files this makes sure that: * - the file exists * - the file has the specified size * - any previous date is cleared * For block devices this makes sure that: * - any existing filesystem header is cleared */ int prepare_image(struct image *image, unsigned long long size) { if (is_block_device(imageoutfile(image))) { insert_image(image, NULL, 2048, 0, 0); } else { int ret; /* for regular files, create the file or truncate it to zero * size to remove all existing content */ int fd = open_file(image, imageoutfile(image), O_TRUNC); if (fd < 0) return fd; /* * Resize the file immediately to the final size. This is not * strictly necessary but this circumvents XFS preallocation * heuristics. Without this, the holes in the image may be smaller * than necessary. */ ret = ftruncate(fd, size); close(fd); if (ret < 0) { ret = -errno; image_error(image, "failed to truncate %s to %lld: %s\n", imageoutfile(image), size, strerror(-ret)); return ret; } } return 0; } /* * Insert the image @sub at offset @offset in @image. If @sub is * smaller than @size (including if @sub is NULL), insert @byte bytes for * the remainder. If @sub is larger than @size, only the first @size * bytes of it will be copied (it's up to the caller to ensure this * doesn't happen). This means that after this call, exactly the range * [offset, offset+size) in the output @image have been updated. */ int insert_image(struct image *image, struct image *sub, unsigned long long size, unsigned long long offset, unsigned char byte) { struct extent *extents = NULL; size_t extent_count = 0; int fd = -1, in_fd = -1; unsigned long long in_pos; const char *infile; unsigned e; int ret; fd = open_file(image, imageoutfile(image), 0); if (fd < 0) { ret = fd; goto out; } if (lseek(fd, offset, SEEK_SET) < 0) { ret = -errno; goto out; } if (!sub) goto fill; infile = imageoutfile(sub); in_fd = open(infile, O_RDONLY); if (in_fd < 0) { ret = -errno; image_error(image, "open %s: %s", infile, strerror(errno)); goto out; } ret = map_file_extents(image, infile, in_fd, size, &extents, &extent_count); if (ret) goto out; image_debug(image, "copying %llu bytes from %s at offset %llu\n", size, infile, offset); in_pos = 0; for (e = 0; e < extent_count && size > 0; e++) { const struct extent *ext = &extents[e]; size_t len = ext->start - in_pos; /* * If the input file is larger than size, it might * have an extent that starts beyond size. */ len = min(len, size); ret = write_bytes(fd, len, offset, 0); // Assumes 'holes' are always 0 bytes if (ret) { image_error(image, "writing %zu bytes failed: %s\n", len, strerror(-ret)); goto out; } size -= len; offset += len; in_pos += len; while (in_pos < ext->end && size > 0) { char buf[4096]; size_t now; int r, w; now = min(ext->end - in_pos, sizeof(buf)); now = min(now, size); r = pread(in_fd, buf, now, in_pos); if (r < 0) { ret = -errno; image_error(image, "reading %zu bytes from %s failed: %s\n", now, infile, strerror(errno)); goto out; } if (r == 0) break; w = pwrite(fd, buf, r, offset); if (w < r) { ret = w < 0 ? -errno : -EIO; if (w < 0) image_error(image, "write %d bytes: %s\n", r, strerror(errno)); else image_error(image, "short write (%d vs %d)\n", w, r); goto out; } size -= w; offset += w; in_pos += w; } } fill: image_debug(image, "adding %llu %#hhx bytes at offset %llu\n", size, byte, offset); ret = write_bytes(fd, size, offset, byte); if (ret) image_error(image, "writing %llu bytes failed: %s\n", size, strerror(-ret)); out: if (fd >= 0) close(fd); if (in_fd >= 0) close(in_fd); free(extents); return ret; } int insert_data(struct image *image, const void *_data, const char *outfile, size_t size, unsigned long long offset) { const char *data = _data; int outf = -1; int now, r; int ret = 0; outf = open_file(image, outfile, 0); if (outf < 0) return outf; if (lseek(outf, offset, SEEK_SET) < 0) { ret = -errno; image_error(image, "seek %s: %s\n", outfile, strerror(errno)); goto err_out; } while (size) { now = min(size, 4096); r = write(outf, data, now); if (r < now) { ret = -errno; image_error(image, "write %s: %s\n", outfile, strerror(errno)); goto err_out; } size -= now; data += now; } err_out: close(outf); return ret; } int extend_file(struct image *image, size_t size) { const char *outfile = imageoutfile(image); 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; ret = ftruncate(f, size); if (ret == -1) { ret = -errno; image_error(image, "ftruncate %s: %s\n", outfile, strerror(errno)); goto out; } ret = 0; out: close(f); return ret; } int uuid_validate(const char *str) { int i; if (strlen(str) != 36) return -1; for (i = 0; i < 36; i++) { if (i == 8 || i == 13 || i == 18 || i == 23) { if (str[i] != '-') return -1; continue; } if (!isxdigit(str[i])) return -1; } return 0; } static unsigned char uuid_byte(const char *hex) { char buf[3]; buf[0] = hex[0]; buf[1] = hex[1]; buf[2] = 0; return strtoul(buf, NULL, 16); } void uuid_parse(const char *str, unsigned char *uuid) { uuid[0] = uuid_byte(str + 6); uuid[1] = uuid_byte(str + 4); uuid[2] = uuid_byte(str + 2); uuid[3] = uuid_byte(str); uuid[4] = uuid_byte(str + 11); uuid[5] = uuid_byte(str + 9); uuid[6] = uuid_byte(str + 16); uuid[7] = uuid_byte(str + 14); uuid[8] = uuid_byte(str + 19); uuid[9] = uuid_byte(str + 21); uuid[10] = uuid_byte(str + 24); uuid[11] = uuid_byte(str + 26); uuid[12] = uuid_byte(str + 28); uuid[13] = uuid_byte(str + 30); uuid[14] = uuid_byte(str + 32); uuid[15] = uuid_byte(str + 34); } char *uuid_random(void) { char *uuid; xasprintf(&uuid, "%04lx%04lx-%04lx-%04lx-%04lx-%04lx%04lx%04lx", random() & 0xffff, random() & 0xffff, random() & 0xffff, (random() & 0x0fff) | 0x4000, (random() & 0x3fff) | 0x8000, random() & 0xffff, random() & 0xffff, random() & 0xffff); return uuid; } int block_device_size(struct image *image, const char *blkdev, unsigned long long *size) { struct stat st; int fd, ret; off_t offset; fd = open(blkdev, O_RDONLY); if (fd < 0 || fstat(fd, &st) < 0) { ret = -errno; goto out; } if ((st.st_mode & S_IFMT) != S_IFBLK) { ret = -EINVAL; goto out; } offset = lseek(fd, 0, SEEK_END); if (offset < 0) { ret = -errno; goto out; } *size = offset; ret = 0; out: if (ret) image_error(image, "failed to determine size of block device %s: %s", blkdev, strerror(-ret)); if (fd >= 0) close(fd); return ret; } int reload_partitions(struct image *image) { #ifdef HAVE_LINUX_FS_H const char *outfile = imageoutfile(image); int fd; if (!is_block_device(outfile)) return 0; fd = open(outfile, O_WRONLY|O_EXCL); if (fd < 0) { int ret = -errno; image_error(image, "open: %s\n", strerror(errno)); return ret; } /* no error because not all block devices support this */ if (ioctl(fd, BLKRRPART) < 0) image_info(image, "failed to re-read partition table: %s\n", strerror(errno)); close(fd); #endif 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)); close(fd); 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); } closedir(dir); close(fd); return size + blocksize; } unsigned long long image_dir_size(struct image *image) { if (image->empty) return 0; return dir_size(image, AT_FDCWD, mountpath(image), 4096); } int parse_holes(struct image *image, cfg_t *cfg) { int i; if (image->n_holes > 0) return 0; image->n_holes = cfg ? cfg_size(cfg, "holes") : 0; if (image->n_holes == 0) return 0; image->holes = xzalloc(image->n_holes * sizeof(*image->holes)); for (i = 0; i < image->n_holes; i++) { const char *s = cfg_getnstr(cfg, "holes", i); char *start, *end; int len; if (sscanf(s, " ( %m[0-9skKMG] ; %m[0-9skKMG] ) %n", &start, &end, &len) != 2 || len != (int)strlen(s)) { image_error(image, "invalid hole specification '%s', use '(;)'\n", s); return -EINVAL; } image->holes[i].start = strtoul_suffix(start, NULL, NULL); image->holes[i].end = strtoul_suffix(end, NULL, NULL); free(start); free(end); image_debug(image, "added hole (%llu, %llu)\n", image->holes[i].start, image->holes[i].end); } return 0; }