smeserver-thinclient/root/etc/e-smith/web/functions/thinclient

1762 lines
53 KiB
Plaintext
Raw Permalink Normal View History

#!/usr/bin/perl -wT
# =====================================================================
#
# heading : Configuration
# description : Thin Clients
# navigation : 7500 7700
#
# =====================================================================
# ===
# === by Trevor Batley, trevor@batley.id.au
# ===
# =====================================================================
# ===
# === Read History in README
# === Versionnumber: 2.0.0-1
# ===
# =====================================================================
package esmith;
use strict;
use CGI ':all';
use CGI::Carp qw(fatalsToBrowser);
use esmith::cgi;
use esmith::ConfigDB;
use esmith::util;
use FileHandle;
use File::Basename;
use File::Path qw(make_path remove_tree);
sub showInitial ($$$$);
sub showStatusReport ($$$$);
sub showFooter ($);
sub showConfigurationPanel ($);
sub showPXEClients ($);
sub showPXEDists ($);
sub loadConfiguration ($);
sub saveClient ($);
sub saveDistribution ($);
sub saveConfiguration ($);
sub showDistributionPanel ($$$);
sub showWorkstationPanel ($$$);
sub checkarchive ($);
sub readini($);
BEGIN
{
# Clear PATH and related environment variables so that calls to
# external programs do not cause results to be tainted. See
# "perlsec" manual page for details.
$ENV {'PATH'} = '/bin:/usr/bin';
$ENV {'SHELL'} = '/bin/bash';
delete $ENV {'ENV'};
}
esmith::util::setRealToEffective ();
my $config = esmith::ConfigDB->open;
my $pxeclients = esmith::ConfigDB->open('thinclient');
my $hosts = esmith::ConfigDB->open_ro('hosts');
my $version = '2.2-1';
my $email = 'trevor@batley.id.au';
my $title = 'Thin Client Configuration';
my $copyright = 'copyright (c) 2004, Trevor Batley, <a href=mailto:'.$email.'>'.$email.'</a>';
my $sendreports = 'Please raise Bugs and Feature Requests in <a target=_blank href=http://bugs.contribs.org/>Bugzilla</a> (SMEContribs => smeserver-thinclient)';
my $thinclientstatus;
my $pxedefaultbase;
my $pxedir;
my @rg_onoffdisplay = ("Enabled", "Disabled");
my @rg_onoffvalue = ("enabled", "disabled");
my %rg_onoffhash =($rg_onoffvalue[0] => $rg_onoffdisplay[0],
$rg_onoffvalue[1] => $rg_onoffdisplay[1]);
# ------------------------------------------------------------------------------
# ---
# --- examine state parameter and display the appropriate form
# ---
# ------------------------------------------------------------------------------
my $q = new CGI;
if (! grep (/^state$/, $q->param))
{
showInitial ($q, '', '', '');
}
elsif ($q->param ('state') eq "configurethinclient")
{
saveConfiguration ($q);
}
elsif ($q->param ('state') eq "showDist")
{
showDistributionPanel ($q, '', '');
}
elsif ($q->param ('state') eq "saveDist")
{
saveDistribution ($q);
}
elsif ($q->param ('state') eq "showClient")
{
showWorkstationPanel ($q, '', '');
}
elsif ($q->param ('state') eq "saveClient")
{
saveClient ($q);
}
else
{
esmith::cgi::genStateError ($q, $config);
}
exit (0);
# ------------------------------------------------------------------------------
# ---
# --- subroutine to display initial form
# ---
# ------------------------------------------------------------------------------
sub showInitial ($$$$)
{
my ($q, $status, $msg, $log) = @_;
$q = new CGI("");
esmith::cgi::genHeaderNonCacheable ($q, $config, $title);
if ($status ne '') {showStatusReport ($q, $status, $msg, $log)};
showConfigurationPanel ($q);
showFooter ($q);
return;
}
# ------------------------------------------------------------------------------
# ---
# --- subroutine to display Status Report
# ---
# ------------------------------------------------------------------------------
sub showStatusReport ($$$$)
{
my ($q, $status, $msg, $log) = @_;
my $img_string = qq(src="/server-common/checkmark.jpg" ALT="ERROR");
if ($status eq "success")
{
$img_string = qq(src="/server-common/tickmark.jpg" ALT="SUCCESS");
}
print $q->table({-class => "sme-borders"},
$q->Tr(
$q->td("<img $img_string>"),
$q->td($q->div({-class => $status},
$q->h2('Operation Status Report'),
$q->p($msg))),
));
if ($log ne '')
{
open (LOG, $log) || die ("Error while opening temporal log file.\n");
while (<LOG>)
{
print "$_". "<BR>";
}
close LOG;
}
print $q->hr;
return;
}
# ------------------------------------------------------------------------------
# ---
# --- subroutine to display Footer Signature
# ---
# ------------------------------------------------------------------------------
sub showFooter ($)
{
my $q=shift;
print $q->p ($q->hr, $q->font ({size=>"-3"}, $copyright, "<br>",
$sendreports, "<br>",
"Version ", $version) );
}
# ----------------------------------------------------------------------------
# ---
# --- subroutine showConfigurationPanel
# ---
# ----------------------------------------------------------------------------
sub showConfigurationPanel($)
{
my ($q) = @_;
print $q->start_multipart_form (-method=>'POST', -action=>$q->url (-absolute=>1));
# --- PXE Globals
showPXEGlobals ($q);
# --- PXE Distributions
print $q->hr;
showPXEDists ($q);
# --- PXE Clients
print $q->hr;
showPXEClients ($q);
print $q->hidden (-name=>'state', -override=>1, -default=>'configurethinclient');
print $q->endform;
return;
}
# ----------------------------------------------------------------------------
# ---
# --- subroutine showPXEGlobals
# ---
# ----------------------------------------------------------------------------
sub showPXEGlobals($)
{
my ($q) = @_;
# get the pxe and thinclient configuration settings from the configuration database
my $pxerec = $config->get('pxe');
my $defaultbase = $pxeclients->get_value('defaultbase');
# Load display list of available distributions
my @distrecs = $pxeclients->get_all_by_prop('type' => 'dist');
my @displaylist = ("default", "None");
foreach my $distrec (sort @distrecs)
{
push (@displaylist, $distrec->key);
}
# Load a list of alternate local hosts for the tftpserver parameter including Self & Other
my @local = $hosts->get_all_by_prop('HostType'=>'Local');
my @hostlist = ("Self", "Other");
foreach my $local (sort @local)
{
push (@hostlist, $local->key);
}
# --- Print everything
print $q->start_table ({-class => "sme-noborders"});
print $q->p ('PXE Booting is a facility for allowing LAN workstations to boot an operating system ',
'over the network.<BR>',
'If PXE Booting is enabled, dhcp will supply the filepath of ',
'a pxe bootable image to any LAN workstation requesting it.',
);
print $q->p ('You must specifiy which tftp server you will be using to supply the image.<BR>',
'Selecting <B>Self</B> will activate the tftp server running on this server (if you have installed one - e.g. smeserver-tftp-server).<BR>',
'You can also select from any host defined on your network (preferred), or specify ',
'the IP address of the machine your tftp server is running on.',
);
print $q->p ('The default distribution will be used by all Workstations unless you specify individual ',
'settings for a Workstation.<BR>',
'If you select \'None\', you will need to use individual Workstation settings for all Workstations.',
);
# --- PXE Boot Status
my $pxestatus = ($config->get_prop('pxe', 'status') || "disabled");
print $q->Tr(
$q->td({-class => "sme-noborders-label"},
"Your PXE Boot Server is "
),
$q->td({-class => "sme-noborders-content"},
$q->radio_group (
-name => 'pxestatus',
-values => \@rg_onoffvalue,
-linebreak => 'true',
-default => $pxestatus,
-labels => \%rg_onoffhash
)
),
);
# --- TFTP Server
# If using an undefined host set dropdown default to other
my $ipdefault = ($config->get_prop('pxe', 'nextserver') || "") || "Self";
my $listdefault = "Other";
foreach my $host (@hostlist)
{
if ($host eq $ipdefault)
{
$listdefault = $ipdefault;
$ipdefault = "";
last;
}
}
print $q->Tr(
$q->td({-class => "sme-noborders-label"},
"Your TFTP Server is "
),
$q->td({-class => "sme-noborders-content"},
$q->popup_menu (
-name => 'tftpserver',
-values => \@hostlist,
-linebreak => 'true',
-default => $listdefault),
),
$q->td(" Or "),
$q->td({class => "sme-noborders-content"},
$q->textfield (
-name => 'tftpip',
-default => $ipdefault,
-overide => 1,
-size => 15)),
);
# --- Default Distribution
print $q->Tr(
$q->td ({-class => "sme-noborders-label"},
"The default Distribution is "
),
$q->td({-class => "sme-noborders-content"},
$q->popup_menu (
-name => 'pxedist',
-values => \@displaylist,
-linebreak => 'true',
-default => ($defaultbase)),
),
);
print $q->p ({-class => "sme-noborders-label"},
esmith::cgi::genButtonRow ($q,
$q->submit (-name=>'acct', -value=>'Apply'))
);
print $q->end_table;
# --- TFTP Status (if Self and not turned on issue a warning)
if (($config->get_prop('pxe', 'nextserver') || "") eq "") # Self
{
# --- We only look for tftp (possibly need to check if others exist)
if ($config->get('tftp'))
{
if ($config->get_prop('tftp', 'status') ne 'enabled')
{
print $q->p ({-CLASS => "sme-norborders"},
$q->p ('<B>WARNING:</B> a tftp server is required to supply the boot image to your workstations.<BR> ',
'tftp is currently disabled, but will be enabled when you enable PXE Boot Server (you will need to click Apply above).'));
}
}
else
{
print $q->p ({-CLASS => "sme-noborders"},
$q->p ('<B>WARNING:</B> a tftp server is required to supply the boot image to your workstations.<BR> ',
'I can\'t find any settings for tftp, so can only assume that you are managing this!'));
}
}
# --- DHCPD Status (if not turned on issue a warning)
if ($config->get_prop('dhcpd', 'status') ne 'enabled')
{
print $q->p ({-CLASS => "sme-norborders"},
$q->p ('<B>WARNING:</B> all this information is supplied to your workstations via dhcpd.<BR> ',
'dhcpd is currently disabled, and none of this will work until you enable it!'));
}
return;
}
# ----------------------------------------------------------------------------
# ---
# --- subroutine showPXEDists
# ---
# ----------------------------------------------------------------------------
sub showPXEDists($)
{
my ($q) = @_;
my $tftproot = "/tftpboot/";
if ($config->get('tftp'))
{
if ($config->get_prop('tftp', 'status') eq 'enabled')
{
$tftproot = $config->get_prop('tftp', 'tftproot') || "/tftpboot/";
}
}
print $q->h2 ('Distributions');
print $q->start_table ({-class => "sme-noborders"});
print $q->p ('The following is a list of the Distributions that you have available for PXE Booting. ',
'They have either been installed via a package or added manually.',
);
my @pxedist = $pxeclients->get_all_by_prop('type' => 'dist');
if (@pxedist < 1)
{
print $q->p ($q->a ({href => $q->url (-absolute => 1) . "?state=showDist&acct=Add"},
'Click here'),
'to add your first Thin Client Distribution.');
}
else
{
#show table
print $q->p ($q->a ({href => $q->url (-absolute => 1) . "?state=showDist&acct=Add"},
'Click here'),
' to add another Thin Client Distribution. You currently have ' . @pxedist . ' Distribution/s available.');
}
print $q->p ;
#header
print $q->Tr (esmith::cgi::genSmallCell ($q, $q->b ('Distribution'), 'header'),
esmith::cgi::genSmallCell ($q, $q->b ('Base Directory'), 'header'),
esmith::cgi::genSmallCell ($q, $q->b ('Type'), 'header'),
$q->td ('&nbsp;'),
$q->td ('&nbsp;'));
# default distribution is the gloable PXE parameters
my $dist = "default";
my $install = "system";
print $q->Tr (esmith::cgi::genSmallCell ($q, $dist, 'normal'),
esmith::cgi::genSmallCell ($q, $tftproot.($config->get_prop('pxe', 'dir') || ""), 'normal'),
esmith::cgi::genSmallCell ($q, $install, 'normal'),
esmith::cgi::genCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=showDist&acct=Show&dist="
. $dist}, 'Show...'), 'normal'));
if (@pxedist)
{
# Get sorted list of Distributions - Gotta be a better way!!!
my @distkeys;
foreach my $drec (@pxedist)
{push (@distkeys, $drec->key)};
foreach my $dist (sort @distkeys)
{
my $distrec = $pxeclients->get($dist);
my $install = $distrec->prop('install') || "Manual";
if ($install eq "Manual" || $install eq 'Archive')
{
print $q->Tr (esmith::cgi::genSmallCell ($q, $dist, 'normal'),
esmith::cgi::genSmallCell ($q, $tftproot.($distrec->prop('dir') || ""), 'normal'),
esmith::cgi::genSmallCell ($q, $install, 'normal'),
esmith::cgi::genCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=showDist&acct=Show&dist="
. $dist}, 'Show...'), 'normal'),
esmith::cgi::genCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=showDist&acct=Delete&dist="
. $dist}, 'Remove...'), 'normal'),
esmith::cgi::genCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=showDist&acct=Change&dist="
. $dist}, 'Modify...'), 'normal'));
}
else
{
print $q->Tr (esmith::cgi::genSmallCell ($q, $dist, 'normal'),
esmith::cgi::genSmallCell ($q, $tftproot . ($distrec->prop('dir') || ""), 'normal'),
esmith::cgi::genSmallCell ($q, $install, 'normal'),
esmith::cgi::genCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=showDist&acct=Show&dist="
. $dist}, 'Show...'), 'normal'),
esmith::cgi::genCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=showDist&acct=Delete&dist="
. $dist}, 'Remove...'), 'normal'));
}
}
}
print $q->end_table;
return;
}
# ----------------------------------------------------------------------------
# ---
# --- subroutine showPXEClients
# ---
# ----------------------------------------------------------------------------
sub showPXEClients($)
{
my ($q) = @_;
print $q->h2 ('Individually Controlled Workstations');
print $q->start_table ({-class => "sme-noborders"});
print $q->p ('The following is a list of the individual Workstation you have configured for PXE Booting.<BR>',
'You ONLY need to use this if you want to control an individual Workstations settings independently ',
'from the default or you don\'t wish to use a default.',
);
my @clients = $pxeclients->get_all_by_prop('type' => 'mac');
if (@clients < 1)
{
print $q->p ($q->a ({href => $q->url (-absolute => 1) . "?state=showClient&acct=Add"},
'Click here'),
' to add your first individually controlled Thin Client Workstation.');
}
else
{
#show table
print $q->p ($q->a ({href => $q->url (-absolute => 1) . "?state=showClient&acct=Add"},
'Click here'),
' to add another individually controlled Thin Client Workstation.<BR>',
'You currently have ' . @clients . ' individually controlled Thin Client Workstation/s defined.');
#header
print $q->Tr (esmith::cgi::genSmallCell ($q, $q->b ('mac address'), 'header'),
esmith::cgi::genSmallCell ($q, $q->b ('Name'), 'header'),
esmith::cgi::genSmallCell ($q, $q->b ('Distribution'), 'header'),
esmith::cgi::genSmallCell ($q, $q->b ('Status'), 'header'),
$q->td ('&nbsp;'),
$q->td ('&nbsp;'));
# Get sorted list of Workstations - Gotta be a better way!!!
my @mackeys;
foreach my $macrec (@clients)
{push (@mackeys, $macrec->key)};
foreach my $client (sort @mackeys)
{
my $clientrec = $pxeclients->get($client);
print $q->Tr (esmith::cgi::genSmallCell ($q, $client, 'normal'),
esmith::cgi::genSmallCell ($q, $clientrec->prop("name") || '', 'normal'),
esmith::cgi::genSmallCell ($q, $clientrec->prop("base") || '', 'normal'),
esmith::cgi::genSmallCell ($q, $clientrec->prop("status") || '', 'normal'),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=showClient&acct=Delete&mac="
. $client}, 'Remove...'), 'normal'),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=showClient&acct=Change&mac="
. $client}, 'Modify...'), 'normal'));
}
print $q->end_table;
}
return;
}
# ----------------------------------------------------------------------------
# ---
# --- subroutine showDistributionPanel
# ---
# ----------------------------------------------------------------------------
sub showDistributionPanel($$$)
{
my ($q, $err, $log) = @_;
my $action = $q->param ('acct');
my $dist = $q->param ('dist') || "";
my $dir = $q->param ('dir') || "";
my $prog = $q->param ('prog') || "pxelinux.0";
my $ini = $q->param('ini') || "";
my $origdir = $q->param('origdir') || "";
my $install = $q->param('install') || "Manual";
my $tftproot = "/tftpboot/";
my $arch = "";
my $aprog = "";
my $aname = "";
if ($config->get('tftp'))
{
if ($config->get_prop('tftp', 'status') eq 'enabled')
{
$tftproot = $config->get_prop('tftp', 'tftproot') || "/tftpboot/";
}
}
# Get all architectures
my $pxerecord = $config->get('pxe');
my %pxearch = $pxerecord->props();
my @archkeys;
while (my ($arch, $prog) = each %pxearch)
{
unless ($arch eq 'dir' || $arch eq 'default' || $arch eq 'status' || $arch eq 'type' || $arch eq 'nextserver')
{
push (@archkeys, $arch);
}
}
esmith::cgi::genHeaderNonCacheable ($q, $config, $action . " Distribution");
print $q->start_multipart_form (-method=>'POST', -action=>$q->url (-absolute=>1));
if ($err ne '') {showStatusReport ($q, 'error', $err, $log)};
# --- Distribution Name
if ($action eq 'Add')
{
print $q->p ('You can add a Distribution via a prebuilt archive.<BR><BR>',
'Select the file to load from your local workstation. Minimal checking is done on this file!',
);
print $q->p ;
print $q->start_table ({-class => "sme-noborders"});
print $q->Tr (
$q->td ({-class => "sme-noborders-label"}, "Archive:"),
$q->td ({-class => "sme-noborders-content"},
$q->filefield(-name => 'archive',
-default => "smeserver-thinclient-<dist>-<version>.noarch.rpm",
-size => 32)));
print $q->end_table;
print $q->start_table ({-class => "sme-noborders"});
print $q->Tr ('Or you can manually add a distribution. You must create the required directories and ',
'populate them yourself.<BR>Please read the documentation that comes with the distribution.',
);
$dist = "";
print $q->p ;
print $q->Tr (
$q->td ({-class => "sme-noborders-label"}, "Distribution:"),
$q->td ({-class => "sme-noborders-content"}, $q->textfield (-name => "dist", -override => 1, -default => $dist, -size => 32)));
print $q->Tr (
$q->td ({-class => "sme-noborders-label"}, "Directory:".$tftproot),
$q->td ({-class => "sme-noborders-content"}, $q->textfield (-name => "dir", -override => 1, -default => $dir, -size => 32)));
print $q->Tr (
$q->td ({-class => "sme-noborders-label"}, "Default Executable:"),
$q->td ({-class => "sme-noborders-content"}, $q->textfield (-name => "prog", -override => 1, -default => $prog, -size => 32)));
# Get sorted list of Architectures and associated executable
foreach my $arch (sort @archkeys)
{
if ($pxeclients->get($arch)) { $aname = $pxeclients->get_prop($arch, 'name') || $arch; } else { $aname = $arch; }
$aprog = $config->get_prop('pxe', $arch);
print $q->Tr (
$q->td ({-class => "sme-noborders-label"}, $aname." Executable:"),
$q->td ({-class => "sme-noborders-content"}, $q->textfield (-name => $arch, -override => 1, -default => $aprog, -size => 32)));
}
print $q->end_table;
}
elsif ($action eq 'Confirm')
# Confirm ONLY applies to Distributions from an archive or if they have entered the name of an existing Distribution
{
if ($pxeclients->get($dist))
{
print $q->p ('<B>'.$dist.'</B> already exists. Do you really want to do this? Or do you want to define a new name and directory below?');
}
else
{
if ( $dir && -e "$tftproot$dir" )
{
print $q->p ($tftproot.$dir.' already exists. Do you really want to put this here? Or do you want to define a new directory below?');
}
}
if ($ini)
{
print $q->p ('These values came from your uploaded archive, you can change them if you want.<BR>',
'We will move the content to the new directory, if you change it.'
);
}
else
{
my $message = "Please enter the values you want for this distribution.<BR>";
if ($install eq "Manual")
{
$message .= "This will just store these parameters in the database.";
}
else
{
$message .= "Files from the archive will be installed into the directory you define.";
}
print $q->p ($message);
}
print $q->p ;
print $q->start_table ({-class => "sme-noborders"});
print $q->Tr ($q->td ({-class => "sme-noborders-label"}, "Distribution:"),
$q->td ({-class => "sme-noborders-content"},
$q->textfield (-name => "dist", -override => 1, -default => $dist, -size => 32)));
print $q->Tr ($q->td ({-class => "sme-noborders-label"}, "Directory:".$tftproot),
$q->td ({-class => "sme-noborders-content"},
$q->textfield (-name => "dir", -override => 1, -default => $dir, -size => 32)));
print $q->Tr (
$q->td ({-class => "sme-noborders-label"}, "Default Executable:"),
$q->td ({-class => "sme-noborders-content"}, $q->textfield (-name => "prog", -override => 1, -default => $prog, -size => 32)));
# Get sorted list of Architectures and associated executable
foreach my $arch (sort @archkeys)
{
if ($pxeclients->get($arch)) { $aname = $pxeclients->get_prop($arch, 'name') || $arch; } else { $aname = $arch; }
$aprog = q->param ($arch);
print $q->Tr (
$q->td ({-class => "sme-noborders-label"}, $aname." Executable:"),
$q->td ({-class => "sme-noborders-content"}, $q->textfield (-name => $arch, -override => 1, -default => $aprog, -size => 32)));
}
print $q->end_table;
print $q->p ('Press Confirm to install this distribution in the directory defined.');
print $q->p ;
print $q->hidden (-name=>'install', -value=>'archive');
}
elsif ($action eq 'Show')
{
# Show ONLY shows the parameters for a distribution, nothing else....
if ($dist eq 'default')
{
$dir = "";
$prog = $config->get_prop('pxe', 'default');
$install = "system";
print $q->p ('These are the Global PXE parameters for your system. They can\'t be changed from here.');
}
else
{
$dir = $pxeclients->get_prop($dist, 'dir');
$prog = $pxeclients->get_prop($dist, 'prog');
$install = $pxeclients->get_prop($dist, 'install');
print $q->p ('These are the parameters for the '.$dist.' Distribution from the database');
}
print $q->p;
print $q->start_table ({-class => "sme-noborders"});
print $q->Tr(
$q->td ({-class => "sme-noborders-label"}, "Name: "),
$q->td({-class => "sme-noborders-content"}, $dist),
);
print $q->Tr(
$q->td ({-class => "sme-noborders-label"}, "Directory: "),
$q->td ({-class => "sme-noborders-content"}, $tftproot.$dir),
);
print $q->Tr(
$q->td ({-class => "sme-noborders-label"}, "Default Executable: "),
$q->td ({-class => "sme-noborders-content"}, $prog),
);
foreach my $arch (sort @archkeys)
{
$aprog;
if ($pxeclients->get($arch)) { $aname = $pxeclients->get_prop($arch, 'name') || $arch; } else { $aname = $arch; }
if ($dist eq 'default')
{
$aprog = $config->get_prop('pxe', $arch);
}
else
{
$aprog = $pxeclients->get_prop($dist, $arch);
}
if ($aprog)
{
print $q->Tr (
$q->td ({-class => "sme-noborders-label"}, $aname." Executable:"),
$q->td ({-class => "sme-noborders-content"}, $aprog),
);
}
}
print $q->Tr(
$q->td ({-class => "sme-noborders-label"}, "Install Type: "),
$q->td ({-class => "sme-noborders-content"}, $install),
);
print $q->end_table;
print $q->p ;
}
elsif ($action eq 'Delete')
{
# Check to see if any workstations are using the distribution
my @clients = $pxeclients->get_all_by_prop('base' => $dist);
if (@clients)
{
print $q->p ('<B>WARNING:</B> You have Workstations using the '.$dist.' Distribution. They will not work until you change their configuration.');
}
my $distrec = $pxeclients->get($dist);
if ($dist eq "default")
{
$dir = "";
$prog = $config->get_prop('pxe', 'default');
$install = "system";
}
else
{
$dir = $distrec->prop('dir') || "";
$prog = $distrec->prop('prog') || "pxelinux.0";
$install = $distrec->prop('install') || "Manual";
}
print $q->p ('This will delete the '.$dist.' Distribution from the database');
print $q->p ;
print $q->start_table ({-class => "sme-noborders"});
print $q->Tr(
$q->td ({-class => "sme-noborders-label"}, "Name: "),
$q->td({-class => "sme-noborders-content"}, $dist),
);
print $q->Tr(
$q->td ({-class => "sme-noborders-label"}, "Directory: "),
$q->td ({-class => "sme-noborders-content"}, $tftproot.$dir),
);
print $q->Tr(
$q->td ({-class => "sme-noborders-label"}, "Default Executable: "),
$q->td ({-class => "sme-noborders-content"}, $prog),
);
foreach my $arch (sort @archkeys)
{
if ($pxeclients->get($arch)) { $aname = $pxeclients->get_prop($arch, 'name') || $arch; } else { $aname = $arch; }
$aprog = $distrec->prop($arch);
if ($aprog)
{
print $q->Tr (
$q->td ({-class => "sme-noborders-label"}, $aname." Executable:"),
$q->td ({-class => "sme-noborders-content"}, $aprog),
);
}
}
print $q->end_table;
if ($dist eq "default")
{
print $q->p ("You can't delete the Default distribution. These are the global PXE parameters");
}
elsif ($install eq 'Manual' || $install eq 'Archive')
{
if ($dir)
# Don't try to delete the tftp root directory :)
{
print $q->p ('If you want to remove the '.$tftproot.$dir.' directory, and all files, please tick "Delete the '.$tftproot.$dir.' directory and all contents?"');
}
else
{
print $q->p ("You can't delete the $tftproot$dir directory, so you'll have to manipulate the files yourself");
}
}
else
{
print $q->p ('This Distribution was installed as an rpm, it will be removed via rpm -e!<BR>',
'Which will remove all associated files and database entries.',
);
}
if ($install eq 'Manual' || $install eq 'Archive')
{
if ($dir)
# Don't try to delete the tftp root directory :)
{
print $q->p ("<input type=\"checkbox\" name=\"deldir\" value=\"yes\" />Delete the $tftproot$dir directory and all contents?");
print $q->p ;
}
print $q->hidden (-name=>'dir', -value=>$dir);
}
print $q->hidden (-name=>'dist', -value=>$dist);
print $q->hidden (-name=>'install', -value=>$install);
}
elsif ($action eq 'Change')
{
if ($dist eq "default")
{
$dir = $config->get_prop('pxe', 'dir') | "";
$prog = $config->get_prop('pxe', 'default') || "pxelinux.0";
print $q->p ('This will alter the system wide PXE defaults');
}
else
{
$dir = $pxeclients->get_prop($dist, 'dir') || "";
$prog = $pxeclients->get_prop($dist, 'prog') || "pxelinux.0";
print $q->p ('You can alter the '.$dist.' Distribution parameters in the database');
}
if ($dir)
# Don't try to move the tftp root directory :)
{
print $q->p ('If you want to move the '.$tftproot.$dir.' directory, and all files,<BR>',
'- please enter the new directory name in the Directory box, and<BR>',
'- tick "Move '.$tftproot.$dir.' and contents?"'
);
}
else
{
print $q->p ("You can't move the $tftproot$dir directory, but we will move the contents for you");
}
print $q->p ;
print $q->start_table ({-class => "sme-noborders"});
print $q->Tr (
esmith::cgi::genNameValueRow ($q, "Name", "dist", $dist),
);
print $q->Tr(
$q->td ({-class => "sme-noborders-label"}, "Directory: "),
$q->td ({-class => "sme-borders-content"}, "$tftproot<input type=\"text\" name=\"dir\" value=\"$dir\">"),
);
print $q->Tr(
$q->td ({-class => "sme-noborders-label"}, "Default Executable: "),
$q->td ({-class => "sme-borders-content"}, "<input type=\"text\" name=\"prog\" value=\"$prog\">"),
);
foreach my $arch (sort @archkeys)
{
if ($pxeclients->get($arch)) { $aname = $pxeclients->get_prop($arch, 'name') || $arch; } else { $aname = $arch; }
# default distribution is the global pxe parameters
if ($dist eq "default")
{
$aprog = $config->get_prop('pxe', $arch);
print $q->Tr (
$q->td ({-class => "sme-noborders-label"}, $aname." Executable:"),
$q->td ({-class => "sme-noborders-content"}, "<input type=\"text\" name=\"$arch\" value=\"$aprog\">"),
);
}
else
{
$aprog = $pxeclients->get_prop($dist, $arch);
print $q->Tr (
$q->td ({-class => "sme-noborders-label"}, $aname." Executable:"),
$q->td ({-class => "sme-noborders-content"}, "<input type=\"text\" name=\"$arch\" value=\"$aprog\">"),
);
}
}
print $q->end_table;
if ($dir)
# Don't try to move the tftp root directory :)
{
print $q->p ({-class => "sme-noborders-content"}, "<input type=\"checkbox\" name=\"movedir\" value=\"yes\">Move $tftproot$dir and contents?");
print $q->p ;
}
}
else
{
showStatusReport ($q, 'error', "We should never get here (Action=$action)", $log)
}
if ($action eq 'Show')
{
print $q->defaults (-name=>'Return');
}
else
{
print $q->submit (-name=>'acct', -value=>$action);
if ($action ne 'Delete')
{
print $q->submit (-name=>'reset', -value=>'Reset');
print $q->hidden (-name=>'origacct', -value=>$action);
print $q->hidden (-name=>'origdist', -value=>$dist);
print $q->hidden (-name=>'origdir', -value=>$dir);
}
print $q->defaults (-name=>'Cancel');
}
print $q->hidden (-name=>'state', -override=>1, -default=>'saveDist');
print $q->endform;
showFooter ($q);
return;
}
# ----------------------------------------------------------------------------
# ---
# --- subroutine showWorkstationPanel
# ---
# ----------------------------------------------------------------------------
sub showWorkstationPanel($$$)
{
my ($q, $err, $log) = @_;
my $action = $q->param ('acct');
my $mac = $q->param ('mac');
my $name = "";
my $base = "";
my $status = "";
my $distdir = "";
my $tftproot = "/tftpboot/";
if ($config->get('tftp'))
{
if ($config->get_prop('tftp', 'status') eq 'enabled')
{
$tftproot = $config->get_prop('tftp', 'tftproot') || "/tftpboot/";
}
}
esmith::cgi::genHeaderNonCacheable ($q, $config, $action . " Workstation");
print $q->start_multipart_form (-method=>'POST', -action=>$q->url (-absolute=>1));
if ($err ne '')
{
showStatusReport ($q, 'error', $err, $log);
$name = $q->param ('name');
$base = $q->param ('base');
$status = $q->param ('status');
}
print $q->start_table ({-class => "sme-noborders"});
if ($action eq "Add")
{
if ($err eq '')
{
$mac = "";
$name = "";
$base = ($pxeclients->get_value('defaultbase') || "");
$status = "enabled";
}
print $q->p ('These settings over-ride the global parameters for this Workstation ONLY!',);
# Can ONLY enter the mac address on add
print $q->Tr ({-CLASS => "sme-noborders"},
esmith::cgi::genNameValueRow ($q, "Device Address", "mac", $mac)
),"\n";
}
else
{
my $clientrec = $pxeclients->get($mac);
if ($err eq '')
{
$name = $clientrec->prop('name');
$base = $clientrec->prop('base') || "";
$status = $clientrec->prop('status') || "enabled";
}
if ($action eq "Delete")
{
print $q->p ('Deleting these settings will return this Workstation to using the global parameters.',);
}
else
{
print $q->p ('These settings over-ride the global parameters for this Workstation ONLY!',);
}
# Can't change the mac address on change or delete
print $q->Tr(
$q->td ({-class => "sme-noborders-label"},
"Device Address: "
),
$q->td ({-class => "sme-noborders-content"},
$mac
),
);
print $q->hidden (-name=>'mac', -value=>$mac);
}
$distdir = $pxeclients->get_prop($base, 'dir') || "";
if ($action eq 'Delete')
{
# --- Just display the stuff for confirmation of the delete
print $q->Tr(
$q->td ({-class => "sme-noborders-label"},
"Device Name: "
),
$q->td ({-class => "sme-noborders-content"},
$name
),
);
print $q->Tr(
$q->td ({-class => "sme-noborders-label"},
"The Distribution used is: "
),
$q->td ({-class => "sme-noborders-content"},
"$base \($tftproot$distdir\)"
),
);
print $q->Tr(
$q->td ({-class => "sme-noborders-label"},
"Status: "
),
$q->td ({-class => "sme-noborders-content"},
$status
),
);
print $q->hidden (-name=>'name', -value=>$name);
print $q->hidden (-name=>'base', -value=>$base);
print $q->hidden (-name=>'status', -value=>$status);
}
else
{
# Allow alteration of all fields
print $q->Tr ({-CLASS => "sme-noborders"},
esmith::cgi::genNameValueRow ($q, "Device Name", "name", $name)
);
# Load display list of available distributions
my @distrecs = $pxeclients->get_all_by_prop('type' => 'dist');
my @displaylist;
foreach my $distrec (@distrecs)
{
push (@displaylist, $distrec->key);
}
print $q->Tr(
$q->td ({-class => "sme-noborders-label"},
"The Distribution used is: "
),
$q->td({-class => "sme-noborders-content"},
$q->popup_menu (
-name => 'base',
-values => \@displaylist,
-linebreak => 'true',
-default => $base
)
),
$q->td ({-class => "sme-noborders"},
" \(" . $tftproot . $distdir . "\)"
),
);
print $q->Tr(
$q->td({-class => "sme-noborders-label"},
"Device Status: "
),
$q->td({-class => "sme-noborders-content"},
$q->radio_group (
-name => 'status',
-values => \@rg_onoffvalue,
-linebreak => 'true',
-default => $status,
-labels => \%rg_onoffhash
),
$q->td ('these parameters ONLY! Global parameters will apply if individual parameters are disabled'),
),
);
}
print $q->end_table,"\n";
print $q->submit (-name=>'acct', -value=>$action);
if ($action ne 'Delete')
{
print $q->submit (-name=>'reset', -value=>'Reset');
print $q->hidden (-name=>'origacct', -value=>$action);
print $q->hidden (-name=>'origmac', -value=>$mac);
}
print $q->defaults (-name=>'Cancel');
print $q->hidden (-name=>'state', -override=>1, -default=>'saveClient');
print $q->endform;
showFooter ($q);
return;
}
# ------------------------------------------------------------------------------
# ---
# --- subroutine Save Configuration
# ---
# ------------------------------------------------------------------------------
sub saveConfiguration ($)
{
my ($q) = @_;
my $pxestatus = $q->param('pxestatus');
my $tftpserver = $q->param('tftpserver');
my $pxedefaultbase = $q->param('pxedist');
my $tftpip = "";
my $nextserver = "";
my $pxerec = $config->get('pxe');
# if ((($tftpserver eq $pxerec->prop('nextserver')) || ($tftpserver eq "Other")) && $q->param('tftpip'))
if ($tftpserver eq "Other")
{
if ($q->param('tftpip'))
{
$tftpip = $q->param('tftpip');
my $err = checkip($tftpip);
if ($err eq "OK")
{
$nextserver = $tftpip;
}
else
{
showInitial ($q, "error", "Incorrect IP [$tftpip], $err, Update unsuccessfull", '');
return;
}
}
else # Can only get this if Other is selected & no IP entered
{
showInitial ($q, "error", "You must enter an IP if you select Other, Update unsuccessfull", '');
return;
}
}
elsif ($tftpserver ne "Self")
{
$nextserver = $hosts->get_prop($tftpserver, 'InternalIP');
# $nextserver = $tftpserver;
}
$pxerec->set_prop('status' => $pxestatus);
if ($nextserver) { $pxerec->set_prop('nextserver' => $nextserver); } else { $pxerec->delete_prop('nextserver'); }
$pxeclients->set_value('defaultbase' => $pxedefaultbase);
# What else needs to be activated if we are enabling PXE Booting?
# Turn on/off the bootp=allow parameter in the dhcpd configuration item (don't care if it's activated ATM)
my $dhcprec = $config->get('dhcpd');
if ($pxestatus eq "enabled")
{
$dhcprec->set_prop('Bootp' => "allow");
}
else
{
$dhcprec->set_prop('Bootp' => "deny");
}
# If we are using the tftp server locally, enable &/or disable in alignment with pxe
if ($tftpserver eq "Self")
{
if ($config->get('tftp'))
{
my $tftprec = $config->get('tftp');
$tftprec->set_prop('status' => $pxestatus);
}
}
if (system ("/sbin/e-smith/signal-event smeserver-thinclient-update > /var/log/thinclient.log 2>&1"))
{
showInitial($q, "error", "Error occurred during smeserver-thinclient-update event.", "/var/log/thinclient.log");
return;
}
# If we are using the tftp server locally trigger a tftp reconfiguration
if ($tftpserver eq "Self")
{
if (system ("/sbin/e-smith/signal-event smeserver-tftp-server-update > /var/log/thinclient.log 2>&1"))
{
showInitial($q, "error", "Error occurred during smeserver-tftp-server-update event.", "/var/log/thinclient.log");
return;
}
}
showInitial ($q, "success", "ThinClient parameters successfully updated.", "");
return;
}
# ----------------------------------------------------------------------------
# ---
# --- subroutine saveClient
# ---
# ----------------------------------------------------------------------------
sub saveClient ($)
{
my ($q) = @_;
if ($q->param('reset'))
{
my $origacct = $q->param('origacct');
my $origmac = $q->param('origmac');
$q = new CGI("");
$q->param(-name=>'acct', -value=>$origacct);
$q->param(-name=>'mac', -value=>$origmac);
showWorkstationPanel ($q, '', '');
return;
}
my $action = $q->param('acct');
my $mac = $q->param('mac');
my $macrec;
if ($action eq "Delete")
{
$macrec = $pxeclients->get($mac);
$macrec->delete;
}
else
{
my $name = $q->param('name');
# If no name entered use mac address (without :'s)
if ($name eq "")
{
$name = $mac;
$name =~ s/://g;
}
# Validate the name does NOT contain spaces - dhcpd.conf can't handle this
if ($name =~ / /gi)
{
showWorkstationPanel ($q, "Workstation name [$name], cannot contain spaces. $action unsuccessfull", "");
return;
}
my $base = $q->param('base');
my $status = $q->param('status');
if ($action eq "Add")
{
# Validate the mac address
my $err = checkmac($mac);
if ($err ne "OK")
{
showWorkstationPanel ($q, "Incorrect mac [$mac], $err. $action unsuccessfull", "");
return;
}
# All OK, add the details
my %newvalues = ('type' => 'mac',
'name' => $name,
'base' => $base,
'status' => $status);
$macrec = $pxeclients->new_record($mac, \%newvalues);
}
else
{
# All OK, update the details
$macrec = $pxeclients->get($mac);
$macrec->set_prop('name' => $name);
$macrec->set_prop('base' => $base);
$macrec->set_prop('status' => $status);
}
}
if (system ("/sbin/e-smith/signal-event smeserver-thinclient-update > /var/log/thinclient.log 2>&1"))
{
showWorkstationPanel($q, "Error occurred during thinclient-update event.", "/var/log/thinclient.log");
return;
}
showInitial ($q, "success", "$action of Workstation [$mac], successfull", "");
return;
}
# ----------------------------------------------------------------------------
# ---
# --- subroutine saveDistribution
# ---
# ----------------------------------------------------------------------------
sub saveDistribution ($)
{
my ($q) = @_;
my $action = $q->param('acct');
my $dist = $q->param('dist');
my $dir = $q->param('dir');
my $prog = $q->param('prog');
my $archive = $q->param('archive');
my $ext = $q->param('ext') || "";
my $deldir = $q->param('deldir');
my $movedir = $q->param('movedir');
my $install = $q->param('install') || "Manual";
my $origacct = $q->param('origacct');
my $origdist = $q->param('origdist');
my $origdir = $q->param('origdir');
my $safe_filename_characters = "a-zA-Z0-9_.-";
my $tftproot = $config->get_prop('tftp', 'tftproot') || "/tftpboot/";
my $ini = "";
my $arch = "";
my $aprog = "";
# Get all architectures
my $pxeconfig = $config->get('pxe');
my %pxearch = $pxeconfig->props;
my @archkeys;
while (my ($arch, $prog) = each %pxearch)
{
unless ($arch eq 'dir' || $arch eq 'default' || $arch eq 'status' || $arch eq 'type' || $arch eq 'nextserver')
{
push (@archkeys, $arch);
}
}
my %archs;
foreach my $arch (@archkeys)
{
my $aprog = $q->param($arch);
$archs {$arch} = $aprog;
}
if ($q->param('reset'))
{
$q = new CGI("");
$q->param(-name=>'acct', -value=>$origacct);
$q->param(-name=>'dist', -value=>$origdist);
$q->param(-name=>'dir', -value=>$origdir);
foreach my $arch (@archkeys)
{
my $aprog = $config-get_prop($arch, 'prog');
$q->param(-name=>$arch, -value=>$aprog);
}
showDistributionPanel ($q, '', '');
return;
}
if ($action eq 'Add')
{
if ($archive)
{
# If we are adding via an archive:
# - upload the archive
# - extract the archive
# - check if it has a thinclient.ini file and load defaults if it does
$install = "Archive";
# Untaint the filename
if ( $archive =~ /^([$safe_filename_characters]+)$/ )
{
$archive = $1;
}
else
{
die "Filename contains invalid characters";
}
# Upload the file
my $fharchive = $q->param('archive');
remove_tree ("/tmp/$archive");
open (WR,">/tmp/$archive") || die ("Error while opening temporally file.\n");
binmode WR;
while ( <$fharchive> )
{
print WR;
}
close WR;
# Extract the archive
my ( $name, $path, $ext ) = fileparse ( $archive, qr/\.[^.]*/ );
my $unzip = "/bin/tar -xf /tmp/$archive -C /tmp/thinclient";
if ($ext eq ".rpm")
{
$unzip = "/bin/rpm -Uvh /tmp/$archive";
$install = $archive;
}
elsif ($ext eq ".zip")
{
$unzip = "/usr/bin/unzip /tmp/$archive -d /tmp/thinclient";
}
else
{
$unzip = "/bin/tar -xf /tmp/$archive -C /tmp/thinclient";
}
remove_tree ("/tmp/thinclient");
mkdir "/tmp/thinclient";
if (system ($unzip." > /var/log/thinclient.log 2>&1"))
{
showDistributionPanel($q, "Error occurred during archive extract.(ext=$ext)", "/var/log/thinclient.log");
return;
}
# Now that we have unpacked it, delete the uploaded archive
unlink "/tmp/$archive";
# If there is a thinclient.ini within the archive, use the parameters in it
if (-e "/tmp/thinclient/thinclient.ini")
{
my $cfg = readini( "/tmp/thinclient/thinclient.ini" );
unlink "/tmp/thinclient/thinclient.ini";
$dist = $cfg->{"params"}->{"dist"};
$dir = $cfg->{"params"}->{"dir"};
$prog = $cfg->{"params"}->{"prog"} || "pxelinux.0";
$ini = "yes";
}
if ($ext ne ".rpm")
# rpms do everything themselves (db params & install)
# We ask for confirmation of parameters for all other archive types
{
$q = new CGI("");
$q->param(-name=>'acct', -value=>"Confirm");
$q->param(-name=>'dist', -value=>$dist);
$q->param(-name=>'dir', -value=>$dir);
$q->param(-name=>'prog', -value=>$prog);
while (($arch, $aprog) = each (%archs))
{
$q->param(-name=>$arch, -value=>$aprog);
}
$q->param(-name=>'install', -value=>$install);
$q->param(-name=>'ini', -value=>$ini);
showDistributionPanel ($q, '', '');
return;
}
}
else
{
# It must be a Manual entry
if ($pxeclients->get($dist))
{
$q = new CGI("");
$q->param(-name=>'acct', -value=>"Confirm");
$q->param(-name=>'dist', -value=>$dist);
$q->param(-name=>'dir', -value=>$dir);
$q->param(-name=>'prog', -value=>$prog);
while (($arch, $aprog) = each (%archs))
{
$q->param(-name=>$arch, -value=>$aprog);
}
$q->param(-name=>'install', -value=>"Manual");
showDistributionPanel ($q, '', '');
return;
}
my %newvalues = ('type' => 'dist',
'dir' => $dir,
'prog' => $prog,
'install' => 'Manual');
while (($arch, $aprog) = each (%archs))
{
$newvalues{$arch} = $aprog;
}
if ( $dir =~ /^([$safe_filename_characters]+)$/ )
{
$dir = $1;
}
else
{
die "Directory contains invalid characters\n";
}
my $owner = $config->get_prop('tftp', 'user') || "nobody";
unless (-d "$tftproot$dir") {make_path "$tftproot$dir", {owner=>$owner, group=>$owner};}
my $distrecord = $pxeclients->new_record($dist, \%newvalues);
}
}
elsif ($action eq 'Confirm')
{
# We ONLY get to Confirm, if it's an archive install (non rpm)
# Move the contents of the archive into the specified directory
# and update the config
if ( $dist eq "" )
{
showDistributionPanel ($q, "You MUST define a Distribution name.", '');
return;
}
if ( $dir =~ /^([$safe_filename_characters]+)$/ )
{
$dir = $1;
}
else
{
die "Directory contains invalid characters\n";
}
rename ("/tmp/thinclient", "$tftproot$dir");
my %newvalues = ('type' => 'dist',
'dir' => $dir,
'prog' => $prog,
'install' => 'Archive');
while (($arch, $aprog) = each (%archs))
{
$newvalues{$arch} = $aprog;
}
my $distrecord = $pxeclients->new_record($dist, \%newvalues);
}
elsif ($action eq "Delete")
{
if ($install eq "Manual" || $install eq "Archive")
{
my $distrecord = $pxeclients->get($dist);
$distrecord->delete;
# If they ticked the delete directory box, delete it
if ( $dir =~ /^([$safe_filename_characters]+)$/ )
{
$dir = $1;
}
else
{
die "Filename contains invalid characters";
}
if ($deldir eq 'yes')
{
remove_tree ("$tftproot$dir");
}
}
else
# We have to assume it's via rpm
{
my $rpm = $pxeclients->get_prop($dist, 'install');
if (system ("/bin/rpm -e $rpm > /var/log/thinclient.log 2>&1"))
{
showDistributionPanel($q, "Error occurred during rpm uninstall.", "/var/log/thinclient.log");
return;
}
}
}
elsif ($action eq "Change")
{
if ($dist eq "default")
# Changes to the default are changes to the global PXE configuration
{
if ($dir) { $pxeconfig->set_prop('dir' => $dir );} else { $pxeconfig->delete_prop('dir'); };
$pxeconfig->set_prop('default' => $prog);
while (($arch, $aprog) = each (%archs))
{
$pxeconfig->set_prop($arch => $aprog);
}
}
elsif ($install eq "Manual" || $install eq "Archive")
{
if ($dist eq $origdist)
# If the Distribution name hasn't changed, just update the fields
{
my $distrecord = $pxeclients->get($origdist);
$distrecord->set_prop('dir' => $dir);
$distrecord->set_prop('prog' => $prog);
while (($arch, $aprog) = each (%archs))
{
$distrecord->set_prop($arch => $aprog);
}
}
else
# If the Distribution name has changed, create the new one and delete the old
{
my %newvalues = ('type' => 'dist',
'dir' => $dir,
'prog' => $prog,
'install' => $install);
while (($arch, $aprog) = each (%archs))
{
$newvalues{$arch} = $aprog;
}
my $distrecord = $pxeclients->new_record($dist, \%newvalues);
my $distrecord = $pxeclients->get($origdist);
$distrecord->delete;
}
# If the directory has changed and we selected move directory
if ($dir ne $origdir && $movedir eq 'yes')
{
if ( $origdir =~ /^([$safe_filename_characters]+)$/ )
{
$origdir = $1;
}
else
{
die "Filename $origdir contains invalid characters";
}
if ( $dir =~ /^([$safe_filename_characters]+)$/ )
{
$dir = $1;
}
else
{
die "Filename $dir contains invalid characters";
}
rename ("$tftproot$origdir", "$tftproot$dir");
}
}
else
{
showDistributionPanel ($q, "This Distribution was installed via rpm. You can\'t modify these settings.", '');
return;
}
}
else
{
showDistributionPanel ($q, "$action, Oops!", '');
return;
}
if (system ("/sbin/e-smith/signal-event smeserver-thinclient-update > /var/log/thinclient.log 2>&1"))
{
showInitial($q, "error", "Error occurred during thinclient-update event.", "/var/log/thinclient.log");
return;
}
showInitial ($q, "success", "$action of Distribution $dist, successfull", "");
return;
}
# ----------------------------------------------------------------------------
# ---
# --- subroutine checkmac
# ---
# ----------------------------------------------------------------------------
sub checkmac($)
{
my ($mac) = @_;
$_ = lc $mac; # easier to match on $_
if (not defined $_)
{
return "You must provide a MAC address";
}
elsif (/^([0-9a-f][0-9a-f](:[0-9a-f][0-9a-f]){5})$/)
{
my @macexists = $hosts->get_all_by_prop('MACAddress'=>$mac);
if (@macexists > 0)
{
return "MAC address already assigned as a Local host";
}
elsif ($pxeclients->get($_))
{
return "MAC address already assigned as a Workstation";
}
else
{
return "OK";
}
}
else
{
return "The MAC address you provided was not valid";
}
}
# ----------------------------------------------------------------------------
# ---
# --- subroutine checkip
# ---
# ----------------------------------------------------------------------------
sub checkip($)
{
my ($ip) = @_;
return undef unless defined $ip;
return 'Doesn\'t look like an IP' unless $ip =~ /^[\d.]+$/;
my @octets = split /\./, $ip;
return 'Not enough octets (expected X.X.X.X)' unless scalar @octets == 4;
foreach my $octet (@octets)
{
return "$octet is more than 255" if $octet > 255;
}
return 'OK';
}
# ----------------------------------------------------------------------------
# ---
# --- subroutine checkarchive
# --- check the archive type and determine appropriate command to extract
# ---
# ----------------------------------------------------------------------------
sub checkarchive($)
{
my ($archive) = @_;
return undef unless defined $archive;
my ($ext) = $archive =~ /((\.[^.\s]+)+)$/;
if ($ext eq "tar.gz" || $ext eq "tgz" || $ext eq "tar.bz2" || $ext eq "tbz2" )
{
return "/bin/tar -xf /tmp/$archive -C /tmp/thinclient/", $ext;
}
elsif ($ext eq "zip")
{
return "/usr/bin/unzip /tmp/$archive -d /tmp/thinclient/", $ext;
}
elsif ($ext eq "rpm")
{
return "/bin/rpm -Uvh /tmp/$archive", $ext;
}
else
{
# We'll try tar and hope it understands the extension.....
return "/bin/tar -xf /tmp/$archive -C /tmp/thinclient/", $ext;
}
}
# ----------------------------------------------------------------------------
# ---
# --- subroutine read an ini file
# ---
# ----------------------------------------------------------------------------
sub readini($)
{
my ($ini) = @_;
my $cfg;
my $section;
open (INI, "$ini") || die "Can't open $ini: $!\n";
while (<INI>) {
chomp;
if ( /^\s*\[\s*(.+?)\s*\]\s*$/ )
{
$section = $1;
}
if ( /^\s*([^=]+?)\s*=\s*(.*?)\s*$/ )
{
$cfg->{$section}->{$1} = $2;
}
}
close (INI);
return $cfg;
}