# 
# Copyright (C) 2000,2001,2002,2003,2004 Mandrakesoft
# 
# Author: Florent Villard <warly@mandraesoft.com>
#
# 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# to prepare, create and burn iso images
#

package Mkcd::Functions;

our $VERSION = '1.3.0';

use strict;
use File::Path;
use MDK::Common qw(substInFile);
use File::NCopy qw(copy);       
use Mkcd::Tools qw(cpal du checkDiscs imageSize printDiscsFile config readBatchFile log_ convert_size compute_files_md5 fix_dir);
use Mkcd::Package qw(mkcd_build_hdlist get_sorted_packages);

=head1 NAME

Functions - mkcd module

=head1 SYNOPSYS

    require Mkcd::Functions;

=head1 DESCRIPTION

<Mkcd::Functions> include the disc building standard functions.

=head1 SEE ALSO

mkcd

=head1 COPYRIGHT

Copyright (C) 2000,2001,2002,2003,2004 Mandrakesoft <warly@mandrakesoft.com>

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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

=cut
my (%functions, $config);

# need to do it to have its address
#my %functions = ();
# [ function name, matching regexp, [arguments list (same as above)]] 

$functions{disc} = [ 
    [ "", "disc", 5, "[options] <disc config number> <size> <serial> <longname> <label>", "disc configuration file parameters", 
    sub { my ($cd, $name, $size, $serial, $longname, $label) = @_;
	$size = convert_size($size);
	log_("disc: disc $cd size $size\n", $config->{verbose}, $config->{LOG},3);
	$config->{disc}[$cd]{size} = $size;
        $config->{disc}[$cd]{serial} = substr $serial, 0, 128;
        $config->{disc}[$cd]{longname} = $longname;
        $config->{disc}[$cd]{label} = substr $label, 0, 32;
        if (!$config->{disc}[$cd]{appname}) { $config->{disc}[$cd]{appname} = substr $longname, 0, 128 }
	1
    }, "Setting disc configuration" ],
    [ "d", "discnumber", 1 , "<disc real number>", "Set the real disc number", 
    sub { my ($cd, $discnb) = @_;
        log_("disc: disc $cd setting real disc number to $discnb\n", $config->{verbose}, $config->{LOG},3);
	$config->{disc}[$cd]{name} = $discnb;
    }, "Setting the real disc number" ],
    [ "p", "publisher", 1 , "<disc publisher id>", "Set the disc publisher", 
    sub { my ($cd, $publisher) = @_;
        log_("disc: disc $cd setting publisher as $publisher\n", $config->{verbose}, $config->{LOG},3);
	$config->{disc}[$cd]{Publisher} = substr $publisher, 0, 128;
    }, "Setting the publisher ID flag" ]
];

$functions{list} = [ 
    [ "", "list", -1, "[options] <list config number> <list config file 1> <list config file 2> ... <list config file n>", "list configuration file parameters", 
    sub { 
	my ($list, undef, @list_file) = @_;
	log_("list: list $list file list @list_file\n", $config->{verbose}, $config->{LOG},3);
	push @{$config->{list}[$list]{filelist}}, @list_file;
	1
    }, "Setting list configuration" ],
    [ "k", "key", 1 , "<pubkey file>", "Select public key file associated with this list", 
    sub { my ($list, $keyfile) = @_;
        log_("list: list $list setting pubkey file $keyfile\n", $config->{verbose}, $config->{LOG},3);
	push @{$config->{list}[$list]{keyfiles}}, $keyfile;
	1
    }, "Setting pubkey file" ],
];

