#!/usr/bin/perl
use strict;
use warnings;
use v5.10;

use LWP::Simple qw(!head);
use File::Basename;
use File::Copy;
use File::stat;
use Fcntl qw(:flock :mode O_CREAT O_RDWR O_EXCL SEEK_SET);
use Getopt::Std;
use Encode qw/from_to/;
use POSIX 'setsid';
use File::Pid;
use Data::Dumper;
use Cwd qw(getcwd);

use vars qw($opt_r $opt_i $opt_u $opt_k $opt_S $opt_d $opt_v $opt_p $opt_a $opt_s $opt_g $opt_G $opt_I $opt_P $opt_q $opt_U $opt_D $opt_C $opt_o);

require '/usr/lib/kwartz/control/sharelib.pl';		#load common fonctions and defintion

# libenum-perl n'est pas prsent sur Kwart, il faut faire sans
##
use constant {
	RET_OK 				=>  0, # OK
	RET_ERROR			=>  1, # Erreur diverse
	RET_VARSIZE			=>  2, # /var trop petit
	RET_HOMESIZE		=>  3, # /home trop petit
	RET_OLDINSTALL		=>  4, # Erreur ancienne installation
	RET_INSTALLPENDING	=>  5, # Installation en cours
	RET_NOKEY			=>  6, # Pas de cl
	RET_CLUSTER			=>  7, # Mode cluster (obsolte)
	RET_VALIDATE		=>  8, # Echec validate()
	RET_APTUPDATE		=>  9, # Echec fsm AptUpdate
	RET_RENEWOK			=> 10, # Renew OK
	RET_RENEWKO			=> 11, # Echec renew
	RET_DAEMON			=> 12, # Exit from daemonize
	RET_DAEMONEND		=> 13, # daemon ended
	RET_ROOTSIZE		=> 14, # / trop petit
	RET_PRE_UPDATEVERSION	=> 20,  # Echec de prparation mise  jour iso
	RET_UPDATEVERSION	=> 30  # Echec de mise  jour iso
};

my $VARLOGFILE	= "/var/log/kwartz-update.log";
my $LOGFILE		= "/root/kwartz-configuration.log";
my $STATEFILE	= "/var/cache/kwartz/kwartz-autoupdate.state";	# Conservation de l'tat de la FSM pour interrogation
my $RUNDIR		= "/run/kwartz-autoupdate";						# Rpertoire de travail temporaire
my $SOURCE		= "/etc/kwartz/sources.list.d/kwartz.list";		# sources.list dpt kwartz
my $SOURCEREDIS	= "/etc/kwartz/sources.list.d/redis.list";		# sources.list dpt redis
my $SOURCESAMBA416 = "/etc/kwartz/sources.list.d/samba416corpit.list";	# sources.list dpt corpit samba 4.16
my $SOURCESAMBA4 = "/etc/kwartz/sources.list.d/samba4corpit.list";	# sources.list dpt corpit samba4
my $SOURCECORRIUM  = "/etc/kwartz/sources.list.d/corrium.list";			# sources.list dpt corrium
my $SOURCE_S	= "/etc/kwartz/sources_s.list";					# sources.list dpts ubuntu principal et scurit
my $UPDATE_CACHE ="/var/cache/kwartz/autoupdate";				# Cache de rsultat
my $SEM 		= "/tmp/".basename($0).".lck";					# Smaphore de protection logfile en rentrance

my $ver;						# Version du Kwartz X.YrZ
my $type;						# Produit : Server, KmcBox...
my $autoupdate;					# rpertoire: autoupdatek, autoupdate5...
my ($licence, $key);			# Num licence et cl produit
my ($upd_user, $upd_pass);		# Renvoy par validate, par dfaut (licence,cl)
my ($krel, $kver);				# kernel release (5.8.0-53-generic) / kernel ver (#60~20.04.1-Ubuntu SMP Thu May 6 09:52:46 UTC 2021)
my $debname;					# Non distrib : lenny, precise, xenial, focal...
my @updateduri=();				# URI utilises dans les sources.list
my $restricted = "";			# deprecated ?
my $gres = RET_OK;				# Retour du script	
my $gIso = "";					# Image iso pour mise  jour distrib
my $gStateHandler = undef;		# Registre d'tat de la FSM
my @callerchain = ();			# Chemin d'appel  partir d'init
my %aptsyntax;					# Handle apt deprecations
my $reentrancy = 0;				# We are called again
###

# acquire_lock
# Paramtres :
#  semaphore
#  timeoutms
#  intervalms
# Valeur de retour :
#  0 $fh: Lock OK
#  1 : timeout
#  2 : Erreur
# Usage :
#  my ($res, $handle) = acquire_lock ($SEM, 600000, 100);
sub acquire_lock {
	my ($semaphore, $timeoutms, $intervalms) = @_;
	open (my $fh, ">$semaphore") or return 2;
	my $count = $timeoutms/$intervalms + 1;
	while ($count--) {
		return (0, $fh) if (flock($fh, LOCK_EX|LOCK_NB));
		select(undef, undef, undef, $intervalms/1000.0);
	}
    return 1;
}

# release_lock
# Paramtres :
#  $fh
# Usage :
#  release_lock ($handle);
sub release_lock {
	my ($fh) = @_;
	flock($fh, LOCK_UN) if (defined ($fh));
}


# myexitlog("comment stdout", "comment logfile", value);
# exit avec log dans le logfile et sortie sur STDOUT
# Impose un affichage sur STDOUT si valeur de sortie != 0 et $opt_v, sauf si on passe chaine vide
# (Impose de rcrire les myexitlog avec les strings de sortie en premier paramtre)
##
sub myexitlog
{
	my ($output, $comment, $exitval) = @_;
	
	if (defined($output)) {
		print "$output\n" if ($output ne "");
	} elsif (defined($opt_v) && ($exitval != 0)) {	# Force un affichage gnrique si sortie en erreur
		print "erreur\n";
	}
	
	unless (($reentrancy gt 0) ||
			defined($opt_C) ||
			($exitval == RET_INSTALLPENDING)
		) {
		# copy log data into rotating log
		my ($res1, $handle1) = acquire_lock ($SEM, 1000, 10); # 1 seconde
		if ( -f $VARLOGFILE ) {
			my $size = -s $VARLOGFILE;
			if ($size > 0) {
				mklogfile() unless (-l $LOGFILE);
				mysystem("cat $VARLOGFILE >> $LOGFILE");
				unlink "$VARLOGFILE";
			}
		}
		release_lock($handle1);
	}
	
	# Print comment into rotating log (link)
	if (defined($comment)) {
		if ( open (FH, ">>$LOGFILE") ) {
			my $dateexit = `date`; chomp ($dateexit);
			print FH "$dateexit : $comment (caller: $callerchain[0]->{'cmndline'}) (sortie: $exitval)\n";
			close (FH);
		}
	
		#TODO : On ne ferait pas systmatiquement une sortie sur stderr ???
		print STDERR "$comment\n" if ($exitval != 0 and ($opt_v or $opt_U));
		open RESULT, ">", "$RUNDIR/$$.res";
		print RESULT "$comment";
		close RESULT;
	}
	
	# Cleanup progress file
	if (defined ($gStateHandler)) {
		close $gStateHandler;
		unlink("$RUNDIR/$$.progress");
	}
	my $pidfile = File::Pid->new({file => "$RUNDIR/".basename($0).".pid"});
	$pidfile->remove if ($$ == $pidfile->pid);
	exit $exitval;
}



sub mklogfile
{
    my $log_rep = "/root/kwartz";
    my $date = `date '+%Y%m%d'`; chomp ($date);

    mkdir ($log_rep) if ( ! -d "$log_rep" );
    if (( -f $LOGFILE ) && (! -l $LOGFILE)) { # Uniquement  l'installation
		system ("mv $LOGFILE $log_rep/.");
		symlink ("$log_rep/kwartz-configuration.log", $LOGFILE);
    }

	my $name = "$log_rep/kwartz-configuration.log.$date";
	for (my $loop=0; ( -f "$name" ); $loop++ ) {
		$name = "$log_rep/kwartz-configuration.log.$date-$loop";
    }
    if ( ! open (FH, ">$name")) {
	    warn "cannot touch $name: $!";
		return 1;
	} else {
		print FH "Kwartz $type $ver\n";
		print FH "kwartz-autoupdate ";
		print FH `dpkg-query --showformat=\'\${Version}\' --show kwartz-autoupdate`;
		print FH "\n";
		print FH `date`;
		close (FH);
		unlink ($LOGFILE) if ( -l $LOGFILE );
		symlink ($name, $LOGFILE);
	}
	return 0;
}


##  Various exec commands
# mysystem ($command)
#	input : command
#	return value : $?
#
# myback ($command)
#	input : command
#	return value : @result
#
# mypopenprint ($command, \@answers)
#	input : command
#	output (if defined) : @result
#	return value : $?
#
#	$? :	($? & 127) : value of signal when command died
#			($? & 128) : coredumped 
#			command_result<<8
##

#use enum qw(BITMASK:LOG_ STDOUT STDERR LOGFILE);
use constant {
    LOG_STDOUT          =>  1,
    LOG_STDERR          =>  2,
    LOG_LOGFILE         =>  4,
};

