Hello community, here is the log from the commit of package mksusecd for openSUSE:Factory checked in at 2017-04-07 13:55:52 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/mksusecd (Old) and /work/SRC/openSUSE:Factory/.mksusecd.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "mksusecd" Fri Apr 7 13:55:52 2017 rev:34 rq:485854 version:1.49 Changes: -------- --- /work/SRC/openSUSE:Factory/mksusecd/mksusecd.changes 2017-03-21 22:51:13.656545141 +0100 +++ /work/SRC/openSUSE:Factory/.mksusecd.new/mksusecd.changes 2017-04-07 13:55:58.484865701 +0200 @@ -1,0 +2,25 @@ +Wed Apr 5 15:00:18 UTC 2017 - snw...@suse.com + +- add support for disk images with FAT file system +- 1.49 + +------------------------------------------------------------------- +Mon Apr 3 15:30:15 UTC 2017 - snw...@suse.com + +- undo accidental mksusecd patch +- 1.48 + +------------------------------------------------------------------- +Mon Apr 3 15:20:13 UTC 2017 - snw...@suse.com + +- some small doc fixes +- add dvd/disk image layout description +- 1.47 + +------------------------------------------------------------------- +Mon Apr 3 10:15:13 UTC 2017 - snw...@suse.com + +- isohybrid: add --size option to specify image size +- 1.46 + +------------------------------------------------------------------- Old: ---- mksusecd-1.45.tar.xz New: ---- mksusecd-1.49.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ mksusecd.spec ++++++ --- /var/tmp/diff_new_pack.SQL81q/_old 2017-04-07 13:56:00.764543677 +0200 +++ /var/tmp/diff_new_pack.SQL81q/_new 2017-04-07 13:56:00.764543677 +0200 @@ -18,7 +18,7 @@ Name: mksusecd -Version: 1.45 +Version: 1.49 Release: 0 Summary: Create SUSE Linux installation ISOs License: GPL-3.0+ ++++++ mksusecd-1.45.tar.xz -> mksusecd-1.49.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mksusecd-1.45/VERSION new/mksusecd-1.49/VERSION --- old/mksusecd-1.45/VERSION 2017-03-20 17:19:36.000000000 +0100 +++ new/mksusecd-1.49/VERSION 2017-04-05 16:57:14.000000000 +0200 @@ -1 +1 @@ -1.45 +1.49 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mksusecd-1.45/changelog new/mksusecd-1.49/changelog --- old/mksusecd-1.45/changelog 2017-03-20 17:19:36.000000000 +0100 +++ new/mksusecd-1.49/changelog 2017-04-05 16:57:14.000000000 +0200 @@ -1,3 +1,16 @@ +2017-04-05: 1.49 + - add support for disk images with FAT file system + +2017-04-03: 1.48 + - undo accidental mksusecd patch + +2017-04-03: 1.47 + - some small doc fixes + - add dvd/disk image layout description + +2017-03-31: 1.46 + - isohybrid: add --size option to specify image size + 2017-03-17: 1.45 - fix typo - add --rebuild-initrd option for smaller initrds diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mksusecd-1.45/isohybrid.c new/mksusecd-1.49/isohybrid.c --- old/mksusecd-1.45/isohybrid.c 2017-03-20 17:19:36.000000000 +0100 +++ new/mksusecd-1.49/isohybrid.c 2017-04-05 16:57:14.000000000 +0200 @@ -76,6 +76,7 @@ unsigned no_mbr:1; /* gpt: don't write protective mbr */ unsigned no_code:1; /* no mbr boot code */ unsigned no_chs:1; /* fill in 0xffffff instead of real chs values */ + off_t size; /* total size MBR partition table should cover */ } opt; @@ -252,6 +253,7 @@ printf(FMT, " --no-mbr", "Don't write protective MBR for GPT"); printf(FMT, " --no-code", "Don't include MBR boot code"); printf(FMT, " --no-chs", "Don't fill in CHS values, use 0xffffff instead"); + printf(FMT, " --size", "Specify disk size to assume when writing MBR (in 512 byte units)"); printf("\n"); printf(FMT, " --forcehd0", "Assume we are loaded as disk ID 0"); @@ -279,6 +281,7 @@ { { "entry", required_argument, NULL, 'e' }, { "offset", required_argument, NULL, 'o' }, + { "size", required_argument, NULL, 1006 }, { "type", required_argument, NULL, 't' }, { "id", required_argument, NULL, 'i' }, { "gpt", no_argument, NULL, 1001 }, @@ -385,6 +388,12 @@ opt.no_chs = 1; break; + case 1006: + opt.size = strtoul(optarg, &err, 0); + if (*err) + errx(1, "invalid size: `%s'", optarg); + break; + case 'V': printf("%s version %s\n", prog, VERSION); exit(0); @@ -615,7 +624,11 @@ s = (ofs % sector) + 1; h = (ofs / sector) % head; c = ofs / (sector * head); - if(c > 1023) c = 1023; + if(c > 1023) { + c = 1023; + s = sector; + h = head - 1; + } return ((c & 0xff) << 24) + ((s + ((c >> 8) << 6)) << 16) + (h << 8); } @@ -689,7 +702,7 @@ mbr[1] = chs >> 8; mbr[2] = chs >> 16; mbr[3] = chs >> 24; - chs = ofs2chs(c * head * sector - 1); + chs = ofs2chs((opt.size ?: c * head * sector) - 1); mbr[4] = type; mbr[5] = chs >> 8; mbr[6] = chs >> 16; @@ -698,7 +711,7 @@ tmp = lendian_int(offset); memcpy(&mbr[8], &tmp, sizeof(tmp)); - tmp = lendian_int(c * head * sector - offset); + tmp = lendian_int((opt.size ?: c * head * sector) - offset); memcpy(&mbr[12], &tmp, sizeof(tmp)); } @@ -1219,7 +1232,7 @@ fwrite(buf, sizeof(char), apm_size, fp); } - if (padding) + if (padding && !opt.size) { if (fsync(fileno(fp))) err(1, "%s: could not synchronise", argv[0]); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mksusecd-1.45/layout.md new/mksusecd-1.49/layout.md --- old/mksusecd-1.45/layout.md 1970-01-01 01:00:00.000000000 +0100 +++ new/mksusecd-1.49/layout.md 2017-04-05 16:57:14.000000000 +0200 @@ -0,0 +1,183 @@ +## isohybrid images done right + +'[isohybrid](http://www.syslinux.org/wiki/index.php?title=Isohybrid)' +describes an image that can be both used as dvd (it has a valid +[iso9660](https://en.wikipedia.org/wiki/ISO_9660) file system +at offset 0) and as disk image (it also has a valid partition table). + +The partition table type +([gpt](https://en.wikipedia.org/wiki/GUID_Partition_Table), +[mbr](https://en.wikipedia.org/wiki/Master_boot_record), +or even [apple](https://en.wikipedia.org/wiki/Apple_Partition_Map)) +doesn't matter - the +iso fs leaves enough unassigned space at its start (32 kB) to accomodate any of those types. + +The catch is: Where should the data partition itself start? Obviously, at block 0 +would be a choice. But such a partition would again enclose the partition +table itself and partitioning tools really don't like such a layout. + +Also, if the image should be +[EFI bootable](https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface#Booting), +the EFI boot image needs its own +partition. You can of course create a partition pointing to the EFI image +included in the iso fs but then you get overlapping partitions +and partitioning tools will eat you for lunch - this time for sure. + +So, we do it differently. For isohybrid images we aim to create an image that + +1. looks like an iso fs **and** +2. has a valid (sane) partition table with + - one partition containing the same fs as 1. and + - (optionally) another partition containing an EFI boot image + +### Using an iso9660 file system for the partition + +To achieve this, two [mkisofs](https://software.opensuse.org/package/mkisofs) runs are needed. +To understand why the following works it's important to know that the iso fs layout starts with +fs meta data, followed by directory data, followed by file data. + +Now imagine you manage to put valid iso meta/directory data into the first +data file: this basically means you have an iso fs (excluding this file) that doesn't start at offset 0 +but at the offset of the first data file. + +Let's see how this works in detail. + +There are two special files in our iso fs we need below: + +- `efi`: (optional) EFI (fat-) boot image file (full path on x86_64 is `boot/x86_64/efi`) +- `glump`: hidden(!) 2k-block containing a magic blob (as the file doesn't have a +directory entry, we need the magic to find it in the image) + +`efi` must be the 1st file, `glump` the 2nd (mkisofs lets you force the file order +easily). + +The fs layout looks like this after a 1st mkisofs run: + +``` +== 1st run == +iso meta/dir 1 +data 1 + efi 1 + glump 1 + magic 1 + other files 1 +``` + +(Indentation is used to indicate 'contains'.) + +So, `glump` contains the magic blob, and `data` consists of `efi`, `glump`, +and `other files`. + +The numbers are a reminder of the run the data was generated. + +Now we copy `iso meta/dir` ... `glump` (inclusive) into a new `glump` and run +mkisofs on the same tree again. We get this layout: + +``` +== 2nd run == +ofs 0-> iso meta/dir 2 + data 2 +part1-> efi 2 +part2-> glump 2 + iso meta/dir 1 + data 1 + efi 1 + glump 1 + magic 1 + other files 2 +``` + +Note that `other files 1` and `other files 2` are identical (we didn't change +any data there). + +So, the result is: + +- a valid iso fs at offset 0 +- a valid iso fs at `glump 2` == `iso meta/dir 1` + +This means we can add a partition table where: + +- part1 points to the EFI boot partition +- part2 points to a valid iso fs referencing the same files as via offset 0 +- part1 and part2 don't overlap + +Note that the EFI boot image exists twice - but `efi 1` is unused +([El Torito](https://en.wikipedia.org/wiki/El_Torito_%28CD-ROM_standard%29) +references `efi 2` for booting). It would technically be possible to exclude +it in the 1st run (`efi 1` would then be gone) without loss of +functionality. But this would mean the users see different things depending on +whether they mount at offset 0 compared to partition 2. So, let's keep it +and waste the few bytes. + + +### Using a fat file system for the partition + +Why not have an iso fs at offset 0 but a differnt fs type in partition 2? + +The [fat](https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system) file system +has a similar structure than iso fs: first fs meta data, then (mixed) +directory and file data. But it's easy to disentangle directory and file data +and ensure directories are first. So we can achieve the same basic fs layout and +use the same trick as above again. + +Let's start by running mkisofs: + +``` +== 1st run == +iso meta/dir 1 +data 1 + efi 1 + glump 1 + magic 1 + other files 1 +``` + +Now we need to prepare the content of `glump`. This is a bit more tricky +than with the iso fs above - but possible. + +Here are the details: + +1. create a new fat fs, with desired size (enough for all files, at least) +2. choose cluster size 2k, so files are aligned as in the iso fs (which also uses 2k blocks) +3. but: fat meta data can still be non-2k aligned - for this we will later move the +start of the whole file system so the start of the file data is 2k-aligned +4. create all files in the order they are in the iso fs, but with size 0 - +this will take care of creating all needed directory entries +5. then truncate all files to the correct size +6. while we do this, check if there are hidden files in the iso fs that would destroy +the relative file alignment; if such a gap is detected, insert padding files into the fat fs +7. delete any inserted padding files +8. verify that the (relative) file offsets match the offsets in the iso fs +9. determine the alignment blocks needed (as explained in step 3.) +10. copy alignment blocks + fat fs up to the start of the file data into `glump` +11. add `efi` (full 2k-blocks) to `glump`, if it exists + +Then, after a 2nd mkisofs run, the layout looks like this: + +``` +== 2nd run == +ofs 0-> iso meta/dir 2 + data 2 +part1-> efi 2 + glump 2 + alignment +part2-> fat meta/dir + efi + other files 2 +``` + +So, the result is: + +- a valid iso fs at offset 0 +- a valid fat fs at `fat meta/dir` + +This means we can add a partition table where: + +- part1 points to the EFI boot partition +- part2 points to a valid fat fs referencing the same files as via offset 0 +- part1 and part2 don't overlap + +Note that the fat fs is in fact **writable** but modifying any files will disrupt the +iso fs side. This shouldn't cause any problems in real life as users +probably don't copy the image onto a usb stick, use it for a while, and +then later burn a dvd with it. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mksusecd-1.45/mksusecd new/mksusecd-1.49/mksusecd --- old/mksusecd-1.45/mksusecd 2017-03-20 17:19:36.000000000 +0100 +++ new/mksusecd-1.49/mksusecd 2017-04-05 16:57:14.000000000 +0200 @@ -157,11 +157,13 @@ sub rerun_mkisofs; sub run_isohybrid; sub run_isozipl; +sub run_syslinux; sub run_createrepo; sub isols; sub find_magic; sub meta_iso; sub meta_fat; +sub fat_data_start; sub create_initrd; sub get_kernel_initrd; sub update_kernel_initrd; @@ -196,6 +198,7 @@ sub new_products_xml; sub prepare_addon; sub check_mksquashfs_comp; +sub eval_size; my %config; my $sudo; @@ -236,6 +239,7 @@ my $opt_addon_alias; my $opt_addon_prio = 60; my $opt_rebuild_initrd; +my $opt_size; GetOptions( @@ -258,6 +262,8 @@ 'hybrid' => \$opt_hybrid, 'no-hybrid' => sub { $opt_hybrid = 0 }, 'hybrid-fs=s' => sub { $opt_hybrid = 1; $opt_hybrid_fs = $_[1] }, + 'fat' => sub { $opt_hybrid = 1; $opt_hybrid_fs = 'fat' }, + 'size=s' => \$opt_size, 'protective-mbr' => sub { $opt_no_prot_mbr = 0 }, 'no-protective-mbr' => \$opt_no_prot_mbr, 'mbr-code' => sub { $opt_no_mbr_code = 0 }, @@ -298,6 +304,8 @@ usage 1 if $opt_hybrid_fs !~ '^(|iso|fat)$'; usage 1 if defined($opt_digest) && $opt_digest !~ '^(md5|sha1|sha224|sha256|sha384|sha512)$'; +$ENV{PATH} = "$LIBEXECDIR/mksusecd:/usr/bin:/bin:/usr/sbin:/sbin"; + if($opt_rebuild_initrd && $>) { die "mksusecd must be run with root permissions when --rebuild-initrd is used\n" } @@ -355,17 +363,23 @@ my $warned; my $read_write; my $mksquashfs_has_comp; +my $image_size; +my $syslinux_config; my $progress_start = 0; my $progress_end = 100; my $progress_txt = 'building:'; $mkisofs->{command} = "/usr/bin/genisoimage" if ! -x $mkisofs->{command}; - die "mkisofs: command not found\n" if ! -x $mkisofs->{command}; $mksquashfs_has_comp = check_mksquashfs_comp; +if(defined $opt_size) { + $image_size = eval_size $opt_size; + die "$opt_size: invalid size\n" unless $image_size; +} + if($opt_create) { # if(@opt_kernel_rpms) { # die "Sorry, you must run mksusecd as root to replace kernel modules." if $>; @@ -376,6 +390,8 @@ $iso_file = $opt_dst; + die "$iso_file: block device not allowed\n" if -b $iso_file; + for (@ARGV) { s#/*$##; next if $_ eq ""; @@ -467,7 +483,10 @@ fix_catalog; relocate_catalog; - run_isohybrid if $opt_hybrid; + if($opt_hybrid) { + run_isohybrid; + run_syslinux if $opt_hybrid_fs eq 'fat'; + } run_isozipl if $opt_zipl; if(defined $opt_digest) { @@ -541,6 +560,13 @@ image (partitioning tools don't really like this) or 'iso' or 'fat' in which case you get a regular partition with an ISO960 or FAT file system (default: 'iso'). + --fat An alias for '--hybrid-fs fat'. + --size SIZE_SPEC When using a FAT file system, you can set the intended size of + the disk image. + SIZE_SPEC can be a number, optionally followed by a unit ('b', + 'k', 'm', 'g', 't') indicating blocks, kiB, MiB, GiB, or TiB. + But SIZE_SPEC can also be a device name like '/dev/sda', in + which casee the size of the device is used. --zipl Make zIPL bootable (default on s390x). --no-zipl Don't make zIPL bootable (default except on s390x). --initrd DIR|RPM|DUD Add directory DIR or package RPM or driver update DUD @@ -1298,6 +1324,10 @@ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# rerun_mkisofs() +# +# Prepare hybrid image and run mkisofs again. +# sub rerun_mkisofs { my $iso_file_list = isols; @@ -1323,10 +1353,20 @@ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# run_isohybrid() +# +# Add a partition table to the iso image and, on x86, add boot code to the +# partition table. +# sub run_isohybrid { my $opt; my $ok; + my $part_type = $hybrid_part_type; + + if($opt_hybrid_fs eq 'fat') { + $part_type = 0x0c if !$part_type; + } $opt .= " --uefi" if $has_efi; $opt .= " --gpt" if $opt_hybrid_gpt; @@ -1334,14 +1374,11 @@ $opt .= " --no-mbr" if $opt_no_prot_mbr; $opt .= " --no-code" if $opt_no_mbr_code; $opt .= " --no-chs" if $opt_no_mbr_chs; - $opt .= sprintf(" --type 0x%x", $hybrid_part_type) if $hybrid_part_type; + $opt .= sprintf(" --type 0x%x", $part_type) if $part_type; $opt .= " --offset $mkisofs->{partition_start}" if $mkisofs->{partition_start}; + $opt .= " --size $image_size" if $image_size; - # prefer our own isohybrid variant - my $cmd = "$LIBEXECDIR/mksusecd/isohybrid"; - $cmd = "isohybrid" unless -x $cmd; - - $cmd .= "$opt $iso_file"; + my $cmd = "isohybrid $opt '$iso_file'"; print "running:\n$cmd\n" if $opt_verbose >= 1; @@ -1360,16 +1397,45 @@ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# run_syslinux() +# +# Make fat partition bootable using syslinux. This requires the 'real' +# syslinux package and does not work on non-x86 achitectures. +# +sub run_syslinux +{ + return unless $syslinux_config && $mkisofs->{partition_start}; + + my $mbr; + if(open my $f, "/usr/share/syslinux/mbr.bin") { + local $/; + $mbr = <$f>; + close $f; + } + + if(!-x "/usr/bin/syslinux" || length($mbr) != 440) { + die "syslinux is needed to build a bootable FAT image, please install package 'syslinux'\n" + } + + system "syslinux -t " . ($mkisofs->{partition_start} << 9) . " -d '$syslinux_config' -i '$iso_file'"; + + die "$iso_file: $!\n" unless open $iso_fh, "+<", $iso_file; + syswrite $iso_fh, $mbr; + close $iso_fh; +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# run_isozipl() +# +# Make iso image zipl bootable. +# sub run_isozipl { my $opt; my $ok; - # prefer our own isozipl variant - my $cmd = "$LIBEXECDIR/mksusecd/isozipl"; - $cmd = "isozipl" unless -x $cmd; - - $cmd .= " $iso_file"; + my $cmd = "isozipl '$iso_file'"; print "running:\n$cmd\n" if $opt_verbose >= 1; @@ -1474,7 +1540,15 @@ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# find magic block +# magic = find_magic(file_list) +# +# Find magic block. +# - file_list: array ref with file names as produced by isols() +# - magic: hash ref with offset of magic block ('block') and +# offset of first (with lowest start offset) file ('extra') +# +# Offsets are in 2k units (due to iso fs heritage). +# sub find_magic { my $cnt; @@ -1513,6 +1587,11 @@ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# metca_iso(magic) +# +# Prepare hybrid image using iso fs for partition. +# - magic: hash ref as returned by find_magic() +# sub meta_iso { my $magic = shift; @@ -1538,6 +1617,33 @@ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# fat_mkfs(name, size, hidden) +# +# Create a fat file system image. +# - name: image name +# - size: size in blocks +# - hidden: hidden blocks (aka planned partition offset) +# +sub fat_mkfs +{ + my ($name, $size, $hidden) = @_; + + open my $fh, ">", $name; + close $fh; + truncate $name, $size << 9; + # try fat32 first + system "mformat -i '$name' -T $size -H $hidden -s 32 -h 64 -c 4 -F -d 1 -v 'SUSEDISK' :: 2>/dev/null" and + system "mformat -i '$name' -T $size -H $hidden -s 32 -h 64 -c 4 -d 1 -v 'SUSEDISK' ::"; +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# meta_fat(magic, file_list) +# +# Prepare hybrid image using fat fs for partition. +# - magic: hash ref as returned by find_magic() +# - file_list: array ref with file names as produced by isols() +# sub meta_fat { my $magic = shift; @@ -1549,7 +1655,7 @@ for (reverse @$iso_files) { next unless $_->{type} eq ' '; - $fat_size = $_->{start} + (($_->{size} + 0x7ff) >> 11); + $fat_size = $_->{start} + (($_->{size} + 0x7ff) >> 11); last; } @@ -1560,22 +1666,38 @@ $fat_size += ($fat_size >> 8) + 4; - # add a bit free space (4MB) - $fat_size += 4 << 9; + # we want $fat_size to count 512 byte blocks, not 2k blocks as in iso fs + $fat_size *= 4; + + # add a bit free space (4 MB) + $fat_size += 4 << 11; # and round up to full MB - my $fat_mb = ($fat_size + 511) >> 9; + my $fat_size = (($fat_size + 2047) >> 11) << 11; - $fat_size = $fat_mb << 9; + printf "fat_size (auto) = $fat_size\n" if $opt_verbose >= 2; - printf "fat_size = $fat_size\n" if $opt_verbose >= 2; + # disk size - partition offset - max alignment + my $user_fat_size = $image_size - ($magic->{block} << 2) - 3; - open my $fh, ">", $tmp_fat; - close $fh; - truncate $tmp_fat, $fat_mb << 20; - # try fat32 first - system "mformat -i '$tmp_fat|cylinders=" . $fat_mb * 4 . " heads=16 sectors=32' -c 4 -F -v 'SUSEDVD' :: 2>/dev/null" and - system "mformat -i '$tmp_fat|cylinders=" . $fat_mb * 4 . " heads=16 sectors=32' -c 4 -v 'SUSEDVD' ::"; + # use user-specified value, if possible + $fat_size = $user_fat_size if $user_fat_size > $fat_size; + + printf "fat_size (final) = $fat_size\n" if $opt_verbose >= 2; + + fat_mkfs $tmp_fat, $fat_size, 0; + + my $fat_data_start = fat_data_start $tmp_fat; + + my $align = ($fat_data_start & 0x7ff) >> 9; + $align = (4 - $align) & 3; + + print "fat fs alignment: $align blocks\n" if $opt_verbose >= 2; + + $mkisofs->{partition_start} = ($magic->{block} << 2) + $align; + + # remake, but with correct start offset stored in bpb + fat_mkfs $tmp_fat, $fat_size, $mkisofs->{partition_start}; # 1.: directories for (@$iso_files) { @@ -1651,18 +1773,23 @@ print "last block: $last_block\n" if $opt_verbose >= 2; - - my $data_start; - for (`dosfsck -v '$tmp_fat'`) { - if(/Data area starts at byte (\d+)/) { - $data_start = $1 + (($first - 2) << 11); - $last_block = ($1 >> 9) + (($last_block - 2) << 2); + # we're going to use syslinux instead of isolinux, so rename the config file + if($opt_hybrid_fs eq 'fat') { + for (@$iso_files) { + if($_->{name} =~ m#/isolinux.cfg$#) { + system "mren -i '$tmp_fat' '::$_->{name}' syslinux.cfg"; + $syslinux_config = $_->{name}; + $syslinux_config =~ s#^/##; + $syslinux_config =~ s#/[^/]+$##; + last; + } } } - printf "last_block = $last_block\n" if $opt_verbose >= 2; + my $data_start = $fat_data_start + (($first - 2) << 11); + $last_block = ($fat_data_start >> 9) + (($last_block - 2) << 2); - my $iso_pad = (($fat_size << 2) - $last_block) >> 2; + printf "last_block = $last_block\n" if $opt_verbose >= 2; die "$tmp_fat: oops, data start not found\n" unless $data_start; @@ -1670,18 +1797,6 @@ truncate $tmp_fat, $data_start; - my $align = ($data_start & 0x7ff) >> 9; - $align = (4 - $align) & 3; - - if($align) { - print "alignment needed: $align\n" if $opt_verbose >= 2; - $iso_pad++; - } - - printf "iso_pad = $iso_pad\n" if $opt_verbose >= 2; - - $mkisofs->{partition_start} = ($magic->{block} << 2) + $align; - # now copy the fat open my $fh, ">", "$tmp_new/glump"; @@ -1720,6 +1835,29 @@ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# fat_data_start(fs_image_file) +# +# Returns the offset (in bytes) of the data area of the fat fs in +# fs_image_file or not at all if there are problems detecting it. +# +sub fat_data_start +{ + my $data_start; + + for (`dosfsck -v '$_[0]' 2>/dev/null`) { + if(/Data area starts at byte (\d+)/) { + $data_start = $1; + last; + } + } + + die "error: dosfsck failed\n" unless $data_start; + + return $data_start; +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sub create_initrd { return undef if !@opt_initrds; @@ -3385,3 +3523,49 @@ return $comp_ok; } + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# eval_size(size_string) +# +# Interpret size_string and return size in (512 byte)-blocks. +# +# size_string is either a numerical size like '64G' or a file or block +# device name. In this case the size of the file or block device is used. +# +sub eval_size +{ + my $size = $_[0]; + my $unit = { b => 9 - 9, k => 10 - 9, m => 20 - 9, g => 30 - 9, t => 40 - 9 }; + + return undef unless $size; + + if($size =~ /^(\d+)\s*([bkmgt]?)/i) { + $size <<= $unit->{"\L$2"} if $2; + } + elsif($size =~ m#/dev/#) { + my $s; + my $x = `readlink -f $size 2>/dev/null`; + if($x =~ m#/dev/([^/]+?)\s*$#) { + my $dev = $1; + for (</sys/block/$dev/size /sys/block/*/$dev/size>) { + if(open(my $f, $_)) { + $s = <$f> + 0; + close $f; + last; + } + } + } + $size = $s; + } + elsif(-s $size) { + $size = (-s _) >> 9; + } + else { + $size = undef; + } + + printf "target image size: %.2f GiB ($size blocks)\n", $size / (1 << 21); + + return $size; +} +