$functions{rpmlist} = [ 
   [ "", "rpmlist", 0, "[options]", "rpm list associated with a list", 
   sub { 
       my ($list) = @_;
       push @{$config->{list}[$list]{packages}}, { };
       log_("rpmlist: main\n", $config->{verbose}, $config->{LOG}, 1);
       $config->{list}[$list]{arg}{update} = 0;
       1 
   }, "Setting rpm list" ],
   [ "b", "binaries", -1, "<rpm path 1> <rpm path 2> ... <rpm path n>", "rpm list associated with a list", 
   sub { 
       my ($list, undef, @rpms) = @_;
       my $idx = $#{$config->{list}[$list]{packages}};
       push @{$config->{list}[$list]{packages}[$idx]{rpm}}, @rpms;
       log_("rpmlist: main (update $config->{list}[$list]{update})\n", $config->{verbose}, $config->{LOG}, 1);
       if ($config->{list}[$list]{arg}{update}) {
	   foreach my $dir (@rpms) {
	       log_("rpmlist: adding for list $list update rep $dir\n", $config->{verbose}, $config->{LOG}, 1);
	       push @{$config->{list}[$list]{prelist}},  map { s/\.rpm//; [ $_, { regexp => 1 } ] } all $dir
	   }
	   push @{$config->{list}[$list]{prelist}},  [ "basesystem", { regexp => 1 } ]
       }

       1 
   }, "Setting rpm list" ],
   [ "d", "dynamic", -1, "<disc1/dir1> <disc2/dir2> ... <discn/dirn>", "dynamic rpm list based on disc generated by this config file", 
   sub { 
       my ($list, undef, @rpms) = @_;
       foreach my $l (@rpms) {
	   my ($cd, $rep) = $l =~ m,(\d+)/(\S+), or do { log_("ERROR rpmlist: $l is not a valid <disc>/<rep> dynamic list definition\n", $config->{verbose}, $config->{LOG}, 1); next };
	   #$config->{list}[$list]{prelist} = [ [ ".*", { regexp => 1 } ] ];
	   push @{$config->{list}[$list]{virtual}}, { disc => $cd, repname => $rep };
       }
       1 
   }, "Setting dynamic rpm list" ],
   [ "s", "sources", -1, "<source path 1> <source path 2> ... <source path n>", "rpm list associated with a list", 
   sub { 
       my ($list, undef, @srpms) = @_;
       my $idx = $#{$config->{list}[$list]{packages}};
       push @{$config->{list}[$list]{packages}[$idx]{srpm}}, @srpms;
       1 
   }, "Setting source rpm list" ],
   [ "u", "update", 0, "", "select all the rpm in these directories to be in the filelist", 
   sub { 
       my ($list, undef) = @_;
       log_("rpmlist: update\n", $config->{verbose}, $config->{LOG}, 1);
       $config->{list}[$list]{arg}{update} = 1;
       1 
   }, "Setting update mode" ],

];

$functions{dir} =
	[
	    #0
	    [ "", "dir",2, "<directory name> <directory location>", "Set directory name",
	    sub { 	my ($cd, $fn, $repname, $reploc) = @_;
		my @a = ("dir", { repname => $repname, reploc => $reploc });
		$config->{disc}[$cd]{function}{data}{dir}{$repname} and log_("WARNING: disc $cd: duplicate directory $repname ($reploc)\n", $config->{verbose}, $config->{LOG}, 3);
		$config->{disc}[$cd]{function}{list}[$fn] = \@a;
		$config->{disc}[$cd]{function}{data}{dir}{$repname} = \@a;
		log_("dir: disc $cd rep $repname ($reploc)\n", $config->{verbose}, $config->{LOG}, 3);
		push @{$config->{disc}[$cd]{steps}}, \@a;
		1
	    }, "Setting directory" ],
	    # 1
     	    [ "", "sep_arch", 0, "", "Create separate subdirs for each architecture", sub { my ($cd, $fn) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{sep_arch} = 1 }, "Setting separate architecture flag for this dir" ]
];
#
# generic options
#
# source => source dir
#
# done  => done
#

$functions{generic} =
	[ 
	    # 0
	    ["", "generic", -2, "<directory name> <list1 name> <list2 name> ... <listn name>", "Copy rpms from one list or several lists to a directory. List is either a predefined list number of the configuration file or an other disc directory (e.g. 13/rpms2)", 
		sub {	
		    my ($cd, $fn, $repname, @lists) = @_; 
		    $config->{disc}[$cd]{function}{data}{dir}{$repname} or log_("ERROR: disc $cd: $repname not defined\n", $config->{verbose}, $config->{LOG}, 0);
		    my @a = ("generic", { repname => $repname });
		    foreach my $list (@lists) {
			if ($list =~ /^\d+$/) { 
			    if (!$config->{list}[$list]) { log_("ERROR: lists $list does not exist, ignoring\n", $config->{verbose}, $config->{LOG}, 0); next }
			    push @{$a[1]{lists}}, $list;
			} else {
			    log_("ERROR generic: $list is not a valid list name for rep $cd/$repname\n", $config->{verbose}, $config->{LOG}, 0);
			    next
			}
		    }
		    log_("generic: disc $cd repname $repname lists @lists\n", $config->{verbose}, $config->{LOG}, 3);
		    if (!ref $a[1]{lists}) { log_("ERROR generic: $cd/$repname has no valid list, ignoring\n", $config->{verbose}, $config->{LOG}, 0); return }
		    $config->{disc}[$cd]{function}{list}[$fn] = \@a;
		    push @{$config->{disc}[$cd]{function}{data}{generic}{$repname}}, \@a;
		    push @{$config->{disc}[$cd]{fastgeneric}}, \@a;
		    push @{$config->{disc}[$cd]{steps}}, \@a;
		    1
		}, "Copying rpms to directory"],
	    # 1
	    ["s", "source", [
	    [ "", "source", 0, "", "Source mode configuration", 
		sub { 	my ($tmp) = @_;
		    $tmp->[0]{source} = 1;
		}, "Source mode" ],
# 2002 03 14 deprecated
#	    [ "p", "priority", 1, "<priority>", "Set the repository priority", sub { my ($tmp, $prio) = @_; $tmp->[0]{priority} = $prio}, "Setting source repository priority"]
	    ], "[options]", "Source mode setting", 
		sub { my ($cd, $fn, $options) = @_; 
		    foreach (keys %$options) { $config->{disc}[$cd]{function}{list}[$fn][1]{$_} = $options->{$_} }
	    	    1
		}, "Source mode option configuration"],
	    # 2
	    [ "", "synthesis", 0, "", "Add synthesis file in the repository", sub { my ($cd, $fn) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{synthesis} = 1 }, "Setting synthesis tag" ],
	    # 3
	    [ "", "hdlist", 0, "", "Add hdlist file in the repository", sub { my ($cd, $fn) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{hdlist} = 1 }, "Setting hdlist tag" ],
	    # 4
	    [ "l", "limit", [
	        [ "", "limit", 1, "<limit>", "Limit repository size", 
	    	    sub { 	my ($tmp, $limit) = @_;
		        $tmp->[0]{limit} = 1;
		        $tmp->[0]{value} = $limit;
			1
		    }, "Limit mode" ],
		[ "s", "soft",0, "", "Soft mode, do not limit size if disc is not full", sub { my ($tmp) = @_; $tmp->[0]{soft} = 1 } , "Setting soft limit flag" ]
	    
	    ], "[options] <limit>", "Limit the space of this directory on the disc", 
	        sub { my ($cd, $fn, $options) = @_; 
		    $config->{disc}[$cd]{function}{list}[$fn][1]{limit} = $options
		}, "Setting limit option" ],
	    # 5
    	    [ "", "nodeps", 0, "", "Do not include deps", sub { my ($cd, $fn) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{nodeps} = 1 }, "Setting nodeps flag for this generic rep" ],
	    # 6
    	    [ "g", "group", 1, "<group name>", "Add this generic repository in an alone group", 
	    sub { my ($cd, $fn, $group) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{group} = $group }, 
	    "Setting an alone group name for this generic rep" ],
	];
	    
	    
#
# installation data
#
$functions{installation} = 
	[ 
	# 0
	    [ "", "installation", 0, "", "Preparing the installation directory and dependencies files", 
		sub {	my ($cd, $fn) = @_; 
		    my @a = ('installation', { });
		    if (ref $config->{disc}[$cd]{function}{data}{installation}) { log_("ERROR: disc $cd: duplicate installation procedure, ignored\n", $config->{verbose}, $config->{LOG}); return 0 };
		    $config->{disc}[$cd]{function}{list}[$fn] = \@a;
		    $config->{disc}[$cd]{function}{data}{installation} = \@a;
		    push @{$config->{disc}[$cd]{steps}}, \@a;
		    1
		}, "Setting up installation files" ],
    # 1
	    [ "b", "bootimg", 1, "<boot image>", "boot image for the cd", sub { my ($cd, $fn, $img) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{bootimg} = $img; 1 }, "Setting boot image" ],
    # 2
	    [ "c", "compss", 1, "<compsUser file>", "Choose alternative compssUser file", sub { my ($cd, $fn, $compss) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{compssUsers} = $compss; 1 }, "Setting alternative compssUser file" ],
    # 3
	    [ "f", "fixed", [
		["", "fixed", -1, "<repository> <extra RPMS directory 1> <extra RPMS directory 2> ... <extra RPMS directory n>", "Fixed repository option configuration", 
		    sub { 	my ($tmp, @arg) = @_;
		       	$tmp->[0]{fixed} = 1;
	    		push @$tmp, @arg;
    			1
    		    }, "Setting fixed option arguments"],
    		["d", "dup", 0, "", "Duplicate mode, accept to put package present in already done discs", 
			sub { 
			    my ($tmp) = @_; 
			    $tmp->[0]{dup} = 1; 1 
			}, "Setting duplicate mode"],
    		["", "noprovide", 0, "", "Do not handle other discs dependencies", 
			sub { 
			    my ($tmp) = @_; 
			    $tmp->[0]{noprovide} = 1; 1 
			}, "Setting noprovide mode"],
    		["", "relocatable", 0, "", "Create virtual rep to save as much space as possible on updates discs", 
			sub { 
			    my ($tmp) = @_; 
			    $tmp->[0]{relocatable} = 1; 1 
			}, "Setting relocatable mode"],
    		["", "update", 0, "", "Update mode, update already done packages", 
			sub { 
			    my ($tmp) = @_; 
			    $tmp->[0]{update} = 1; 1 }, "Setting update mode"],
    		["", "nodupkernel", 0, "", "Remove old kernel from hdlists", 
			sub { 
			    my ($tmp) = @_; 
			    $tmp->[0]{nodupkernel} = 1; 1 }, "Setting nodupkernel mode"],
    		], "[options] <fixed dir 1> <fixed dir 2> ... <fixed dir n>", "repositories that must not be computed but integrated in the installation group", 
		    sub { my ($cd, $fn, $options, @fixed) = @_; 
			get_rpmsdir('rpmsdir', $cd, $fn, \@fixed, $options);
			$config->{disc}[$cd]{function}{list}[$fn][1]{fixed} = 1;
		    1 }, "Setting fixed option" ],
	    # 4  
	    [ "l", "lang", 1, "<languages to include>", "languages that are conisdered by the install", sub { my ($cd, $fn, $lang) = @_; my @l = split ',', $lang; push @{$config->{disc}[$cd]{function}{list}[$fn][1]{lang}},  @l; 1 }, "Setting language supported" ],
	    # 5
	    [ "i", "installdir", 1, "<installation directory source>", "Installation directory source", sub { my ($cd, $fn, $dir) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{install} = $dir; 1 }, "Setting install source directory" ],
	    # 6 
	    [ "", "nosources", 0, "", "Do not add source rpm for this installation group", sub { my ($cd, $fn) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{nosources} = 1; 1 }, "Setting nosources tag for this installation group" ],
	    # 7
	    [ "", "nosrcfit", 0, "", "Do not stop if sources discs are full", sub { my ($cd, $fn) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{nosrcfit} = 1; 1 }, "Setting nosourcefit tag for this installation group" ],
	    # 8
	    [ "o", "sortweight", 1, "<list of respective ordering weight (size,dependencies,rpmsrate)>", "Set the weight for automatic sorting rules", sub { my ($cd, $fn, $weight) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{score} = [split ',', $weight]; 1 }, "Setting sorting weights" ],
	    # 9
	    [ "r", "rpmsrate", 1, "<rpmsrate file>", "Choose alternative rpmsrate", sub { my ($cd, $fn, $rpmsrate) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{rpmsrate} = $rpmsrate }, "Setting alternative rpmsrate file" ],
	    # 10
	    [ "t", "tag name", 1, "<tag name>", "Tag added to the VERSION file", sub { my ($cd, $fn, $tag) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{tag} = $tag }, "Setting the tag name" ],
	    # 11
	    [ "", "dup", 0, "", "Authorize duplicate version for this install", sub { my ($cd, $fn) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{dup} = 1 }, "Setting the tag name" ],
	    # 12
	    [ "", "nodeps", 0, "", "Do not include deps", sub { my ($cd, $fn) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{nodeps} = 1 }, "Setting nodeps flag for this installation" ],
	    # 13
	    [ "", "isolinux", 0, "", "Isolinux mode", sub { my ($cd, $fn) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{isolinux} = 1 }, "Build an isolinux install" ],
	    # 14
	    [ "", "synthesis", 0, "", "Add synthesis file in the repository", sub { my ($cd, $fn) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{synthesis} = 1 }, "Setting synthesis tag" ],
	    # 15
	    [ "", "sequential", 0, "", "Build disc in a sequential way", sub { my ($cd, $fn) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{sequential} = 1 }, "Setting sequential tag" ],
	    # 16
	    # FIXME oem mode never tested nor debugged
	    [ "", "oem", [
		["", "oem", 1, "[options] <rpms dir>", "OEM mode configuration", 
		    sub { 	my ($tmp, @arg) = @_;
		       	$tmp->[0]{oem} = 1;
	    		push @$tmp, @arg;
    			1
    		    }, "Setting oem option arguments"],
	        ["d", "dir", -1, "<installation dir> <root dir 1> ... <root dir n>", "Create OEM disc based on existing directories list", 
		    sub { 
		        my ($tmp, $instdir, @dir) = @_; 
			if ($tmp->[0]{file}) { 
			    log_("ERROR installation oem: could not use file and dir option in the same time, ignoring dir\n", $config->{verbose}, $config->{LOG});
			    return 0 }
			log_("dir $instdir @dir\n", $config->{verbose}, $config->{LOG}, 3);
			$tmp->[0]{instdir} = $instdir; 
			$tmp->[0]{dir} = \@dir; 
			1 }, "Selecting directories"],
	        ["h", "hdlists", 1, "<hdlists to include>", "Select hdlists to include (all if omitted)", sub { my ($tmp, $hdlists) = @_; $tmp->[0]{hdlists} = $hdlists; 1 }, "Selecting hdlists to include"],
    		["f", "file", 2, "<script file> <installation disc>", "Script file describing the discs (generated with printscript)", 
		    sub { 
			my ($tmp, $file, $instdisc) = @_; 
			if ($tmp->[0]{dir}) {
			    log_("ERROR installation oem: could not use file and dir option in the same time, ignoring file\n", $config->{verbose}, $config->{LOG}); 
			    return 0 }
			$tmp->[0]{file} = $file;
			$tmp->[0]{instdisc} = $instdisc; 1 
		    }, "Setting update mode"],
		["l", "listfile", 1, "<list of package to choose>", "Choose an alternative method to select package to select in OEM mode (default is to use packages with rate greater than 2 in rpmsrate ", sub { my ($tmp, $file) = @_; $tmp->[0]{file} = $file; 1 }, "Selecting list file"],
    		["n", "norebuild", 0, "", "Do not rebuild hdlists", sub { my ($tmp, $file) = @_; $tmp->[0]{norebuild} = 1; 1 }, "Setting no rebuilding flag"],
    		["r", "rpmsrate", 1, "<rpmsrate file>", "Rpmsrate file to use for OEM mode (use the installation one if omitted)", sub { my ($tmp, $rpmsrate) = @_; $tmp->[0]{rpmsrate} = $rpmsrate; 1 }, "Setting rpmsrate file OEM file"]
    		], "[options] <rpms dir>", "OEM mode", 
		    sub { my ($cd, $fn, $options, $rpmsdir) = @_; 
		    $config->{disc}[$cd]{function}{list}[$fn][1]{oem}{oem} = 1;
		    $config->{disc}[$cd]{function}{list}[$fn][1]{oem} = $options;
		    if ($options->{dir}) {
			my $list = @{$config->{list}};
			$config->{list}[$list]{prelist} = [
				[ "INSTALL", { section => 1, force => 1 } ],
				[ "SERVER", { section => 1, regexp => 1, exclude => 1 } ],
				[ ".*", { section => 4, regexp => 1 } ]
					];
			log_("installation oem: adding list $list for OEM mode\n", $config->{verbose}, $config->{LOG}, 3);
			my $struct_v = $config->{struct_version};
			my $install_dir = $config->{struct}{$struct_v}{media_info};
			my $hdlists = "$options->{instdir}/$install_dir/hdlists";
			local *A; open A, $hdlists or die "ERROR oem: could not open hdlists $hdlists file"; 
			my $i;
			while (<A>) {
			    my ($hdlist, $rep, $mname) = /(\S+)\s+(\S+)\s+(.*)/ or next;
			    log_("$i -- $hdlist -- $rep -- $options->{dir}[$i]\n", $config->{verbose}, $config->{LOG}, 4);
			    $options->{dir}[$i] or last;
			    push @{$options->{hdlist}}, [ "$options->{instdir}/$install_dir/", $hdlist, $rep, $mname ];
			    push @{$config->{list}[$list]{packages}}, [ { rpm => [ "$options->{dir}[$i]/$rep" ] } ];
			    $i++
			}
			for ($rpmsdir) {
			    my ($cdrep, $repname) = m,^(\d+)/([^/]+)$,;
			    my $gfn = @{$config->{disc}[$cdrep]{function}{list}};
			    log_("installation oem: adding function $gfn for generic oem packages on cd $cdrep\n", $config->{verbose}, $config->{LOG}, 4);
			    $functions{generic}[0][5]($cdrep, $gfn, $repname, $list);
			    if ($cd == $cdrep) {
				# FIXME trick to have this generic function done before the installation
				my $a = pop @{$config->{disc}[$cdrep]{steps}};
				unshift @{$config->{disc}[$cdrep]{steps}}, $a
			    }
			    push @{$config->{disc}[$cd]{function}{list}[$fn][1]{rpmsdir}}, [ $list, $cdrep, $repname, { oem => 1 } ];
			}
		    } elsif ($options->{file}) {
			my $oemconfig;
			config($options->{file}, $oemconfig, \%functions);
			my ($discsFiles) = readBatchFile($options->{file}) or do { log_("ERROR installation oem: cannot read script file $options->{file}\n", $config->{verbose}, $config->{LOG}); return 0 };
			my $list = @{$config->{list}};
			log_("installation oem: adding list $list for OEM mode\n", $config->{verbose}, $config->{LOG}, 3);
			foreach (@{$config->{list}}) {
			    $_ or next;
			    push @{$config->{list}[$list]{packages}}, @{$_->{packages}}
		        }
			my $gfn = @{$config->{disc}[$cd]{function}{list}};
			$config->{list}[$list]{prelist} = [[ ".*", { section => 3, regexp => 1 } ]];
			log_("installation oem: adding function $gfn for generic oem packages\n", $config->{verbose}, $config->{LOG}, 3);
			$functions{generic}[0][5]($cd, $gfn, "rpms", $list);
		    } else {
			log_("ERROR installation oem: no disc to build OEM on (either file or dir option are needed)\n", $config->{verbose}, $config->{LOG});
			$config->{disc}[$cd]{function}{list}[$fn][1]{oem} = 0;
			return 0
		    }
		    1 }, "Setting oem option" ],
            # 17
	    [ "s", "sources", -1, "<srpms directory name 1> <srpms directory name 2> ... <srpms directory name n>", "Select the sources list where to put packages", 
		sub { my ($cd, $fn, @sources) = @_; 
		    get_rpmsdir('srpmsdir', $cd, $fn, \@sources);
		    $config->{disc}[$cd]{function}{list}[$fn][1]{sources} = 1;
		    1 }, "Setting fixed option" ],
	    # 18
            [ "d", "rpmsdir", -1, "<rpms directory 1 cd/rpms directory 1 name/rpms directory 1 list> <rpms directory 2 cd/rpms directory 2 name/rpms directory 2 list> ... <rpms directory n cd/rpms directory n name/rpms directory n list>", "Select rpms dir to take into account", 
		sub {	my ($cd, $fn, @rpms) = @_; 
		    get_rpmsdir('rpmsdir', $cd, $fn, \@rpms);
		    1
		}, "Setting rpms dir" ],
	    # 19
            [ "", "boot_medium", 1, "<boot medium number>", "select alternatives boot medium",
		sub {	my ($cd, $fn, $nb) = @_; 
		    $config->{disc}[$cd]{function}{list}[$fn][1]{boot_medium} = $nb;
		    1
		}, "Setting rpms dir" ],
	    # 20
            [ "", "suppl", 0, "", "ask for new media during installation",
		sub {	my ($cd, $fn) = @_; 
		    $config->{disc}[$cd]{function}{list}[$fn][1]{suppl} = 1;
		    1
		}, "Setting the suppl switch in hdlists" ],
	    # 21
            [ "", "suppl_cd", 0, "", "to create a extra packages disc",
		sub {	my ($cd, $fn) = @_; 
		    $config->{disc}[$cd]{function}{list}[$fn][1]{suppl_cd} = 1;
		    1
		}, "Setting the suppl_cd for this disk" ],
	    # 22
            [ "", "askmedia", 0, "", "to ask which media are configured during installation",
		sub {	my ($cd, $fn) = @_; 
		    $config->{disc}[$cd]{function}{list}[$fn][1]{askmedia} = 1;
		    1
		}, "Setting the askmedia for this disk" ],
	];
#
#
# advertising option
#
#    img
#    lang (new advertising mode in 8.2 deprecates this option)
#    

$functions{advertising} =
	[
	    [ "", "advertising", -1, "<picture 1> <picture 2> ... <picture n>", "Setting the advertising pictures used by the installation", 
		sub { my ($cd, $fn, @img) = @_;
		    my @a = ('advertising', { img => \@img });	
		    $config->{disc}[$cd]{function}{list}[$fn] = \@a;
		    push @{$config->{disc}[$cd]{function}{data}{advertising}}, \@a;
		    push @{$config->{disc}[$cd]{steps}}, \@a
	 	}, "Setting the advertising pictures" ],
	 [ "l", "lang", 1, "<language>", "Set the advertising picture language", sub { my ($cd, $fn, $lang) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{lang} = $lang; 1 }, "Setting the picture language" ]
];

#
# cdcom data
#
#      dir
#
#      source
#
$functions{cdcom} =
	 [
	 #0
   	    [ "", "cdcom", 2, "<directory name> <disc directory location>", "Commercial disc",
       		sub { my ($cd, $fn, $dir, $source, @list_files) = @_;
	   	    my @a = ('cdcom', { dir => $dir, source => $source });
		    $config->{disc}[$cd]{function}{list}[$fn] = \@a;
		    push @{$config->{disc}[$cd]{function}{data}{cdcom}}, \@a;
		    my $list = @{$config->{list}};
		    $a[1]{list} = $list;
		    my $struct_v = $config->{struct_version};
		    my $media = $config->{struct}{$struct_v}{media};
		    log_("cdcom: disc $cd adding list $list for $source/$media\n", $config->{verbose}, $config->{LOG}, 3);
		    $config->{list}[$list]{packages} = [ { rpm => [ "$source/$media" ] } ];
		    # $config->{list}[$list]{prelist} = [[ ".*", { regexp => 1 }]];
		    $config->{list}[$list]{done} = 1;
		    $config->{list}[$list]{nosize} = 1;
		    push @{$config->{disc}[$cd]{fastgeneric}}, [ '', { repname => $dir , lists => [ $list ] } ];
		    push @{$config->{disc}[$cd]{steps}}, \@a;
		    1
		}, "Configuring a commercial disc" ],
	#1
	   [ "d", "dest", 1, "<destination on the disc>", "Select the destination directory on the disc", sub { my ($cd, $fn, $dest) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{dest} = $dest; 1 }, "Selecting destination directory" ],
	#2
	   [ "k", "key", 1 , "<pubkey file>", "Select public key file associated with this list", 
	   sub { 
	       my ($cd, $fn, $keyfile) = @_;
	       my $list = $config->{disc}[$cd]{function}{list}[$fn][1]{list};
	       log_("cdcom: list $list setting pubkey file $keyfile\n", $config->{verbose}, $config->{LOG},3);
	       push @{$config->{list}[$list]{keyfiles}}, $keyfile;
	       1
           }, "Setting pubkey file" ],
	 # 3
	    [ "", "synthesis", 0, "", "Add synthesis file in the repository", 
	    	sub { 
		    my ($cd, $fn) = @_; 
		    $config->{disc}[$cd]{function}{list}[$fn][1]{synthesis} = 1 
		}, "Setting synthesis tag" ],
	 # 4
	    [ "", "hdlist", 0, "", "Add hdlist file in the repository", 
	    	sub { 
		    my ($cd, $fn) = @_; 
		    $config->{disc}[$cd]{function}{list}[$fn][1]{hdlist} = 1 
		}, "Setting hdlist tag" ],
];
#
# fixed
#
$functions{fixed} =
	 [
	 #0
   	    [ "", "fixed", -2, "<directory name> <disc directory location> <filter list 1> <filter list 2> ... <filter list n>", "Commercial disc",
       		sub { my ($cd, $fn, $dir, $source, @list_files) = @_;
	   	    my @a = ('fixed', { dir => $dir, source => $source, repname => $dir });
		    $config->{disc}[$cd]{function}{list}[$fn] = \@a;
		    push @{$config->{disc}[$cd]{function}{data}{fixed}}, \@a;
		    my $list = @{$config->{list}};
		    # FIXME something must be duplicated here
		    $a[1]{list} = $list;
		    $a[1]{lists} = [ $list ];
		    log_("fixed: disc $cd adding list $list for $source\n", $config->{verbose}, $config->{LOG}, 3);
		    $config->{list}[$list]{packages} = [ { rpm => [ $source ] } ];
		    # $config->{list}[$list]{prelist} = [[ ".*", { regexp => 1 }]];
		    $config->{list}[$list]{pseudo_done} = 1;
		    $config->{list}[$list]{nosize} = 1;
		    push @{$config->{list}[$list]{filelist}}, @list_files;
		    push @{$config->{disc}[$cd]{fastgeneric}}, \@a;
		    push @{$config->{disc}[$cd]{steps}}, \@a;
		    1
		}, "Configuring a commercial disc" ],
	#1
	   [ "d", "dest", 1, "<destination on the disc>", "Select the destination directory on the disc", sub { my ($cd, $fn, $dest) = @_; $config->{disc}[$cd]{function}{list}[$fn][1]{dest} = $dest; 1 }, "Selecting destination directory" ],
	#2
	   [ "k", "key", 1 , "<pubkey file>", "Select public key file associated with this list", 
	   sub { 
	       my ($cd, $fn, $keyfile) = @_;
	       my $list = $config->{disc}[$cd]{function}{list}[$fn][1]{list};
	       log_("fixed: list $list setting pubkey file $keyfile\n", $config->{verbose}, $config->{LOG},3);
	       push @{$config->{list}[$list]{keyfiles}}, $keyfile;
	       1
           }, "Setting pubkey file" ],
	 # 3
	    [ "", "synthesis", 0, "", "Add synthesis file in the repository", 
	    	sub { 
		    my ($cd, $fn) = @_; 
		    $config->{disc}[$cd]{function}{list}[$fn][1]{synthesis} = 1 
		}, "Setting synthesis tag" ],
	 # 4
	    [ "", "hdlist", 0, "", "Add hdlist file in the repository", 
	    	sub { 
		    my ($cd, $fn) = @_; 
		    $config->{disc}[$cd]{function}{list}[$fn][1]{hdlist} = 1 
		}, "Setting hdlist tag" ],
	# 5
    	    [ "", "nodeps", 0, "", "Do not include deps", 
	        sub { 
		    my ($cd, $fn) = @_; 
		    $config->{disc}[$cd]{function}{list}[$fn][1]{nodeps} = 1 
		}, "Setting nodeps flag for this fixed rep" ],
];
#
# cp 
#
$functions{cp} =
	[
	    [ "", "cp", 2, "<file source> <file destination>", "Copy",
	       	sub { my ($cd, $fn, $src, $dest) = @_;
		    my @a = ('cp', { src => $src, dest => $dest });
		    $config->{disc}[$cd]{function}{list}[$fn] = \@a;
		    push @{$config->{disc}[$cd]{function}{data}{cp}}, \@a;
		    push @{$config->{disc}[$cd]{steps}}, \@a;
		    1
	}, "Copying files" ],
     # 1
	[ "", "first", 0, "", "Remove files in the files copied with first option", 
	    sub { 
		my ($cd, $fn) = @_; 
	        $config->{disc}[$cd]{function}{list}[$fn][1]{first} = 1;
		1
	    }, "Setting first flag"
	],
];
 #
 # boot 
 #
$functions{boot} = 
    [ 
    # 0
	[ "", "boot", 0, "<options> <files or dir to copy 1> <files or dir to copy 2> .. <files or dir to copy 3>", "Boot parameters and files", 
	    sub {   my ($cd, $fn) = @_; 
		    my @a = ('boot', { });
		    $config->{disc}[$cd]{function}{list}[$fn] = \@a;
		    push @{$config->{disc}[$cd]{function}{data}{boot}}, \@a;
		    push @{$config->{disc}[$cd]{steps}}, \@a;
		    1
	  }, "Setting boot parameters"
	],
	  # 1
	[ "", "isolinux", [
		["", "isolinux", 0, "", "Create an isolinux bootable disc", 
		    sub { 	
			my ($tmp, @args) = @_;
		       	$tmp->[0]{isolinux} = 1;
			push @$tmp, @args
    		    }, "Setting an isolinux boot disc"],
    		], "<options>", "isolinux boot disc", 
		    sub { my ($cd, $fn, $options) = @_; 
			foreach (@{ $config->{disc}[$cd]{function}{data}{boot} }) {
				if (ref $_->[1]{isolinux}) { log_("ERROR: disc $cd: duplicate isolinux boot image, ignored\n", $config->{verbose}, $config->{LOG}); return 0 }
		    	}
		      	$config->{disc}[$cd]{function}{list}[$fn][1]{isolinux} = [ $options ]
		    }, "Setting isolinux image"
	],
	  #2
	[ "b", "bootimg", [
	    [ "", "bootimg", 1, "<boot image name>", "set boot image name",
		    sub { my ($tmp, @args) = @_;
			$tmp->[0]{bootimg} = 1;
			push @$tmp, @args
		    }, "setting boot image name"
	    ],
	    [ "d", "dir", 1, "<directory>", "duplicate the boot image in directory and put it first in the ISO",
	       sub { my ($tmp, $dir) = @_; $tmp->[0]{dir} = $dir }, ""	
	    ]
		], "<options> <boot image>", "Create a bootable iso with given image", 
		    sub { my ($cd, $fn, $options, $img) = @_;
			foreach (@{ $config->{disc}[$cd]{function}{data}{boot} }) {
				if (ref $_->[1]{bootimg}) { log_("ERROR: disc $cd: duplicate boot image, ignored\n", $config->{verbose}, $config->{LOG}); return 0 }
		    	}
			$config->{disc}[$cd]{function}{list}[$fn][1]{bootimg} = [ $img, $options ]
		    }, "Setting boot image options"
	],
	  #3
	[ "f", "files", [
		[ "", "files", -1, "<file 1> <file 2> .. <file n>", "Set options for files copied",
		    sub { 
			my ($tmp, @args) = @_;
			$tmp->[0] = {};
			push @$tmp, @args
		    }, "Setting files options" ],
		[ "", "first", 0 , "", "Put this files first in the ISO", 
			sub { 
			    my ($tmp) = @_; 
			    $tmp->[0]{first} = 1; 
			    1 
			}, "Setting first flag for files" ],
		[ "d", "dest", 1 , "<destination on the targe disc>", "Choose where to copy the files", 
			sub { 
			    my ($tmp, $dest) = @_; 
			    $tmp->[0]{dest} = $dest;
			    1 
			}, "Setting destination location for files" ],
	    ], "[options] <files 1> <files 2> .. <files n>", "Setting files to copy", 
		sub { my ($cd, $fn, $options, @files) = @_; 
		    foreach (fix_dir(@files)) {
			log_("boot: file $_ (to $options->{dest})\n", $config->{verbose}, $config->{LOG});
			push @{$config->{disc}[$cd]{function}{list}[$fn][1]{files}}, [ $_, $options ]
		    }
		    1
		}, 
	    "Setting files to copy"
	    ],
	#4
	[ "", "oem", 0, "", "Set default boot to oem mode", 
	    sub { my ($cd, $fn) = @_; 
		$config->{disc}[$cd]{function}{list}[$fn][1]{oem} = 1
	    }, "Setting oem boot mode"
	],

];

#
# clone
#
$functions{clone} = 
    [ 
    # 0
	[ "", "clone", 1, "<disc to clone>", "Clone the given disc", 
	    sub {   my ($cd, $fn, $disc) = @_; 
		    my @a = ('clone', { disc => $disc });
		    $config->{disc}[$cd]{function}{list}[$fn] = \@a;
		    push @{$config->{disc}[$cd]{function}{data}{clone}}, \@a;
		    push @{$config->{disc}[$cd]{steps}}, \@a;
		    1
	  }, "Setting clone parameters"
	],
	  # 1
	[ "i", "include", -2, "<directory name 1> <directory path 1> <directory name 2> <directory path 2> ... <directory name n> <directory path n>", "include declaration of copied directory", 
	    sub {   my ($cd, $fn, @dir) = @_; 
		    my $list = @{$config->{list}};
		    while (@dir) {
			my $rpmdir = shift @dir;
			my $path = shift @dir or last;
			$config->{disc}[$cd]{function}{data}{dir}{$rpmdir} = [ "clone_dir", { reploc => $path } ];
			$config->{disc}[$cd]{function}{list}[$fn][1]{rpmsdir} = $path;
			log_("clone: disc $cd adding list $list for virtual rep $rpmdir path $path\n", $config->{verbose}, $config->{LOG},3);
			$config->{list}[$list]{virtual} = [ { disc => $cd, repname => $rpmdir } ];
			push @{$config->{disc}[$cd]{fastgeneric}}, [ '', { repname => $rpmdir, lists => [ $list ] } ];
		    }
		    $config->{list}[$list]{done} = 1;
		    1
	    }, "Setting directory name and path parameters"
	]
#	[ "d", "delete", -1, "<function 1 nb to delete> <function 1 nb to delete> ... <function n nb to delete>", "delete these functions in the cloned disc", 
#	    sub {   my ($cd, $fn,@to_del) = @_; 
#		    $config->{disc}[$cd]{function}{list}[$fn][1]{to_del} = \@to_del;
#		    1
#	    }, "Setting delete parametes"
#	]
];

#
# rm
#
$functions{rm} =
    [
     # 0
	[ "", "rm", -1, "<disc to rm>", "Delete the given file or directory on the disc image", 
	    sub {   my ($cd, $fn, @files) = @_; 
		    my @a = ('rm', { files => \@files });
		    $config->{disc}[$cd]{function}{list}[$fn] = \@a;
		    push @{$config->{disc}[$cd]{function}{data}{files}}, \@a;
		    push @{$config->{disc}[$cd]{steps}}, \@a;
		    1
	  }, "Setting rm parameters"
	],
     # 1
	[ "", "first", 0, "", "Remove files in the files copied with first option", 
	    sub { 
		my ($cd, $fn) = @_; 
	        $config->{disc}[$cd]{function}{list}[$fn][1]{first} = 1;
		1
	    }, "Setting first flag"
	],
];

sub new {
    my ($class, $conf) = @_;
    $config = $conf;
    bless {
	config       => $conf,
	functions    => \%functions
    }, $class;
}

sub get_rpmsdir {
    my ($type, $cd, $fn, $rpms, $opts) = @_;
    my $options = '(?:(noauto):)?';
    # FIXME taken from Tools.pm
    my $match_val2 = q(((?:[^"\s]*(?:[^"\s]+|"[^\"]+")[^"\s]*)+));
    foreach (@$rpms)  {
	log_("get_rpmsdir: $_\n", $config->{verbose}, $config->{LOG}, 3);
	my %options;
	foreach (keys %$opts)  { $options{$_} = $opts->{$_} }
	if (my ($opt, $hdlist, $hdlist_path, $hdlist_name, $pubkey) = m/${options}hdlist:([^,]+),([^,]+),$match_val2(?:,(.*))?/) { 
	    if (!$config->{disc}[$cd]{function}{list}[$fn][1]{fixed}) {
	        $config->{disc}[$cd]{function}{list}[$fn][1]{fixed} = 1;
		log_("WARNING get_rpmsdir: hdlist rpmsdir could only be fixed, forcing fixed flag\n", $config->{verbose}, $config->{LOG}, 0);
	    }
	    my $list = add_list($cd, "hdlist_rpm", $hdlist, $pubkey);
	    my $new_cd = @{$config->{disc}};
	    log_("get_rpmsdir: adding virtual disc $new_cd for hdlist $hdlist (path $hdlist_path disc_name $hdlist_name)\n", $config->{verbose}, $config->{LOG}, 3);
	    push @{$config->{virtual_disc}}, $new_cd;
	    $functions{disc}[0][5]->($new_cd, $hdlist_name, 0, 0, $hdlist_name, 0);
	    $functions{dir}[0][5]->($new_cd, 1, "rpms", $hdlist_path);
	    $functions{generic}[0][5]->($new_cd, 2, "rpms", $list);
	    $options{hdlist} = $hdlist;
	    foreach (split ',', $opt)  { $options{$_} = 1 }
	    push @{$config->{disc}[$cd]{function}{list}[$fn][1]{$type}}, [ $list, $new_cd, 'rpms', \%options ]
	} elsif (my ($opt, $cdrep, $repname, $list) = m,$options(\d+)/([^/]+)(?:/(\d+))?,) { 
	    foreach (split ',', $opt)  { $options{$_} = 1 }
	    push @{$config->{disc}[$cd]{function}{list}[$fn][1]{$type}}, [ $list, $cdrep, $repname, \%options ]
	} else {
	    log_("ERROR get_rpmsdir: could not parse rpmsdir value $_\n", $config->{verbose}, $config->{LOG}, 0);
	}
    } 
}

sub add_list {
    my ($cd, $type, $pkg_list, $pubkey) = @_;
    my $list = @{$config->{list}};
    log_("add_list: disc $cd adding list $list for $type $pkg_list\n", $config->{verbose}, $config->{LOG}, 3);
    $config->{list}[$list]{packages} = [ { $type => [ $pkg_list ] } ];
    $config->{list}[$list]{done} = 1;
    $config->{list}[$list]{nosize} = 1;
    if ($pubkey) {
	log_("add_list: adding pubkey file $pubkey for list $list\n", $config->{verbose}, $config->{LOG}, 3);
	push @{$config->{list}[$list]{keyfiles}}, $pubkey;
    }
    $list
}

sub template {
    my ($class, $dir, $fixed, $nolive, $cdnum, $cd, $cdfile, $list, $mkisos, $totgraft, $inode, $discsFiles) = @_;
    if (!$fixed) {
	my $size;
	if ($nolive) {
	    return $size
	} else {

	}
    } elsif ($fixed == 1) {
	my $mkiso;
	if ($nolive) {
	} else {
	    
	}
    } elsif ($fixed == 2) {
	my $mkiso;
	if ($nolive) {
	} else {
	    
	}
    }	
}

sub clone {
    my ($class, $fct, $dir, $fixed, $nolive, $cdnum, $cd, $cdfile, $list, $mkisos, $totgraft, $inode, $discsFiles) = @_;
    my $graft = $totgraft->{$cdnum};
    my $disc_src = $fct->[1]{disc};
    if ($fixed == 0) {
	if ($nolive) {
	    if ($fct->[1]{full_copy}) {
		log_("clone: full copy of disc $disc_src nolive mode\n", $config->{verbose}, $config->{LOG},2);
		if ($totgraft->{$disc_src}) {
		    log_("clone: getting disc from current build\n", $config->{verbose}, $config->{LOG},3);
		    $graft = $totgraft->{$disc_src}
		} elsif (-d "$dir/$disc_src") {
		    log_("clone: getting disc from filesystem\n", $config->{verbose}, $config->{LOG},3);
		    $graft->{"/"}{"$dir/$disc_src"} = 1
		} else {
		    log_("ERROR clone: source disc not available\n", $config->{verbose}, $config->{LOG},3);
		}
	    }
	} else {
	    if ($fct->[1]{full_copy}) {
		log_("clone: full copy of disc $disc_src\n", $config->{verbose}, $config->{LOG},2);
		if (-d "$dir/$disc_src") {
		    log_("clone: getting disc from filesystem\n", $config->{verbose}, $config->{LOG},3);
		    $graft->{"/"}{"$dir/$disc_src"} = undef;
		    cpal("$dir/$disc_src/", "$dir/$cdnum");
		} else {
		    log_("ERROR clone: source disc not available\n", $config->{verbose}, $config->{LOG},3);
		}
	    }
	}
    }
    1
}

sub rm {
    my ($class, $fct, $dir, $fixed, $nolive, $cdnum, $cd, $cdfile, $list, $mkisos, $totgraft, $inode, $discsFiles) = @_;
    my $graft = $totgraft->{$cdnum};
    my $files = $fct->[1]{files};
#    use File::Find;
    if ($fixed == 0) {
	if ($nolive) {
	    # FIXME this does not really works in no live mode (exclude files does not work with mkisofs properly)
	    my $size;
	    foreach my $r (@$files) {
		log_("rm: trying $r\n", $config->{verbose}, $config->{LOG},2);
		$r = "/$r" if $r !~ m,^/,;
		#$graft->{$r} = 3;
		$r =~ s/\*/.+/;
		foreach my $g (keys %$graft) {
		    ref $graft->{$g} or next;
		    log_("rm: graft $g ($r)\n", $config->{verbose}, $config->{LOG},3);
		    if ($g =~ m,^/?$r/?$,) {
			foreach my $f (keys %{$graft->{$g}}) {
			     $size -= du $f
			}
			$g =~ m,^/, and $g = "/$g";
			$graft->{$g} = 0;
			log_("rm: deleting $g (size $size)\n", $config->{verbose}, $config->{LOG},4);
		    }
		}
		my @up = grep { $_ } split '/', $r;
		my $last = pop @up;
		while (@up) {
		    my $uppath = join '/', @up;
		    $uppath = "/$uppath";
		    log_("rm: testing $uppath\n", $config->{verbose}, $config->{LOG},4);
		    $uppath = $graft->{$uppath} ? $uppath : $graft->{"/$uppath"} ? "/$uppath" : $graft->{"$uppath/"} ? "$uppath/" : "/$uppath/";
		    log_("rm: graft $graft->{$uppath}\n", $config->{verbose}, $config->{LOG},4);
		    if (ref $graft->{$uppath}) {
			foreach (keys %{$graft->{$uppath}}) {
			    log_("rm: testing $uppath ($_)\n", $config->{verbose}, $config->{LOG},4);
			    if (-d $_) {
				log_("rm: opening $_\n", $config->{verbose}, $config->{LOG},4);
				opendir my $dir, $_ or next;
				foreach my $first (readdir $dir) {
				    $first =~ /^\.{1,2}$/ and next;
				    log_("rm: FIRST 2 $first in $uppath$first ($r) " . $graft->{"$uppath$first"} . "\n", $config->{verbose}, $config->{LOG},4);
				    if ("$uppath$first" ne $r) {
					log_("rm: adding $_/$first in $uppath\n", $config->{verbose}, $config->{LOG},4);
					$graft->{"$uppath$first"} ||= {};
				        $graft->{"$uppath$first"}{"$_/$first"} = 1;
				    }
				}
				delete $graft->{$uppath}{$_}
			    }
			}
			last
		    }
		    $last = pop @up;
		}
	    }
#	    my @find;
#	    foreach my $k (keys %$graft){
#		ref $graft->{$k} or next;
#		foreach my $f (keys %{$graft->{$k}}){
#		    $f =~ s|/{2,}|/|g;
#		    find({ wanted => sub { s,/?\Q$f,,; $_ = "$k/$_"; s|/{2,}|/|g; push @find, [ $f, $_ ] }, no_chdir => 1 }, $f);
#		}
#	    }
#	    foreach (@$files) { s|/{2,}|/|g }
#	    foreach my $t (@find){
#		my ($k, $f) = @$t;
#		foreach my $r (@$files){
#		    next if $f =~ m,^/?$r/[^/]+,;
#		    if ($f =~ m,^/?$r/?$,){
#			log_("rm: deleting $f (path $k regexp $r)\n", $config->{verbose}, $config->{LOG});
#			$graft->{$f} = 0;
#			$size -= du $k;
#			$size -= du "$k/$f";
#		    }
#		}
#	    }
	    return $size
	} else {
	    my $first = "first/" if $fct->[1]{first};
	    foreach (@$files) {
		my @file = glob "$dir/$first$cdnum/$_";
		foreach my $f (@file) {
		    if (-d $f) {
			log_("rm: deleting directory $f\n", $config->{verbose}, $config->{LOG}, 2);
			my $err = rmtree $f;
			if (!$err) { log_("ERROR rm: deleting $f failed: $!,\n", $config->{verbose}, $config->{LOG}) }
		    } else {
			log_("rm: deleting file $f\n", $config->{verbose}, $config->{LOG},2);
			my $err = unlink $f;
			if (!$err) { log_("ERROR rm: deleting $f failed: $!,\n", $config->{verbose}, $config->{LOG}) }
		    }
		}
	    }
	    return 
	}
    }
    1
}

sub cp {
    my ($class, $fct, $dir, $fixed, $nolive, $cdnum, $cd, $cdfile, $list, $mkisos, $totgraft, $inode, $discsFiles, $sort) = @_;
    my $graft = $totgraft->{$cdnum};
    if (!$fixed) {
	my $size;
	my $source = $fct->[1]{src};
	my $dest = $fct->[1]{dest};
	if ($nolive) {
	    $size += du($source, $inode);
	    log_("cp: copying $source => $dest (size $size)\n", $config->{verbose}, $config->{LOG},1);
	    $graft->{"/$dest"}{$source} = 1;
	    return $size
	} else {
	    my $first = "first/" if $fct->[1]{first};
	    cpal($source, "$dir/$first$cdnum/$dest");
	    $graft->{"$dir/$cdnum/$dest"}{$source} = 1;
	    push @{$sort->{$cdnum}}, [ "$dir/$first$cdnum/$dest" ] if $fct->[1]{first};
	    return
	}
    }
}

sub fixed {
    my ($class, $fct, $dir, $fixed, $nolive, $cdnum, $cd, $cdfile, $list, $mkisos, $totgraft, $inode, $discs_file) = @_;
    my $graft = $totgraft->{$cdnum};
    my $destination = $fct->[1]{dest};
    my ($fdest, $nocopy);
    my $rep = $fct->[1]{dir}; 
    my $dest_dir = $cd->{function}{data}{dir}{$rep}[1];
    my $reploc = $dest_dir->{reploc};
    my $reploc_full = "$dir/$cdnum/$reploc/";
    if ($destination) {
	$fdest = "$dir/$cdnum/$destination";
    } else {
	$fdest = "$dir/$cdnum/$reploc";
	$nocopy = 1
    }
    my $size;
    if (!$fixed) {
	my $source = $fct->[1]{source};
	my $uppath = $destination;
	$uppath =~ s,([^/]+),../,g;
	$uppath =~ s,/+,/,g;
	log_("DEST: $destination uppath $uppath dest $reploc_full\n", $config->{verbose}, $config->{LOG},3);
	-d $fdest or mkpath $fdest;
	if ($nolive) {
	    -d $reploc_full or mkpath $reploc_full;
	    opendir my $A, $source;
	    log_("fixed: $source\n", $config->{verbose}, $config->{LOG},3);
	    my $struct_v = $config->{struct_version};
	    my $media = $config->{struct}{$struct_v}{media};
	    my $install_dir = $config->{struct}{$struct_v}{install};
	    foreach (readdir $A) {
		/^\.{1,2}$/ and next;
		if (! /^$install_dir$/) {
		    $size += du("$source/$_", $inode);
		    log_("fixed: adding $_ (size $size)\n", $config->{verbose}, $config->{LOG},4);
		    $graft->{"/$destination/$_/"}{"$source/$_"} = 1
		} else {
		    $graft->{"/$reploc/"}{"$source/$media/"} = 1
		}
	    }
	    log_("fixed: creating symlink $uppath$reploc => $fdest/RPMS\n", $config->{verbose}, $config->{LOG}, 4);
	    my $err = symlink "$uppath$reploc", "$fdest/RPMS";                                            
	    !$err and log_("ERROR fixed: $!\n", $config->{verbose}, $config->{LOG});
	    $graft->{"/"}{"$fdest/RPMS"} = 1;
	} else {
	    log_("fixed: copying $source to $fdest\n", $config->{verbose}, $config->{LOG});
	    cpal($source, $fdest);
	    if (!$nocopy) {
		log_("fixed: creating symlink $uppath$reploc => $fdest/RPMS\n", $config->{verbose}, $config->{LOG});
		my $err = symlink "$uppath$reploc", "$fdest/RPMS";                                            
		!$err and log_("ERROR fixed: $!\n", $config->{verbose}, $config->{LOG});
	    }
	}
	return $size
    } else {
	# there is only one (virtual) list for fixed
	my $list = $fct->[1]{list};
	log_("fixed: list $list\n", $config->{verbose}, $config->{LOG});
	my $rep = $fct->[1]{dir}; 
	my $sep_arch = $dest_dir->{sep_arch};
	my $nolive_rep = $reploc;
	if ($nolive) {
	    if (!$nocopy) {
		foreach my $src (keys %{$cdfile->[$cdnum]{$rep}{$list}}) {
		    log_("fixed: src $src\n", $config->{verbose}, $config->{LOG});
		    foreach (@{$cdfile->[$cdnum]{$rep}{$list}{$src}}) {
			$graft->{"$nolive_rep/$_->[1]"}{"$src/$_->[1]"} = 1
		    }
		}
	    }
	} else {
	    if (!$nocopy) {
		foreach my $src (keys %{$cdfile->[$cdnum]{$rep}{$list}}) {
		    log_("fixed: src $src\n", $config->{verbose}, $config->{LOG});
		    foreach (@{$cdfile->[$cdnum]{$rep}{$list}{$src}}) {
			link("$fdest/$_->[1]", "$reploc_full/$_->[1]")	
		    }
		}
	    }
	}
	$size += process_hdlist_flags($nolive, $fct->[1]{synthesis}, $fct->[1]{hdlist}, $discs_file->[$cdnum]{$rep}{$list}, $dir, $cdnum, $fct, $rep, $reploc_full, $sep_arch, $graft, $list, $reploc);
	$size
    }
}

sub cdcom {
    my ($class, $fct, $dir, $fixed, $nolive, $cdnum, $cd, $cdfile, $list, $mkisos, $totgraft, $inode, $discs_file) = @_;
    my $graft = $totgraft->{$cdnum};
    if (!$fixed) {
	my $size;
	my $source = $fct->[1]{source};
	my $dest = $config->{disc}[$cdnum]{function}{data}{dir}{$fct->[1]{dir}}[1]{reploc};
	my $destination = $fct->[1]{dest};
	my $uppath = $destination;
	$uppath =~ s,([^/]+),../,g;
	$uppath =~ s,/+,/,g;
	log_("DEST: $destination uppath $uppath dest $dest\n", $config->{verbose}, $config->{LOG},3);
	my $fdest = "$dir/$cdnum/$destination";
	my $struct_v = $config->{struct_version};
	my $media = $config->{struct}{$struct_v}{media};
	my $install_dir = $config->{struct}{$struct_v}{install};
	if ($nolive) {
	    my $path = "$dir/$cdnum/$dest";
	    -d $path or mkpath $path;
	    opendir my $A, $source;
	    log_("cdcom: $source\n", $config->{verbose}, $config->{LOG},3);
	    foreach (readdir $A) {
		/^\.{1,2}$/ and next;
		if (! /^$install_dir$/) {
		    $size += du("$source/$_", $inode);
		    log_("cdcom: adding $_ (size $size)\n", $config->{verbose}, $config->{LOG},4);
		    $graft->{"/$destination/$_/"}{"$source/$_"} = 1
		} else {
		    $graft->{"/$dest/"}{"$source/$media/"} = 1
		}
	    }
	    #local *A; opendir A, "$source/Mandrake/RPMS";
	    #foreach (readdir A){
	    #    /^\.{1,2}$/ and next;
	    #    my $newdest = readlink "$source/Mandrake/RPMS/$_";
	    #    $newdest =~ s,((?:../))*(.*), $1/$destination/$2,;
	    #    log_("cdcom: creating symlink $dest/$_ => $newdest\n", $config->{verbose}, $config->{LOG});
	    #    my $err = symlink $newdest, "$dir/$cdnum/$dest/$_";
	    #    !$err and log_("ERROR cdcom: $!\n", $config->{verbose}, $config->{LOG}) and next;
	    #    $graft->{"/$dest/"}{"$dir/$cdnum/$dest/$_"} = 1
	    #}
	    #$graft->{"/$dest/"}{"$source/Mandrake/RPMS"} = 1;
	    log_("cdcom: creating symlink $uppath$dest => $fdest/RPMS\n", $config->{verbose}, $config->{LOG}, 4);
	    -d $fdest or mkpath $fdest;
	    my $err = symlink "$uppath$dest", "$fdest/RPMS";                                            
	    !$err and log_("ERROR cdcom: $!\n", $config->{verbose}, $config->{LOG});
	    $graft->{"/"}{"$fdest/RPMS"} = 1;
	    return $size
	} else {
	    -f $fdest or mkpath $fdest;
	    cpal($source, $fdest, $media);
	    local *A; opendir A, "$source/$media";
	    foreach (readdir A) {
		/^\.{1,2}$/ and next;
		my $newdest = readlink "$source/$media/$_";
		$newdest =~ s,((?:../)*)(.*),$1$destination/$2,;
		log_("cdcom: creating symlink $dir/$cdnum/$dest/$_ => $dir/$cdnum/$dest/$newdest\n", $config->{verbose}, $config->{LOG},2);
		my $err = link "$dir/$cdnum/$dest/$newdest", "$dir/$cdnum/$dest/$_";
		# should be OK with new du with inode checking
		#$size -= du("$dir/$cdnum/$dest/$newdest");
		!$err and log_("ERROR cdcom: $!\n", $config->{verbose}, $config->{LOG})
	    }
	    log_("cdcom: creating symlink $uppath$dest => $fdest/RPMS\n", $config->{verbose}, $config->{LOG});
	    my $err = symlink "$uppath$dest", "$fdest/RPMS";                                            
	    !$err and log_("ERROR cdcom: $!\n", $config->{verbose}, $config->{LOG});
	        
	    return $size
	}
	my $rep = $fct->[1]{dir}; 
	my $lists = $fct->[1]{lists};
	my $dest_dir = $cd->{function}{data}{dir}{$rep}[1];
	my $reploc = "$dir/$cdnum/$dest_dir->{reploc}/";
	my $sep_arch = $dest_dir->{sep_arch};
	foreach my $list (@$lists) {
	    $size += process_hdlist_flags($nolive, $fct->[1]{synthesis}, $fct->[1]{hdlist}, $discs_file->[$cdnum]{$rep}{$list}, $dir, $cdnum, $fct, $rep, $reploc, $sep_arch, $graft, $list, $dest_dir->{reploc});
	}
	return $size
    }
}

sub process_hdlist_flags {
    my ($nolive, $synthesis, $hdlist, $discs_files, $dir, $cdnum, $fct, $rep, $reploc, $sep_arch, $graft, $list, $nolive_rep) = @_;
    my $size;
    log_("process_hdlist_flags: synthesis $synthesis hdlist $hdlist disc $cdnum reploc $reploc\n", $config->{verbose}, $config->{LOG});
    my $media_hdlist = $config->{struct}{$config->{struct_version}}{media_hdlist};
    if ($nolive) {
	if ($synthesis || $hdlist) {
	    if (ref $discs_files) {
		my (undef, $path) = buildGenericHdlist($dir, $cdnum, $fct, $rep, "$reploc/$media_hdlist", $discs_files, $sep_arch);
		if ($fct->[1]{hdlist})  {
		    $size += du("$reploc/$media_hdlist/hdlist.cz");
		    $graft->{"$nolive_rep/$media_hdlist/hdlist.cz"}{"$reploc/$media_hdlist/hdlist.cz"} = 1
		}
		if ($fct->[1]{synthesis}) {
		    $size += du("$reploc/$media_hdlist/synthesis.hdlist.cz");
		    $graft->{"$nolive_rep/$media_hdlist/synthesis.hdlist.cz"}{"$reploc/$media_hdlist/synthesis.hdlist.cz"} = 1
		}
	    } else {
		log_("WARNING process_hdlist_flags: disc $cdnum rep $rep list $list is empty, no hdlist or synthesis created\n", $config->{verbose}, $config->{LOG});
	    }
	}
    } else {
	if ($synthesis || $hdlist) {
	    if (ref $discs_files) {
		buildGenericHdlist($dir, $cdnum, $fct, $rep, "$reploc/$media_hdlist", $discs_files, $sep_arch);
	    } else {
		log_("WARNING process_hdlist_flags: disc $cdnum rep $rep list $list is empty, no hdlist or synthesis created\n", $config->{verbose}, $config->{LOG});
	    }
	}
    }
    $size
}

sub printSize {
    my ($img, $file) = @_;
    local *A; open A, ">$file";
    my $size = imageSize($img);
    log_("printSize: creating $file for $img\n", $config->{verbose}, $config->{LOG});
    if ($size) {
	print A <<EOF
#!/usr/bin/perl

\$width = $size->[0];
\$height = $size->[1];
\@data = ()
EOF
    } else {
	print "ERROR advertising: $size/n";
	return 0
    }
}

sub advertising {
    my ($class, $fct, $dir, $fixed, $nolive, $cdnum, $cd, $cdfile, $list, $mkisos, $totgraft, $inode) = @_;
    my $graft = $totgraft->{$cdnum};
    if (!$fixed) {
	my $size;
	my $struct_v = $config->{struct_version};
	my $extra = $config->{struct}{$struct_v}{extra};
	if ($nolive) {
	    log_("Getting advertising images size\n", $config->{verbose}, $config->{LOG});
	    my $addir = "$extra/advertising" . ($fct->[1]{lang} ? ".$fct->[1]{lang}" : "");
	    my $rep = "$dir/$cdnum/$addir";
	    -d $rep or mkpath $rep;
	    local *L; open L, ">$rep/list";
	    foreach (@{$fct->[1]{img}}) {
		s/\.png$//;
		my ($name) = m,([^/]*)$,;
		$size += du($_, $inode);
		print L "$name\n";
		if (-f "$_.png") { $graft->{"$addir/$name.png"}{"$_.png"} = 1 } else { next }
		if (-f "$_.pl") { $graft->{"$addir/$name.pl"}{"$_.pl"} = 1
		} else {
		    printSize("$_.png", "$rep/$name.pl");
		    $graft->{"$addir/$name.pl"}{"$_.pl"} = 1
	    	}
		-f "${_}_icon.png" and $graft->{"$addir/$name-icon.png"}{"${_}_icon.png"} = 1
	    } 
	    close L;
	    $graft->{"$addir/list"}{"$rep/list"} = 1;
	    $size += du("$rep/list");
	    return $size
	} else {
	    my $rep = "$dir/$cdnum/$extra/advertising" . ($fct->[1]{lang} ? ".$fct->[1]{lang}" : "");
	    log_("Creating advertising images directory ($rep)\n", $config->{verbose}, $config->{LOG});
	    -d $rep or mkpath $rep;
	    local *L; open L, ">$rep/list";
	    foreach (@{$fct->[1]{img}}) {
		s/\.png$//;
		my ($name) = m,([^/]*)$,;
		if (-f "$_.png") { cpal("$_.png", "$rep/$name.png") } else { next }
		if (-f "$_.pl") { cpal("$_.pl", "$rep/$name.pl") } else { printSize("$_.png", "$rep/$name.pl") }
		-f "${_}_icon.png" and cpal("${_}_icon.png", "$rep/${name}_icon.png");
		print L "$name.png\n"
	    }
	    close L;
	    return
	}
    }
}

sub dir {
    my ($class, $fct, $dir, $fixed, $nolive, $cdnum, $cd) = @_;
    if (!$fixed) {
	if ($nolive) {
	    return 0
	} else {
	    my $reploc = "$dir/$cdnum/$fct->[1]{reploc}";
	    log_("dir: creating $reploc\n", $config->{verbose}, $config->{LOG});
	    -d $reploc or mkpath $reploc;
	    return 0	
	}
    }
}

sub generic {
    my ($class, $fct, $dir, $fixed, $nolive, $cdnum, $cd, $cdfile, $list, $mkisos, $totgraft, $inode, $discsFile) = @_;
    my $graft = $totgraft->{$cdnum};
    my $size;
    my $rep = $fct->[1]{repname};
    my $dest_dir = $cd->{function}{data}{dir}{$rep}[1];
    my $nolive_rep = $dest_dir->{reploc};
    if ($fixed) {
	my $lists = $fct->[1]{lists};
	log_("generic: rep $rep\n", $config->{verbose}, $config->{LOG});
	my $reploc = "$dir/$cdnum/$dest_dir->{reploc}/";
	my $sep_arch = $dest_dir->{sep_arch};
	my %list;
	if ($sep_arch) {
	    if (-f "$reploc/list") {
		open my $list_file, "$reploc/list";
		while (<$list_file>) {
		    chomp;
		    $list{$_} = 1
		}
	    }
	}
	if ($nolive) {
	    if ($fixed > 0) {
		foreach my $list (@$lists) {
		    log_("generic: list $list\n", $config->{verbose}, $config->{LOG});
		    foreach my $src (keys %{$cdfile->[$cdnum]{$rep}{$list}}) {
			log_("generic: src $src\n", $config->{verbose}, $config->{LOG});
			foreach (@{$cdfile->[$cdnum]{$rep}{$list}{$src}}) {
			    if ($_->[0] == 1) {
				my $d = $nolive_rep;
				if ($sep_arch) {
				    $_->[1] =~ /([^.]+)\.rpm$/  or log_("WARNING generic: could not find arch of $_\n", $config->{verbose}, $config->{LOG});
				    $d .= "/$1"
				}
				$graft->{"$d/$_->[1]"}{"$src/$_->[1]"} = 1
			    } elsif ($_->[0] == 2) {
				my $d = $nolive_rep;
				if ($sep_arch) {
				    $_->[1] =~ /([^.]+)\.rpm$/  or log_("WARNING generic: could not find arch of $_\n", $config->{verbose}, $config->{LOG});
				    $d .= "/$1"
				}
				delete $graft->{"$d/$_->[1]"}{"$src/$_->[1]"} 
			    }
			}
		    }
		    $size += process_hdlist_flags($nolive, $fct->[1]{synthesis}, $fct->[1]{hdlist}, $discsFile->[$cdnum]{$rep}{$list}, $dir, $cdnum, $fct, $rep, $reploc, $sep_arch, $graft, $list, $nolive_rep);
		}
	    }
	    if ($sep_arch) {
		open my $list_file, ">$reploc/list";
		foreach (sort keys %list) { print $list_file "$_\n" if $list{$_} }
		close $list_file;
		$size += du("$dir/$cdnum/$reploc/list");
		$graft->{"$nolive_rep/list"}{"$reploc/list"} = 1
	    }
	    return $size
	} else {
	    foreach my $list (@$lists) {
		log_("generic: list $list\n", $config->{verbose}, $config->{LOG});
		foreach my $src (keys %{$cdfile->[$cdnum]{$rep}{$list}}) {
		    log_("generic: src $src\n", $config->{verbose}, $config->{LOG});
		    foreach (@{$cdfile->[$cdnum]{$rep}{$list}{$src}}) {
			if ($_->[0] == 1) {
			    my $d = $reploc;
			    if ($sep_arch) {
			        $_->[1] =~ /([^.]+)\.rpm$/ or log_("WARNING generic: could not find arch of $_\n", $config->{verbose}, $config->{LOG});
				$d .= "/$1";
				$list{"$1/$_->[1]"} = 1;
				-d $d or mkdir $d;
			    }
			    cpal("$src/$_->[1]", $d)	
			}  elsif ($_->[0] == 2) {
			    log_("generic: deleting $reploc/$_->[1]\n", $config->{verbose}, $config->{LOG});
			    my $d = $reploc;
			    if ($sep_arch) {
				$_->[1] =~ /([^.]+)\.rpm$/ or log_("WARNING generic: could not find arch of $_\n", $config->{verbose}, $config->{LOG});
				$list{"$1/$_->[1]"} = 0;
				$d = "$reploc/$1";
			    }
			    unlink "$d/$_->[1]";
			}
		    }
		}
		$size += process_hdlist_flags($nolive, $fct->[1]{synthesis}, $fct->[1]{hdlist}, $discsFile->[$cdnum]{$rep}{$list}, $dir, $cdnum, $fct, $rep, $reploc, $sep_arch, $graft, $list, $nolive_rep);
	    }
	    if ($sep_arch) {
		open my $list_file, ">$reploc/list";
		foreach (sort keys %list) { print $list_file "$_\n" if $list{$_} }
		close $list_file;
	    }
	    return 0
	}
	
    }
}

sub printVERSION {
    my ($name, $file, $tag) = @_;
    open my $VERSION, ">$file";
    my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time());
    $year += 1900;
    printf $VERSION "Mandrakelinux $name $tag %04d%02d%02d $hour:%02d\n", $year, $mon+1, $mday, $min;
}

sub buildGenericHdlist {
    my ($dir, $cdnum, $fct, $rep, $reploc, $discsFilescdrep, $sep_arch) = @_;
    my @rpm = map { "$discsFilescdrep->{$_}/$_.rpm" } keys %$discsFilescdrep;
    
    if ($fct->[1]{synthesis}) {
	-d $reploc or mkpath $reploc;
    }
    # $hdlist = "$reploc/hdlist$cdnum$rep.cz" if $fct->[1]{hdlist};
    # my $synthesis = "$reploc/synthesis.hdlist$cdnum$rep.cz" if $fct->[1]{synthesis};
    my ($hdlist, $synthesis, @md5files);
    my $struct_v = $config->{struct_version};
    if ($fct->[1]{hdlist}) {
        $hdlist = "$reploc/hdlist.cz";
	-d $reploc or mkdir $reploc;
	push @md5files, $hdlist
    }
    if ($fct->[1]{synthesis}) {
        $synthesis = "$reploc/synthesis.hdlist.cz";
	-d $reploc or mkdir $reploc;
	push @md5files, $synthesis
    }
    my $urpm = mkcd_build_hdlist(1, [ 0, { hdlist => $hdlist, rpms => \@rpm , synthesis => $synthesis } ], "$config->{tmp}/.mkcd_build_hdlist");
    compute_files_md5("$reploc/MD5SUM", \@md5files);
    $urpm, $reploc
}

sub buildInstallHdlist {
    my ($dir, $cdnum, $inst, $list, $discsFiles, $sort, $nolive) = @_;
    my (@hdlist, @hdlist_list);
    my $struct_v = $config->{struct_version};
    my $media_info = $config->{struct}{$struct_v}{media_info};
    -d "$dir/$cdnum/$media_info" or mkpath "$dir/$cdnum/$media_info";
    open my $HDLISTS, ">$dir/$cdnum/$media_info/hdlists";
    my (%rpmdone, %cd_rep);
    my %kerneldone;
    my $repnum = 1;
    my (@thisInstallRep, @check, @md5files);
    my $headers_dir = "$config->{tmp}/.mkcd_build_hdlist";
    my $path = "$dir/$cdnum/$media_info";
    my $suppl_cd = $inst->[1]{suppl_cd};
    my $suppl_postfix = 's' if $suppl_cd;
    log_("buildInstallHdlist: suppl_postfix is '$suppl_postfix' ($suppl_cd && $struct_v)\n", $config->{verbose}, $config->{LOG});
    foreach my $rd (@{$inst->[1]{tmp_rpmsdir}}) {
	my ($ls, $cdrep, $repname, $opts) = @$rd;
	log_("buildInstallHdlist: suppl_cd $suppl_cd cd $cdrep repname $repname fixed $opts->{fixed}\n", $config->{verbose}, $config->{LOG});
	next if $suppl_cd && $opts->{fixed};
	if (!$list->{$cdrep}) { log_("WARNING buildInstallHdlist: disc $cdrep not in list, ignoring\n", $config->{verbose}, $config->{LOG}); next }
	my $a = $discsFiles->[$cdrep]{$repname};
	if (!(ref($a) && %$a)) { log_("WARNING buildInstallHdlist: $cdrep/$repname is empty\n", $config->{verbose}, $config->{LOG}); next }
	my $realcd = $config->{disc}[$cdrep]{name};
	my $rpmdir = $config->{disc}[$cdrep]{function}{data}{dir}{$repname}[1]{reploc};
	$rpmdir .= "/%{ARCH}" if $config->{disc}[$cdrep]{function}{data}{dir}{$repname}[1]{sep_arch};
	if (!$rpmdir) { log_("ERROR buildInstallHdlist: disc $cdrep: $repname not defined\n", $config->{verbose}, $config->{LOG}); next }
	$hdlist[$repnum]{rpms} = [];
	if ($opts->{oem}) {
	    log_("buildInstallHdlist: oem mode for $cdrep/$repname ($rpmdir)\n", $config->{verbose}, $config->{LOG});
	    foreach (@{$inst->[1]{oem}{hdlist}}) {
		my ($oemdir, $hl, $rep, $name) = @$_;
		print $HDLISTS "noauto:" if $opts->{noauto};
		print $HDLISTS "$hl $rep $name\n";
		my $hdlist = "$path/$hl";
		log_("buildInstallHdlist: adding oem hdlist $hdlist from $dir\n", $config->{verbose}, $config->{LOG});
		if ($inst->[1]{oem}{norebuild}) {
		    cpal("$oemdir/$hl", $hdlist)
		}
		$hdlist[$repnum]{hdlist} = $hdlist;
		$hdlist_list[$repnum] = $hdlist;
		$hdlist[$repnum]{synthesis} = "$path/synthesis.$hl";
		push @md5files, ($hdlist, "$path/synthesis.$hl");
	        $repnum++
	    }
	} else {
	    #
	    # even for live sources rpm are taken, this may lead to errors in some special case, where
	    # the sources change after the live is created, but this could help in combined live/nolive
	    # situation
	    #
	    log_("installation: $cdrep - $repname - list $ls\n", $config->{verbose}, $config->{LOG});
	    foreach my $list (keys %{$discsFiles->[$cdrep]{$repname}}) {
		next if $ls && $ls != $list;
		$thisInstallRep[$cdrep]{$repname}{$list} = $discsFiles->[$cdrep]{$repname}{$list};
		push @{$check[$repnum]}, [$cdrep, $repname, $list];
		log_("installation: list $list\n", $config->{verbose}, $config->{LOG});
		my $cdsfilesrpms = $discsFiles->[$cdrep]{$repname}{$list};
		my %localdone;
		my %localkerneldone;
		# FIXME taken from tools
		my $kernel_like = "((?:(?:NVIDIA_)?kernel.*)|NVIDIA_nforce.*|cm2020.*)";
		#
		log_("buildInstallHdlist: update ($opts->{update}) nodupkernel ($opts->{nodupkernel}) mode for $cdrep/$repname list $list\n", $config->{verbose}, $config->{LOG}, 3);
		push @{$hdlist[$repnum]{rpms}}, map {
		    if (/$kernel_like-[^.]+(?:\.[^.]+){3,5}mdk-[^-]+-[^-]+\.[^.]+$/) {
			$kerneldone{$1} = 1;
		    }
		    if (/(.*)-[^-]+-[^-]+\.[^.]+$/) {
			$rpmdone{$_} = 1;
			$rpmdone{$1} = 1;
			"$cdsfilesrpms->{$_}/$_.rpm" }
		    } grep {
			if ($opts->{nodupkernel} && /($kernel_like-[^.]+(?:\.[^.]+){3,5}mdk)-[^-]+-[^-]+\.[^.]+$/) {
			    if ($localdone{$1} || $localkerneldone{$2}) { 0 }
			    else {
				$localkerneldone{$2} = 1;
				$localdone{$1} = 1;
				! ($kerneldone{$2} || $rpmdone{$_} || !$opts->{update} && $rpmdone{$1})
			    }
			} elsif (/(.*)-[^-]+-[^-]+\.[^.]+$/) {
			    if ($localdone{$1}) { $inst->[1]{dup} }
			    else {
				$localdone{$1} = 1;
				$inst->[1]{dup} || ! ($rpmdone{$_} || !$opts->{update} && $rpmdone{$1})
			    } } } keys %$cdsfilesrpms;
	        $hdlist[$repnum]{callback} = sub {
		       my ($urpm, $id) = @_;
		       my $pkg = $urpm->{depslist}[$id];
		       my $filename = $pkg->filename;
		       $urpm->{id}{$filename} = $id;
		       $pkg->pack_header
		   }
	    }
	    if (@{$hdlist[$repnum]{rpms}}) {
		print $HDLISTS "noauto:" if $opts->{noauto};
		if ($realcd) {
		    print $HDLISTS "hdlist$repnum$suppl_postfix.cz $rpmdir disc $realcd $config->{disc}[$cdrep]{longname}\n";
		} else {
		    print $HDLISTS "hdlist$repnum$suppl_postfix.cz $rpmdir $config->{disc}[$cdrep]{longname}\n";
		}
		$cd_rep{$repnum} = [ $cdrep, $rpmdir ];
		my %keys;
		my $text;
		foreach my $list (keys %{$discsFiles->[$cdrep]{$repname}}) {
		    foreach my $keyfile (@{$config->{list}[$list]{keyfiles}}) {
			if (-f $keyfile) {
			    log_("buildInstallHdlist: dumping $keyfile in $dir/$cdnum/$media_info/pubkey$repnum$suppl_postfix\n", $config->{verbose}, $config->{LOG}, 3);
			    open my $KF, $keyfile;
			    my $key;
			    while (<$KF>) {
				$key .= $_;
				if (/^-----END PGP PUBLIC KEY BLOCK-----/) {
				    if (! $keys{$key}) {
					$keys{$key} = 1;
					$text .= $key
				    }
				    $key = ''
			    	}
			    }
			    close $KF
			} else { 
			    log_("ERROR buildInstallHdlist: $keyfile file does not exist\n", $config->{verbose}, $config->{LOG}, 0);
			}
		    }
		}
		if ($text) {
		    open my $KEY, ">$dir/$cdnum/$media_info/pubkey$repnum$suppl_postfix";
		    print $KEY $text;
		    close $KEY;
		}
		$hdlist_list[$repnum] = "$path/hdlist$repnum$suppl_postfix.cz";
		$hdlist[$repnum]{hdlist} = $hdlist_list[$repnum];
		push @md5files, $hdlist_list[$repnum];
		if ($inst->[1]{synthesis}) { 
		    $hdlist[$repnum]{synthesis} = "$path/synthesis.hdlist$repnum$suppl_postfix.cz";
		    push @md5files, $hdlist[$repnum]{synthesis}
		}
		$repnum++
	    } else {
		log_("WARNING installation: $cdrep $repname is empty, ignoring\n", $config->{verbose}, $config->{LOG});
	    }
	}
    }
    # FIXME OEM mode not tested, moreover this norebuild test is wrong, new URPM need to rebuild hdlist.
    if (!$inst->[1]{oem}{norebuild}) {
	my $urpm = mkcd_build_hdlist($repnum - 1, \@hdlist, $headers_dir, "$path/depslist.ordered", "$path/provides", "$path/compss");
	get_sorted_packages($urpm, \@hdlist, $sort, \%cd_rep, "$dir/$cdnum", $nolive, $config->{verbose}, $config->{LOG});
    }
    log_("installation: compute_files_md5 @md5files\n", $config->{verbose}, $config->{LOG});
    compute_files_md5("$dir/$cdnum/$media_info/MD5SUM", \@md5files);

    log_("installation: oem ($inst->[1]{oem})\n", $config->{verbose}, $config->{LOG});
    if (!$inst->[1]{oem}{oem}) {
        log_("installation: checkDiscs\n", $config->{verbose}, $config->{LOG});
	checkDiscs(\@hdlist_list, "$path/depslist.ordered", \@thisInstallRep, \@check, $config->{LOG}) or die "depslist.ordered, hdlists and RPMS mismatch\n";
    }
# Add sources
    foreach my $rd (@{$inst->[1]{srpmsdir}}) {
	my ($ls, $cdrep, $repname, $opts) = @$rd;
	if (!$list->{$cdrep}) { log_("WARNING buildInstallHdlist: disc $cdrep not in list, ignoring\n", $config->{verbose}, $config->{LOG}); next }
	foreach my $list (keys %{$discsFiles->[$cdrep]{$repname}}) {
	    next if $ls && $ls == $list;
	    $thisInstallRep[$cdrep]{$repname}{$list} = $discsFiles->[$cdrep]{$repname}{$list};
	}
    }
    if ($inst->[1]{suppl}) {
	print $HDLISTS "suppl\n"
    }
    if ($inst->[1]{askmedia}) {
	print $HDLISTS "askmedia\n"
    }
    my $pfile = "$dir/$cdnum/pkg-$config->{name}" . ($inst->[1]{tag} ? "-$inst->[1]{tag}" : "") . ".idx";
    printDiscsFile($config, \@thisInstallRep, $pfile);
    return $repnum, $path, $pfile, $suppl_postfix
}

sub boot {
    my ($class, $fct, $dir, $fixed, $nolive, $cdnum, $cd, $cdfile, $list, $mkisos, $totgraft, $inode, $discsFiles, $sort) = @_;
    my $graft = $totgraft->{$cdnum};
    my $isolinux = $fct->[1]{isolinux};
    my $bootimg = $fct->[1]{bootimg};
    log_("Boot: $fixed nolive $nolive\n", $config->{verbose}, $config->{LOG});
    my $struct_v = $config->{struct_version};
    my $isolinux_dir = $fct->[1]{isolinux_dir} || $config->{struct}{$struct_v}{isolinux};
    if (!$fixed) {
	my $size;
	my (@chunk_first, @chunk);
	if ($nolive) {
	    my $mkiso;
	    my $img;
	    my $dir;
	    my $path;
	    if ($isolinux) {
		log_("boot: isolinux mode (bootimg $bootimg)\n", $config->{verbose}, $config->{LOG});
		my $img = $bootimg ? $bootimg->[0] : "$isolinux_dir/isolinux.bin"; 
		$mkiso = qq( -b $img -c $isolinux_dir/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table);
		push @chunk_first, $img;
		$graft->{"$isolinux_dir/boot.cat"} = 0;
	    } elsif ($bootimg) {
		log_("boot: el torito mode (bootimg $bootimg)\n", $config->{verbose}, $config->{LOG});
		$img = $bootimg->[0];
		$dir = $bootimg->[1]{dir};
		$img =~ s,(.*)/([^/]+)$,$2,;
		$dir or ($dir) = $1;
		$mkiso = qq( -b $dir/$img -c ${dir}/boot.cat);
		$graft->{"$dir/boot.cat"} = 0;
	    }
	    foreach (@{$fct->[1]{files}}) {
		my ($files, $opt) = @$_;
		my $dest = $opt->{dest};
		$size += du($files);
		my ($dirname) = $files =~ m,([^/]*)$,;
		log_("boot: files $files dest $dest dirname $dirname\n", $config->{verbose}, $config->{LOG});
		if ($img) { 
		    my $bimg = $bootimg->[0];
		    $bimg =~ s/^$dest\/$dirname//;
		    log_("boot: boot image $files/$bimg in $dir/$img (" . (stat "$files/$bimg")[7] . ")\n", $config->{verbose}, $config->{LOG});
		    if (-f "$files/$bimg") { 
			if ((stat "$files/$bimg")[7] > 3000000) { 
			    $mkiso .= qq( -no-emul-boot)
			}
			# $mkiso .= qq( $dir/$img=$files/$bimg)
			push @chunk_first, "$files/$bimg";
		    	$graft->{"$dir/$img"}{"$files/$bimg"} = 1
		    }
		}
		
		# if (-d "$files") { $mkiso .= " $dest/$dirname/=$files"; next }
		# $mkiso .= " $dest/=$files";
		if (-d $files) { 
		    $graft->{"$dest/$dirname/"}{$files} = 1 
		} else { 
		    $graft->{"$dest/"}{$files} = 1 
		}
		$dest =~ s,/+,/,g;
		if ($opt->{first}) {
		    push @chunk_first, $dest
		} else {
		    unshift @chunk, $dest 
		}
		push @chunk_first, "$dir/boot.cat"
	    }
	    # it is = and not .= because mkcdisos->[$cdnum] has been added already at the beginning
	    $mkisos->[$cdnum] = "$mkiso $mkisos->[$cdnum]";
	} else {
	    log_("FILES $fct->[1]{files}\n", $config->{verbose}, $config->{LOG});
	    foreach (@{$fct->[1]{files}}) {
		my ($files, $opt) = @$_;
		my $dest = "$config->{topdir}/build/$config->{name}/" . ($opt->{first} ? "first/" : "") . "$cdnum/";
		# FIXME first should ne obsolete, however it appears in several place, and the removal must be done with care
		-d $dest or mkpath $dest;
		my $odest = $opt->{dest};
		log_("boot: file $files (first $opt->{first} to $dest odest $odest)\n", $config->{verbose}, $config->{LOG});
		if ($odest) {
		    $dest .= "/$odest";
		    if ($odest =~ m,/$,) { mkpath $dest }
		} else {
		    my ($dirname) = $files =~ m,([^/]*)$,;
		    $dest .= "/$dirname"
		}
		$dest =~ s,/+,/,g;
		log_("boot: file $files (to $dest odest $odest)\n", $config->{verbose}, $config->{LOG});
		cpal($files, $dest, "(rr_moved|boot.cat)");
		if ($opt->{first}) {
		    push @chunk_first, $dest
		} else {
		    unshift @chunk, $dest 
		}
		push @chunk_first, "$dir/boot.cat"
	    }
	    if ($fct->[1]{oem}) {
		log_("boot: setting default boot to oem\n", $config->{verbose}, $config->{LOG});
		my $dest = "$config->{topdir}/build/$config->{name}/first/$cdnum/$isolinux_dir";
		-d $dest or mkpath $dest;
		my $old = "$dest/isolinux.cfg";
		my $new = "$dest/isolinux.cfg.new";
		copy $old, $new;
		unlink $old;
		link $new, $old;
		unlink $new;
		substInFile { s/default linux/default oem/ } $old
	    }
	    $graft->{"/"}{"$dir/first/$cdnum/"} = 1;
	    $size = du("$dir/first/$cdnum/", $inode);
	}
	push @{$sort->{$cdnum}}, \@chunk_first;
	unshift @{$sort->{$cdnum}}, \@chunk;
	return $size
    } elsif ($fixed == 1) {
	if (!$nolive) {
	    if ($isolinux) {
		my $img = $bootimg ? $bootimg->[0] : "$isolinux_dir/isolinux.bin"; 
		$mkisos->[$cdnum] .= qq( -b $img -c $isolinux_dir/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table "$config->{topdir}/build/$config->{name}/first/$cdnum");
		if (-f "$dir/$cdnum/$img") {
		    push @{$sort->{$cdnum}}, [ "$dir/$cdnum/$img" ];
		} elsif (-f "$dir/first/$cdnum/$img") {
		    push @{$sort->{$cdnum}}, [ "$dir/first/$cdnum/$img" ];
		}
		$graft->{"$isolinux_dir/boot.cat"} = 0
	    } elsif ($bootimg) {
		my $img = $bootimg->[0];
		my $sdir = $bootimg->[1]{dir};
		$img =~ s,(.*/)([^/]+)$,$2,;
		$sdir or ($sdir) = $1;
		$sdir =~ s,//+,/,g;
		$sdir =~ s,/$,,g;
		log_("boot: boot image $sdir/$img\n", $config->{verbose}, $config->{LOG});
		$mkisos->[$cdnum] .= qq(-b $sdir/$img);
		my $Bootdir;
		my $cdimages;
		log_("boot: try to find boot image in $cdimages/$bootimg->[0] and $dir/first/$cdnum/$bootimg->[0]\n", $config->{verbose}, $config->{LOG});
		if (-f "$cdimages/$bootimg->[0]") {
		    $cdimages = "$dir/$cdnum";
		    $Bootdir = "$dir/$cdnum/$sdir/";
		} elsif (-f "$dir/first/$cdnum/$bootimg->[0]") {
		    $cdimages = "$dir/first/$cdnum";
		    $Bootdir = "$dir/first/$cdnum/$sdir/";
		} else {
		    die "FATAL boot: could not find boot image\n";
		}
		if ((stat "$cdimages/$bootimg->[0]")[7] > 3000000) { 
		    $mkisos->[$cdnum] .= qq( -no-emul-boot)
		}
		push @{$sort->{$cdnum}}, [ "$cdimages/$bootimg->[0]" ];
		$Bootdir =~ s,//+,/,g;
		$Bootdir =~ s,/$,,g;
		if (! -f "$Bootdir/$img") {
		    if (! -d $Bootdir) { mkpath $Bootdir or die "cannot create $Bootdir\n" }
		    my $err = link "$cdimages/$bootimg->[0]", "$Bootdir/$img";
		    if (!$err) { log_("Linking failed $cdimages/$bootimg->[0]: $!\n", $config->{verbose}, $config->{LOG}) };
		}
		$mkisos->[$cdnum] .= qq( -c $sdir/boot.cat $dir/first/$cdnum);
		$graft->{"$sdir/boot.cat"} = 0;
		log_("BOOT $mkisos->[$cdnum]\n", $config->{verbose}, $config->{LOG});
	    }
	}
    }
}

sub installation {
    my ($class, $inst, $dir, $fixed, $nolive, $cdnum, $cd, $cdfile, $list, $mkisos, $totgraft, $inode, $discsFiles, $sort) = @_;
    my $graft = $totgraft->{$cdnum};
    my $install = $inst->[1]{install};
    my $struct_v = $config->{struct_version};
    my $struct = $config->{struct}{$struct_v};
    my ($isolinux_dir, $images_dir, $media_base, $extra_dir, $media_info, $install_dir, $compss_name) = ($struct->{isolinux}, $struct->{images}, $struct->{media_base}, $struct->{extra}, $struct->{media_info}, $struct->{install}, $struct->{compssUsers});
    if (!$fixed) {
	my $size;
	my $media_dir = $struct->{media};
	my $compss = $cd->{function}{data}{installation}[1]{compssUsers};
	$compss = "$install/$media_info/$compss_name" if !$compss && $install;
	if ($nolive) {
	    if ($install) {
		opendir my $A, $install;
		foreach (readdir $A) {
		    /~$/ and next;
		    /^(\.{1,2}|$install_dir|LICENSE-APPS\.txt|$isolinux_dir|$images_dir|VERSION|boot\.cat|rr_moved|$media_base)$/ and next;
		    $size += du("$install/$_");
		    if (-d "$install/$_") { $graft->{"/$_/"}{"$install/$_"} = 1; next }
		    $graft->{"/"}{"$install/$_"} = 1
		}

		local *A; opendir A, "$install/$install_dir";
		foreach (readdir A) {
		    log_("$install_dir -- $_\n", $config->{verbose}, $config->{LOG}, 3);
		    /~$/ and next;
		    # FIXME both old and new structure detailed
		    "$install_dir/$_" =~ m{^($install_dir/(\.{1,2}|$media_base))$|$media_dir|$extra_dir|$images_dir|$isolinux_dir} and next;
		    $size += du("$install/$install_dir/$_");
		    # if (-d "$install/Mandrake/$_") { $mkiso .= " Mandrake/$_/=$install/Mandrake/$_"; next }
		    # $graft->{"Mandrake/"}{"$install/Mandrake/$_"} = 1;
		    if (-d "$install/$install_dir/$_") { $graft->{"$install_dir/$_/"}{"$install/$install_dir/$_"} = 1; next }
		    $graft->{"$install_dir/"}{"$install/$install_dir/$_"} = 1;
		}

		local *A; opendir A, "$install/$media_info";
		foreach (readdir A) {
		    /~$/ and next; 
		    /(^(\.{1,2}|compss|provides|depslist.ordered|MD5SUM|pubkey.*|synthesis|$compss_name|rpmsrate|rpmslist|filelist|Serial|hashfile)|hdlist|cooker)/ and next;
		    $size += du("$install/$media_info/$_");
		    # if (-d "$install/Mandrake/base/$_") { $mkiso .= " Mandrake/base/$_/=$install/Mandrake/base/$_"; next}
		    # $mkiso .= " Mandrake/base/=$install/Mandrake/base/$_";
		    if (-d "$install/$media_info/$_") { $graft->{"$media_info/$_/"}{"$install/$media_info/$_"} = 1; next }
		    $graft->{"$media_info/"}{"$install/$media_info/$_"} = 1
		}
	    }
	    if (-f $compss) { 
		log_("installation: $compss_name $compss\n", $config->{verbose}, $config->{LOG}, 2);
		$size += du($compss);
		$graft->{"$media_info/$compss_name"}{$compss} = 1
	    } else { log_("ERROR installation: $compss file does not exist", $config->{verbose}, $config->{LOG}, 0) }
	} else {
	    if ($install) {
		cpal("$install/$install_dir","$dir/$cdnum/$install_dir","$install/*($extra_dir|$images_dir|($install_dir/*)?$isolinux_dir|$media_dir|$media_info)");
		cpal("$install/","$dir/$cdnum/","$install/*($install_dir|$images_dir|$isolinux_dir|$media_base|tutorial|misc|doc|LICENSE-APPS.txt|boot.cat|rr_moved)");
		cpal("$install/$media_info","$dir/$cdnum/$media_info","$install/*$media_info/*(hdlist|MD5SUM|pubkey|depslist|synthesis|rpmslist|filelist|Serial|hashfile|$compss_name|rpmsrate)");

		#cpal("$install/", "$dir/$cdnum", "($install/+(media/+|install/+(extra|images|isolinux)|(Mandrake/+base|media/+media_info)/+(hdlist|MD5SUM|pubkey|depslist|synthesis|rpmslist|filelist|Serial|hashfile|compssUsers|rpmsrate)|Mandrake/+RPMS|Mandrake/+share|isolinux|images|tutorial|misc|doc|LICENSE-APPS.txt|boot.cat|rr_moved))");
		if (!$inst->[1]{oem}) {
		    cpal("$install/tutorial", "$dir/$cdnum/tutorial") if -d "$install/tutorial";
		    cpal("$install/misc", "$dir/$cdnum/misc") if -d "$install/misc";
		    cpal("$install/doc", "$dir/$cdnum/doc") if -d "$install/doc";
		}

	    }
	    if (-f $compss) {
		my $path = "$dir/$cdnum/$media_info";
		-d $path or mkpath $path;
		log_("installation: $compss_name $compss\n", $config->{verbose}, $config->{LOG}, 2);
		cpal($compss, "$path/$compss_name");
	    } else { log_("ERROR installation: $compss file does not exist", $config->{verbose}, $config->{LOG}, 0) }
	}
	return $size
    } else {
	my $patch_dir = $struct->{patch};
	my $stage2 = $struct->{stage2};
	if ($nolive) {
	    my $size;
	    if ($inst->[1]{boot_medium}) {
		-d "$dir/$cdnum/$patch_dir" or mkpath "$dir/$cdnum/$patch_dir";
		my $file = "$dir/$cdnum/$patch_dir/patch-oem.pl";
		my $A;
		if (-f "$install/$patch_dir/patch-oem.pl") {
		    copy "$install/$patch_dir/patch-oem.pl", $file;
		    open $A, ">>$file" or print "ERROR installation: could not open $file for writing\n";
		} else {
		    open $A, ">$file" or print "ERROR installation: could not open $file for writing\n";
		}
		print $A "use install_any;
package install_any;

\$current_medium = $inst->[1]{boot_medium};
\$asked_medium = $inst->[1]{boot_medium};
		";
		$graft->{"$patch_dir/"}{$file} = 1;
		$size += du($file, $inode)
	    }
	    my ($repnum, $path, $pfile, $suppl_postfix) = buildInstallHdlist($dir, $cdnum, $inst, $list, $discsFiles, $sort, $nolive);
	    if ($install && $fixed == 1) {
		my $rpmsrate = $cd->{function}{data}{installation}[1]{rpmsrate} || "$install/$media_info/base/rpmsrate";
		# $mkiso = " Mandrake/base/=$path/compss Mandrake/base/=$path/depslist.ordered Mandrake/base/=$path/provides Mandrake/base/=$path/hdlists /=$pfile";
		$graft->{"$media_info/"}{"$path/compss"} = 1;
		$graft->{"$media_info/"}{"$path/depslist.ordered"} = 1; 
		$graft->{"$media_info/"}{"$path/provides"} = 1;
		$graft->{"$media_info/"}{"$path/hdlists"} = 1;
		$graft->{"$media_info/"}{"$path/MD5SUM"} = 1;
		$graft->{"/"}{$pfile} = 1;
		if (-f $rpmsrate) {
		    $size += du($rpmsrate);
		    # $mkiso .= " Mandrake/base/rpmsrate=$rpmsrate"
		    $graft->{"$media_info/rpmsrate"}{$rpmsrate} = 1
		} else { log_("ERROR installation: $rpmsrate file does not exist", $config->{verbose}, $config->{LOG}, 0); return 0 }
		$size += du("$path/compss", $inode);
		$size += du("$path/depslist.ordered");
		$size += du("$path/provides");
		$size += du($pfile, $inode);
		unshift @{$sort->{$cdnum}}, [ "$path/", "$install/$stage2" ]
	    }
	    my $version = "$dir/$cdnum/VERSION";
	    $size += du("$path/hdlists");
	    printVERSION($config->{name}, $version, $inst->[1]{tag});
	    $graft->{VERSION}{$version} = 1;
	    $size += du($version);	
	    foreach my $n (1 .. $repnum - 1) {
		# $mkiso .= " Mandrake/base/=$path/hdlist$n.cz";
		$graft->{"$media_info/"}{"$path/hdlist$n$suppl_postfix.cz"} = 1;
		# FIXME This is wrong, previous hdlist size must be deduced in iterative rebuild mode
		$size += du("$path/hdlist$n$suppl_postfix.cz");
		if (-f "$path/pubkey$n") { 
		    $graft->{"$media_info/"}{"$path/pubkey$n$suppl_postfix"} = 1;
		    $size += du("$path/pubkey$n$suppl_postfix");
		}
		if ($inst->[1]{synthesis}) {
		    # $mkiso .= " Mandrake/base/=$path/synthesis.hdlist$n.cz";
		    $graft->{"$media_info/"}{"$path/synthesis.hdlist$n$suppl_postfix.cz"} = 1;
		    $size += du("$path/synthesys.hdlist$n$suppl_postfix.cz")
		}
	    }
	    return $size;
	} else {
	    if (!$install) { mkpath "$dir/$cdnum/$media_info/" ; mkpath "$dir/$cdnum/$install_dir" }
	    if ($inst->[1]{boot_medium}) {
		log_("installation: boot_medium defined to $inst->[1]{boot_medium}\n", $config->{verbose}, $config->{LOG}, 2);
		my $file = "$dir/$cdnum/$patch_dir/patch-oem.pl";
		my $A;
		if (-f $file) {
		    unlink $file;
		    copy "$install/$patch_dir/patch-oem.pl", $file;
		    open $A, ">>$file" or print "ERROR installation: could not open $file for writing\n";
		} else {
		    open $A, ">$file" or print "ERROR installation: could not open $file for writing\n";
		}
		print $A "use install_any;
package install_any;

\$current_medium = $inst->[1]{boot_medium};
\$asked_medium = $inst->[1]{boot_medium};
";
	    } 
	    unlink "$dir/$cdnum/$media_info/hdlists";
	    buildInstallHdlist($dir, $cdnum, $inst, $list, $discsFiles, $sort);
	    if ($fixed == 1) {
		my $rpmsrate = $cd->{function}{data}{installation}[1]{rpmsrate} || "$install/$media_info/rpmsrate";
		if (-f $rpmsrate) {
		    log_("installation: rpmsrate: $rpmsrate\n", $config->{verbose}, $config->{LOG}, 2);
		    cpal($rpmsrate, "$dir/$cdnum/$media_info/rpmsrate");
		} else { log_("ERROR installation: $rpmsrate file does not exist", $config->{verbose}, $config->{LOG}, 0); return 0 }
		if ($install) {
		    unshift @{$sort->{$cdnum}}, [ "$dir/$cdnum/$media_info/", "$dir/$cdnum/$stage2" ]
		}
	    }
	    my $version = "$dir/$cdnum/VERSION";
	    unlink $version;
	    printVERSION($config->{name}, $version, $inst->[1]{tag});
	}
    }
}

1

# 
# Changeloh
#
# 2002 03 15
# new sources handling in installation
#
# 2002 03 19
# cdcom are now build as normal ones not to force deps, use standard list
#
# 2002 03 29
# fix a bug in nolive mode that prevent rpmsrate to be put on discs
#
# 2002 05 13
# finish md5 check
# fix commented du in sub installation
#
# 2002 08 01
# add noauto options for rpmsdir
#
# 2002 08 14
# fix little bug in buildGenericHdlists
#
# 2002 10 02 
# allow glob in rm function for live mode (need to do it for nolive mode)
#
# 20030401
# get_rpmsdir now manages hdlist dir