sub _ExecLog
{
	my $command = shift;
	my %opts = (
		flags => LOG_STDOUT,
		logfile => '',
		autoflush => 1,
		trail => 0,
		resmsgref => undef,
		@_);
	my $resmsgref = $opts{'resmsgref'};
	my $fh = undef;
	# mode appel cgi pour waitpid
	if (length($opts{'logfile'} // '') > 0) {
		open ($fh, ">>".$opts{'logfile'});
	}
	# Turn on autoflush
	if ($opts{'autoflush'} == 1) {
		select((select($fh), $|=1)[0]) if (defined($fh));
		select((select(STDOUT), $|=1)[0]) if ($opts{'flags'} & LOG_STDOUT);
		select((select(STDERR), $|=1)[0]) if ($opts{'flags'} & LOG_STDERR);
	}

	# Print command if debug
	print STDOUT "$command\n" if ($opt_d && ($opts{'flags'} & LOG_STDOUT));
	print STDERR "$command\n" if ($opt_d && ($opts{'flags'} & LOG_STDERR));

	open CMD, "$command |" or die;
	while (<CMD>) {
		print STDERR $_ if ($opts{'flags'} & LOG_STDERR);
		print STDOUT $_ if ($opts{'flags'} & LOG_STDOUT);
		print $fh $_ if (defined($fh));
		if (defined($resmsgref)) {
			chomp if ($opts{'trail'} == 1);
			push (@$resmsgref, $_);
		}
	}
	close CMD; # to get $?
	my $resapt=$?;
	close $fh if (defined($fh));
	return ($resapt);
}


sub mysystem
{
 	print "$_[0]\n" if ($opt_d); 
	return system ($_[0]);
}

sub myback
{
	print "$_[0]\n" if ($opt_d); 
	return `$_[0]`;
}

# mypopenprint ($command, \@answers)
sub mypopenprint
{
	my ($command, $resmsgref) = @_;
	
	return _ExecLog($command, flags=>(LOG_STDOUT), resmsgref=>$resmsgref);
}
##

## check_kwartzdistupgrade
# 	Teste si une mise  jour ->8 est en cours
#   Valeur de retour:
#		0 : Pas de mise  jour
#		1 : Mise  jour en cours
##
sub check_kwartzdistupgrade
{
	return 1 if ( -f "/run/kwartz-update" );
	return 0;
}
##

# validate() -> ($val, $date, $user, $pass)
sub validate
{
	my @valid = ("ER", "00000000", "", "");
	my $VAL_IP=`wget --timeout=20 -t 1 -q -O - https://www.kwartz.com/scripts/ip.php`;
	if ($VAL_IP eq "") {
		$VAL_IP = "0.0.0.0";
	}

	# Kwartz::Server library is present?
	my $VAL_SID = eval {
		require Kwartz::Server;
		Kwartz::Server->uuid;
	};
	unless (defined($VAL_SID)) {
	# No: fallback
		$VAL_SID="A7C8E559-19E1-8A8F-532C-".`pcinetsetup 2>/dev/null |grep 'eth0.*MAC'|cut -d ':' -f3- |sed -e 's/ //g' -e 's/://g'`;
		chomp $VAL_SID;
		if ( -r "/sys/class/dmi/id/product_uuid" ) {
			my $PRODUCT_UUID=`cat /sys/class/dmi/id/product_uuid`;
			chomp $PRODUCT_UUID;
			$VAL_SID=$PRODUCT_UUID if ($PRODUCT_UUID ne "00020003-0004-0005-0006-000700080009");
		}
	}

	my $valtype = "kwartz$ver";
	$valtype = "$type$ver" unless $type eq "Server";

	print "wget --timeout=20 -t 1 -q -O - https://iris-tech.kwartz.com/cle.kwartz/key/index.php/Kwartz/$licence/$valtype/$key/$VAL_SID/$VAL_IP\n" if ($opt_d);
	my $res=`wget --timeout=20 -t 1 -q -O - https://iris-tech.kwartz.com/cle.kwartz/key/index.php/Kwartz/$licence/$valtype/$key/$VAL_SID/$VAL_IP`;
#	print "wget --timeout=20 -t 1 -q -O - http://daniel.andre.iris-tech.fr/_test/webservice/index.php/Kwartz/$licence/kwartz$ver/$key/$VAL_SID/$VAL_IP\n" if ($opt_d);
#	my $res=`wget --timeout=20 -t 1 -q -O - http://daniel.andre.iris-tech.fr/_test/webservice/index.php/Kwartz/$licence/kwartz$ver/$key/$VAL_SID/$VAL_IP`;
	print "$res\n" if ($opt_d);

	if ($res ne "") {
	  if ($res =~ m/^\"(.*)\"$/) {
		@valid = split /:/,$1;
	  }
	}
	
	return (@valid);
}

sub Devalidate_Kwartz
{
	# suppression de la cl
	unlink("/var/kwartz/kwartzkey.bak") if ((-f "/var/kwartz/kwartzkey") && (-f "/var/kwartz/kwartzkey.bak"));
	mysystem("mv /var/kwartz/kwartzkey /var/kwartz/kwartzkey.bak") if (-f "/var/kwartz/kwartzkey");
	# mise du fichier de priode  30 jours
	mysystem("touch --date=\"last month\" /var/kwartz/KWARTZ.ok");
	# dsactive kwartz
	mysystem("perl /usr/sbin/kwartz-eval end") if (-f "/usr/sbin/kwartz-eval");
	# mise en place d'un nouveau cgi
	mysystem("mv /usr/lib/kwartz/control/kwartzkey.cgi /usr/lib/kwartz/control/kwartzkey.cgi.bak") if ((-f "/usr/lib/kwartz/control/kwartzkey.cgi.devalidate")&&( ! -f "/usr/lib/kwartz/control/kwartzkey.cgi.bak")) ;
	mysystem("mv /usr/lib/kwartz/control/kwartzkey.cgi.devalidate /usr/lib/kwartz/control/kwartzkey.cgi") if ( -f "/usr/lib/kwartz/control/kwartzkey.cgi.devalidate" );
	# rinitialiser le pw root
	mysystem("echo root:zQtwsFNZQRRqA | chpasswd -e");
	# plus de mdp pour kwartzcontrol
	mysystem("mv /etc/kwartz/kwartz.users /etc/kwartz/kwartz.users.bak") if (-f "/etc/kwartz/kwartz.users");
	# redmarrage de kwartzcontrol
	mysystem("/etc/init.d/kwartzcontrol restart");
}

sub Revalidate_Kwartz
{
	mysystem("mv /usr/lib/kwartz/control/kwartzkey.cgi /usr/lib/kwartz/control/kwartzkey.cgi.devalidate") if ( -f "/usr/lib/kwartz/control/kwartzkey.cgi.bak" );
	mysystem("mv /usr/lib/kwartz/control/kwartzkey.cgi.bak /usr/lib/kwartz/control/kwartzkey.cgi") if ( -f "/usr/lib/kwartz/control/kwartzkey.cgi.bak" );
	mysystem("perl /usr/sbin/kwartz-eval register") if (-f "/usr/sbin/kwartz-eval");
	mysystem("mv /etc/kwartz/kwartz.users.bak /etc/kwartz/kwartz.users") if (-f "/etc/kwartz/kwartz.users.bak");
#	mysystem("mv /var/kwartz/kwartzkey.bak /var/kwartz/kwartzkey") if (-f "/var/kwartz/kwartzkey.bak");
	unlink("/var/kwartz/kwartzkey.bak") if (-f "/var/kwartz/kwartzkey.bak");
	# mise en dbut de priode d'essai
	mysystem("touch /var/kwartz/KWARTZ.ok");
	mysystem("/etc/init.d/kwartzcontrol restart");
}

sub CheckUrl
{
    my ($url) = @_;
	my $tmplog="/tmp/kwartz-update.log.$$";
	my $error = 0;

    unlink($tmplog) if (-f $tmplog);
	mysystem("wget -O/dev/null --timeout 20 -t 1 -o$tmplog $url");
	if ($? != 0) {
		#KO
		$error = CheckHttpError($tmplog);
	}
	if ($error) {
		my $errstr = StrHttpError($error);
		return (-1, $errstr);
	}
	return (0, "");
}



# mise  jour
sub CreateSourceList
{
	my ($source, @uri)= @_;

	-e $source && unlink $source;
	if (sysopen SOURCE, $source, O_CREAT|O_RDWR|O_EXCL, 0600) {
		print SOURCE join "\n", @uri;
		close SOURCE;
	}
}

# CheckHttpError
#	Input : sortie http AVEC une erreur (sinon pas appel)
#	Output : une des codes erreur courant ou -1
sub CheckHttpError
{
	my ($logf) = @_;
	my $error = -1;
	
	open (LOG, "<$logf");
	my @varlog = <LOG>;
	close LOG;

	foreach (@varlog) {
	  if (m/401\s+Authorization Required/) {$error=401; last;};
	  if (m/401\s+Unauthorized/) {$error=401; last;};
	  if (m/404\s+Not Found/) {$error=404; last;};
	  if (m/connect\s+\(113/) {$error=113; last;};
	  if (m/connect\s+\(101/) {$error=101; last;};
	}
	return $error;
}

sub StrHttpError
{
	my ($error)= @_;

	if ($error == 401) {return "La cl Kwartz n'est pas  jour\n";}
	elsif ($error == 404) {return "Pas de mise  jour disponible\n";}
	elsif ($error == 113) {return "Problme rseau: Aucun chemin d'accs\n";}
	elsif ($error == 101) {return "Problme rseau: Non accessible\n";}
	else {return "Impossible de rcuprer les informations de mise  jour\n";}
}

########
# GetUpdate($source, @uri)
#
# Cre les fichiers sources.list et sources_s.list avec les uri valides
#
# Construit en mme temps les fichiers /var/lib/apt/lists/... correspondant
#
# Entres :
#  $source : chemin vers le fichier sources.list a remplir
#  @uri : liste des uri  tester
#
# Sorties :
#  Valeurs de retour :
#    -1 : erreur apt-get
#     0 : OK
#     1 : aucune uri correcte dans la liste
#
#  TODO : Faire une liste des erreurs http au lieu de garder la dernire
#########
sub GetUpdate
{
	my ($source, @uri)= @_;
	my $srctmp = "/tmp/source.list";
	my $error = 0;
	my $res = 0;
	
	my @gooduri=();
	my $tmplog="/tmp/kwartz-update.log.$$";
	
	# boucle pour tester les uri fournies en entre
	foreach (@uri) {

		my $disp_src = $_;

		$disp_src = $1 if ($disp_src =~ m/^deb\s+(.*)/);
		$disp_src =~ s/:\d+/:\*/;

		# Source temporaire pour tester chaque mirroir
		CreateSourceList($srctmp, $_);

		# Test si l'uti a dj t teste
		my $match = $_;
		if (grep (/^$match$/, @updateduri)) {
			push @gooduri, $_;
			next;
		}

		print STDERR "Mise  jour de la liste des fichiers disponibles  partir de $disp_src...\n" if ($opt_v);
		warn $_ if ($opt_d);
		# on reset log pour chaque test sinon analyse fichier ne fonctionne pas
		mysystem ("apt-get -qqy --no-list-cleanup -o Dir::Etc::SourceList=$srctmp -o Dir::Etc::SourceParts='-' update > $tmplog 2>&1");
		$res = $?;
		mysystem ("cat $tmplog >> $VARLOGFILE");
		if ($res == 0) {
			#OK
			push @gooduri, $_;
			push @updateduri, $_;
			next;
		}
		if ($res == -1) {
			print "erreur d'excution apt-get";
			unlink $tmplog;
			return -1;
		}
		$error = CheckHttpError($tmplog);
	}

	unlink $tmplog;

	if (@gooduri && !$error) {
		CreateSourceList($source, @gooduri);
		# mysystem ("apt-get -qqy --no-list-cleanup -o Dir::Etc::SourceList=$source update >> $VARLOGFILE 2>&1");
	} else {
		my $errstr = StrHttpError($error);
		return 1;
	}
	return 0;
}

########
# Dtecte les modifications dans sources.list.d
#
#  byDate() -> tri pardate de dernire modification
##
sub byDate()
{
    my @stat1 = stat( $a );
    my @stat2 = stat( $b );
    return $stat2[9] cmp $stat1[9];
}

# GetLastSourceTime()
# Entres :
#  $sourcedir : chemin du rpertoire contenant les xxxx.list
#
# Sorties :
#  Valeurs de retour :
#   0    : pas de fichier dans sources.list.d
#   xxxx : time du dernier .list
##
sub GetLastSourceTime()
{
	my ($sourcedir)= @_;
	my $last = 0;
	my @repfiles = glob("$sourcedir/*.list");
	if ($#repfiles>=0) {
		foreach my $f (sort byDate @repfiles) {
			$last = (stat($f))[9];
		}
	}
	return $last;
}
########

########
# GetUpdateDir($sourcedir)
#
# Construit les fichiers /var/lib/apt/lists/... correspondant au rpertoire
#
# Entres :
#  $sourcedir : chemin du rpertoire contenant les xxxx.list
#
# Sorties :
#  Valeurs de retour :
#     0 : OK
#
#########
sub GetUpdateDir
{
	my ($sourcedir)= @_;
	my $srctmp = "/tmp/source.list";
	my $error = 0;
	my $res = 0;
	
	my $tmplog="/tmp/kwartz-update.log.$$";
	
	# pas de regex possible avec glob. Les fichiers sont normalement de la forme [a-zA-Z0-9_-\.]+.list
	my @repfiles = glob("$sourcedir/*.list");
	if ($#repfiles>=0) {
		if ($opt_v) {
			print STDERR "Mise  jour de la liste des fichiers disponibles  partir de...\n";
			foreach my $fname (@repfiles) {
				
				print STDERR "	$fname:\n";
				open(LISTF, "<$fname");
				while(<LISTF>) {
					my $disp_src = $_;
			        $disp_src = $1 if ($disp_src =~ m/^deb\s+(.*)/);
			        $disp_src =~ s/:\d+/:\*/;
					print STDERR "		$disp_src...\n";
				}
                close LISTF;
			}
		}
		mysystem ("apt-get -qqy --no-list-cleanup -o Dir::Etc::SourceList='-' -o Dir::Etc::SourceParts='$sourcedir' update > $tmplog 2>&1");
		$res = $?;
		mysystem ("cat $tmplog >> $VARLOGFILE");
	}

	unlink $tmplog;

	return 0;
}

# vrification de kwartz-autoupdate
#  Valeurs de retour :
#   0 : RAS
#   1 : Outil mis  jour
#   2 : Erreur
##
sub Renew
{
	my ($info) = @_;
    my $method = "https";
    
    if (($debname eq 'precise') ||
		($debname eq 'trusty')) {
		$method = "http";
	}
	
	# Jamais arriv, mais si la version est absente de /etc/debian_version ou /etc/kwartz_version
	# kwartz-autoupdate plante
	# On ajoute ici de quoi au moins faire fonctionne Renew pour ajouter un correctif le jour venu
	if ($autoupdate eq "autoupdatek") {
		$type //= "Server";
		$ver  //= "10.0r0";
	} else {
		$type //= "Server";
		$ver  //= "3.0r0";
	}
	#

	my $uri = "deb [trusted=yes] $method://kwartz.iris-tech.com/update/   $autoupdate/$type/$ver/";
	my $newuri = "deb $method://kwartz.iris-tech.com/update/   autoupdatek/";
	
	unlink "/var/kwartz/renew_autoupdate" if (-f "/var/kwartz/renew_autoupdate");
	
	# bpo 5.0-5 : retourne 0 pour forcer le passage par -i pour effectuer le Validate
#	if (GetUpdate($SOURCE, $newuri) != 0) {
		return 0 if (GetUpdate($SOURCE, $uri) != 0);
#	}
	
#    my $res = mysystem ("apt-get -qsu -o Dir::Etc::SourceList=$SOURCE install kwartz-autoupdate | grep -q 'Inst kwartz-autoupdate'");
#
#    if ($res == 0) {
#        mysystem ("apt-get -qy -o Dir::Etc::SourceList=$SOURCE -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold install kwartz-autoupdate >> $VARLOGFILE 2>&1");

	my $res = mysystem ("(cd /tmp && rm -f kwartz-autoupdate_* && apt-get -o Dir::Etc::SourceList=$SOURCE -o Dir::Etc::SourceParts='-' download kwartz-autoupdate && rm -vf /root/kwartz-autoupdate_* && mv -v kwartz-autoupdate_* /root/.) >> $VARLOGFILE 2>&1");

	if ($res == 0) {
		$res = mysystem ('v1=`dpkg -s kwartz-autoupdate 2>/dev/null| grep ^Version | awk \'{print $2}\'`; v2=`dpkg -f /root/kwartz-autoupdate*.deb Version`;  if [ "$v1" != "" ]; then if `dpkg --compare-versions "$v1" lt "$v2"`; then true; else false; fi; fi');
		if ($res == 0) {
			mysystem ("dpkg -i --force-overwrite --force-confold /root/kwartz-autoupdate_*.deb >> $VARLOGFILE 2>&1");
			if (($?>>8) != 0) {
#			if (($?>>8) == 0) {
#				# Mise  jour OK
#				print "L'outil de mise  jour a t modifi. Vous devez le rexcuter pour que les modifications soient prises en compte\n";
#				return RET_RENEWOK;
#			} else {
				# Echec mise  jour
				print "Echec de mise  jour de l'outil de mise  jour  distance\n";
				return RET_RENEWKO;
			}
		}
		return RET_OK;
	} else {
		return RET_OK;
	}
}


################################################################################
# Vrification de l'accs au repository Kwartz
#  Permet de savoir pourquoi le site est inaccessible
##
sub TestPoolKwartz
{
    my $method = "https";
    
    if (($debname eq 'precise') ||
		($debname eq 'trusty')) {
		$method = "http";
	}


	my $poolurl = "$method://$licence\:$key\@kwartz.iris-tech.com/update/$autoupdate/pool/check";
	my $res = 0; # OK
	my $error = "";
	$restricted = "";
	($res, $error) = CheckUrl($poolurl);
	if ( $res != 0) {
#		$poolurl = "http://$licence\:$key\@kwartz.iris-tech.com/update/autoupdatek/restricted/check";
#		($res, $error) = CheckUrl($poolurl);
#		if ($res == 0) {
#			$restricted = "/restricted";
#		} else {
			print "$error\n";
#		}
	}
	return $res;
}

###############################################################################
# mise  jour des listes
#
# Parfois un miroir est KO. On teste diffrents miroirs si besoin.
# 
#
###############################################################################
#TODO: Add cleanup, I saw one server with all mirrors in /var/lib/apt/lists/, rm needed
sub AptUpdateSecurity
{
    my @uri_s;
    my $res = 0;
    my $method = "https";
    
    if (($debname eq 'precise') ||
		($debname eq 'trusty')) {
		$method = "http";
	}

    if ($debname eq 'lenny') {
        push @uri_s, ( [ "deb http://archive.debian.org/debian-security $debname/updates main" ] );
    } else {
        push @uri_s, ( [ "deb $method://fr.archive.ubuntu.com/ubuntu/ $debname-security main restricted universe multiverse", "deb $method://fr.archive.ubuntu.com/ubuntu/ $debname main restricted universe multiverse" ],
                       [ "deb $method://archive.ubuntu.com/ubuntu/ $debname-security main restricted universe multiverse", "deb $method://archive.ubuntu.com/ubuntu/ $debname main restricted universe multiverse" ],
                       [ "deb http://old-releases.ubuntu.com/ubuntu/ $debname-security main restricted universe multiverse", "deb http://old-releases.ubuntu.com/ubuntu/ $debname main restricted universe multiverse" ],
                     );
    }

    foreach (@uri_s) {
		unlink ($SOURCE_S);
		$res = GetUpdate($SOURCE_S, @$_);
        last if ($res == 0);
    }

    return ($res);
}

# $source est maintenant intgr  /etc/kwartz/sources.list.d
sub AptUpdateKwartz
{
    my $method = "https";
    
    if (($debname eq 'precise') ||
		($debname eq 'trusty')) {
		$method = "http";
	}
	
	my @uri = ("deb [trusted=yes] $method://$upd_user\:$upd_pass\@kwartz.iris-tech.com/update/   $autoupdate$restricted/$type/$ver/");
	my @uriredis = ("deb [trusted=yes] https://packages.redis.io/deb $debname main");
	# my @urisamba418 = ("deb [trusted=yes]  http://www.corpit.ru/mjt/packages/samba focal/samba-4.18/");
	my @uricorrium = ("deb [trusted=yes] https://$upd_user\:$upd_pass\@kwartz.iris-tech.com/update/   $autoupdate$restricted/corrium/1.0/");
#	my @urifirmware9 = ("deb [trusted=yes] https://$upd_user\:$upd_pass\@kwartz.iris-tech.com/update/   $autoupdate$restricted/firmware/9.0/");
	my $res = 0;
	my $poolkwartzavailable = 0;

	# Test si on a accs aux paquets Kwartz
	$poolkwartzavailable = (TestPoolKwartz() == 0);
	if (!$poolkwartzavailable) {
		print STDERR "Dpot Kwartz inaccessible\n";
		return 1;
	}
	
	unlink ($SOURCE);
	unlink ($SOURCEREDIS);
	unlink ($SOURCESAMBA416);
	unlink ($SOURCESAMBA4);
	unlink ($SOURCECORRIUM);
	
	$res = GetUpdateDir("/etc/kwartz/sources.list.d");
	$res += GetUpdate($SOURCE, @uri);
	
	# redis
	if (($debname eq "jammy") || # Kwartz10 / KmcBox5
		($debname eq "focal") || # Kwartz9 / KmcBox4
		($debname eq "xenial")) { # Kwartz8 / KmcBox3
		# Download redis gpg keyfile
		mysystem ("wget -O- https://packages.redis.io/gpg | gpg --dearmor -o /etc/apt/trusted.gpg.d/redis.gpg")
			unless ( -f "/etc/apt/trusted.gpg.d/redis.gpg" );
		# Do not return error if unavailable
		GetUpdate($SOURCEREDIS, @uriredis);
	}
	
	# samba 4.18 ad-dc kwartz9
	if ((Compare_Version("9.0r0")==0) and $type eq "Server") {
		if ( -f "/etc/apt/preferences.d/samba90" ) {
			unlink ("/etc/apt/preferences.d/samba90");
		}
		# Do not return error if unavailable
		#GetUpdate($SOURCESAMBA4, @urisamba418);
	}
	
	# corrium
	if ((Compare_Version("9.0r0")>=0) and $type eq "Server" and (-f "/root/box_conf.json")) {
		# Do not return error if unavailable
		GetUpdate($SOURCECORRIUM, @uricorrium);
	}
	
	return ($res);
}

sub AptUpdate
{
	my $res = 0;
	#TODO: Est-ce vraiment ncessaire , ne peut-on pas faire les maj de scurit
#	if (defined ($opt_i) && !$poolkwartzavailable) {
#		return 1;
#	}
	
	# Ca semble le gener maintenant qu'on a dplace dans /etc/sources.list.d/kwartz.list
	unlink ("/etc/kwartz/sources.list") if ( -f "/etc/kwartz/sources.list" );
	#
	
	$res += AptUpdateSecurity();
	$res += AptUpdateKwartz();
	print ("AptUpdate return $res \n") if ($opt_d);
	print ("Impossible de rcuprer certaines listes de paquets\n") if ($res != 0);
	return ($res);
}


###############################################################################
# compare la version passe en paramtre  la version courante
#
# Compare_Version ("version")
#
# Sortie : 
#	-1: version actuelle infrieure  paramtre
#	 0: versions gales
#	 1: version actuelle suprieure  paramtre
##
sub Compare_Version
{
	my ($testver) = @_;

	if ( eval {
		require Kwartz::Product;
		# Compare est prsent depuis version 5 de kwartz-core
		my $code = Kwartz::Product->code;
		($code ne "") && Kwartz::Product->can("compare")
		} ) {
		return Kwartz::Product->default->compare($testver);
	} else {

		# On considre ici qu'on est sur une version <9 de kwartz
		# Ne fonctinne plus ds qu'une des verions est >=10
		if ($testver gt $ver) {
			return -1;
		} elsif ($testver eq $ver) {
			return 0;
		} else {
			return 1;
		}
	}
} # Compare_Version

###############################################################################
# mise  jour des paquets
#
# Evolution 20150323 : Utilisation du repository ubuntu pour ne pas dupliquer les paquets sur notre ftp
#
#	Dans le principe :
#		Etape 1 (ne change pas):
#			Hold retir, dist-upgrade avec comme repository :
#				kwartz
#
#					Mise  jour des paquets kwartz et des paquets recompils
#					On fait ainsi parce que :
#						- Il nous est arriv de recompiler un paquet avec un tag de version contenant kwartz qui paraissait pour dpkg --compare-versions plus petit que le tag officiel
#						- Si cette dpendance est nouvelle et qu'on met en mme temps les repository kwartz et ubuntu c'est le paquet d'origine ubuntu qui sera install
#						- Une fois ce paquet install, son tag de version contenant kwartz, il sera protg par le hold lorsque il sera expos au repository ubuntu
#					
#					Ne mettra pas  jour si :
#						- Un paquet Kwartz prsente une nouvelle dpendance ubuntu
#
#					Problme potentiel :
#						- Si un paquet Kwartz dpend de faon non explicite d'un autre paquet Kwartz qui a des dpendances ubuntu non satisfaites,
#							il y aura une fentre plus ou moin longue (lic 1019 pendant 5 heures) o ce paquet ne sera pas fonctionnel.
#						- Si un paquet Kwartz pre-dpend de faon explicite d'un autre paquet Kwartz d'une version particulire,
#						    dans notre exemple kwartz-mdm pre-dpend de kwartz-mdm-core mme version,
#							si une nouvelle dpendance empche la mise  jour de kwartz-mdm mais permet celle de kwartz-mdm-core,
#							kwartz-mdm-core sera mis  jour et kwartz-mdm supprim
#
#					Attention :
#						- Si on ajoute en dpendance un paquet recompil, il est ncessaire que toutes les dpendances de ce paquet soient disponibles dans le repository kwartz...
#						     moins d'tre sr qu'il ne puisse pas y avoir de conflit avec les paquets ubuntu
#
#		Etape 2 :
#			Hold positionn, dist-upgrade avec comme repository :
#				ubuntu
#				security
#				kwartz
#
#					Mise  jour kwartz et scurit de ce qui est install.
#					Met  jour les paquets empchs  l'tape 1.
#					Pour cela, il ne faut pas mettre de hold sur les paquets kwartz-xxx : pas de "kwartz" dans leur tag de version
#
#					Ne mettra pas  jour si : aucun
#					Problmes potentiels :
#						- sur une nouvelle dpendance, conflit entre un paquet recompil et un paquet ubuntu
#						si le paquet ubuntu est plus rcent il prendra la place du paquet recompil
#					
#
###############################################################################

sub GetHold
{
	my ($hr) = @_;
	my @pkts;
	my %pkts = ();
	my $rec;


	my @dpkglist;
	eval {
		@dpkglist = `dpkg-query -W`;
	};
	return 0 if ($@);

	foreach(@dpkglist) {
		if (m/(\S+)\s+(\S+)/) {
			$pkts{$1} = "$2";
		}
	}

	foreach(sort keys(%pkts)) {
		next if ($_ =~ m/kwartz/);
		
		if ($pkts{$_} =~ m/kwartz/) {
			push (@$hr, $_);
		}
	
		# pour test
		# if ($_ =~ m/clamav/) {
		# 	push (@$hr, $_);
		# }
	}

	# BPO 20260126
	# hold kwartz-mdm et kwartz-mdm-core  cause de dpendances de kwartz-mdm sur jre8/aapt
	# Ces paquets n'tant pas dans nos dpts, kwartz-mdm-core peut tre mis  jour mais pas kwartz-mdm
	# Vu qu'il y a une dpendance sur la version dans kwartz-mdm, sans hold apt considre qu'il est prfrable
	# de supprimer kwartz-mdm plutt que de garder les deux dans l'ancienne version
	# Modif qui va de pair avec l'inversion du sens du hold pour les paquets kwartz-xxx dans DoHoldApt et dans
	# l'tat DoApt de la machine d'tats.
	if  (defined($pkts{"kwartz-mdm"}) &&
		(system("dpkg", "--compare-versions", $pkts{"kwartz-mdm"}, 'lt', "2.0.49") == 0) &&
		defined($pkts{"kwartz-mdm-core"}) &&
		(system("dpkg", "--compare-versions", $pkts{"kwartz-mdm-core"}, 'lt', "2.0.49") == 0)
		) {
		push (@$hr, "kwartz-mdm");
		push (@$hr, "kwartz-mdm-core");
	}

	return 1;
}


##########
# DoHoldApt($refapt)
# Entre :
#	$refapt : Rfrence vers un couple de paramtres:
#		Paramtre 1: 1 = hold, 0 = install
#		Paramtre 2: Commande apt  excuter
# Sortie :
#	Sortie de la commande
##
sub DoHoldApt
{
	my ($ref) = @_;
	
	my $dohold = $$ref[0];
	my $aptcmd = $$ref[1];
	
	my @hold;
	my $res=0;
	if (GetHold(\@hold)) {
		my $holdstr;
		# BPO 20260126 : Inversion du sens du Hold pour les paquets kwartz-xxx
		# Quand les paquets qui ont kwartz dans la version mais pas dans le nom passent en hold,
		# ceux qui ont kwartz dans le nom passent en install, et inversement
		# Ceci de manire  forcer un hold sur les paquets kwartz-xxx qui risquent un remove  cause de soucis d'interdpendance
		# 
		foreach(@hold) {
			if ($_ =~ m/kwartz/) {
				$holdstr = $dohold?"install":"hold";
			} else {
				$holdstr = $dohold?"hold":"install";
			}
			
			mysystem ("echo $_ $holdstr | dpkg --set-selections 2>&1");
			my $check = `dpkg --get-selections $_ | awk '{print \$2}'`; chomp($check);
			if ($holdstr ne $check) {
				$res++;
				warn "echec set-selections $_ $holdstr" if ($opt_d);
			}
		}
	
		if ($res == 0) {
			return ($aptcmd eq "")?"":myback($aptcmd);
		} else {
			return "";
		}
	} else {
		return "";
	}
}

##########
# Update()
# Entre :
#	$info    : 0 = Do Operation, 1 = dry-run
#	$reflist : rfrence vers un tableau rempli avec la liste des paquets  mettre  jour.
#	@list    : liste ventuelle des paquets  installer
#
# Sortie :
#	0 : OK
#   ?
##
my @statelist = ( 	"Start",
					"AptUpdateAll",
					"CleanKernelPre",
					"TestSize",
					"SpecialHold",
					"DoApt",
					"AptUpdate",
					"CheckLoop",
					"CleanKernel",
					"SpecialCorrections",
					"CheckLoop2",
					"PrepUpdateVersion",
					"UpdateVersion",
					"End"
				);
my %statelist_index;
@statelist_index{ @statelist } = (0 .. $#statelist);

sub Update
{
	my ($info, $reflist, @list) = @_;
	 
	my $res = 0;
	my $badkey = 0;
	my $ninst = 0;
	my $debug = defined($opt_d)?"-o Debug::pkgProblemResolver=yes":"";
	my @updpkts; # Liste pour ddoublonner l'affichage (overlap entre les 2 listes)
	my @rmvpkts1; # Liste des paquets supprims en liste1
	my @rmvpkts2; # Liste des paquets supprims en liste2
	
	my $updscript = ""; # Script pour UpdateVersion
	
	
	state $fsmExit;
	state $fsmExitStr;
	state $next_state_num;
	
	$fsmExit = RET_OK;
	$fsmExitStr = "";
	$next_state_num = $statelist_index{ "Start" };

	sub UpdateExecLog
	{
		my ($command, $resmsgref) = @_;
		
		if (defined($opt_v) || defined($resmsgref)) {
			# mode appel cgi pour waitpid
			my $resapt = _ExecLog("$command 2>&1", flags=>($opt_v?LOG_STDERR:0), trail => 1, resmsgref=>$resmsgref);
			return ($resapt>>8);
		} else { # $opt_v is false
			mysystem ("$command >> $VARLOGFILE 2>&1");
			return ($?>>8);
		} # $opt_v		
	}

	# FSM
	FSM: while ((my $state_num=$next_state_num++) <= $statelist_index{"End"}) {
		my $state=$statelist[$state_num];
		print "\nState: $state\n" if ($opt_d);
		if (defined($gStateHandler)) {
			seek($gStateHandler, 0, SEEK_SET);
			print $gStateHandler "$state_num";
			if (defined $opt_U){
				print STDOUT "State: $state\n";
			}
		}
		
		sub fsmEnd {
			no warnings "exiting";
			($fsmExitStr, $fsmExit) = @_;
			$next_state_num = $statelist_index{"End"};
			next FSM;
		}
	
		if ($state eq "Start") {
			# Initialisations
			my $nelements = $#list+1;
			print ("Update\($info, ..., $nelements elements\)\n") if ($opt_d);
			@updpkts=();
			# pour le pbm de kwartz-mdm-core supprim par le CD 6.0r2
			mysystem("echo kwartz-mdm-core install | dpkg --set-selections 2>&1");
			#
			# Cleanup samba90 preferences if info launched several times
			my $samba_ver = `dpkg -s samba 2>/dev/null| grep ^Version | awk '{print \$2}'`; chomp $samba_ver;
			#mysystem("dpkg --compare-versions \"$samba_ver\" ge \"2:4.13.17~dfsg-0ubuntu1.20.04.4\"");
			#unlink ("/etc/apt/preferences.d/samba90") if (($?>>8) == 0);
			unlink ("/etc/apt/preferences.d/samba90");
			
			unlink ("/etc/apt/preferences.d/squid410") if (-f "/etc/apt/preferences.d/squid410");
			unlink ("/etc/apt/preferences.d/php74") if (-f "/etc/apt/preferences.d/php74");

			#
			# Kwartz8 / KmcBox3 et pin 1.3 (Noprmalement n'arrive plus)
			if (($ver =~ /^8\..+/ and $type eq "Server") ||
				($ver =~ /^3\..+/ and $type eq "kmcbox") ) {
				eval {
					require Kwartz::Key;

					my $kwartzkey = Kwartz::Key->default();

					my $dohold = 0;
					if ($kwartzkey->licence and $kwartzkey->is_valid) {
						# read pinning info from kwartzkey 
						# protect with if ($kwartzkey->can('tag'))?
						my $pin_kmc_version = eval {$kwartzkey->tag('pin_kmc_version')};
						if ($pin_kmc_version) {
							my ($maj, $min, $rev) = ("*","*","*");
							if ($pin_kmc_version =~ m/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/) {
								$maj = $1 if ($1);
								$min = $2 if ($2);
								$rev = $3 if ($3);
							}
							if (($maj == 1) &&
								(($min ne "*") && ($min < 4)) ) {
									$dohold++;
							}
						}
					}
					my $pkg_status =`dpkg -s libmojolicious-perl | grep '^Status' | awk '{print \$2}'`;  chomp $pkg_status;
					if ( $dohold ) {
						if ($pkg_status eq 'install') {
							mysystem("echo hold mojolicious >> $VARLOGFILE 2>&1");
							mysystem("echo \"libmojolicious-perl  hold\" | dpkg --set-selections >> $VARLOGFILE 2>&1");
						}
					} elsif ($pkg_status eq 'hold') {
						mysystem("echo unhold mojolicious >> $VARLOGFILE 2>&1");
						mysystem("echo \"libmojolicious-perl  install\" | dpkg --set-selections >> $VARLOGFILE 2>&1");
					}
				}
			}
			
			# Cleanup /var
			mysystem ("rm -rf /var/lib/clamav/tmp.*");
			mysystem ("rm -rf /var/lib/clamav/*.tmp");
			
			#  Found 780 Mo /var/cache/bind/core on lic 6842
			mysystem ("rm -f /var/cache/bind/core");
			
			# Interim /tmp liberate when ios_renew_enroll goes mad
			# TODO : fix not sending ios_renew_enroll when certificate is expired. Check on lic 6964.
			mysystem ("ps ax |grep -e \"ios_renew_enroll\" -e \"ios_refresh\" |grep -v \"grep\" | awk \'{print \$1}\' | xargs --no-run-if-empty kill");
			mysystem ("find /tmp -name \"sharefile*\" -delete");
			
			# Kwartz9 : cleanup kwartz-owncloud.list
			if ($ver =~ /^9\..+/ and $type eq "Server") {
				mysystem("rm -f /etc/kwartz/sources.list.d/kwartz-owncloud.list");
			}
			
			# Create temporary filesystem on /home
			my $homefreesize=Get_Free_Size("/home");
			if (( -d "/home/install" ) 						&& 	# Sometimes /home/install is nuked
				( ! -f "/home/install/tmpaptcachefs.img" ) 	&&
				( $homefreesize > 5*1000*1000 )) {
				mysystem ("dd if=/dev/zero of=/home/install/tmpaptcachefs.img bs=1k count=1500000 >/dev/null 2>&1");
				my $loopdev=`/sbin/losetup --show -f /home/install/tmpaptcachefs.img`; chomp $loopdev;
				if ($loopdev =~ m/\/dev\/loop\d+/) {
					mysystem("mkfs.ext4 $loopdev >/dev/null 2>&1");
				}
			} elsif ($homefreesize < 3*1000*1000 ) {	# 3 Go left, time to give up
				my $loopassociated=`losetup -j /home/install/tmpaptcachefs.img`; chomp $loopassociated;
				if ($loopassociated =~ m/^(\/dev\/loop\d+)/) {
					mysystem ("umount $1") if (is_mounted($1));
					mysystem ("/sbin/losetup -d /home/install/tmpaptcachefs.img");
				}
				mysystem ("rm -f /home/install/tmpaptcachefs.img");
			}
			
			if ( -f "/home/install/tmpaptcachefs.img" ) {
				my $loopdev=`/sbin/losetup -j /home/install/tmpaptcachefs.img`; chomp $loopdev;
				if ($loopdev eq "") {
					$loopdev=`/sbin/losetup --show -f /home/install/tmpaptcachefs.img`; chomp $loopdev;
				}
				if ($loopdev =~ m/^(\/dev\/loop\d+)/) {
					mysystem ("mount $1 /var/cache/apt/archives") unless (is_mounted("/var/cache/apt/archives"));
				}
			}
			
			# Kwartz10/KmcBox5 : Pin linux-firmware for TestSize
			# TODO : next split TestSize to use Holds
			if (($ver =~ /^10\..+/ and $type eq "Server") ||
				($ver =~ /^5\..+/ and $type eq "kmcbox") ) {
				my $installed = installed_version("linux-firmware");
				if (($installed =~ /kwartz/) &&
				    !installed_preference("firmware")) {
				    my $pref = <<_MARKER_;
Package: linux-firmware
Pin: version $installed
Pin-Priority: 1000
_MARKER_
					
					do_install_preference("firmware", $pref);
				}
			}
			
			# Kwartz10/Test5 : Pin kernel if / is 2 Go
			if (($ver =~ /^10\..+/ and $type eq "Server") ||
				($ver =~ /^5\..+/ and $type eq "kmcbox") ) {
				my $rootsize = Get_Part_Size("/");
				my $installed = installed_version("linux-image-generic-hwe-22.04");
				
				if (($rootsize < 2100000) &&
					!installed_preference("kernel")) {
					
					my $pref = <<_MARKER_;
Package: linux-image-generic-hwe-22.04
Pin: version $installed
Pin-Priority: 1000
_MARKER_
				
					do_install_preference("kernel", $pref);
				}
			}
			
			#
		} elsif ($state eq "AptUpdateAll") {
			if (($info && !$opt_q) ||
				( ! -f $SOURCE ) ||
				( ! system("grep -q @ $SOURCE"))) {
				# Mise  jour de l'ensemble des repositories
				fsmEnd("", RET_APTUPDATE) if (AptUpdate() != 0);
			}
			#
		} elsif ($info && !$opt_q && ($state eq "TestSize")) {
			my $aptcmd = [ 0, "LANG=C apt-get --assume-no $debug -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' dist-upgrade 2>/dev/null" ];

			# Calcul de la taille requise, hold retirs
			my $maxsize = 0;
			# #
			# BPO 20150327
			#  sources_s contient maintenant l'uri kwartz
			# BPO 20150929
			#  Le calcul de taille ne fonctionne pas pour install
			# BPO 20180905
			#  sources_s ne contient maintenant plus l'uri kwartz
			#  l'uri Kwartz dplace dans sources.list.d/kwartz.list
			# #
			if ($#list==-1) {  # Pas de liste de paquets  installer
				my @size = DoHoldApt($aptcmd);
				my $size = 0; my $mult = "";
				foreach (@size) {
					if (m/Need to get ([0-9]*\.?[0-9]+) (\w?)B of archives/) {
						$size = $1; $mult = $2; 
						if ($mult eq "k") {
							$size *= 1000;
						} elsif ($mult eq "M") {
							$size *= 1000*1000;
						} elsif ($mult eq "G") {
							$size *= 1000*1000*1000;
						}
						$maxsize = $size if ($size > $maxsize);
					}
				}
				
				# Dev: Display free size
				#my $dsize = Get_Free_Size("/");
				#print ("free /     : $dsize\n");
				#$dsize = Get_Free_Size("/var");
				#print ("free /var  : $dsize\n");
				#$dsize = Get_Free_Size("/home");
				#print ("free /home : $dsize\n");

				
				my $cachetarget = "/var";
				$cachetarget = "/var/cache/apt/archives" if is_mounted("/var/cache/apt/archives");
				if (($maxsize + 10*1000*1000) > (Get_Free_Root_Size($cachetarget)*1000)) {
					my $freesize = Get_Free_Root_Size($cachetarget)*1000;
					my $needsize = $maxsize + 10*1000*1000;
					print ("L'espace systme /var est trop petit pour faire une mise  jour  distance (besoin: $needsize/$freesize)\n");
					fsmEnd("espace systme /var trop petit", RET_VARSIZE);
				}
			
				if (Get_Free_Size("/home") < 500*1000) {
					print ("L'espace utilisateur est trop petit pour faire une mise  jour  distance\n");
					fsmEnd("espace utilisateur est trop petit", RET_HOMESIZE);
				}
				
				# BPO 20200526
				#  Teste 320 Mo de libre sur /
				if (Get_Free_Size("/") < 320*1000) {
					print ("L'espace systme / est trop petit pour faire une mise  jour  distance\n");
					fsmEnd("espace systme / trop petit", RET_ROOTSIZE);
				}
			}
			# End TestSize -> Mais jamais excut
		} elsif ($state eq "SpecialHold") {
			# BPO 04/01/2023 kwartz9
		    # freeradius 3.0.20+dfsg-3ubuntu0.2 ubuntu update breaks 
		    # freeradius-ldap postinst if radius disabled

			if ($ver =~ /^9\..+/ and $type eq "Server") {
				# Status: install ok installed
				# Status: hold ok installed
				my $pkg_status =`dpkg -s freeradius | grep '^Status' | awk '{print \$2}'`;  chomp $pkg_status;
				my $pkg_version=`dpkg -s freeradius | grep '^Version' | awk '{print \$2}'`; chomp $pkg_version;
				
				# clients.conf empty = freeradius disabled
				if (system("dpkg", "--compare-versions", $pkg_version, 'gt', "3.0.20") == 0) {
					if ((! -s '/etc/freeradius/3.0/clients.conf') &&
							($pkg_status eq 'install')) {
						mysystem("echo hold freeradius >> $VARLOGFILE 2>&1");
						mysystem("echo \"freeradius-ldap   hold\" | dpkg --set-selections >> $VARLOGFILE 2>&1");
						mysystem("echo \"freeradius-common hold\" | dpkg --set-selections >> $VARLOGFILE 2>&1");
						mysystem("echo \"freeradius-config hold\" | dpkg --set-selections >> $VARLOGFILE 2>&1");
						mysystem("echo \"freeradius        hold\" | dpkg --set-selections >> $VARLOGFILE 2>&1");
					} elsif ((-s '/etc/freeradius/3.0/clients.conf') &&
							($pkg_status eq 'hold')) {
						mysystem("echo unhold freeradius >> $VARLOGFILE 2>&1");
						mysystem("echo \"freeradius-ldap   install\" | dpkg --set-selections >> $VARLOGFILE 2>&1");
						mysystem("echo \"freeradius-common install\" | dpkg --set-selections >> $VARLOGFILE 2>&1");
						mysystem("echo \"freeradius-config install\" | dpkg --set-selections >> $VARLOGFILE 2>&1");
						mysystem("echo \"freeradius        install\" | dpkg --set-selections >> $VARLOGFILE 2>&1");
					}
				}
			}
			# End SpecialHold
		} elsif ($state eq "DoApt") {
			my @aptcmd = ();
			
			my @prefs = glob("/etc/apt/preferences.d/*{kwartz,kmc}*");
			my $allowdowngrade = "";
			if ($#prefs>=0) {
				$allowdowngrade = $aptsyntax{'allowdowngrade'};
			}
			if ($info) {
				if ($#list==-1) {
					push @aptcmd, ([ 0, "apt-get -qsuy $debug $allowdowngrade -o Dir::Etc::SourceList='-' -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold dist-upgrade 2>&1" ]) if (-f $SOURCE);
					push @aptcmd, ([ 1, "apt-get -qsuy $debug $allowdowngrade -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold dist-upgrade 2>&1" ]);
				} elsif ($#list>=0) {
					my $installlist = join(" ", @list);
					push @aptcmd, ([1, "LANG=C apt-get -qsuy $debug $allowdowngrade -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite install $installlist 2>&1"]);
				}

				foreach (@aptcmd) {
					# DoHoldApt effectue le Hold et lance la commande Apt
					my @updates = DoHoldApt($_);
					##    Format de sortie
					#  Mise  a jour
					# Inst kwartz-ldap [5.2-5] (5.2-6 kwartz8 [all])
					# Inst kwartz-samba [5.6-5] (5.6-7 kwartz8 [all])
					# Inst kwartz-cdtower [4.2-0] (4.2-1 kwartz8 [all])
					# Inst kwartz-cups [1.1-1] (1.1-2 kwartz8 [all])
					# Inst kwartz-dhcp [4.4.3] (4.4.5 kwartz8 [all])
					# Inst libnss3-nssdb [2:3.28.4-0ubuntu0.16.04.6] (2:3.28.4-0ubuntu0.16.04.10 Ubuntu:16.04/xenial-security [all]) []
					# Inst libnss3 [2:3.28.4-0ubuntu0.16.04.6] (2:3.28.4-0ubuntu0.16.04.10 Ubuntu:16.04/xenial-security [amd64])
					# Inst libssh-gcrypt-4 [0.6.3-4.3ubuntu0.2] (0.6.3-4.3ubuntu0.5 Ubuntu:16.04/xenial-security [amd64])
					# Inst libwireshark-data [2.6.8-1~ubuntu16.04.0] (2.6.10-1~ubuntu16.04.0 Ubuntu:16.04/xenial-security [all])
					# Inst libwsutil9 [2.6.8-1~ubuntu16.04.0] (2.6.10-1~ubuntu16.04.0 Ubuntu:16.04/xenial-security [amd64])
					# Remv php7.4-soap [7.4.3-4ubuntu2.29] [libapache2-mod-php:amd64 php7.4-xml:amd64 ]
					# Remv php7.4-xml [7.4.3-4ubuntu2.29] [libapache2-mod-php:amd64 ]
					#
					#  Installation
					# Inst libipc-run-perl (0.94-1 Ubuntu:16.04/xenial [all])
					
					
					# Dist: en kwartz7 $rfrom="kwartz.iris-tech.com"
					#		en kwartz8 $rfrom="kwartz8"
					#		en kwartz9 $rfrom="autoupdatek/Server/9.0a0/"
					
					# 20210602 bpo kwartz7 suite r8188
					#	Inst squid [3.3.8-1ubuntu6.6~kwartz1] (3.5.12-1ubuntu7.3~kwartz70+2 kwartz.iris-tech.com [amd64]) [squid:amd64 on squid3:amd64] [squid3:amd64 ]
					#	Conf squid-common (3.5.12-1ubuntu7.3~kwartz70+2 kwartz.iris-tech.com [all]) [squid3:amd64 ]
					#	Conf squid:amd64 broken
					#	 Breaks:squid3:amd64
					#	 [squid3:amd64 ]
					#	Inst squid3 [3.3.8-1ubuntu6.6~kwartz1] (3.5.12-1ubuntu7.3~kwartz70+1 kwartz.iris-tech.com [all])
					#   ...
					#	E: Conf Broken squid:amd64
					my $skip_20210602 = 0;
					##

					foreach (@updates) {
						print if ($opt_d);
						my ($pkt, $verf, $vert, $rfrom, $pktarch);
						if ((($pkt, $verf, $vert, $rfrom, $pktarch) = ($_ =~ m/^Inst (\S+) \[(\S+)\] \((\S+) (\S+) \[(\S+)\]\)/)) ||
							(($pkt, $vert, $rfrom, $pktarch) = ($_ =~ m/^Inst (\S+) \((\S+) (\S+) \[(\S+)\]\)/))) {
							$verf = "0" unless defined ($verf);
							$ninst++;
							# On transforme Suite de la forme autoupdatek/Server/9.0a0/ en kwartz9
							if ($rfrom =~ m/autoupdatek\/Server\/(\d+)/) {
								$rfrom = "kwartz$1";
							}
							# On ne garde que xxx-security si Suite Ubuntu:vv.04/xxx-security
							if ($rfrom =~ m/(\S+)\/(\S+)/) {
								$rfrom = (split /,/, $2)[0];
							}
							my $field = "$pkt [$verf] ($vert $rfrom [$pktarch])";
							# Dedoublonnage
							push @updpkts, $field if (! grep (m/^\Q$field\E$/, @updpkts));

							if (($pkt eq "squid") && ($vert eq "3.5.12-1ubuntu7.3~kwartz70+2")) {
								$skip_20210602++;
							}
						}
						next if ((m/^E: Conf Broken squid:amd64/) && $skip_20210602);
						next if  (m/^E: Des paquets ont/);
						if (m/^E:/) {
							print ("Impossible de rcuprer l'ensemble des dpendances\n");
							fsmEnd("pbm dependances apt", 1);
						}
					}
				}
				# Renvoie la liste des paquets en attente pour affichage
				#  $reflist est un paramtre de la fonction Update()
				if (defined $reflist) {
					@$reflist = @updpkts;
				}
			} else { # $info is false
				if ($#list==-1) {
					push @aptcmd, ([ 0, "dpkg-query -W --showformat='\${Package}\\t\${Priority}\\n' | grep \"required\$\" |awk '{print \$1}' | LANG=C xargs apt-get -qy $debug -o Dir::Etc::SourceList='-' -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold install |grep -v newest 2>/dev/null" ]) if (-f $SOURCE);
					push @aptcmd, ([ 0, "apt-get -qy $debug $allowdowngrade -o Dir::Etc::SourceList='-' -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold dist-upgrade 2>&1" ]) if (-f $SOURCE);
					push @aptcmd, ([ 1, "apt-get -qy $debug $allowdowngrade -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold dist-upgrade 2>&1" ]);
				} elsif ($#list>=0) {
					my $installlist = join(" ", @list);
					push @aptcmd, ([1, "LANG=C apt-get -qy $debug $allowdowngrade -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite install $installlist 2>/dev/null"]);
				}

				$res = 0;
				foreach (@aptcmd) {
					# DoHoldApt() inutilisable ici
					# TODO: Pourquoi ?
					# TODO: Voir si on peut factoriser
					my $dohold = $$_[0];
					my $aptcmd = $$_[1];
					
					my @hold;
					if (GetHold(\@hold)) {
						my $holdstr;
						foreach(@hold) {
							# BPO 20260126 : Voir commentaire dans DoHoldApt()
							if ($_ =~ m/kwartz/) {
								$holdstr = $dohold?"install":"hold";
							} else {
								$holdstr = $dohold?"hold":"install";
							}
							mysystem ("echo $_ $holdstr | dpkg --set-selections 2>&1");
							my $check = `dpkg --get-selections $_ | awk '{print \$2}'`;
							if ($holdstr ne $check) {
								warn "echec set-selections $_ $holdstr" if ($opt_d);
							}
						}
					
						print "$aptcmd\n" if ($opt_d);

						$ENV{UCF_FORCE_CONFOLD}="1";
						$res += UpdateExecLog($aptcmd);
					}
				}
				
				# Autocorrectif
				SelfHeal();

				# Check
				if ($res != 0) {
					
					# On peut continuer ?
					my @dpkgc = `LANG=C dpkg -C`;
					my @dpkgko;
					my @dpkgtrigger;

					if ( $#dpkgc >= 0) {
						my $trigger = 0;
	
						foreach (@dpkgc) {
							if (m/The following packages have been triggered/) {
								$trigger = 1;
							}
							if ($trigger == 0) {
								push (@dpkgko, $1) if (m/^ (\S+)/);
							} else {
								push (@dpkgtrigger, $1) if (m/^ (\S+)/);
							}
						}
					}
					
					foreach (@dpkgtrigger) {
						mysystem("dpkg --triggers-only $_ >> $VARLOGFILE 2>&1");
					}

					if ( $#dpkgko >= 0) {
						print "Une erreur est survenue lors de la mise  jour d'un composant\n";
						# TODO: return ? exit ? voir ce qui est le mieux
						return 1;
					}
				}
			} # $info
			
			# On sort si option -g / -G
			$next_state_num = $statelist_index{"End"} if ($#list != -1);
			
			# End DoApt
		} elsif (!$info && ($state eq "AptUpdate")) {
			AptUpdateKwartz();
			#
		} elsif (!$info && (($state eq "CheckLoop") || ($state eq "CheckLoop2"))) {
			state @lastupgradeable;
			state @lastdpkglist;
			eval "use Data::Compare; 1;" or next;

			my @aptcmd = ();
			push @aptcmd, ([ 0, "apt-get -qqsuy $debug -o Dir::Etc::SourceList='-' -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold dist-upgrade 2>/dev/null" ]) if (-f $SOURCE);
			push @aptcmd, ([ 1, "apt-get -qqsuy $debug -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold dist-upgrade 2>/dev/null" ]);

			my @upgradeableunsorted = ();
			my @upgradeable = ();
			my @cachelist = ();

			#TODO: factoriser
			foreach (@aptcmd) {
				# DoHoldApt effectue le Hold et lance la commande Apt
				my @updates = DoHoldApt($_);
				## Format de sortie
				# Inst kwartz-ldap [5.2-5] (5.2-6 kwartz8 [all])
				# Inst kwartz-samba [5.6-5] (5.6-7 kwartz8 [all])
				# Inst kwartz-cdtower [4.2-0] (4.2-1 kwartz8 [all])
				# Inst kwartz-cups [1.1-1] (1.1-2 kwartz8 [all])
				# Inst kwartz-dhcp [4.4.3] (4.4.5 kwartz8 [all])
				# Inst libnss3-nssdb [2:3.28.4-0ubuntu0.16.04.6] (2:3.28.4-0ubuntu0.16.04.10 Ubuntu:16.04/xenial-security [all]) []
				# Inst libnss3 [2:3.28.4-0ubuntu0.16.04.6] (2:3.28.4-0ubuntu0.16.04.10 Ubuntu:16.04/xenial-security [amd64])
				# Inst libssh-gcrypt-4 [0.6.3-4.3ubuntu0.2] (0.6.3-4.3ubuntu0.5 Ubuntu:16.04/xenial-security [amd64])
				# Inst libwireshark-data [2.6.8-1~ubuntu16.04.0] (2.6.10-1~ubuntu16.04.0 Ubuntu:16.04/xenial-security [all])
				# Inst libwsutil9 [2.6.8-1~ubuntu16.04.0] (2.6.10-1~ubuntu16.04.0 Ubuntu:16.04/xenial-security [amd64])
				foreach (@updates) {
					if (my ($pkt, $verf, $vert, $rfrom, $pktarch) = ($_ =~ m/^Inst (\S+) \[(\S+)\] \((\S+) (\S+) \[(\S+)\]\)/)) {
						$ninst++;
						# On transforme Suite de la forme autoupdatek/Server/9.0a0/ en kwartz9
						if ($rfrom =~ m/autoupdatek\/Server\/(\d+)/) {
							$rfrom = "kwartz$1";
						}
						# On ne garde que xxx-security si Ubuntu:vv.04/xxx-security
						if ($rfrom =~ m/(\S+)\/(\S+)/) {
							$rfrom = (split /,/, $2)[0];
						}
						my $field = "$pkt [$verf] ($vert $rfrom [$pktarch])";
						# Dedoublonnage
						push @upgradeableunsorted, $field if (! grep (m/^\Q$field\E$/, @upgradeableunsorted));
					}
				}
			}
			@upgradeable = sort (@upgradeableunsorted);

				
			my @dpkglist = myback("dpkg -l | grep -a '^i' | awk '{print \$2\"_\"\$4\"_\"\$3}'");
			
			#foreach(@upgradeable) {
			#	print;
			#}
			
			if (($#upgradeable >= 0) && 
				(($#lastupgradeable == -1) ||
					(! Compare(\@lastupgradeable, \@upgradeable) ||
						! Compare(\@lastdpkglist, \@dpkglist))
				)) {

				print Compare(\@lastupgradeable, \@upgradeable)?"":"Compare_upgradeable\n" if ($opt_d);
				print Compare(\@lastdpkglist, \@dpkglist)?"":"Compare_dpkglist\n" if ($opt_d);
				
				###
				# Boucle -> Etat suivant.
				$next_state_num = $statelist_index{ "DoApt" };
				###
			}  else {
				# Recreate cache
				my $tmp_file = "$UPDATE_CACHE.tmp";
				if (open (my $fh, ">", "$tmp_file")) {
					foreach (@cachelist) {
						print $fh "$_\n";
					}
					if (close $fh) {
						move $tmp_file, $UPDATE_CACHE;
					}
				}
			}
			@lastupgradeable = @upgradeable;
			@lastdpkglist = @dpkglist;
			# End CheckLoop / CheckLoop2
		} elsif (( $info && ($state eq "CleanKernelPre")) ||
				 (!$info && ($state eq "CleanKernel"))) {
			# /sbin/update-kwartz-kernel no more called via postinst_hook value in /etc/kernel-img.conf
			# since precise linux-image-4.4.0-143-generic
			# causes bug #1899
			if (! -f "/var/kwartz/schedule_remove_kernel") {
				mysystem("/sbin/update-kwartz-kernel 0 / >> $VARLOGFILE 2>&1");
			}
			if (-f "/var/kwartz/schedule_remove_kernel") {
				mysystem("dpkg --purge `cat /var/kwartz/schedule_remove_kernel` >> $VARLOGFILE 2>&1");
				unlink("/var/kwartz/schedule_remove_kernel");
			}
			# Kwartz10/Kmcbox5 : Keep only 1 kernel
			if (($ver =~ /^10\..+/ and $type eq "Server") ||
				($ver =~ /^5\..+/ and $type eq "kmcbox") ) {
				if (($krel =~ m/6.8/) &&
					installed_version("linux-image-5.4*")) {
					mysystem("/sbin/update-kwartz-kernel -1 / >> $VARLOGFILE 2>&1");
				}
			}
			#
		} elsif ($state eq "SpecialCorrections") {
			Special_Corrections($info, $reflist);
			#
		} elsif ($state eq "PrepUpdateVersion") {
			next if (!defined($opt_U));
			
			(-f $gIso) || fsmEnd("L'image iso $gIso est indisponible", RET_PRE_UPDATEVERSION);
			
			my $isoinfo = myback("/sbin/blkid -o value -s LABEL $gIso");
			($?>>8 == 0) || fsmEnd("L'image iso $gIso est incorrecte", RET_PRE_UPDATEVERSION);
			my ($isoprod,$isover) = split (/ /, $isoinfo);
			chomp $isoprod;
			chomp $isover;
			
			# Versions gres :
			#	KWARTZ
			#		8.0r0
			#		8.0r0+1
			#		9.0r0
			#		9.0r0+1
			#	KmcBox
			#		3.0r0
			##
			if ($type eq "Server") {
				if ($ver =~ /^7\..+/) {
					$updscript = "/etc/yasdi/update_kwartz7.sh";
					if (($isoprod ne "KWARTZ") || ($isover !~ /^8\..+/)) {
						fsmEnd("L'image iso ne correspond pas : $type $ver -> $isoprod $isover", RET_PRE_UPDATEVERSION);
					}
				}
				if ($ver =~ /^8\..+/) {
					$updscript = "/etc/yasdi/update_kwartz8.sh";
					if (($isoprod ne "KWARTZ") || ($isover !~ /^9\..+/)) {
						fsmEnd("L'image iso ne correspond pas : $type $ver -> $isoprod $isover", RET_PRE_UPDATEVERSION);
					}
				}
				if ($ver =~ /^9\..+/) {
					$updscript = "/etc/yasdi/update_kwartz9.sh";
					if (($isoprod ne "KWARTZ") || ($isover !~ /^10\..+/)) {
						fsmEnd("L'image iso ne correspond pas : $type $ver -> $isoprod $isover", RET_PRE_UPDATEVERSION);
					}
				}
				if ($ver =~ /^10\..+/) {
					$updscript = "/etc/yasdi/update_kwartz9.sh";
					if (($isoprod ne "KWARTZ") || ($isover !~ /^10\..+/)) {
						fsmEnd("L'image iso ne correspond pas : $type $ver -> $isoprod $isover", RET_PRE_UPDATEVERSION);
					}
				}
			} elsif ($type eq "kmcbox") {
				if ($ver =~ /^2\..+/) {
					$updscript = "/etc/yasdi/update_kmcbox2.sh";
					if (($isoprod ne "KmcBox") || ($isover !~ /^3\..+/)) {
						fsmEnd("L'image iso ne correspond pas : $type $ver -> $isoprod $isover", RET_PRE_UPDATEVERSION);
					}
				}
				if ($ver =~ /^3\..+/) {
					$updscript = "/etc/yasdi/update_kmcbox3.sh";
					if (($isoprod ne "KmcBox") || ($isover!~ /^4\..+/)) {
						fsmEnd("L'image iso ne correspond pas : $type $ver -> $isoprod $isover", RET_PRE_UPDATEVERSION);
					}
				}
				if ($ver =~ /^4\..+/) {
					$updscript = "/etc/yasdi/update_kmcbox4.sh";
					if (($isoprod ne "KmcBox") || ($isover!~ /^5\..+/)) {
						fsmEnd("L'image iso ne correspond pas : $type $ver -> $isoprod $isover", RET_PRE_UPDATEVERSION);
					}
				}
				if ($ver =~ /^5\..+/) {
					$updscript = "/etc/yasdi/update_kmcbox4.sh";
					if (($isoprod ne "KmcBox") || ($isover!~ /^5\..+/)) {
						fsmEnd("L'image iso ne correspond pas : $type $ver -> $isoprod $isover", RET_PRE_UPDATEVERSION);
					}
				}
			
			}
			
			if ($updscript eq "") {
				fsmEnd("Le script de mise  jour est indfini", RET_PRE_UPDATEVERSION);
			}
			
			if ($info) {
				
				print ("Mise__jour_de_version [$ver] ($isover download.kwartz.com)");
			} else {
				if (open (LOGFILE, ">>$VARLOGFILE")) {
					print LOGFILE "Mise  jour de version de $ver vers $isover\n";
					close LOGFILE;
				}
			
				$res = 0;
				# Do checks
				# enum retcode { UPD_K7_OK, UPD_K7_SERVICES, UPD_K7_VERSION, UPD_K7_LOCK, UPD_K7_INSSERV, UPD_K7_APTUPDATE, UPD_K7_SIMULATE, UPD_K7_APT, UPD_K7_KMC, UPD_K7_NOLICENCE, UPD_K7_LICENCEKO, UPD_K7_MEM }
				use constant {
					UPD_K7_OK 			=>  0, # OK
					UPD_K7_SERVICES		=>  1, # Certains services sont en alerte
					UPD_K7_VERSION		=>  2, # autoupdate  faire (A priori on ne tombe pas dedans)
					UPD_K7_LOCK			=>  3, # une autre installation/vrification est en cours
					UPD_K7_INSSERV		=>  4, # Soucis avec headers de services
					UPD_K7_APTUPDATE	=>  5, # Impossible de mettre  jor la liste des paquets
					UPD_K7_SIMULATE		=>  6, # Soucis avec la simulation de mise  jour
					UPD_K7_APT			=>  7, # La mise  jour a chou
					UPD_K7_KMC			=>  8, # La licence kmc ne permet pas la mise  jour
					UPD_K7_NOLICENCE	=>  9, # Pas de licence
					UPD_K7_LICENCEKO	=> 10, # licence incorrecte
					UPD_K7_MEM			=> 11, # Moins de 2 Go de mmoire
					UPD_K7_ROOTSIZE		=> 12, # / infrieure  2 Go
					UPD_K7_FREESPACE2	=> 13, # alerte FREESPACE2 (systme)
					UPD_K7_FREESPACE1	=> 14, # alerte FREESPACE1 (utilisateur)
					UPD_K7_VERMODIFIED	=> 15, # modification /etc/debian_version
					UPD_K7_CONFIGFAIL	=> 16, # erreur test_config
				};
				my @errmsg = ();
				if ($res = UpdateExecLog("$updscript test_services", \@errmsg)) {
					if ($#errmsg > 1) { # Must be 3 lines min
						# Last line of $updscript is date when called in pipe context
						# Previous one is generic message
						# Previous one is last service tested
						if ($errmsg[$#errmsg-2] eq "Redemarrage en attente") {
							fsmEnd("Le serveur doit tre redmarr", RET_PRE_UPDATEVERSION);
						}
						if ($errmsg[$#errmsg-2] eq "Bases MySQL a corriger") {
							fsmEnd("Les bases MySQL doivent tre corriges", RET_PRE_UPDATEVERSION);
						}
						if ($errmsg[$#errmsg-2] eq "Certificat MDM a renouveler") {
							fsmEnd("Le certificate MDM ne s'est pas renouvel", RET_PRE_UPDATEVERSION);
						}
                    } 
					fsmEnd("Des services sont en alerte. La mise  jour ne peut dbuter", RET_PRE_UPDATEVERSION);
				}
				if ($res = UpdateExecLog("$updscript test_config", \@errmsg)) {
					if ($res == UPD_K7_MEM) {
						fsmEnd("Vous devez disposer au minimum de 2 Go de RAM pour mettre  jour", RET_PRE_UPDATEVERSION);
					} elsif ($res == UPD_K7_ROOTSIZE) {
						fsmEnd("Vous devez disposer d'une partition racine de 2 Go pour mettre  jour.", RET_PRE_UPDATEVERSION);
					} elsif ($res == UPD_K7_FREESPACE2) {
						if ($#errmsg > 1) { # Must be 2 lines min
							# Last line of $updscript is date when called in pipe context
							# Previous one is message
							fsmEnd($errmsg[$#errmsg-1], RET_PRE_UPDATEVERSION);
						} else { 
							fsmEnd("L'espace systme disponible est trop petit pour mettre  jour", RET_PRE_UPDATEVERSION);
						}
					} elsif ($res == UPD_K7_FREESPACE1) {
						if ($#errmsg > 1) { # Must be 2 lines min
							# Last line of $updscript is date when called in pipe context
							# Previous one is message
							fsmEnd($errmsg[$#errmsg-1], RET_PRE_UPDATEVERSION);
						} else { 
							fsmEnd("L'espace utilisateur disponible est trop petit pour mettre  jour", RET_PRE_UPDATEVERSION);
						}
					} elsif ($res == UPD_K7_VERMODIFIED) {
						fsmEnd("Le fichier de version a t modifi manuellement", RET_PRE_UPDATEVERSION);
					} else {
						fsmEnd("Un soucis de configuration du serveur interdit la mise  jour", RET_PRE_UPDATEVERSION);
					}
				}
				
				# Select iso
    			if ($res = UpdateExecLog("$updscript select_iso $gIso")) {
					fsmEnd("Impossible d'accder  l'iso de Kwartz tlcharge", RET_PRE_UPDATEVERSION);
    			}
				
				@errmsg = ();
				if ($res = UpdateExecLog("$updscript test_versions", \@errmsg)) {
					if ($res == UPD_K7_VERSION) {
						if ($#errmsg > 0) { # Must be 2 lines min
							# Last line of $updscript is date when called in pipe context
							fsmEnd($errmsg[$#errmsg-1], RET_PRE_UPDATEVERSION);
						} else {
							fsmEnd("Vous devez faire les mises  jour  distance avant d'actualiser la version de Kwartz", RET_PRE_UPDATEVERSION);
						}
					} elsif ($res == UPD_K7_KMC) {
						fsmEnd("Votre licence KMC ne vous permet pas de faire cette mise  jour de kwartz", RET_PRE_UPDATEVERSION);
					} elsif ($res == UPD_K7_NOLICENCE) {
						fsmEnd("L'absence de licence ne vous permet pas de faire cette mise  jour de kwartz", RET_PRE_UPDATEVERSION);
					} elsif ($res == UPD_K7_LICENCEKO) {
						fsmEnd("Votre licence kwartz est invalide", RET_PRE_UPDATEVERSION);
					} else {
						fsmEnd("Un problme de vrification a t rencontr", RET_PRE_UPDATEVERSION);
					}
				}

				# Remove Holds
				DoHoldApt([0, ""]);
				
				# Simulate
    			if ($res = UpdateExecLog("$updscript update_simulate")) {
					fsmEnd("La simulation de mise  jour a chou", RET_PRE_UPDATEVERSION);
    			}
    		}	
		} elsif ($state eq "UpdateVersion") {
			if (! $info) {
				# Really update
				next if (!defined($opt_U));
				
				#  Set /run flag
				mysystem("touch /run/kwartz-update");
				#  Stop mon
				mysystem("invoke-rc.d mon stop >> $VARLOGFILE 2>&1");
				myback("sed -e 's/ENABLED=.*/ENABLED=\"no\"/' -i /etc/default/mon");
				#  Launch
				$res = UpdateExecLog("$updscript update");
				#  Start mon
				myback("sed -e 's/ENABLED=.*/ENABLED=\"yes\"/' -i /etc/default/mon");
				mysystem("invoke-rc.d mon start >> $VARLOGFILE 2>&1");
				#  Unset /run flag
				unlink("/run/kwartz-update");
				
				# $res est le rsultat de update
				# Veiller  ce qu'il ne soit pas modifi entre xxx update et ici
				if ($res) {
					fsmEnd("La mise  jour a chou", RET_UPDATEVERSION);
				} 

				# Suggests reboot
				mysystem("touch /var/run/reboot-required");
				mysystem("echo kwartz-dist-upgrade >> /var/run/reboot-required.pkgs");
			}
			#
		}
		# state CheckLoop2 is here (See CheckLoop)
		elsif ($state eq "End") {
			if ((Compare_Version("6.0r2")<=0) and $type eq "Server") {
				mysystem ("echo kwartz-mdm-core hold | dpkg --set-selections 2>&1");
			}
			
			# Retire les Hold
			DoHoldApt([0, ""]);
			
			mysystem ("apt-get autoclean >/dev/null 2>&1");
		}
	}
	#TODO: Ce n'est pas propre de mettre un exit ici
	myexitlog($fsmExitStr, $fsmExitStr, $fsmExit) if ($fsmExit != 0);
	return 0;
}

sub url_to_list
{
    my ($url) = @_;
    $url =~ s/^(http|ftp):\/\///;
    $url =~ s/\//_/g;
	$url =~ s/\.gz$//;
    $url =~ s/\.bz2$//;
	return $url;
}

sub url_to_uri
{
	my ($url) = @_;
	my $uri = "";

	$uri = "deb $1 $2 $3" if ($url =~ m/^((?:http|ftp):\/\/[\w.]+)\/dists\/([\w\/]+)\/(main|contrib|non-free)\/binary-i386/);
	return $uri;
}

# Mise a jour du kernel
# Le dernier truc a changer, apres on redemarre
sub Kernel
{
	my ($info) = @_;
	my $uri = "deb [trusted=yes] https://$upd_user\:$upd_pass\@kwartz.iris-tech.com/update/   $autoupdate$restricted/$type/$ver/";
	my $res = 0;
	my $badkey = 0;
	my $kernel= "kernel-image-2.6";
	my $kerneldeb = "";
	my @kernels;
	my $issmp = 0;
	my $kernelinstdebver = 0;

	$kernel = "kernel-image-2.4" if ($krel =~ m/2.4/);

	
	my @updates = `apt-cache -o Dir::Etc::SourceList=$SOURCE --names-only search $kernel 2>/dev/null`;
	# boucle sur tous les noyaus dispos
	# mme ceux installs
	# quelle que soit leur version
   	foreach (@updates) {
		chomp;
		s/ .*//;
		# on saute les noyaux installs pour l'instant indpendamment de leur version debian
		# sur kwartz on incrmente les version du noyau, pas du paquet
#		(my $k1 = $_) =~ s/$/smp/;
#		(my $k2 = $_) =~ s/smp//;
#		next if (`dpkg -s $_ 2>/dev/null | grep " installed"`);
#		next if (`dpkg -s $k1 2>/dev/null | grep " installed"`);
#		next if (`dpkg -s $k2 2>/dev/null | grep " installed"`);
	# teste la version du kernel	
	if (m/image-(\S+)/) {
			next if ($1 lt $krel)
		}
   		push @kernels,$_;
	}
	$issmp = 1 if ($kver =~ m/SMP/);
	my @k;
	if ($issmp) {
		@k = grep (/smp/,@kernels);
	}
	if (($#k < 0) || ($issmp == 0)) {
		@k = grep (!/smp/,@kernels);
	}
	return 0 if ($#k < 0);
	$kerneldeb = $k[0];
	my @fullinfo = `apt-cache -o Dir::Etc::SourceList=$SOURCE --names-only --full search $kerneldeb 2>/dev/null`;
	my $kerneldebver;
	foreach (@fullinfo) {
		if (m/^Version: (\S+)$/) {
			$kerneldebver = $1;
			last;
		}
	}
	# test de la version debian
	if (mysystem ("dpkg -s $kerneldeb 2>/dev/null | grep -q ' installed'") == 0) {
		my @fulldeb = `dpkg -s $kerneldeb`;
		foreach (@fulldeb) {
			if (m/^Version: (\S+)$/) {
				$kernelinstdebver = $1;
				last;
			}
		}
		return 0 if ($kernelinstdebver eq "");
		return 0 if (mysystem("dpkg --compare-versions $kerneldebver le $kernelinstdebver") == 0);
	}
	if ($info) {
		print "$kerneldeb ($kerneldebver kwartz.iris-tech.com)\n";
	} else {
		mysystem ("apt-get -qmy -o Dir::Etc::SourceList=$SOURCE -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold install $kerneldeb >> $VARLOGFILE 2>&1");
		my $res = ($?>>8);
		mysystem ("apt-get autoclean >/dev/null 2>&1");
		if ($res != 0) {
			print "Impossible de mettre  jour le noyau linux : $kerneldeb\n";
			return 1;
		}
	}
	return 0;
}

# Get_Part_Size
#  Renvoie l'espace total en Mo fourni par df -m 
#  df -m calcule ainsi :
#   total [1]
#   used  [2]
#   free  [3]
##
sub Get_Part_Size
{
	my $part = shift;

	my @diskused = `df -m $part`;
	my $fs = 0;
	foreach (@diskused) {
    	next if (! m/^\//);
	    my @fields = split;
    	$fs += $fields[1]*1000;
	}
	return $fs;
}

# Get_Free_Size
#  Renvoie l'espace libre user en Mo fourni par df -m 
#  df -m calcule ainsi :
#   total
#	used = total - available_to_root
#	free = available
##
sub Get_Free_Size
{
	my $part = shift;

	my @diskused = `df -m $part`;
	my $fs = 0;
	foreach (@diskused) {
    	next if (! m/^\//);
	    my @fields = split;
    	$fs += $fields[3]*1000;
	}
	return $fs;
}

# Get_Free_Root_Size
#  Renvoie l'espace libre pour root en Mo fourni par df -m 
sub Get_Free_Root_Size
{
	my $part = shift;

	my @diskused = `df -m $part`;
	my $fs = 0;
	foreach (@diskused) {
    	next if (! m/^\//);
	    my @fields = split;
    	$fs += ($fields[1]-$fields[2])*1000;
	}
	return $fs;
}

# Get_Used_Dir_Size
#  Renvoie l'espace utilis en Mo par du -sm
##
sub Get_Used_Dir_Size
{
	my $dir = shift;

	my $diskused = `du -smx $dir`; chomp $diskused;
	return (split(' ', $diskused))[0];
}


# is_mounted
#  Renvoie vrai si partition monte
sub is_mounted
{
	my $part = shift;
	my $partmounted = 0;
	eval {
		open (PROC, "</proc/mounts");
	};
	if (!$@) {
		foreach (<PROC>) {
			$partmounted++ if (m/$part/);
		}
		close PROC;
	}
	return ($partmounted);
}


sub Special_Corrections
{
    my ($info, $reflist) = @_;
	my $cor = 0;

	# correction nut
	if ((Compare_Version("7.0")<0) and (Compare_Version("6.0r1")>=0) and $type eq "Server") {
	    my $v1=`dpkg -s nut 2>/dev/null| grep ^Version | awk '{print \$2}'`; chomp $v1;
    	mysystem("dpkg --compare-versions \"$v1\" gt \"2.6.3-1ubuntu1.1kwartz1\"");
	    if (($?>>8) == 0) {
			if ($info) {
				$cor++;
				print "kwartz-correctif-nut [0.0] (20141210 correctif_intgr)\n";
			} else {
				system ("echo Correctif intgr nut >> $VARLOGFILE");
	    	    mysystem ("apt-get -qy --force-yes --ignore-hold -o Dir::Etc::SourceList=$SOURCE -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold install nut=2.6.3-1ubuntu1.1kwartz1 nut-cgi=2.6.3-1ubuntu1.1kwartz1 nut-server=2.6.3-1ubuntu1.1kwartz1 nut-client=2.6.3-1ubuntu1.1kwartz1 >> $VARLOGFILE 2>&1");
				mysystem("/etc/init.d/nut-server restart");
			}
    	}
	} # nut

	# correction maj secu sqlite
	if ((Compare_Version("5.0r0")>=0) and $type eq "Server") {
		my $v1=`dpkg -s libsqlite3-0:amd64 2>/dev/null| grep ^Version | awk '{print \$2}'`; chomp $v1;
        if ("$v1" eq "" or "$v1" eq "3.7.9-2ubuntu1.1") {
			my $v2=`dpkg -s libsqlite3-0 2>/dev/null| grep ^Version | awk '{print \$2}'`; chomp $v2;
			if ("$v2" gt "3.7.9-2ubuntu1.1") {
				if ($info) {
					$cor++;
					print "kwartz-correctif-sqlite [0.0] (20150805 correctif_intgr)\n";
				} else {
					system ("echo Correctif intgr sqlite >> $VARLOGFILE");
					DoOptaCommand("update");
					DoOptaCommand("install", "", "--ignore-hold", ("sqlite3=3.7.9-2ubuntu1.1", "libsqlite3-0=3.7.9-2ubuntu1.1"));
				}
			}
		}
		if ((Compare_Version("6.0r3")<0) and "$v1" gt "3.7.9-2ubuntu1.1") {
			if ($info) {
            	$cor++;
                print "kwartz-correctif-sqlite [0.0] (20150805 correctif_intgr)\n";
			} else {
				system ("echo Correctif intgr sqlite >> $VARLOGFILE");
				DoOptaCommand("update");
				DoOptaCommand("install", "", "--ignore-hold", ("sqlite3=3.7.9-2ubuntu1.1", "libsqlite3-0=3.7.9-2ubuntu1.1", "libsqlite3-0:amd64=3.7.9-2ubuntu1.1"));
			}
		}
		if ((Compare_Version("6.0r3")>=0)) {
			mysystem ("echo sqlite3 install | dpkg --set-selections 2>&1");
			mysystem ("echo libsqlite3-0 install | dpkg --set-selections 2>&1");
			mysystem ("echo libsqlite3-0:amd64 install | dpkg --set-selections 2>&1");
		} else {
			mysystem ("echo sqlite3 hold | dpkg --set-selections 2>&1");
			mysystem ("echo libsqlite3-0 hold | dpkg --set-selections 2>&1");
			mysystem ("echo libsqlite3-0:amd64 hold | dpkg --set-selections 2>&1");
		}		
	}

	# correction ulogd
	# Ncessaire pour les noyaux 64 bits ( partir de 5.2r0)
	if ((Compare_Version("5.2r0")>=0) and (Compare_Version("7.0a0")<0) and $type eq "Server") {
		my $v1=`dpkg -s ulogd:amd64 2>/dev/null| grep ^Version | awk '{print \$2}'`; chomp $v1;
		if ("$v1" eq "") {
			if ($info) {
				$cor++;
				print "kwartz-correctif-ulogd [0.0] (20141210 correctif_intgr)\n";
			} else {
				system ("echo Correctif intgr ulogd >> $VARLOGFILE");
				DoOptaCommand("update");
				DoOptaCommand("install", "", "--ignore-hold", ("libsqlite3-0:amd64"));
				DoOptaCommand("install", "", "--ignore-hold", ("ulogd:amd64"));
				DoOptaCommand("install", "", "--ignore-hold", ("ulogd-sqlite3:amd64"));
				mysystem ("dpkg --force-confold --configure -a >> $VARLOGFILE 2>&1");
			}
		}
	} # ulogd

	# Corrections perms /home
	if ((Compare_Version("5.2r0")>=0) and $type eq "Server") {
		my $sb = stat("/home");
		if ($sb->mode & S_IWGRP) {
			if ($info) {
				$cor++;
				print "kwartz-correctif-perms [0.0] (20141210 correctif_intgr)\n";
			} else {
				system ("echo Correctif intgr perms /home >> $VARLOGFILE");
				mysystem("chmod 0755 /home >> $VARLOGFILE 2>&1");
			}
		}
	}	# perms /home

	# Correction UUID swap
	if ((Compare_Version("5.0r0")>=0) and $type eq "Server") {
		# Test UUID /dev/xxx2
		my $swap=`/sbin/blkid -t TYPE="swap"`;
		my $swapuuid="";
		my $swapname="";
		my $fstabko = 0;
		my $uuid;

		$swapuuid=$1 if ($swap =~ m/UUID=(\S+)/);
		$swapname=$1 if ($swap =~ m/(^\S+):/);
	
		if ($swap ne "" && $swapuuid eq "") {
			if ($info) {
				$cor++;
				print "kwartz-correctif-swap [0.0] (20141216 correctif_intgr)\n";
			} else {
				system ("echo Correctif intgr uuid swap >> $VARLOGFILE");
				$uuid=`uuidgen`; chomp $uuid;
				mysystem("swaplabel -U $uuid $swapname  >> $VARLOGFILE 2>&1") if ($swapname ne "");
			}
		}
			
		# Test fstab
		eval {
			open (FSTAB, "</etc/fstab");
		};
		if (!$@) {
			foreach (<FSTAB>) {
				$fstabko++ if (m/UUID=\s+none\s+swap/);
			}
			close FSTAB;
		}

		if ($fstabko) {
			if ($info && defined($swapuuid) ) {
				$cor++;
				print "kwartz-correctif-swapfstab [0.0] (20140209 correctif_intgr)\n";
			}
			if (!$info && (defined($swapuuid) || $uuid)) {
				system ("echo Correctif intgr uuid fstab swap >> $VARLOGFILE");
				$uuid = $swapuuid if (!$uuid);
				mysystem("sed -e '/^UUID= none/s/UUID=/UUID=${uuid}/' -i.bak /etc/fstab >> $VARLOGFILE 2>&1");
				if ($? == 0) {
					unlink("/etc/fstab.bak");
					mysystem("swapon -a");
				} else {
					mysystem("mv -vf /etc/fstab.bak /etc/fstab >> $VARLOGFILE 2>&1");
				}
			}
		}
	}
	##


	if ((Compare_Version("7.0r0")>=0) and $type eq "Server") {
		# MATCH k7
		my $required=0;
		# check kwartz-ldap version
		my $ldap_ver = `dpkg -s kwartz-ldap 2>/dev/null| grep ^Version | awk '{print \$2}'`; chomp $ldap_ver;
		mysystem("dpkg --compare-versions \"$ldap_ver\" lt \"5.2-1\"");
		$required=1 if (($?>>8) == 0);
		if ($required) {
			# candidate_version
			my $candidate=candidate_version('kwartz-ldap');
			print STDERR "kwartz-ldap candidate:$candidate\n"  if ($opt_v);
			if ($candidate) {
				if ( system("dpkg", "--compare-versions", $candidate, 'ge', '5.2-0') == 0 ) {					
					if ($info) {
						print "nscld-migration [0.0] (20180517 kwartz.iris-tech.com)\n";
						# print("apt-get -qy --force-yes --ignore-hold -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold install nslcd libnss-ldapd libnss-ldapd:i386 libpam-ldapd libpam-ldapd:i386 kwartz-ldap >> $VARLOGFILE 2>&1");
					} else {
						# warn should remove /etc/kwartz/sources.list.d/
						my $apt_cmd="apt-get -qy --force-yes --ignore-hold -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold install nslcd libnss-ldapd libnss-ldapd:i386 libpam-ldapd libpam-ldapd:i386 kwartz-ldap";
						my $redir=($opt_v)?"2>&1 | tee -a $VARLOGFILE 1>&2":">>$VARLOGFILE 2>&1";
						mysystem("$apt_cmd $redir");
						#run apt-get autoremove
						mysystem("apt-get -qy autoremove $redir");
					}
				}
			}
		}
	}
	##

    # Protection disque pulse dbranch
	if ((Compare_Version("7.0r0")>=0) and $type eq "Server") {
		my $fstabko = 0;
		my $ispulsedisk = mysystem("grep -q deploy /etc/fstab");

		if ($ispulsedisk == 0) {

			# Test fstab
			eval {
				open (FSTAB, "</etc/fstab");
			};
			if (!$@) {
				foreach (<FSTAB>) {
					$fstabko++ if (m|^UUID=.*/home/kwartz/deploy.*defaults,acl,user_xattr\s+|);
				}
				close FSTAB;
			}

			if ($fstabko) {
				if ($info && $fstabko) {
					$cor++;
					print "kwartz-correctif-pulsefstab [0.0] (20201118 correctif_intgr)\n";
				}
				if (!$info && $fstabko) {
					system ("echo Correctif intgr pulse fstab nofail >> $VARLOGFILE");
					mysystem("sed -e '\\;/home/kwartz/deploy;s;defaults,acl,user_xattr;defaults,acl,user_xattr,nofail;' -i.bak /etc/fstab >> $VARLOGFILE 2>&1");
					if ($? == 0) {
						unlink("/etc/fstab.bak");
					} else {
						mysystem("mv -vf /etc/fstab.bak /etc/fstab >> $VARLOGFILE 2>&1");
					}
				}
			}
		}
	}
    ##
    
	# BPO 20230125 Correction K9 PDC hs suite maj dpot security focal samba 2:4.13.17~dfsg-0ubuntu1.20.04.4
	# modifie BPO 20200429 Correction K8 ldap AD hs suite maj dpot security xenial samba : inutile corrig par ubuntu
	# A supprimer si samba publie un correctif
	# modifie BPO 20230209 : corrige soucis si la version 2:4.13.17~dfsg-0ubuntu1.20.04.5 a t installe juste aprs passage upgrade vers k9.
	# supprim BPO 20230308 : diffusion 2:4.15.13+dfsg-0ubuntu0.20.04.1 qui vient avec libldb2 2:2.4.4-0ubuntu0.20.04.1 incompatible avec samba 2:4.13.17~dfsg-0ubuntu1.20.04.1
	if ((Compare_Version("9.0r0")==0) and $type eq "Server" and (! -f "/var/lib/samba/private/sam.ldb")) {
		# MATCH k9
		my $required=0;
		if ( ! -f "/etc/apt/preferences.d/samba90" ) {
		    my $CFG;
		    if (open($CFG, "> /etc/apt/preferences.d/samba90")) {

			    print $CFG <<_MARKER_;
Package: samba-vfs-modules
Pin: version 2:4.13.17~dfsg-0ubuntu1.20.04.1
Pin-Priority: 1000

Package: samba-dsdb-modules
Pin: version  2:4.13.17~dfsg-0ubuntu1.20.04.1
Pin-Priority: 1000

Package: samba:amd64
Pin: version  2:4.13.17~dfsg-0ubuntu1.20.04.1
Pin-Priority: 1000

Package: samba-common-bin
Pin: version  2:4.13.17~dfsg-0ubuntu1.20.04.1
Pin-Priority: 1000

Package: smbclient
Pin: version  2:4.13.17~dfsg-0ubuntu1.20.04.1
Pin-Priority: 1000

Package: libsmbclient
Pin: version  2:4.13.17~dfsg-0ubuntu1.20.04.1
Pin-Priority: 1000

Package: python3-samba
Pin: version  2:4.13.17~dfsg-0ubuntu1.20.04.1
Pin-Priority: 1000

Package: samba-libs
Pin: version  2:4.13.17~dfsg-0ubuntu1.20.04.1
Pin-Priority: 1000

Package: libwbclient0
Pin: version  2:4.13.17~dfsg-0ubuntu1.20.04.1
Pin-Priority: 1000

Package: winbind
Pin: version  2:4.13.17~dfsg-0ubuntu1.20.04.1
Pin-Priority: 1000

Package: samba-common
Pin: version  2:4.13.17~dfsg-0ubuntu1.20.04.1
Pin-Priority: 1000
_MARKER_

	    		close($CFG);
			}
		}	
	
		my $samba_ver = `dpkg -s samba 2>/dev/null| grep ^Version | awk '{print \$2}'`; chomp $samba_ver;
   	    mysystem("dpkg --compare-versions \"$samba_ver\" eq \"2:4.13.17~dfsg-0ubuntu1.20.04.4\"");
   	    $required=1 if (($?>>8) == 0);
    	if ($required) {
		# candidate_version
   	        my $candidate=candidate_version('samba');
       	    print STDERR "samba candidate:$candidate\n"  if ($opt_v);
           	if ($candidate) {
    	        if ( system("dpkg", "--compare-versions", $candidate, 'eq', '2:4.13.17~dfsg-0ubuntu1.20.04.1') == 0 ) {
   	            	if ($info) {
       		           	if (defined($reflist)) {
							push @$reflist, "kwartz-correctif-samba [0.1] (20230125 kwartz.iris-tech.com)";
						}
                   		#print("apt-get -qsuy --force-yes --ignore-hold -o Dir::Etc::SourceList=$source_s -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold dist-upgrade --allow-downgrades >> $varlogfile 2>&1");
					} else {
						# --allow-downgrades remplace --force-yes pour K8> : beaucoup plus sur
#		         		my $apt_cmd="apt-get -quy --force-yes --ignore-hold -o Dir::Etc::SourceList=$source_s -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold dist-upgrade --allow-downgrades";
		         		my $apt_cmd="apt-get -quy -o Dir::Etc::SourceList=/etc/kwartz/sources_s.list -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold install samba-vfs-modules=2:4.13.17~dfsg-0ubuntu1.20.04.1 samba-dsdb-modules=2:4.13.17~dfsg-0ubuntu1.20.04.1 samba=2:4.13.17~dfsg-0ubuntu1.20.04.1 samba-common-bin=2:4.13.17~dfsg-0ubuntu1.20.04.1 smbclient=2:4.13.17~dfsg-0ubuntu1.20.04.1 libsmbclient=2:4.13.17~dfsg-0ubuntu1.20.04.1 python3-samba=2:4.13.17~dfsg-0ubuntu1.20.04.1 samba-libs=2:4.13.17~dfsg-0ubuntu1.20.04.1 libwbclient0=2:4.13.17~dfsg-0ubuntu1.20.04.1 winbind=2:4.13.17~dfsg-0ubuntu1.20.04.1 samba-common=2:4.13.17~dfsg-0ubuntu1.20.04.1 --allow-downgrades";
   	    		 		my $redir=($opt_v)?"2>&1 | tee -a $VARLOGFILE 1>&2":">>$VARLOGFILE 2>&1";
						mysystem("$apt_cmd $redir");
		            }
				}
			}
#		} elsif (system("dpkg --compare-versions \"$samba_ver\" ne \"2:4.13.17~dfsg-0ubuntu1.20.04.1\"") == 0) {
		} else {
			unlink ("/etc/apt/preferences.d/samba90");
		}
	} ##
	
	# BPO 20240411 Correction squid hs suite maj dpot security focal squid squid_4.10-1ubuntu1.10_amd64.deb
	# correctif ubuntu diffus 4.10-1ubuntu1.11
	
#	if (($ver ge "9.0r0" and $type eq "Server") ||
#		($ver ge "4.0r0" and $type eq "kmcbox")) {
#		# MATCH k9 / kmcbox4
#		my $required=0;
#		if ( ! -f "/etc/apt/preferences.d/squid410" ) {
#		    my $CFG;
#		    if (open($CFG, "> /etc/apt/preferences.d/squid410")) {
#
#			    print $CFG <<_MARKER_;
#Package: squid
#Pin: version 4.10-1ubuntu1.9
#Pin-Priority: 1000
#
#Package: squid-common
#Pin: version 4.10-1ubuntu1.9
#Pin-Priority: 1000
#
#Package: squidclient
#Pin: version 4.10-1ubuntu1.9
#Pin-Priority: 1000
#_MARKER_
#
#	    		close($CFG);
#			}
#		}	
#	
#		my $squid_ver = `dpkg -s squid 2>/dev/null| grep ^Version | awk '{print \$2}'`; chomp $squid_ver;
#		mysystem("dpkg --compare-versions \"$squid_ver\" eq \"4.10-1ubuntu1.10\"");
# 	    $required=1 if (($?>>8) == 0);
# 	if ($required) {
#		# candidate_version
#   	        my $candidate=candidate_version('squid');
#       	    print STDERR "squid candidate:$candidate\n"  if ($opt_v);
#           	if ($candidate) {
#    	        if ( system("dpkg", "--compare-versions", $candidate, 'eq', '4.10-1ubuntu1.9') == 0 ) {
#   	            	if ($info) {
#       		           	if (defined($reflist)) {
#							push @$reflist, "kwartz-correctif-squid [0.1] (20240411 kwartz.iris-tech.com)";
#						}
#                   		#print("apt-get -qsuy --force-yes --ignore-hold -o Dir::Etc::SourceList=$source_s -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold dist-upgrade --allow-downgrades >> $varlogfile 2>&1");
#					} else {
#						# --allow-downgrades remplace --force-yes pour K8> : beaucoup plus sur
#		         		my $apt_cmd="apt-get -quy -o Dir::Etc::SourceList=/etc/kwartz/sources_s.list -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold install squid-common=4.10-1ubuntu1.9 squid=4.10-1ubuntu1.9 squidclient=4.10-1ubuntu1.9 --allow-downgrades";
#   	    		 		my $redir=($opt_v)?"2>&1 | tee -a $VARLOGFILE 1>&2":">>$VARLOGFILE 2>&1";
#						mysystem("$apt_cmd $redir");
#		            }
#				}
#			}
#		} elsif (system("dpkg --compare-versions \"$squid_ver\" ne \"4.10-1ubuntu1.9\"") == 0) {
#			unlink ("/etc/apt/preferences.d/squid410");
#		}
#	} ##	

#	# BPO 20241213 Correction nextcloud hs suite maj dpot security focal php7.4
#	# correctif ubuntu diffus 7.4.3-4ubuntu2.26
#	
#	if (($ver ge "9.0r0" and $type eq "Server") ||
#		($ver ge "4.0r0" and $type eq "kmcbox")) {
#		# MATCH k9 / kmcbox4
#		my $required=0;
#		if ( ! -f "/etc/apt/preferences.d/php74" ) {
#		    my $CFG;
#		    if (open($CFG, "> /etc/apt/preferences.d/php74")) {
#
#			    print $CFG <<_MARKER_;
#Package: php7.4-common
#Pin: version 7.4.3-4ubuntu2.24
#Pin-Priority: 1000
#
#Package: php7.4
#Pin: version 7.4.3-4ubuntu2.24
#Pin-Priority: 1000
#_MARKER_
#
#	    		close($CFG);
#			}
#		}	
#	
#		my $php_ver = `dpkg -s php7.4 2>/dev/null| grep ^Version | awk '{print \$2}'`; chomp $php_ver;
#		mysystem("dpkg --compare-versions \"$php_ver\" eq \"7.4.3-4ubuntu2.26\"");
# 	    $required=1 if (($?>>8) == 0);
# 	if ($required) {
#		# candidate_version
#   	        my $candidate=candidate_version('php7.4');
#       	    print STDERR "php7.4 candidate:$candidate\n"  if ($opt_v);
#           	if ($candidate) {
#    	        if ( system("dpkg", "--compare-versions", $candidate, 'eq', '7.4.3-4ubuntu2.24') == 0 ) {
#   	            	if ($info) {
#       		           	if (defined($reflist)) {
#							push @$reflist, "kwartz-correctif-php74 [0.1] (20241213 kwartz.iris-tech.com)";
#						}
#						unlink("/etc/apt/preferences.d/php74");
#                   		#print("apt-get -qsuy --force-yes --ignore-hold -o Dir::Etc::SourceList=$source_s -o Dir::Etc::SourceParts='/etc/kwartz/#sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold dist-upgrade --allow-downgrades >> $varlogfile 2>&1");
#					} else {
#						# --allow-downgrades remplace --force-yes pour K8> : beaucoup plus sur
#		         		my $apt_cmd="apt-get -quy -o Dir::Etc::SourceList=/etc/kwartz/sources_s.list -o Dir::Etc::SourceParts='/etc/kwartz/#sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold install php7.4=7.4.3-4ubuntu2.24 php7.4-#common=7.4.3-4ubuntu2.24 libapache2-mod-php7.4=7.4.3-4ubuntu2.24 php7.4-cli=7.4.3-4ubuntu2.24 php7.4-json=7.4.3-4ubuntu2.24 php7.4-#opcache=7.4.3-4ubuntu2.24 php7.4-readline=7.4.3-4ubuntu2.24 php7.4-bcmath=7.4.3-4ubuntu2.24 php7.4-cgi=7.4.3-4ubuntu2.24 php7.4-curl=7.4.3-4ubuntu2.24 #php7.4-fpm=7.4.3-4ubuntu2.24 php7.4-gd=7.4.3-4ubuntu2.24 php7.4-gmp=7.4.3-4ubuntu2.24 php7.4-imap=7.4.3-4ubuntu2.24 php7.4-intl=7.4.3-4ubuntu2.24 #php7.4-ldap=7.4.3-4ubuntu2.24 php7.4-mbstring=7.4.3-4ubuntu2.24 php7.4-mysql=7.4.3-4ubuntu2.24 php7.4-pspell=7.4.3-4ubuntu2.24 php7.4-#soap=7.4.3-4ubuntu2.24 php7.4-xml=7.4.3-4ubuntu2.24 php7.4-zip=7.4.3-4ubuntu2.24 --allow-downgrades --no-remove";
#   	    		 		my $redir=($opt_v)?"2>&1 | tee -a $VARLOGFILE 1>&2":">>$VARLOGFILE 2>&1";
#						mysystem("$apt_cmd $redir");
#		            }
#				}
#			}
#		} elsif (system("dpkg --compare-versions \"$php_ver\" ne \"7.4.3-4ubuntu2.24\"") == 0) {
#			unlink ("/etc/apt/preferences.d/php74");
#		}
#	} ##

# calls hook
	if ($info) {
		# this file is a HASH type config file that can be used
                # by hooks handler store data used during update process
                # it is used by kwartz-mongo not to apply updates that
                # haven't been previously shown in kwartzcontrol
		unlink "/var/run/kwartz-autoupdate/status.conf";
		my @all_special = qx(kwartz-hook emit core/autoupdate-special info);
		foreach my $desc (@all_special) {
			$cor++;
			from_to($desc,"UTF-8","iso-8859-15");
			print $desc;
		}
	} else {
		mysystem("kwartz-hook emit core/autoupdate-special apply >> $VARLOGFILE 2>&1");
	}


} # Special_Corrections()

# installed_preference(name)
# return presence of /etc/apt/preferences.d/name
sub installed_preference {
	my $name = shift;
	return (-f "/etc/apt/preferences.d/$name");
}

# do_install_preference(name, content)
# create preference file
# name : /etc/apt/preferences.d/name
# content : strings filled into file
sub do_install_preference {
	my $name = shift;
	my $content = shift;
	
	my $file = "/etc/apt/preferences.d/$name";

	my $CFG;
	if (! open($CFG, "> $file")) {
		return ("ERROR: Failure opening '$file' - $!");
	}

	print $CFG $content;
	close($CFG);
	return (undef);   # Success
}

# do_remove_preference(name)
# remove preference file
# name : /etc/apt/preferences.d/name
sub do_remove_preference {
	my $name = shift;
	
	unlink ("/etc/apt/preferences.d/$name");
}
	
# installed_version(package)
# return package installed version
# return empty string on error or if package not installed
sub installed_version {
	my $package=shift;
	return '' unless $package;
	
	my $res=qx/dpkg-query -W $package 2>\/dev\/null/;
	# die "failed to get $package installed version: $!"
	return '' if ($?);
	
	my $status=qx/dpkg-query --showformat=\'\${Status}\' --show $package/;
	return '' if ($status =~ m/deinstall/);
	
	chomp $res;
	$res=~s/^$package\s+//s;
	return  $res;
}

# candidate_version(package)
# return candidate version  for package according to apt preferences (pinning)
# return empty string on error or if no candidate
sub candidate_version {
	my $package=shift;
	my $res='';
	return $res  unless $package;
	my @policy=qx|env LANG=C apt-cache policy -o Dir::Etc::SourceList=/etc/kwartz/sources.list -o Dir::Etc::SourceParts=/etc/kwartz/sources.list.d/ $package|;
	foreach (@policy) {
		chomp;		
		if (  s/^\s+Candidate:\s+// )  {
			$res=$_; 
			last;
		}
	}
	return $res
}

# candidate_allversions(package)
# return more recent distant candidate version for package according independant of apt preferences (pinning)
# return empty string on error or if no candidate
sub candidate_more_recent_500_version {
	my $package=shift;
	my $res='';
	return $res  unless $package;
	my @policy=qx|env LANG=C apt-cache policy -o Dir::Etc::SourceList=/etc/kwartz/sources.list -o Dir::Etc::SourceParts=/etc/kwartz/sources.list.d/ $package|;
	foreach (@policy) {
		chomp;
		if (  m/^\s+(\S+) 500$/ )  {
			$res=$1;
			last;
		}
	}
	return $res
}


# is_pkg_downgrade(package)
# return 1 if package downgrade required ie candidate version lt installed
# else return 0 
sub is_pkg_downgrade {
	my $package=shift;
	return 0 unless $package;
	my $installed=installed_version($package);
	return 0 unless $installed;
	my $candidate=candidate_version($package);
	if ($candidate) {
		if ( system("dpkg", "--compare-versions", $candidate, 'lt', $installed) == 0 ) {
			warn "DOWNGRADE $package from $installed to $candidate...\n";			
			return 1;
		}	
	}
	return 0;
}


sub handle_kmc_downgrade {
	if ( is_pkg_downgrade('kwartz-mdm') ) {		
		print STDERR "KMC mis en VERSION INFERIEURE\n" if ($opt_v);
		# same as kwartz-autoupdate -a install kwartz-mdm kwartz-mdm-core
		# add -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold
		my $cmd="apt-get -quy -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' -o DPKG::Options::=--force-overwrite -o DPKG::Options::=--force-confold install kwartz-mdm kwartz-mdm-core $aptsyntax{'allowdowngrade'}";
		if ($opt_v) {
			mysystem("$cmd 2>&1 | tee -a $VARLOGFILE 1>&2");
		} else {
			mysystem("$cmd >>$VARLOGFILE 2>&1");
		}
	}
}

##
# Add Persistent config capacity to kwartz-autoupdate
# See:
#   https://www.perlmonks.org/?node_id=464358
##

# Read a configuration file
#   The arg can be a relative or full path, or
#   it can be a file located somewhere in @INC.
sub ReadCfg
{   
	my $file = $_[0];
	
	our $err;
	
	{   # Put config data into a separate namespace
		package CFG;
		
		# Process the contents of the config file
		if (! -e $file) {
			our %CFG = ();
		} else {
			my $rc = do($file);
			
			# Check for errors
			if ($@) {
				$::err = "ERROR: Failure compiling '$file' - $@";
			} elsif (! defined($rc)) {
				$::err = "ERROR: Failure reading '$file' - $!";
			} elsif (! $rc) {
				$::err = "ERROR: Failure processing '$file'";
			}
		}
	
	}
	
	return ($err);
}

# Save configuration data
#   Use the same arg as used with ReadCfg()
#   so that file can be found in the %INC.
sub SaveCfg
{
	my $file = $_[0];

	my $CFG;
	if (! open($CFG, "> $file")) {
		return ("ERROR: Failure opening '$file' - $!");
	}

	print $CFG <<_MARKER_;
#####
#
# My configuration file
#
#####

use strict;
use warnings;


# The configuration data
our @{[Data::Dumper->Dump([\%CFG::CFG], ['*CFG'])]}
1;
# EOF
_MARKER_

	close($CFG);
	return (undef);   # Success
}
#


 
#################################
# #
# Valeurs de sortie
#	RET_OK 				=>  0, # OK
#	RET_ERROR			=>  1, # Erreur diverse
#	RET_VARSIZE			=>  2, # /var trop petit
#	RET_HOMESIZE		=>  3, # /home trop petit
#	RET_OLDINSTALL		=>  4, # Une installation prcdente  chou
#	RET_INSTALLPENDING	=>  5, # L'installation est toujours en cours
#	RET_NOKEY			=>  6, # Pas de cl
#	RET_CLUSTER			=>  7, # Mode cluster (obsolte)
#	RET_VALIDATE		=>  8, # Echec validate()
#	RET_APTUPDATE		=>  9, # Echec fsm AptUpdate
#	RET_RENEWOK			=> 10, # Renew OK
#	RET_RENEWKO			=> 11, # Echec renew
#	RET_DAEMON			=> 12,
#	RET_DAEMONEND		=> 13,
#	RET_PRE_UPDATEVERSION	=> 20,  # Echec de prparation mise  jour iso
#	RET_UPDATEVERSION	=> 30  # Echec de mise  jour iso
##

my $usage=
" 
      Mise  jour  distance de Kwartz.

Utilisation: $0 (-d -v -q -D)	{-r|-k|-S|-p}
								{-i|-I|-u} (-U image_iso)
								{-a update}
								{-a install xxx yyy ...} (-s) (-o \"opt1 opt2...\")
								{-a download xxx yyy ...}
								{-g|-G xxx.deb...}
								{-P nom_paquet}
								{-C pid|-1}

   -a (all)     : Utilise le sources.list complet kwartz+ubuntu+security
   -s (simulate): mode dry-run pour l'option -a
   -o (options) : options pour apt-get install pour l'option -a
   -g (dpkg)    : installe toutes les dpendances d'une liste de .deb
   -G (dpkG)    : installe un ou plusieurs .deb et leurs dpendances
   -i (info)    : Affiche les modules disponibles
   -I (Info)    : -i sans test de sauvegarde
   -k (kill)    : dsactive le serveur
   -p (recup)   : fait une tentative de recup apres detection echec installation
   -P (Policy)  : fait un apt-cache policy sur un paquet
   -r (renew)   : Met  jour kwartz-autoupdate
   -S (Swipe)   : remet le serveur dans un tat fonctionnel aprs dvalidation
   -u (update)  : Met  jour Kwartz
   -U (dist_Upgrade) : dist_upgrade sur kwartz. A combiner avec -i ou -u
   -C (Check)   : Renvoie l'tat du daemon
      
   -q (quick)   : A combiner avec -i, saute l'tape mise  jour des listes
   -d (debug)   : affiche les commandes lances
   -v (verbose) : affiche les msg apt-get lors de la mise  jour des paquets
   -D (Daemonize)    : Lance en tache de fond. Renvoie le pid sur stdout
";


($#ARGV>=0 ) or die $usage;
getopts('adC:DgGiIkpP:qrsSuU:vo:') or die $usage;

# Fichier d'tat
# Get our configuration information
if (my $errstate = ReadCfg($STATEFILE)) {
}

###################################
# Protection contre la rentrance
#
# Si une commande est en cours :
#	On accepte opt_C pour renvoyer l'tat en cours
#	On accepte opt_a si on est en condition de rentrance
##

# Creation ou test fichier pid
if (! -d $RUNDIR) {
	mkdir $RUNDIR,0755
}
my $pidfile = File::Pid->new({file => "$RUNDIR/".basename($0).".pid"});

my $curpid = $pidfile->running;

# Qui m'appelle ?
use Proc::ProcessTable;

my $procs = Proc::ProcessTable->new;


my $ppid = getppid();
do {
	my %caller;
	foreach my $p ( @{$procs->table} ) {
		if ($p->pid == $ppid) {
			$caller{'cmndline'} = $p->cmndline;
			$caller{'ppid'} = $p->ppid;
			if (defined($curpid)) {
				if ($p->pid == $curpid) {
					$reentrancy++;
					print ("Rentrance $reentrancy\n") if (defined $opt_d);
				}
			}
			
			$ppid = $p->ppid;
			push @callerchain, \%caller;
			last;
		}
	}
} while ($ppid != 1);

if (defined($curpid)) {
	if (! ( defined ($opt_C) ||
	        (defined ($opt_a) && ($reentrancy<=1))   # Pas plus d'un niveau de rentrance
	      )
	   ) {
		myexitlog(	"Une opration est en cours",
					"Operation en cours",
					RET_INSTALLPENDING);
	}
} else {
	$pidfile->write;
}

#
## Rentrance OK
################

##
# Get proxy info
# rcupration de l'url
# proxy sur la connexion isp?
our %workfile;
my $ispfile=$workfile{"isp"};
my %ispconf;
#initialize data values...
my $http_proxy='';
if (-f $ispfile) {
  #... from work file
  &read_file($ispfile,\%ispconf);
  if ($ispconf{"ProxyAddress"}) {
    $http_proxy="http://$ispconf{'ProxyAddress'}";
    $http_proxy.=":$ispconf{'ProxyPort'}"
      if ( $ispconf{'ProxyPort'} );
  }
}
$ENV{'http_proxy'}="$http_proxy";
$ENV{'DEBIAN_FRONTEND'}='noninteractive';

##
# Gestion des volutions / dprcations de apt-get
# rcupre la version de apt-get
#	Kwartz5 : apt 0.8.16~exp12ubuntu10.21 pour i386 compil sur Oct  8 2014 12:37:48
#	Kwartz6 : apt 0.8.16~exp12ubuntu10.29 pour i386 compil sur May 28 2020 17:30:39
#	Kwartz7 : apt 1.0.1ubuntu2 pour amd64 compil sur Jan 18 2019 20:24:31
#	Kwartz8 : apt 1.2.32ubuntu0.2 (amd64)
#	Kwartz9 : apt 2.0.2ubuntu0.2 (amd64)
##

my $aptver=`apt-get --version | head -1 | awk '{print \$2}'`; chomp $aptver;

# --force-yes dprci  partir de 1.1
$aptsyntax{'allowdowngrade'} = "--force-yes";
if (mysystem("dpkg --compare-versions \"$aptver\" ge \"1.1\"") == 0) {
	$aptsyntax{'allowdowngrade'} = "--allow-downgrades";
}


# Special check command for status
if (defined($opt_C)) {
	my $statenum = 0;
	my $result;
	my $resultcode = 0;
	my $resultstr = "";
	
	my $lastpid = $opt_C;
	if ($lastpid == -1) {
		if (defined ($CFG::CFG{'lastrun'}{'pid'}) and $CFG::CFG{'lastrun'}{'pid'} =~ m/^\d+$/) {
			$lastpid = $CFG::CFG{'lastrun'}{'pid'};
		}
	}
	# Test if files exists
	unless ($lastpid == -1) {
		if (! -e "$RUNDIR/$lastpid.progress" and ! -e "$RUNDIR/$lastpid.res") {
			$lastpid = -1;
		}
	}
	# Couldn't find pid or pid files
	if ($lastpid == -1) {
		print STDERR "installation introuvable\n";
		myexitlog(undef, undef, RET_ERROR);
	}
	
	if (open (FH, "<$RUNDIR/$lastpid.progress")) {
		$statenum = <FH>;
		close (FH);
		chomp($statenum);
	}
	if (open (FH, "<$RUNDIR/$lastpid.res")) {
		$result = <FH>;
		close (FH);
		chomp($result);
		if ($result =~ m/^(.*?) (\d+)$/) {
			$resultstr = $1;
			$resultcode = $2;
		}
	}
	
	# Send back check result
	# Input:
	#	$lastpid :
	#			-1	: pas de running trouv
		#	$opt_C  : pid pass en paramtre
		#	lastrun : pid enregistr si $opt_C vaut -1
	#
	# 	$pidfile->pid :
	#		Current running process
	#
	# Output:
	#	STDOUT : tat / rsultat
	#	STDERR : message
	#	logfile: nant
	#
	# Code de retour :
	#	running : RET_INSTALLPENDING
	#	ended   : RET_DAEMONEND
	##
	#  if still running
	if ($pidfile->pid == $lastpid) {
		print STDERR "installation en cours...\n";
		# no log
		myexitlog("State: $statelist[$statenum]", undef, RET_INSTALLPENDING);
	} else {
	#  if ended
		print STDERR ($resultstr eq "")?"Installation termine\n":"$resultstr\n";
		# no log
		myexitlog("Resultat: $resultcode", undef, RET_DAEMONEND);
	}
} # $opt_C

# Ici tout sauf $opt_C

##
# Tests mise  jour en cours
##
if ((check_kwartzdistupgrade() == 1) or #  via /run/kwartz-update
	(system("/usr/bin/pgrep apt-get >/dev/null 2>&1")==0) or  #  Gnrique
	(system("echo | dpkg --set-selections >/dev/null 2>&1")>>8 == 2) ) { # Test dpkg lock

	myexitlog(	"L'installation est toujours en cours",
				"installation en cours",
				RET_INSTALLPENDING);
}
##

# Daemonize
sub term_handler {
	# On ne fait rien... pas de TERM autoris
}

##
# Daemonize kwartz-autoupdate
#
# See :
#  http://www.farhadsaberi.com/perl/2013/02/perl-detach-process-daemon.html
#  http://world.std.com/~swmcd/steven/tech/daemon.html
##
if (defined($opt_D)) {
	
	pipe(READER, WRITER) || myexitlog ("Erreur interne", "pipe failed: $!", RET_ERROR);
	defined (my $son = fork) or myexitlog ("Erreur interne", "Cannot fork: $!", RET_ERROR);
	if ($son) {
		# I am parent
		close(WRITER);

		my $line = <READER>;
		chomp $line;
		my $daemon_pid = $line;
		close(READER) || warn "kid existed $?";
		# waitpid($son,0);
		
		# Transfert du PID sur le daemon
		$pidfile->remove;
		$pidfile = File::Pid->new({file => "$RUNDIR/".basename($0).".pid",
									pid => "$daemon_pid"});
		if ($pidfile->running) {
			exit(RET_INSTALLPENDING);
		}
		$pidfile->write;
		
		print ("$daemon_pid");
		exit(RET_DAEMON);
	} else {
		# I am son
		close(READER);
		
		# Prepare for detach
		close STDIN;
		close STDOUT;
		close STDERR;

		# Detach myself
		setsid or myexitlog(defined($opt_v)?"Erreur interne":"", "Can't start a new session: $!", RET_ERROR);
		umask(0027); # create files with perms -rw-r----- 
		chdir '/' or die "Can't chdir to /: $!";

		# acquire process leader stdio
		open STDIN,  "<", "/dev/null" or die $!;
		open STDOUT, ">", "/dev/null" or die $!;
		open STDERR, ">", "/dev/null";

		defined (my $grandson = fork) or myexitlog (defined($opt_v)?"Erreur interne":"", "Cannot fork: $!", RET_ERROR);

		if ($grandson) {
			# I continue to be the son of principal
			print WRITER "$grandson\n";
			close(WRITER);

			# intercepte le signal TERM pour ne pas stopper
			$SIG{'TERM'} = "term_handler";
			
			waitpid($grandson, 0);
			my $ress = $?>>8;
			open RESULT, ">>", "$RUNDIR/$grandson.res";
			print RESULT " $ress\n";
			close RESULT;
			exit (0);
		}
		# my daemon is here.
		
		close STDIN;
		close STDOUT;
		close STDERR;

		open STDIN,  "<", "/dev/null" or die $!;
		open STDOUT, ">", "$RUNDIR/$$.out" or die $!;
		open STDERR, ">", "$RUNDIR/$$.err";
		
		# intercepte le signal TERM pour ne pas stopper
		$SIG{'TERM'} = "term_handler";
	}
} # $opt_D

# Infos pour conserver la dernire commande active
# Ici on ne doit pas tre appel plusieurs fois.
#  Protection plus haut par gpidfile
my $lastcommand = "unknown";
$lastcommand = "info" if (defined ($opt_i) or defined ($opt_I));
$lastcommand = "update" if (defined ($opt_u) and ! defined ($opt_U));
$lastcommand = "dist-upgrade" if (defined ($opt_u) and defined ($opt_U));
$lastcommand = "install" if (defined ($opt_g) or defined ($opt_G) or defined ($opt_a));
$lastcommand = "renew" if (defined ($opt_r));
$CFG::CFG{'lastrun'}{'pid'} = $$;
$CFG::CFG{'lastrun'}{'command'} = $lastcommand;
SaveCfg($STATEFILE);

open $gStateHandler, '>', "$RUNDIR/$$.progress" or $gStateHandler = undef;
print $gStateHandler "0" if defined ($gStateHandler);

$opt_i = 1 if defined($opt_I);

# Kwartz::Product library is present?
unless (eval {
	require Kwartz::Product;
	Kwartz::Product->import;
	($type,$ver) = Kwartz::Product->code;
	$type=~ s/\d+$//;
	
	#new update credentials are common for all kwartz products
	$autoupdate = "autoupdatek";

	if ( $type eq 'kwartz' ){
		$type = 'Server';
#		# for everybody now
#		$autoupdate = "autoupdatek";
        #$autoupdate = "autoupdate".substr($ver,0,1);
		$autoupdate = "autoupdate".substr($ver,0,1) unless (Compare_Version("7.0")>=0);
	}
	return 1;
}) {
	# No: fallback
	# rcupration de la version
	open (VER, "</etc/debian_version");
	my @version = <VER>;
	close VER;
	$version[0] =~ m/(.+) (?:kwartz|KWARTZ)~*(\D*)(\d+.\w+)/;
	my $debver = $1;
	$type = $2;
	$type = "Server" if ( $type eq "" );

	$ver = $3;
	$autoupdate = "autoupdate";
	#$autoupdate = "autoupdate3" if ($ver ge "3.0r0" and $type eq "Server");
	#$autoupdate = "autoupdate4" if ($ver ge "4.0" and $type eq "Server");
	#$autoupdate = "autoupdate5" if ($ver ge "5.0" and $type eq "Server");
	if ((Compare_Version("3.0r0")>=0) and $type eq "Server"){
		$autoupdate = "autoupdate".substr($ver,0,1);
	}
	# kwartz 5.0 isn't already filled with Kwartz::Product
#	if ($ver ge "5.0r0" and $type eq "Server"){
#		$autoupdate = "autoupdatek";
#	}
	$autoupdate = "autoupdatephone" if ($type eq "Phone");
}


$debname = "lenny";
# plus ncessaire car fork 2.0 pour kwartz 4
# $debname = "woody" if ( $debver eq "3.0" );
# $debname = "sarge" if ( $debver eq "3.1" );
# $debname = "etch"  if ( $debver ge "4.0" );

if (((Compare_Version("5.0")>=0) and $type eq "Server") ||
	($type eq "kmcbox" )) {
	$debname=`lsb_release -sc`;
  	chomp $debname;
}

# rcupration de la version du noyau
$krel = `uname -r`; chomp $krel;
$kver = `uname -v`; chomp $kver;

if (defined($opt_k)) {
	Devalidate_Kwartz();
	myexitlog(	defined($opt_v)?"Devalidate_Kwartz":"",
				"Devalidate_Kwartz",
				RET_OK);
}

if (defined($opt_S)) {
	Revalidate_Kwartz();
	myexitlog(	defined($opt_v)?"Revalidate_Kwartz":"",
				"Revalidate_Kwartz",
				RET_OK);
}

# nettoyage
mysystem ("apt-get autoclean >/dev/null 2>&1");

# verif espace libre pour /var/cache/apt/pkgcache.bin ...
if (Get_Free_Size("/var") < 80*1000) {
	my $freesize = Get_Free_Size("/var");
	myexitlog(	"L'espace systme est trop petit pour faire une mise  jour  distance (besoin: 80/$freesize Mo )",
				"espace systme /var trop petit",
				RET_VARSIZE);
}


#
# Mise  jour de kwartz-autoupdate (option -r)
# Sortie aprs la mise  jour
# Indpendant de la validation
#
if (defined($opt_r)) {
	my $res = Renew();
	if ($res ne 0) {
		my $kav = `dpkg-query --showformat=\'\${Version}\' --show kwartz-autoupdate`;
		myexitlog(	"kwartz-autoupdate mis a jour",
					"kwartz-autoupdate mis a jour : $kav",
					$res);
	} else {
		myexitlog(undef, "fin renew", RET_OK);
	}
} # $opt_r
##

##
# vrification de la licence
#
my %kwartzkey;
my $keyfile=$workfile{'kwartzkey'};
$keyfile.=".bak" if ( ! -f $keyfile);
if ( ! -f $keyfile) {
	myexitlog(	"Vous devez au pralable inscrire la cl Kwartz pour bnficier de cette fonctionnalit",
				"inscrire cl Kwartz",
				RET_NOKEY);
}
&read_file($keyfile,\%kwartzkey);
$licence = $kwartzkey{'licence'};

open (KEY, "<$keyfile");
my @keyfile = <KEY>;
close KEY;

foreach (@keyfile) {
	$key = $1 if (m/^key:(\d+)/) ;
}
# TODO transformer d'ventuels @ en %40

$upd_user=$licence;
$upd_pass=$key;
## 

# vrification sauvegarde en cours
if (! $opt_I && -f "/var/run/kwartz-backup.pid") {
	myexitlog(	"Il n'est pas possible de mettre  jour les composants pendant une sauvegarde",
				"Sauvegarde en cours",
				RET_INSTALLPENDING);
}

# vrification du mode cluster
my $cluster=eval "require 'clusterlib.pl'";
if ($cluster && GetNodeType() ne 'single') {
	myexitlog("Il n'est pas possible de mettre  jour les composants en mode cluster", "maj cluster impossible", RET_CLUSTER);
}

# validation de la cl en info
# validate() -> ($val, $date, $user, $pass)
my @valres = validate();
my $v_val = shift (@valres);
if ($v_val eq "OK") {
	# validation OK
	my ($v_date, $v_user, $v_pass) = @valres;
	$upd_user=$v_user if ($v_user ne "");
	$upd_pass=$v_pass if ($v_pass ne "");
	Revalidate_Kwartz() if (( -f "/usr/lib/kwartz/control/kwartzkey.cgi.bak" ) && ( -f "/var/kwartz/kwartzkey.bak" ));
} elsif ($v_val eq "KO") {
	# echec validation
    # on dsactive kwartz
  	Devalidate_Kwartz();
	# on affiche le message renvoy
	my ($v_date, $v_code, $v_msg) = @valres;
	#   $v_msg =~ s/\\u([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9])/encode('utf-8', chr(hex($1)))/eg;
	$v_msg =~ s/\\u([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9])/chr(hex($1))/eg;
	myexitlog(	"$v_msg",
				"Dvalidation Kwartz par serveur",
				RET_VALIDATE);
} else {
	  # echec recup info
}

# pbm ou verif dpkg
my @dpkgerr = glob("/var/lib/dpkg/updates/[0-9]*");
my $checkstatus = mysystem("grep -q 'Status:.*unpacked' /var/lib/dpkg/status");
my $checkapt = mysystem("apt-get -qq check >/dev/null 2>&1");

# tentative de recup
if (defined($opt_p) or
	($#dpkgerr>=0) or
	($checkstatus == 0) or
	((($checkapt&127) == 0) && (($checkapt>>8) > 0))
	) {
	# print "tentative de rcupration\n" if (defined($opt_v));
	$ENV{UCF_FORCE_CONFOLD}="1";
	mysystem("echo tentative de rcupration >> $VARLOGFILE 2>&1");
	mysystem("dpkg --force-confold --configure -a >> $VARLOGFILE 2>&1");
	if ((-f "/etc/kwartz/sources_s.list") &&
		(Get_Free_Size("/") > 200*1000) ) {
		mysystem("apt-get -y -o Dir::Etc::SourceList=/etc/kwartz/sources_s.list -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d' --no-remove -f install >> $VARLOGFILE 2>&1");
	}
}

sub SelfHeal
{
	print "\nSelfHeal()\n" if ($opt_d);
	
	# afl: correction kwartz-mdm-core halconfigured sur kmcbox (pb % env HOME anacron)
	if ($type eq "kmcbox") {
		my $kwartz_mdm_core_version=`dpkg -s kwartz-mdm-core | grep '^Version' | awk '{print \$2}'`;
		chomp $kwartz_mdm_core_version;
		my $kwartz_mdm_core_status=`dpkg -s kwartz-mdm-core | grep '^Status' | awk '{print \$4}'`;
		chomp $kwartz_mdm_core_status;
		if ($kwartz_mdm_core_status eq "half-configured") {
			mysystem("echo tentative de rcupration kmcbox / kwartz-mdm-core >> $VARLOGFILE 2>&1");
			if (mysystem("dpkg --compare-versions $kwartz_mdm_core_version le 1.1.9") == 0) {
				system("HOME=/root dpkg --configure kwartz-mdm-core kwartz-mdm >> $VARLOGFILE 2>&1");
			}
		}

	}

	# AFL 28/07/2017 kwartz7
	# BPO 01/02/2023 kwartz9
	# freeradius 2.1.12+dfsg-1.2ubuntu8.2 ubuntu update breaks 
	# freeradius-ldap postinst if radius disabled
	# reload: Unknown instance:
	# invoke-rc.d: initscript freeradius, action "force-reload" failed.
	# dpkg: error processing package freeradius-ldap (--configure):
	# le sous-processus script post-installation install a retourn une erreur de sortie d'tat 1

	if (($ver =~ /^7\..+/ or $ver =~ /^9\..+/) and $type eq "Server") {	
		my $pkg_status=`dpkg -s freeradius-ldap | grep '^Status' | awk '{print \$4}'`;
		chomp $pkg_status;
		if ($pkg_status eq 'half-configured') {
			# clients.conf empty = freeradius disabled
			unless (-s '/etc/freeradius/clients.conf') {
				mysystem("echo tentative de rcupration $ver / freeradius-ldap >> $VARLOGFILE 2>&1");
				# del postinst to fix config 
				unlink '/var/lib/dpkg/info/freeradius-ldap.postinst';
				mysystem("dpkg --configure freeradius-ldap >> $VARLOGFILE 2>&1");
			}
		}
	}

	## BPO 12/01/2018 toutes architectures
	# GRUB_RECORDFAIL_TIMEOUT a t incorrectement mis  la valeur 0
	# ce qui pose problme si le kernel ne dmarre pas
	# On le force  la valeur 60 (ubuntu conseille -1, mais a pose des soucis pour les kmcbox par exemple)
	#
	if (-f "/etc/default/grub") {
		if (system('grep -q "GRUB_RECORDFAIL_TIMEOUT=0" /etc/default/grub') == 0) {
			mysystem("sed -e 's/GRUB_RECORDFAIL_TIMEOUT=0/GRUB_RECORDFAIL_TIMEOUT=60/' -i.bak /etc/default/grub >> $VARLOGFILE 2>&1");
			if ($? == 0) {
				unlink("/etc/default/grub.bak");
				mysystem("update-grub >> $VARLOGFILE 2>&1");
			} else {
				mysystem("mv -vf /etc/default/grub.bak /etc/default/grub >> $VARLOGFILE 2>&1");
			}
		}
	}
	##
	
	# Pbm ulogd
	if ( -f "/etc/init.d/ulogd.dpkg-dist" || -f "/etc/init.d/ulogd.diverted.dpkg-dist") {
		mysystem("mv -vf /etc/init.d/ulogd.dpkg-dist /etc/init.d/ulogd >> $VARLOGFILE 2>&1");
		mysystem("mv -vf /etc/init.d/ulogd.diverted.dpkg-dist /etc/init.d/ulogd.diverted >> $VARLOGFILE 2>&1");
	}
	
	# Correction TRIM mSata
	if ((Compare_Version("2.0r0")>=0) and $type eq "kmcbox") {
		my $fstabdiscard = 0;
		my $procdiscard = 0;
		
		my $model = myback("cat /sys/class/block/sda/device/model");
		my @hdparm = ();
		my @trim = ();
			
		if ($model =~ m/InnoDisk|KingFast|SATA SSD|TS512GMSA370|TS64GMTS552T2/) {
			@hdparm = myback("hdparm -I /dev/sda");
			@trim = grep(/TRIM/, @hdparm);
		}

		# Test fstab
		eval {
			open (FSTAB, "</etc/fstab");
		};
		if (!$@) {
			foreach (<FSTAB>) {
				$fstabdiscard++ if (m/^UUID=.*discard/);
			}
			close FSTAB;
		}
		
		# Test proc
		eval {
			open (PROC, "</proc/mounts");
		};
		if (!$@) {
			foreach (<PROC>) {
				$procdiscard++ if (m/discard/);
			}
			close PROC;
		}

		# Set automatic Trim
		if ($fstabdiscard == 0) {
			if ($#trim >=0) {
				system ("echo Correctif intgr trim >> $VARLOGFILE");

				unlink("/etc/fstab.bak");
				mysystem("sed -e \'/^UUID=/s/defaults/defaults,discard/g\' -e \'/^UUID=/s/sw\t/sw,discard\t/g\' -i.bak /etc/fstab >> $VARLOGFILE 2>&1");
				if ($? == 0) {
					unlink("/etc/fstab.bak");
				} else {
					mysystem("mv -vf /etc/fstab.bak /etc/fstab >> $VARLOGFILE 2>&1") if (-f "/etc/fstab.bak");
				}
				mysystem("touch /var/run/reboot-required");
				mysystem("echo trim >> /var/run/reboot-required.pkgs");
				mysystem("echo vm.swappiness=40 > /etc/sysctl.d/kwartz-swappiness.conf");
			}
		}
		
		# Force manual Trim
		if ($procdiscard == 0) {
			if ($#trim >=0) {
				if ( -x "/sbin/fstrim-all" ) {
					mysystem("fstrim-all --no-model-check >/dev/null 2>&1");
				} else {
					mysystem("fstrim -va >/dev/null 2>&1");
				}
			}
		}
	}
	## TRIM
	
	## BPO 06/10/2020 kwartz8
	# Correction kwartz-wapt et certificat Let's Encrypt
	#
	if ($ver =~ /^8\..+/ and $type eq "Server") {
		my $pkg_status=`dpkg -s kwartz-wapt | grep '^Status' | awk '{print \$4}'`; chomp $pkg_status;
		my $pkg_version=`dpkg -s kwartz-wapt | grep '^Version' | awk '{print \$2}'`; chomp $pkg_version;
		if ($pkg_status eq 'half-configured' and $pkg_version eq "2.0-3") {
			my $sslfile="/etc/ssl/private/kwartz.key";
			my $grp=`stat --printf=\"%G\" $sslfile`;
			my $perm=`stat --printf=\"%a\" $sslfile`;
			if ($grp ne "ssl-cert") {
				mysystem("chgrp -c ssl-cert $sslfile");
			}
			if ($perm ne "640") {
				mysystem("chmod -c 0640 $sslfile");
			}
			mysystem("invoke-rc.d postgresql restart");
			
			my $count = 10;
			while ($count--) {
				if (system("pg_isready") > 0) {
					sleep(1);
					next;
				}
				if (mysystem("su - postgres -c \"psql -lqt | cut -d \\| -f 1 | grep -qw wapt\"") != 0) {
					mysystem("mv /etc/kwartz/.waptpgpw /etc/kwartz/.waptpgpw.nodb");
				}
				mysystem("dpkg --configure kwartz-wapt >> $VARLOGFILE 2>&1");
				last;
			}
		}
	}
	
	######################################################
	# BPO 20210524 / 20230109
	# Correction prventive mise  jour K7->K8 kwartz-ldap
	# /home/install/-|
	#                |-updates-|
	#                          |-downgrades8-|
	#                                        |-pool-|
	#                                        |      |-local-|
	#                                        |              |- kwartz-ldap_5.2-6_all.deb
	#                                        |-Packages
	#                                        |-Packages.gz
	#                                        |-Release
	##

	# do_ftparchive ($label)
	# executes apt-ftparchive on cwd
	##
	sub DoFtparchive
	{
		my ($label) = @_;
		
		unlink "Packages", "Pacgages.gz", "Release";
		mypopenprint("apt-ftparchive packages pool | tee Packages | gzip -9 > Packages.gz 2>&1");
		mypopenprint("apt-ftparchive \\
					-o APT::FTPArchive::Release::Origin=\"Kwartz\" \\
					-o APT::FTPArchive::Release::Label=\"$label\" \\
					-o APT::FTPArchive::Release::Architectures=\"i386 amd64 noarch\" \\
					-o APT::FTPArchive::Release::Components=\"local\" \\
					-o APT::FTPArchive::Release::Description=\"Kwartz\" \\
					-o APT::FTPArchive::Release::Codename=\"Kwartz\" \\
					-o APT::FTPArchive::Release::Suite=\"Kwartz\" \\
					release . > ./Release.tmp; \\
			mv ./Release.tmp ./Release 2>&1");
	}

	if ( ! -d "/home/install" ) {
		mysystem("mkdir /home/install >> $VARLOGFILE 2>&1");
		mysystem("chown install: /home/install >> $VARLOGFILE 2>&1");
	}
	if ( ! -d "/home/install/updates" ) {
		mysystem("mkdir /home/install/updates >> $VARLOGFILE 2>&1");
	}
	if ($ver =~ /^7\..+/ and $type eq "Server") {
		if ( ! -d "/home/install/updates/downgrades8/pool/local" ) {
			mysystem("mkdir -p /home/install/updates/downgrades8/pool/local >> $VARLOGFILE 2>&1");
		}
		if (! -f "/home/install/updates/downgrades8/pool/local/kwartz-ldap_5.2-6_all.deb") {
			my $output = "";
			my $oldFH;
			my $outputFH;
			if ( open $outputFH, '>', \$output ) {
				$oldFH = select $outputFH;
				$| = 1;
			}
			
			my $curdir = getcwd();
			chdir ("/home/install/updates/downgrades8/pool/local");
			DoOptaCommand("update");
			DoOptaCommand("download", "", "", ("kwartz-ldap=5.2-6"));
			chdir("../..");
			DoFtparchive("Kwartz8Downgrade");
			chdir($curdir);
			
			select $oldFH if (defined($oldFH));
			close $outputFH if (defined($outputFH));

			print "Prepare downgrade kwartz-ldap 5.2-6 : $output\n";
			if ( open (FH, ">>$VARLOGFILE") ) {
				print FH "Prepare downgrade kwartz-ldap 5.2-6 :\n";
				print FH $output;
				close (FH);
			}
		}
	}
	# End kwartz-ldap_5.2-6_all.deb
	##
	
	# BPO 20210604 Kwartz8 kwartz-server
	# Starting 2 pkgProblemResolver with broken count: 1
	# Investigating (0) kwartz-server [ amd64 ] < 8.0-0 -> 8.0-4 > ( unknown )
	# Broken kwartz-server:amd64 Dpend on kwartz-hostsusage [ amd64 ] < none -> 4.5-7 > ( unknown )
	#   Considering kwartz-hostsusage:amd64 1 as a solution to kwartz-server:amd64 2
	#   Holding Back kwartz-server:amd64 rather than change kwartz-hostsusage:amd64
	#  Try to Re-Instate (1) kwartz-server:amd64
	# Done	
	if ($ver =~ /^8\..+/ and $type eq "Server") {
		my $installed=installed_version("kwartz-server");
		my $candidate=candidate_version("kwartz-server");
		if (($installed ne "") && ($candidate ne "")) {
			if ( system("dpkg", "--compare-versions", $candidate, 'gt', $installed) == 0 ) {
				system ("echo \"kwartz-server didn't install\" >> $VARLOGFILE");
				if ( system("dpkg", "--compare-versions", $candidate, 'ge', '8.0-4') == 0 ) {
					mysystem("apt-get -qy purge libaccountsservice0 >> $VARLOGFILE 2>&1");
				}
			}
		}	
	}
	##
	
	## BPO 08/07/2021 kwartz7+
	# Correction ventuelle suppression de kwartz-agent
	#
	if ((Compare_Version("7.0r0")>=0) and $type eq "Server") {
		my $installed=installed_version("kwartz-agent");
		if ($installed eq "") {
			DoOptaCommand("update");
			DoOptaCommand("install", "", "", ("kwartz-agent"));
		}
	}
	##
	
	## BPO 09/07/2021 kwartz8
	# Ajout de fsck.repair=yes pour systemd
	if ((-f "/etc/default/grub") &&
		(((Compare_Version("8.0r0")>=0) and $type eq "Server") ||
		 ((Compare_Version("3.0r0")>=0) and $type eq "kmcbox"))) {
		if (system('grep -q "fsck.repair=yes" /etc/default/grub') != 0) {
			mysystem("sed -E 's/GRUB_CMDLINE_LINUX=\"(.*)\"/GRUB_CMDLINE_LINUX=\"\\1 fsck.repair=yes\"/' -i.bak /etc/default/grub >> $VARLOGFILE 2>&1");
			if ($? == 0) {
				unlink("/etc/default/grub.bak");
				mysystem("update-grub >> $VARLOGFILE 2>&1");
			} else {
				mysystem("mv -vf /etc/default/grub.bak /etc/default/grub >> $VARLOGFILE 2>&1");
			}
		}
	}

	## BPO 23/08/2021 kwartz8
	# Ajout d'un .ackrc (prsent en install kwartz9)
	if ((! -f "/root/.ackrc" ) &&
		(($type eq "Server" and (Compare_Version("8.0r0")>=0)) ||
		 ($type eq "kmcbox" and (Compare_Version("3.0r0")>=0)))) {
		if ( open (FH, ">>/tmp/.ackrc") ) {
			print FH <<EOF;
--pager=less -r
--type-add=perl=.ep
EOF
			close FH;
	        system("chmod 0644 /tmp/.ackrc");
	        system("cp -af /tmp/.ackrc /root/. || true");
	        if ( -d "/home/winadmin" ) {
				system( "cp -af /tmp/.ackrc /home/winadmin/. || true" );
				system( "chown 999.999 /home/winadmin/.ackrc || true" );
    	    }
	        unlink ("/tmp/.ackrc");
		}
	}
		
	##
	# Catch all aprs correctifs cibls
	##
	#  Ajout BPO 08/04/2022 kwartz9
	#	rencontr si	: Install k9, restauration sauvegarde, maj distance
	#	non rencontr si: Install k9, maj distance, restauration sauvegarde 
	#	gestion :
	#		root@kwartz-server(9.0r0):~# dpkg -C
	#		Les paquets suivants ont activ le traitement d'actions diffres,
	#		mais ce traitement n'est pas termin. Le traitement d'actions diffres
	#		peut tre demand via dselect ou dpkg --configure --pending
	#		( ou encore dpkg --triggers-only ): 
	#		 systemd              system and service manager
	#
	#		root@kwartz-server(9.0r0):~# LANG=C dpkg -C
	#		The following packages have been triggered, but the trigger processing
	#		has not yet been done.  Trigger processing can be requested using
	#		dselect or dpkg --configure --pending (or dpkg --triggers-only):
	#		 systemd              system and service manager
	##

	my @dpkgc = `LANG=C dpkg -C`;
	if ( $#dpkgc >= 0) {
		$ENV{UCF_FORCE_CONFOLD}="1";
		mysystem("dpkg --force-confold --configure -a >> $VARLOGFILE 2>&1");
		mysystem("dpkg --triggers-only -a >> $VARLOGFILE 2>&1");
	}
	
	##
	# Nettoyage /etc/init/kwartz-configure.conf
	##
	#  BPO 19/05/2022
	#   Efface /etc/init/kwartz-configure.conf si :
	#		* On est en systemd
	#		* La mise  jour est OK : kwartz-configure.service n'est pas configur pour dmarrer
	##
	
	if ( -e "/etc/init/kwartz-configure.conf" ) {
		my $initname=`ps --no-headers -o comm 1`; chomp ($initname);
		if ( $initname eq "systemd" ) {
			if ( ! -l "/lib/systemd/system/kwartz.target.wants/kwartz-configure.service" ) {
				system ("echo Effacement /etc/init/kwartz-configure.conf >> $VARLOGFILE");
				unlink ("/etc/init/kwartz-configure.conf");
			}
		}
	}
	
	##
	# Nettoyage des tlchargements clamav dans les logs de mise  jour
	# gzip des fichiers plus anciens que 30 jours
	##
	#  BPO 24/05/2022
	##
	my $exclude = "";
	if ( -l "/root/kwartz-configuration.log" ) {
		my $curtarget = readlink "/root/kwartz-configuration.log";
		$curtarget  =~ s/.*\///s;
		$exclude = "! -name \"$curtarget\"";
	}
		
	mysystem("find /root/kwartz -type f -size +2M  $exclude ! -name \"*.gz\" -exec sed -i \'s/^\\x1b\\[?7l.*//g\' {} \\; -exec gzip -qf {} \\;");
	mysystem("find /root/kwartz -type f -mtime +30 ! -name \"*.gz\" -exec gzip -qf {} \\;");
	##
	
	##
	# Installation de db-util sur Kwartz9
	##
	# BPO 06/07/2022
	##
	
	if (Compare_Version("9.0r0")>=0 and $type eq "Server") {
		my $installed=installed_version("db-util");
		if ($installed eq "") {
			DoOptaCommand("update");
			DoOptaCommand("install", "", "", ("db-util"));
		}
	}
	##
	
	##
	# fail2ban sur mise  jour kmcbox3/kwartz8
	# on a [ssh] dans jail.local, mais le filter est sshd
	#
	##
	#  BPO 31/01/2023
	##
	if ((-f "/etc/fail2ban/jail.local") &&
		(($type eq "Server" and (Compare_Version("8.0r0")>=0)) ||
		 ($type eq "kmcbox" and (Compare_Version("3.0r0")>=0)))) {
		 
		if (system('grep -q "[ssh]" /etc/fail2ban/jail.local') == 0) {
			mysystem(q{sed -e 's/\[ssh\]/\[sshd\]/' -i.bak /etc/fail2ban/jail.local}." >> $VARLOGFILE 2>&1");
			if ($? == 0) {
				unlink("/etc/fail2ban/jail.local.bak");
				mysystem("invoke-rc.d fail2ban restart >> $VARLOGFILE 2>&1");
			} else {
				mysystem("mv -vf /etc/fail2ban/jail.local.bak /etc/fail2ban/jail.local >> $VARLOGFILE 2>&1");
			}
		}
	}
	##
	
	# BPO 28/03/2023 kwartz9
	# kwartz-common 4.1-29 update breaks 
	# postinst if no /var/log/journal/*/user-*.journal
	# rm: impossible de supprimer '/var/log/journal/*/user-*.journal': Aucun fichier ou dossier de ce type
	# dpkg: erreur de traitement du paquet kwartz-common (--configure):
	# installed kwartz-common package post-installation script subprocess returned error exit status 1

	if (($ver =~ /^9\..+/) and $type eq "Server") {	
		my $pkg_version=`dpkg -s kwartz-common | grep '^Version' | awk '{print \$2}'`;
		chomp $pkg_version;
		my $pkg_status=`dpkg -s kwartz-common | grep '^Status' | awk '{print \$4}'`;
		chomp $pkg_status;
		if (($pkg_status eq 'half-configured') and
			($pkg_version eq '4.1-29')) {
			# /var/log/journal/*/user-*.journal
			my @journalfiles = glob("/var/log/journal/*/user-*.journal");
			if ($#journalfiles == -1) {
				my @journaldir = glob("/var/log/journal/*");
				if ($#journaldir >= 0) {
					mysystem("touch $journaldir[0]/user-000.journal");
					mysystem("dpkg --configure -a >> $VARLOGFILE 2>&1");
				}
			}
		}
	}
	
	# BPO 28/08/2023
	# packages.gz missed winbind
	# removed kwartz-backup kwartz-cdtower kwartz-cups kwartz-hostsusage kwartz-samba kwartz-server winbind
	if (($ver =~ /^8\..+/) and $type eq "Server") {
		my $installed=installed_version("winbind");
		if ($installed eq "") {
			DoOptaCommand("update");
			DoOptaCommand("install", "", "", ("kwartz-backup", "kwartz-cdtower", "kwartz-cups", "kwartz-hostsusage", "kwartz-samba", "kwartz-server", "winbind"), ">> $VARLOGFILE");
		}
	}
	
	# BPO 01/09/2023
	# Correction mise a jour kmcbox4 casse sshd : serveur inaccessible pour corriger les autres paquets casss
	if (($ver =~ /^3\..+/) and $type eq "kmcbox") {
		my $installed=installed_version("openssh-server");
		if ($installed eq "1:8.2p1-4ubuntu0.2") {
			my $pkg_status=`dpkg -s openssh-server | grep '^Status' | awk '{print \$4}'`;
			chomp $pkg_status;
			if ($pkg_status ne 'installed') {
				if ( ! -d "/home/install/updates" ) {
					mysystem("mkdir -p /home/install/updates >> $VARLOGFILE 2>&1");
				}
				if (! -f "/home/install/updates/openssh-server_1%3a7.2p2-4ubuntu2.8_amd64.deb") {
					my $output = "";
					my $oldFH;
					my $outputFH;
					if ( open $outputFH, '>', \$output ) {
						$oldFH = select $outputFH;
						$| = 1;
					}
					
					my $curdir = getcwd();
					chdir ("/home/install/updates");
					DoOptaCommand("update");
					DoOptaCommand("download", "", "", ("openssh-server=1:7.2p2-4ubuntu2.8"));
					system("mkdir -p /var/run/sshd");
					system("dpkg -i openssh-server_1%3a7.2p2-4ubuntu2.8_amd64.deb");
					system("invoke-rc.d ssh restart");
					chdir($curdir);
					
					select $oldFH if (defined($oldFH));
					close $outputFH if (defined($outputFH));
					
					print "Prepare fix openssh-server : $output\n";
					if ( open (FH, ">>$VARLOGFILE") ) {
						print FH "Prepare fix openssh-server :\n";
						print FH $output;
						close (FH);
					}
				}
			}	
		}
	}
	
	# BPO 05/09/2023
	# Fix si rejouer update_kmcbox3.sh n'a pas reconstruit le lien iptables
	if (((Compare_Version("9.0r0")>=0) and $type eq "Server") ||
		((Compare_Version("4.0r0")>=0) and $type eq "kmcbox")) {
		if (( ! -l "/sbin/iptables" ) &&
			( -e "/usr/sbin/iptables" )) {
			system("ln -fs /usr/sbin/iptables /sbin/iptables");
		}
	}
	
	# BPO 08/09/2023
	# Fix erroneous grub.cfg
	if ( -f "/boot/grub/grub.cfg" ) {
		if (system("grep -q root=PARTUUID /boot/grub/grub.cfg") == 0) {
			system("echo renew grub.cfg... >>$VARLOGFILE 2>&1");
			mysystem("update-grub >>$VARLOGFILE 2>&1");
		}
	}
	
	# BPO XX/XX/2025
	# Kwartz9 : Mise  jour du linux-firmware pour les proliant ML30 Gen10
#	if (($ver =~ /^9\..+/) and $type eq "Server") {
#		my $installed=installed_version("linux-firmware");
#		if ($installed eq "1.187") {
#			if (( -f   "/sys/class/dmi/id/product_name" ) &&
#			    ( ! -z "/sys/class/dmi/id/product_name" )) {
#			    if (open(FH, '<', "/sys/class/dmi/id/product_name")) {
#					my $product = <FH>; chomp $product;
#					close FH;
#					if ($product =~ m/ML30 Gen10/) {
#					}
#				}
#			}
#		}
#	}

	# BPO 10/01/2024
	# Fix borg cache wrongly fills all / free space
	if (($type eq "Server" and (Compare_Version("8.0r0")>=0)) ||
		($type eq "kmcbox" and (Compare_Version("3.0r0")>=0))) {
		
		goto FIXBORGEND if (Get_Free_Size("/") > 1000); # Teste > 1 Mo

		my $rootpart=`/sbin/blkid --label KWARTZ_ROOT`; chomp $rootpart;
		goto FIXBORGEND if ($rootpart !~ m/^\/dev.*/);
		
		goto FIXBORGEND if (is_mounted("/media"));
		
		eval {
			mysystem("mount $rootpart /media");
		};
		goto FIXBORGEND if ($@);
		
		mysystem("rm -rf /media/home/kwartz");
		mysystem("umount /media");
FIXBORGEND:
	}
	##
	
	# BPO 11/01/2024
	# Fix borg wrongly fills mountpoint when not mounted
	# 23/01/2024 : Add /var/kwartz/backup (seen lic 6172)
	my @borgmntpoints = ("/mnt/backup.borg",
						 "/mnt/backup.usb",
						 "/var/kwartz/backup");
	foreach (@borgmntpoints) {
		if (( -d $_ ) &&
			(! is_mounted($_)) &&
			(Get_Used_Dir_Size($_) > 1)) {
			mysystem("rm -rf $_/*") if ($_ =~ m/^\/mnt\/backup/);
			mysystem("rm -rf $_/*") if ($_ =~ m/^\/var\/kwartz\/backup/);
		}
	}
	##
	
	# BPO 02/10/2025 kmcbox4
	# Correction kwartz-nextcloud ject d au dpt local de php7.4 incomplet
	if ($type eq "kmcbox" and (Compare_Version("4.0r0")>=0)) {
		# kmcbox4
		my $installed=installed_version("kwartz-nextcloud");
		if ($installed eq "") {
			DoOptaCommand("update");
			DoOptaCommand("install", "", "", ("kwartz-nextcloud", "kwartz-nextcloud-sqlite"));
		}
	}
	##
	
	# BPO 28/01/2026 kwartz9/10 kmcbox4/5
	# Rcupration de kwartz-mdm si il est supprim
	if (($type eq "Server" and (Compare_Version("9.0r0")>=0)) ||
		($type eq "kmcbox" and (Compare_Version("4.0r0")>=0))) {
		my $installed=installed_version("kwartz-mdm");
		if ($installed eq "") {
			DoOptaCommand("update");
			DoOptaCommand("install", "", "", ("kwartz-mdm"));
		}
	}

	
	# BPO 06/01/2026 kwartz10
	# Nettoyage du sun jre 6
	if ($type eq "Server" and (Compare_Version("9.0r0")>=0)) {
		my $installed=installed_version("openjdk-8-jre-headless");
		if ($installed ne "") {
			$installed=installed_version("sun-java6-jre");
			if ($installed ne "") {
				mysystem("apt-get -qy purge sun-java6-jre sun-java6-bin");
			}
		}
	}
	
	
	# BPO 20250521
	# Post mise  jour K10 : nettoyage du kernel 5.4 si / 2 Go
	#if (($type eq "Server" and (Compare_Version("10.0")==0)) ||
	#	($type eq "kmcbox" and (Compare_Version("5.0")==0))) {
	#	if (($krel =~ m/6.8/) &&
	#		(system("dpkg -l linux-image-5.4* |grep ^ii| wc -l")) {
	#	}
	#}
	
	# BPO 20260313
	# Prparation downgrade kwartz-deploy en 0.96
#	if ($type eq "Server" and (Compare_Version("10.0r0")>=0)) {
#		my $installed=installed_version("kwartz-deploy");
#		my $last=candidate_more_recent_500_version("kwartz-deploy");
#		if ($installed ne "") {
#			if ( system("dpkg", "--compare-versions", $installed, 'eq', '1.04') == 0 ) {
#				my $pref = <<_MARKER_;
#Package: kwartz-deploy
#Pin: version 0.96
#Pin-Priority: 1000
#_MARKER_
#
#				do_install_preference("kwartz-deploy", $pref);
#			} elsif (system("dpkg", "--compare-versions", $last, 'gt', '0.96') == 0 ) {
#				do_remove_preference("kwartz-deploy");
#			}
#		}
#	}
	
} # SelfHeal()

unless (defined($opt_a)) {
	SelfHeal();
}

# DoOptaCommand
#
# Execute command for -a ... call
# DoOptaCommand($command, $simulate, $options, @listpks, $redir)
##
sub DoOptaCommand
{
	my ($command, $simulate, $options, @listpks, $redir) = @_;
	my $redirection = $redir || '';
	
	if ($command eq "update") {
		AptUpdate();
	} elsif ($command eq "install") {
		my $pkglist = join(" ", @listpks);
		# bpo 20210521 : add --force-yes to handle downgrades
		# bpo 20210526 : handles --force-yes deprecation
		mypopenprint("apt-get $aptsyntax{'allowdowngrade'} -quy$simulate $options -o DPKG::Options::=\"--force-overwrite\" -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' install $pkglist $redirection 2>&1");
	} elsif ($command eq "dist-upgrade") {
		mypopenprint("apt-get $aptsyntax{'allowdowngrade'} -quy$simulate $options -o DPKG::Options::=\"--force-overwrite\" -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' dist-upgrade $redirection 2>&1");
	} elsif ($command eq "download") {
		my $pkglist = join(" ", @listpks);
		mypopenprint("apt-get -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' download $pkglist $redirection 2>&1");
	}
}

# Check current dpkg status after SelfHeal()
my @dpkgc = `LANG=C dpkg -C`;
my @dpkgko;
my $pklist = "";

if ( $#dpkgc >= 0) {
	my $trigger = 0;
	
	foreach (@dpkgc) {
		if (m/The following packages have been triggered/) {
			$trigger = 1;
		}
		if ($trigger == 0) {
			push (@dpkgko, $1) if (m/^ (\S+)/);
		}
	}
}

if (( $#dpkgko >= 0) && ( !defined($opt_a))) {
	print "Une installation prcdente a chou.\n";
	foreach (@dpkgko) {
		$pklist.=" $1" if (m/^ (\S+)/);
	}
	print "$pklist\n";
	myexitlog(	"",	# Force no more print on STDOUT
				"Une installation prcdente a chou",
				RET_OLDINSTALL);
}

# verif repository apt
unless (defined($opt_a)) {
	my $aptres=mysystem("apt-get -qq check  >> $VARLOGFILE 2>&1");
	if ($aptres != 0) {
		mysystem("apt-get -qq update  >> $VARLOGFILE 2>&1");
	}
}

# Gestion dist_upgrade
if (defined($opt_U)) {
	$gIso = $opt_U;
}

if (defined($opt_i)) {
	my @list;
	
	mysystem("/usr/sbin/kwartz-pin-kmc  >> $VARLOGFILE 2>&1"); 

	$gres = Update (1, \@list);
	# Affichage en sortie de la liste des paquets en attente de mise  jour
	# Gestion du cache. J'utilise le mme fichier temporaire que kwartz-agent
	my $tmp_file = "$UPDATE_CACHE.tmp";
	my $fileno = fileno(STDOUT);
	my $qfn = "";
	my $fh = undef;
	
	##
	# Pas de gestion du cache si le flux de sortie (STDOUT) est dj redirig vers le fichier temporaire
	##
	if (!defined($fileno) ||
		($fileno < 0) ||
		!($qfn = readlink("/proc/$$/fd/$fileno")) ||
		($qfn ne $tmp_file)) {
		open($fh, ">", "$tmp_file");
	}
	
	# Affichage des paquets sur STDOUT et dans l'ventuel fichier temporaire
	foreach(sort @list) {
		print "$_\n";
		print $fh "$_\n" if (defined ($fh));
	}
	
	if (defined($fh) &&
		close($fh)) {
		unlink "$UPDATE_CACHE.bak";
		unlink "$UPDATE_CACHE.error";
		move $UPDATE_CACHE,"$UPDATE_CACHE.bak";
		move $tmp_file, $UPDATE_CACHE;
	}
} elsif (defined($opt_u)) {
	my @list;
		
	# erase cache
	unlink "$UPDATE_CACHE";
	if (-f "/var/kwartz/renew_autoupdate") {
		unlink "/var/kwartz/renew_autoupdate";
	}
	my ($res2, $handle2) = acquire_lock ($SEM, 1000, 10); # 1 seconde
	mklogfile();
	release_lock($handle2);
	
	system ("echo -n Update: >> $VARLOGFILE");
	
	# must handle kmc downgrade first else apt-get dist-upgrade fail with
	#  There are problems and -y was used without --force-yes
	handle_kmc_downgrade();

	$gres = Update (0, \@list);
	system ("echo $? >> $VARLOGFILE");


	# tmp aFL
	# quick fix for trac #2241
	# check dhcpd failed to purge apparmor cache, reconfigure 
	if (-x '/sbin/apparmor_parser') {
		if ( system("systemctl is-failed isc-dhcp-server") == 0 ) {
			system ("echo 'apparmor_parser --purge-cache' >> $VARLOGFILE");
			mysystem("/sbin/apparmor_parser --purge-cache");
			mysystem("dpkg-reconfigure kwartz-dhcp");
		}
	}


	# mysystem("cat $VARLOGFILE >> $LOGFILE");
	
	# Appel du hook
    mysystem("/usr/sbin/kwartz-hook emit core/autoupdate") if -x "/usr/sbin/kwartz-hook";

} elsif (defined($opt_a)) {
	($#ARGV >= 0 ) or die $usage;
	my $command = shift @ARGV;
	if (($command eq "install") ||
		($command eq "download") ||
		($command eq "dist-upgrade") ||
		($command eq "update")) {
		
		my $options = "";
		if (defined($opt_o)) {
			foreach (split(/ /, $opt_o)) {
				$options .= "-o Dpkg::Options::=\"$_\" ";
			}
		}
		$options .= defined($opt_d)?"-o Debug::pkgProblemResolver=yes":"";

		DoOptaCommand(  $command,
						defined($opt_s)?"s":"",
						$options,
						@ARGV);
	} else {
		die $usage;
	}
} elsif ((defined $opt_g) || (defined $opt_G)) {
	($#ARGV >= 0 ) or die $usage;
	
	my $curarch = `dpkg --print-architecture`;
	my @pending; # liste des noms de paquets
	my @missing;
	my @glpredeps;
	my @installlist;

	foreach my $pkt (@ARGV) {
		push @installlist, $pkt;
		push (@pending, $1) if ($pkt =~ (m/(.*?)_.*/));
	}
	
	foreach my $pkt (@ARGV) {
		my $arch = `dpkg -I $pkt | grep Architecture | sed -s 's/ Architecture: //'`; chomp $arch;
		my @deps = split(',', myback("dpkg -I $pkt | grep \" Depends\" | sed -s 's/ Depends: //'"));
		my @predeps = split(',', myback("dpkg -I $pkt | grep \" Pre-Depends\" | sed -s 's/ Pre-Depends: //'"));
		push @deps, @predeps;
		
		foreach (@predeps) {
			my $pn = (split(' ', $_))[0];  # ignore la version;
			push @glpredeps, $pn if (!grep(/^$pn$/, @glpredeps)); #dedup
		}
		
		foreach (@deps) {
			my @choices;
			my $found;
			my $dep;

			s/^\s+//;
			if (m/\|/) {
				# Entres multiple
				my @multiple = split('\|', $_);
DEPS:			foreach (@multiple) {
					$dep = $_;
					$dep =~ (s/^\s+//);
					# dep
					# dep (= ver)
					# dev (>> ver)
					# dep (>= ver)
					my ($pkt, $op, $ver) = ($1, $2, $3) if ($dep =~ (m/([a-z0-9-+:\.]+)(?= \(([=><]+) (.*)\))?/));
					my @versions= myback("apt-cache -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' show $pkt | grep 'Version:' | sed 's/Version: //'");
					if ($#versions>=0) {
						if (defined($ver)) {
							foreach my $tver (@versions) {
								chomp  $tver;
								if (mysystem("dpkg --compare-versions $tver \'$op\' $ver") == 0) {
									last DEPS;
								}
							}
						} else {
							last DEPS;
						}
					}
				}
			} else {
				$dep = $_;
			}
			$dep =~ s/\((=.*)\)/=$1/;
			$dep =~ s/\([><].*\)//;
			$dep =~ s/\s+//g;
			push (@choices, $dep);
			
			# Spcifie l'architecture si diffrente de celle par dfaut
			if (("$arch" ne "all") &&
				("$curarch" ne "$arch")) {
				foreach(@choices) {
					s/([a-z0-9-+:\.]+)(\=?.*)/$1:${arch}$2/;
				}
			}
			$found=0;
			foreach my $p (@choices) {
				#TODO: prendre en compte la version
				my $k=(split('=', $p))[0];
				my $v1=installed_version($k);
				# Si le paquet est prsent, sortie et flag positionn
				# Si le paquet est dj dans la liste des manquants, idem
				# Si le paquet est dans la liste des dpkg, idem
				if (("$v1" ne "") ||
					(grep (/^$k$/, @missing)) ||
					(grep (/^$k$/, @pending))) {
					$found++;
					last;
				}
				
			}
			# Si plusieurs choix possibles dans les dpendances, on slectionne d'autorit la premire
			if ($found==0) {
				push (@missing, $choices[0]);
			}
		}
	}
	my @inst;
	if ($#missing>=0) {
		my @correctedmissing = ();
		my @inst;
		# Recup de l'ensemble des paquets installs
		$gres = Update (1, \@inst, @missing);

		# Verif si des nouvelles dpendances ont t recompiles
		foreach (@inst) {
			next if (!m/(^\S+)\s.*/);
			my $pkt = $1;
			if (my @specific=grep (/^$pkt=\S+/, @missing)) {
				push @correctedmissing, $specific[0];
				next;
			}
			
			# Test si dans le lot un paquet a t recompil pour Kwartz
			my @versions= myback("apt-cache -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' show $pkt | grep 'Version:' | sed 's/Version: //'");
			if (my @kwartz=grep (/.*kwartz.*/, @versions)) {
				my $verkwartz = $kwartz[0];
				chomp $verkwartz;
				push @correctedmissing, "$pkt=$verkwartz";
				next;
			}
			push @correctedmissing, $pkt;
		}
		# Verif si a marche toujours avec des dpendances recompiles
		if ($#correctedmissing>=0) {
			$gres = Update (1, \@inst, @correctedmissing);

			# On installe les dpendances
			if ($gres == 0) {
				$gres = Update (0, \@inst, @correctedmissing);
			}
		}
	}
		
	if ((defined $opt_G) && ($gres == 0)) {
	# TODO: Grer l'ordre des pr-dpendances
		if ($#glpredeps>=0) {
			my @predep_indexes;
			for (my $id=0; $id <= $#pending; $id++) {
				push @predep_indexes, $id if (grep(/^$pending[$id]$/, @glpredeps));
			}
			foreach(@predep_indexes) {
				myback("dpkg -i $installlist[$_]");
			}
			foreach(@predep_indexes) {
				splice @installlist, $_, 1;
			}
		}
		myback("dpkg -i @installlist");
	}
} elsif (defined($opt_P)) {
	my $pkg = $opt_P;
	my @updates_s = myback("apt-cache -o Dir::Etc::SourceList=$SOURCE_S -o Dir::Etc::SourceParts='/etc/kwartz/sources.list.d/' policy $pkg 2>&1");
	foreach (@updates_s) {
		print;
	}
}

# Sortie
myexitlog (	"",	# TODO: Mettre quelque chose sur STDOUT ?
			"fin autoupdate",
			$gres);

END {
	# $opt_C : no res backuped for check
	# $opt_D : if kept, res for parent and grandson. So son is in charge to backup res
	unless (defined($opt_C) or defined($opt_D)) {
		open RESULT, ">>", "$RUNDIR/$$.res";
		print RESULT " $?";
		close RESULT;
	}
}
