#! /usr/bin/perl

# Add/remove key=value pairs from iso application area (0x200 bytes at
# 0x8373). Entries are separated by semicolons ';'.
#
# md5sum is calculated assuming all spaces in that area.


use Getopt::Long;
use Digest::MD5;

sub help;

$opt_md5 = 0;
$opt_check = 0;
$opt_show = 1;
@opt_add_tag;
@opt_remove_tag;

GetOptions(
  'help'         => undef,
  'show'         => \$opt_show,
  'md5|md5sum'   => \$opt_md5,
  'check'        => \$opt_check,
  'add-tag=s'    => \@opt_add_tag,
  'remove-tag=s' => \@opt_remove_tag,
);

$write_iso = $opt_md5 || $opt_check || @opt_add_tag || @opt_remove_tag;

$iso = shift;

help if $iso eq '';

die "$iso: $!\n" unless open F, $iso;
die "$iso: $!\n" unless sysread F, $buf0, 0x8373;
die "$iso: $!\n" unless sysread F, $tag, 0x200;
die "$iso: file too short\n" unless length($buf0) == 0x8373 && length($tag) == 0x200;

if($opt_check) {
  unshift @opt_add_tag, "check=1";
}

# calculate md5sum
if($opt_md5) {
  $md5 = Digest::MD5->new;

  $md5->add($buf0);
  $md5->add(' ' x 0x200);
  $md5->addfile(*F);
  $md5 = $md5->hexdigest;

  unshift @opt_add_tag, "md5sum=$md5";
}

close F;

# replace existing tags
for (@opt_add_tag) {
  $new_tag{$1} = 1 if /^(\S+?)\s*=/;
}
for (split /;/, $tag) {
  s/^\s*|\s*$//g;
  push @old_tags, "$_" unless $_ eq "" || (/^(\S+?)\s*=/ && $new_tag{$1});
}

# remove tags
$rtags{$_} = 1 for @opt_remove_tag;
for (@old_tags, @opt_add_tag) {
  push @tags, $_ unless $_ eq "" || (/^(\S+?)\s*=/ && $rtags{$1}) ;
}

# write new tags
$new_tag = join ';', @tags;
die "too many tags: \"$new_tag\"\n" if length($new_tag) > 0x200;
$new_tag .= " " x (200 - length($new_tag));

if($write_iso) {
  die "$iso: $!\n" unless open F, "+<$iso";
  die "$iso: $!\n" unless seek F, 0x8373, 0;
  die "$iso: $!\n" unless $l = syswrite F, $new_tag, 0x200;
  die "$iso: file too short\n" unless $l = 0x200;
  close F;
}

print "$_\n" for $write_iso ? @tags : @old_tags;

sub help
{
  die
    "usage: tagmedia [options] iso\n" .
    "Add/remove tags to SUSE installation media.\n" .
    "Options:\n" .
    "  --show\t\tlist tags\n" .
    "  --md5\t\t\tadd md5sum\n" .
    "  --check\t\tforce yast check\n" .
    "  --add-tag foo=bar\tadd foo with value bar\n" .
    "  --remove-tag foo\tremove foo\n";
}

