summaryrefslogtreecommitdiffstats
path: root/perl-install/install_any.pm
blob: 185fa478088b32b2532b335f9f7e4083d85a323f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Diffstat (limited to 'man/C/urpmi.cfg.5')
-rw-r--r--man/C/urpmi.cfg.545
1 files changed, 24 insertions, 21 deletions
diff --git a/man/C/urpmi.cfg.5 b/man/C/urpmi.cfg.5
index bcbbd910..a97d8303 100644
--- a/man/C/urpmi.cfg.5
+++ b/man/C/urpmi.cfg.5
@@ -1,13 +1,10 @@
-.TH urpmi.cfg 5 "28 Aug 2003" "MandrakeSoft" "Mandrake Linux"
+.TH urpmi.cfg 5 "28 Aug 2003" "Mandrakesoft" "Mandrakelinux"
.IX urpmi.cfg
.SH NAME
urpmi.cfg \- urpmi option and media configuration file format.
.SH DESCRIPTION
-The urpmi.cfg file format is an enhancement of previous version of urpmi.cfg
-format.
-
-The file is divided in multiple sections: one section to set global options, and as
-many sections as needed for the description of the media managed.
+The urpmi.cfg file is divided in multiple sections: one section to set global
+options, and one section per media.
.SS Global options
@@ -27,7 +24,7 @@ The following options can be written in this section :
.TP
.B verify-rpm
Same as \fB--verify-rpm\fP for \fBurpmi\fP. Enable or disable signature
-checking should be used, enabled by default. Disabling it can be written
+checking (it's enabled by default). Disabling it can be written
in various ways (as for all the other boolean options) :
\fBno-verify-rpm\fP or \fBverify-rpm: no\fP or \fBverify-rpm: off\fP or
\fBverify-rpm: 0\fP.
@@ -58,13 +55,13 @@ Same as \fB--excludedocs\fP for \fBurpmi\fP, default is disabled.
.TP
.B limit-rate
Same as \fB--limit-rate\fP for all tools. This option allows to control download
-speed, there is no limitation by default. The number given is in Kilo-bytes per
-second unless a suffix \fBK\fP, \fBM\fP is given.
+speed, there is no limitation by default. The number is given in kilo-bytes per
+second, unless a suffix \fBK\fP, \fBM\fP is added.
.TP
.B excludepath
-Same as \fB--excludepath\fP for \fBurpmi\fP. This option allow to give comma
-separated list of path to be excluded on installation, there is no path
+Same as \fB--excludepath\fP for \fBurpmi\fP. This options allows to give a comma
+separated list of paths to be excluded on installation. There is no path
exclusion by default.
.TP
@@ -72,7 +69,7 @@ exclusion by default.
This option is not available on the command line. It allows to use a comma
separated list of \fBkey-ids\fP to be globally accepted (keys still need to be
authorized by \fBrpm\fP) for any medium unless a specific \fBkey-ids\fP option
-for this medium is given. There is no default (even MandrakeSoft key id 70771ff3
+for this medium is given. There is no default (even Mandrakesoft key id 70771ff3
is not by default).
.TP
@@ -87,6 +84,10 @@ Same as \fB--split-length\fP for \fBurpmi\fP. This option allows to control the
minimal length of split transaction. The default value is 1 (smallest possible
transaction). Setting this value to 0 disable the split of transaction.
+.TP
+.B downloader
+Specify which download program to use: \fBwget\fP or \fBcurl\fP.
+
.SS Medium description
A medium is described as follows :
@@ -99,18 +100,20 @@ A medium is described as follows :
.br
.B "}"
-where \fBname\fP is name of medium (space character are prefixed by anti-slash)
-and optional \fBurl\fP is url of the medium (if no \fBurl\fP is given, it will
-be guessed according to so mandatory list file).
+where \fBname\fP is the medium name (space characters are prefixed by a backslash)
+and where the optional \fBurl\fP is the medium URL (if no \fBurl\fP is given, it will
+be guessed according to the mandatory list file).
Most other options like \fBlist\fP, \fBwith_hdlist\fP, \fBsynthesis\fP,
\fBremovable\fP, \fBvirtual\fP are for internal use and should be changed only
-for experienced users.
-
-But options like \fBupdate\fP, \fBignore\fP or \fBkey-ids\fP can be modified by
-users to mark medium as an update, to ignore medium or to give allowed GPG key
-ids for packages of the medium for verification (unless of course signature
-checking has been disabled globally).
+by experienced users.
+
+Options like \fBupdate\fP, \fBignore\fP or \fBkey-ids\fP can be modified by
+users to respectively mark mediums as update sources, to have them being
+ignored, or to specify the allowed GPG key ids for packages from the medium for
+verification (unless of course signature checking has been disabled globally).
+It's also possible to override \fBverify-rpm\fP and \fBdownloader\fP in
+a medium description.
Please note that \fBkey-ids\fP is automatically set by \fBurpmi.update\fP or
\fBurpmi.addmedia\fP if a remote pubkey file is available on the mirror. This
75' href='#n275'>275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
package install_any;

use diagnostics;
use strict;
use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK);

@ISA = qw(Exporter);
%EXPORT_TAGS = (
    all => [ qw(getNextStep spawnShell addToBeDone) ],
);
@EXPORT_OK = map { @$_ } values %EXPORT_TAGS;

#-######################################################################################
#- misc imports
#-######################################################################################
use common qw(:common :system :functional :file);
use commands;
use run_program;
use partition_table qw(:types);
use partition_table_raw;
use devices;
use fsedit;
use network;
use modules;
use lilo;
use detect_devices;
use pkgs;
use fs;
use log;


#-######################################################################################
#- Functions
#-######################################################################################
sub relGetFile($) {
    local $_ = $_[0];
    my $dir = m|/| ? "mdkinst" :
      (member($_, qw(compss compssList compssUsers depslist hdlist)) ? "base" : "RPMS");
    $_ = "Mandrake/$dir/$_";
    s/i386/i586/;
    $_;
}
sub getFile($) {
    local $^W = 0;
    if ($::o->{method} && $::o->{method} eq "ftp") {
	require 'ftp.pm';
	*install_any::getFile = \&ftp::getFile;
    } elsif ($::o->{method} && $::o->{method} eq "http") {
	require 'http.pm';
	*install_any::getFile = \&http::getFile;
    } else {
	*install_any::getFile = sub($) {
	    open getFile, "/tmp/rhimage/" . relGetFile($_[0]) or return;
	    *getFile;
	};
    }
    goto &getFile;
}

sub kernelVersion {
    local $_ = readlink("$::o->{prefix}/boot/vmlinuz") || $::testing && "vmlinuz-2.2.testversion" or die "I couldn't find the kernel package!";
    first(/vmlinuz-(.*)/);
}


sub getNextStep {
    my ($s) = $::o->{steps}{first};
    $s = $::o->{steps}{$s}{next} while $::o->{steps}{$s}{done} || !$::o->{steps}{$s}{reachable};
    $s;
}

sub spawnShell {
    return if $::o->{localInstall} || $::testing;

    -x "/bin/sh" or die "cannot open shell - /usr/bin/sh doesn't exist";

    fork and return;

    local *F;
    sysopen F, "/dev/tty2", 2 or die "cannot open /dev/tty2 -- no shell will be provided";

    open STDIN, "<&F" or die '';
    open STDOUT, ">&F" or die '';
    open STDERR, ">&F" or die '';
    close F;

    c::setsid();

    ioctl(STDIN, c::TIOCSCTTY(), 0) or warn "could not set new controlling tty: $!";

    exec {"/bin/sh"} "-/bin/sh" or log::l("exec of /bin/sh failed: $!");
}

sub shells($) {
    my ($o) = @_;
    my @l = grep { -x "$o->{prefix}$_" } @{$o->{shells}};
    @l ? @l : "/bin/bash";
}

sub getAvailableSpace {
    my ($o) = @_;

    do { $_->{mntpoint} eq '/usr' and return int($_->{size} * 512 / 1.07) } foreach @{$o->{fstab}};
    do { $_->{mntpoint} eq '/'    and return int($_->{size} * 512 / 1.07) } foreach @{$o->{fstab}};

    if ($::testing) {
	log::l("taking 200MB for testing");
	return 200 << 20;
    }
    die "missing root partition";
}

sub setPackages($) {
    my ($o) = @_;

    if (is_empty_hash_ref($o->{packages})) {
	my $useHdlist = $o->{method} !~ /nfs|hd/ || $o->{isUpgrade};
	eval { $o->{packages} = pkgs::psUsingHdlist() }  if $useHdlist;
	$o->{packages} = pkgs::psUsingDirectory() if !$useHdlist || $@;

	push @{$o->{default_packages}}, "nfs-utils-clients" if $o->{method} eq "nfs";
	push @{$o->{default_packages}}, "numlock" if $o->{miscellaneous}{numlock};
	push @{$o->{default_packages}}, "kernel-smp" if detect_devices::hasSMP();
	push @{$o->{default_packages}}, "kernel-pcmcia-cs" if $o->{pcmcia};
	push @{$o->{default_packages}}, "raidtools" if !is_empty_hash_ref($o->{raid});

	pkgs::getDeps($o->{packages});

	my $c; ($o->{compss}, $c) = pkgs::readCompss($o->{packages});
	$o->{compssListLevels} = pkgs::readCompssList($o->{packages}, $c, $o->{lang});
	$o->{compssUsers} = pkgs::readCompssUsers($o->{packages}, $o->{compss});

	grep { !$o->{packages}{$_} && log::l("missing base package $_") } @{$o->{base}} and die "missing some base packages";
    } else {
    	$_->{selected} = 0 foreach values %{$o->{packages}};
    }

    #- this will be done if necessary in the selectPackagesToUpgrade,
    #- move the selection here ? this will remove the little window.
    unless ($o->{isUpgrade}) {
	do {
	    my $p = $o->{packages}{$_} or log::l("missing base package $_"), next;
	    pkgs::select($o->{packages}, $p, 1);
	} foreach @{$o->{base}};
	do {
	    my $p = $o->{packages}{$_} or log::l("missing add-on package $_"), next;
	    pkgs::select($o->{packages}, $p);
	} foreach @{$o->{default_packages}};
    }
}

sub selectPackagesToUpgrade($) {
    my ($o) = @_;

    pkgs::selectPackagesToUpgrade($o->{packages}, $o->{prefix}, $o->{base});
}

sub addToBeDone(&$) {
    my ($f, $step) = @_;

    return &$f() if $::o->{steps}{$step}{done};

    push @{$::o->{steps}{$step}{toBeDone}}, $f;
}

sub getHds {
    my ($o) = @_;
    my ($ok, $ok2) = 1;

    my @drives = detect_devices::hds();
    add2hash_($o->{partitioning}, { readonly => 1 }) if partition_table_raw::typeOfMBR($drives[0]{device}) eq 'system_commander';

  getHds: 
    $o->{hds} = catch_cdie { fsedit::hds(\@drives, $o->{partitioning}) }
      sub {
	my ($err) = $@ =~ /(.*) at /;
	$@ =~ /overlapping/ and $o->ask_warn('', $@), return 1;
	$o->ask_okcancel(_("Error"),
[_("I can't read your partition table, it's too corrupted for me :(
I'll try to go on blanking bad partitions"), $err]) unless $o->{partitioning}{readonly};
	$ok = 0; 1 
    };

    if (is_empty_array_ref($o->{hds}) && $o->{autoSCSI}) {
	$o->setupSCSI; #- ask for an unautodetected scsi card
	goto getHds;
    }

    ($o->{hds}, $o->{fstab}, $ok2) = fsedit::verifyHds($o->{hds}, $o->{partitioning}{readonly}, $ok);

    fs::check_mounted($o->{fstab});

    $o->{partitioning}{clearall} and return 1;
    $o->ask_warn('', 
_("DiskDrake failed to read correctly the partition table.
Continue at your own risk!")) if !$ok2 && $ok && !$o->{partitioning}{readonly};

    $ok2;
}

sub searchAndMount4Upgrade {
    my ($o) = @_;
    my ($root, $found);

    my $w = $::beginner && $o->wait_message('', _("Searching root partition."));

    $o->{partitioning}{readonly} = 1;

    #- try to find the partition where the system is installed if beginner
    #- else ask the user the right partition, and test it after.
    getHds($o);

    #- get all ext2 partition that may be root partition.
    my %Parts = my %parts = map { $_->{device} => $_ } grep { isExt2($_) } @{$o->{fstab}};
    while (keys(%parts) > 0) {
	$root = $::beginner ? first(%parts) : $o->selectRootPartition(keys %parts);
	$root = delete $parts{$root};

	my $r; unless ($r = $root->{realMntpoint}) {
	    $r = $o->{prefix};
	    $root->{mntpoint} = "/"; 
	    log::l("trying to mount partition $root->{device}");
	    eval { fs::mount_part($root, $o->{prefix}, 'readonly') };
	    $r = "/*ERROR*" if $@;
	}
	$found = -d "$r/etc/sysconfig" && [ fs::read_fstab("$r/etc/fstab") ];

	unless ($root->{realMntpoint}) {
	    log::l("umounting partition $root->{device}");
	    eval { fs::umount_part($root, $o->{prefix}) };
	}

	last if !is_empty_array_ref($found);

	delete $root->{mntpoint};
	$o->ask_warn(_("Information"), 
		     _("%s: This is not a root partition, please select another one.", $root->{device})) unless $::beginner;
    }
    is_empty_array_ref($found) and die _("No root partition found");
	
    log::l("found root partition : $root->{device}");

    #- test if the partition has to be fschecked and remounted rw.
    if ($root->{realMntpoint}) {
	($o->{prefix}, $root->{mntpoint}) = ($root->{realMntpoint}, '/');
    } else {
	delete $root->{mntpoint};
	($Parts{$_->{device}} || {})->{mntpoint} = $_->{mntpoint} foreach @$found;

	#- TODO fsck, create check_mount_all ?
	fs::mount_all([ grep { isExt2($_) || isSwap($_) } @{$o->{fstab}} ], $o->{prefix});
    }
}

sub write_ldsoconf {
    my ($prefix) = @_;
    my $file = "$prefix/etc/ld.so.conf";

    #- write a minimal ld.so.conf file unless it already exists.
    unless (-s "$file") {
	local *F;
	open F, ">$file" or die "unable to open for writing $file";
	print F "/usr/lib\n";
    }
}

sub setAuthentication() {
    my ($shadow, $md5, $nis, $nis_server) = @{$::o->{authentication} || {}}{qw(shadow md5 NIS NIS_server)};
    my $p = $::o->{prefix};
    enableMD5Shadow($p, $shadow, $md5);
    enableShadow() if $shadow;
    if ($nis) {
	pkg_install($::o, "ypbind");
	my $domain = $::o->{netc}{NISDOMAIN};
	$domain || $nis_server ne "broadcast" or die _("Can't use broadcast with no NIS domain");
	my $t = $domain ? "domain $domain" . ($nis_server ne "broadcast" && " server")
	                : "ypserver";
	substInFile {
	    $_ = "#~$_" unless /^#/;
	    $_ .= "$t $nis_server\n" if eof;
	} "$p/etc/yp.conf";
	network::write_conf("$p/etc/sysconfig/network", $::o->{netc});
    }
}

sub enableShadow() {
    my $p = $::o->{prefix};
    run_program::rooted($p, "pwconv")  or log::l("pwconv failed");
    run_program::rooted($p, "grpconv") or log::l("grpconv failed");

#-    my $chpasswd = sub {
#-	  my ($name, $password) = @_;
#-	  $password =~ s/"/\\"/;
#-
#-	  local *log::l = sub {}; #- disable the logging (otherwise password visible in the log)
#-	  run_program::rooted($p, qq((echo "$password" ; sleep 1 ; echo "$password") | passwd $name));
#-#-	run_program::rooted($p, "echo $name:$password | chpasswd");
#-    };
#-    &$chpasswd("root", $::o->{superuser}{password});
#-    &$chpasswd($_->{name}, $_->{password}) foreach @{$::o->{users} || []};
}

sub enableMD5Shadow($$$) {
    my ($prefix, $shadow, $md5) = @_;
    substInFile {
	if (/^password.*pam_pwdb.so/) {
	    s/\s*shadow//; s/\s*md5//;
	    s/$/ shadow/ if $shadow;
	    s/$/ md5/ if $md5;
	}
    } grep { -r $_ } map { "$prefix/etc/pam.d/$_" } qw(login rlogin passwd);
}

sub crypt($) {
    my ($password) = @_;

    $::o->{authentication}{md5} ?
      c::crypt_md5($password, salt(8)) :
         crypt    ($password, salt(2));
}

sub lnx4win_postinstall {
    my ($prefix) = @_;
    my $dir = "/dos/lnx4win";
    my $kernel = "$dir/vmlinuz";
    rename $kernel, "$kernel.old";
    commands::dd("if=$prefix/boot/vmlinuz", "of=$kernel");
    run_program::run("rdev", $kernel, "/dev/loop7");

    unlink "$dir/size.txt";
    unlink "$dir/swapsize.txt";

    mkdir "$prefix/initrd", 0755;
    symlinkf "/initrd/dos", "$prefix/mnt/dos";
}

sub killCardServices {
    my $pid = chop_(cat_("/tmp/cardmgr.pid"));
    $pid and kill(15, $pid); #- send SIGTERM
}

sub unlockCdrom() {
    cat_("/proc/mounts") =~ m|/tmp/(\S+)\s+/tmp/rhimage|;
    eval { ioctl detect_devices::tryOpen($1), c::CDROM_LOCKDOOR(), 0 };
}
sub ejectCdrom() {
    cat_("/proc/mounts") =~ m|/tmp/(\S+)\s+/tmp/rhimage|;
    my $f = eval { detect_devices::tryOpen($1) } or return;
    getFile("XXX"); #- close still opened filehandle
    eval { fs::umount("/tmp/rhimage") };
    ioctl $f, c::CDROMEJECT(), 1;
}

sub setupFB {
    my ($o, $vga) = @_;

    #- install needed packages for frame buffer.
    pkgs::select($o->{packages}, $o->{packages}{'kernel-fb'});
    pkgs::select($o->{packages}, $o->{packages}{'XFree86-FBDev'});
    $o->installPackages($o->{packages});

    $vga ||= 785; #- assume at least 640x480x16.

    #- update lilo entries with a new fb label. a bit hack unless
    #- a frame buffer kernel is used, in such case we use it instead
    #- with the right mode, nothing more to do.
    if ($o->{bootloader}{entries}{'/boot/vmlinuz-smp'}) {
	$o->{bootloader}{entries}{'/boot/vmlinuz-smp'}{vga} = $vga;
	lilo::install($o->{prefix}, $o->{bootloader});
    } else {
	my $root = $o->{bootloader}{entries}{'/boot/vmlinuz'}{root};
	if (lilo::add_kernel($o->{prefix}, $o->{bootloader}, kernelVersion(), 'fb',
			     {
			      label => 'linux-fb',
			      root => $root,
			      vga => $vga,
			     })) {
	    $o->{bootloader}{default} = 'linux-fb';
	    lilo::install($o->{prefix}, $o->{bootloader});
	} else {
	    log::l("unable to install kernel with frame buffer support, disabling");
	    return 0;
	}
    }
    1;
}

sub auto_inst_file() { ($::g_auto_install ? "/tmp" : "$::o->{prefix}/root") . "/auto_inst.cfg.pl" }

sub g_auto_install(;$) {
    my ($f) = @_; $f ||= auto_inst_file;
    my $o = {};

    $o->{default_packages} = [ map { $_->{name} } grep { $_->{selected} && !$_->{base} } values %{$::o->{packages}} ];

    my @fields = qw(mntpoint type size);
    $o->{partitions} = [ map { my %l; @l{@fields} = @$_{@fields}; \%l } grep { $_->{mntpoint} } @{$::o->{fstab}} ];
    
    exists $::o->{$_} and $o->{$_} = $::o->{$_} foreach qw(lang autoSCSI authentication printer mouse netc timezone superuser intf keyboard mkbootdisk base users installClass partitioning isUpgrade manualFstab nomouseprobe crypto); #- TODO modules bootloader 

    if (my $card = $::o->{X}{card}) {
	$o->{X}{card}{$_} = $card->{$_} foreach qw(default_depth);
	$o->{X}{card}{resolution_wanted} ||= join "x", @{$card->{depth}{$card->{default_depth}}[0]} if $card->{depth};
    }

#-    local $o->{partitioning}{clearall} = 1;

    $_ = { %{$_ || {}} }, delete @$_{qw(oldu oldg password password2)} foreach $o->{superuser}, @{$o->{users} || []};
    
    local *F;
    open F, ">$f" or log::l("can't output the auto_install script in $f"), return;
    print F Data::Dumper->Dump([$o], ['$o']), "\0";
}

sub loadO {
    my ($O, $f) = @_; $f ||= auto_inst_file;
    my $o;
    if ($f =~ /^(floppy|patch)$/) {
	my $f = $f eq "floppy" ? "auto_inst.cfg" : "patch";
	unless ($::testing) {
	    fs::mount(devices::make("fd0"), "/mnt", "vfat", 0);
	    $f = "/mnt/$f";
	}
	-e $f or $f .= ".pl";

	my $b = before_leaving {
	    fs::umount("/mnt") unless $::testing;
	    modules::unload($_) foreach qw(vfat fat);
	};
	$o = loadO($O, $f);
    } else {
	-e $f or $f .= ".pl";
	{
	    local *F;
	    open F, $f or die _("Error reading file $f");

	    local $/ = "\0";
	    no strict;
	    eval <F>;
	}
	$@ and log::l _("Bad kickstart file %s (failed %s)", $f, $@);
	add2hash_($o ||= {}, $O);
    }
    bless $o, ref $O;
}

sub pkg_install {
    my ($o, $name) = @_;
    pkgs::select($o->{packages}, $o->{packages}{$name} || die "$name rpm not found");
    install_steps::installPackages ($o, $o->{packages});
}

sub fsck_option() {
    my $y = $::o->{security} < 3 && $::beginner ? "-y " : "";
    substInFile { s/^(\s*fsckoptions="?)(-y )?/$1$y/ } "$::o->{prefix}/etc/rc.d/rc.sysinit";
}

sub install_urpmi {
    my ($prefix, $method) = @_;

    (my $name = _("installation")) =~ s/\s/_/g; #- in case translators are too good :-/

    my $f = "$prefix/etc/urpmi/hdlist.$name";
    {
	my $fd = getFile("hdlist") or return;
	local *OUT;
	open OUT, ">$f" or log::l("failed to write $f"), return;
	local $/ = \ (16 * 1024);
	print OUT foreach <$fd>;
    }
    {
	local *F = getFile("depslist");
	output("$prefix/etc/urpmi/depslist", <F>);
    }
    {
	local *LIST;
	open LIST, ">$prefix/etc/urpmi/list.$name" or log::l("failed to write list.$name"), return;

	my $dir = ${{ nfs => "file://mnt/nfs", 
		      ftp => $ENV{URLPREFIX}, 
		      http => $ENV{URLPREFIX}, 
		      cdrom => "removable_cdrom_1://mnt/cdrom" }}{$method};
	local *FILES; open FILES, "hdlist2files $f|";
	chop, print LIST "$dir/Mandrake/RPMS/$_\n" foreach <FILES>;
	close FILES or die "hdlist2files failed";

	$dir .= "/Mandrake/RPMS with ../base/hdlist" if $method =~ /ftp|http/;
	eval { output "$prefix/etc/urpmi/urpmi.cfg", "$name $dir\n" };
    }
}

sub list_home($) {
    my ($prefix) = @_;
    local *F; open F, "$prefix/etc/passwd";
    map { $_->[5] } grep { $_->[2] > 501 } map { [ split ':' ] } <F>;
}

sub template2userfile($$$$%) {
    my ($prefix, $inputfile, $outputrelfile, $force, %toreplace) = @_;

    foreach ("/etc/skel", "/root", list_home($prefix)) {
	my $outputfile = "$prefix/$_/$outputrelfile";
	if (-d dirname($outputfile) && ($force || ! -e $outputfile)) {
	    log::l("generating $outputfile from template $inputfile");
	    template2file($inputfile, $outputfile, %toreplace);
	}
    }
}

sub kdeicons_postinstall {
    my ($prefix) = @_;

    #- parse etc/fstab file to search for dos/win, zip, cdroms icons.
    #- avoid rewriting existing file.
    local *F;
    open F, "$prefix/etc/fstab" or log::l("failed to read $prefix/etc/fstab"), return;

    foreach (<F>) {
	if (/^\/dev\/(\S+)\s+\/mnt\/cdrom (\d*)\s+/x) {
	    my %toreplace = ( device => $1, id => $2 );
	    template2userfile($prefix, "/usr/share/cdrom.kdelnk.in", "Desktop/cdrom$2.kdelnk", 0, %toreplace);
	} elsif (/^\/dev\/(\S+)\s+\/mnt\/zip (\d*)\s+/x) {
	    my %toreplace = ( device => $1, id => $2 );
	    template2userfile($prefix, "/usr/share/zip.kdelnk.in", "Desktop/zip$2.kdelnk", 0, %toreplace);
	} elsif (/^\/dev\/(\S+)\s+\/mnt\/DOS_ (\S*)\s+/x) {
	    my %toreplace = ( device => $1, id => $2 );
	    template2userfile($prefix, "/usr/share/Dos_.kdelnk.in", "Desktop/Dos_$2.kdelnk", 0, %toreplace);
	}
    }
}

1;