1762 lines
53 KiB
Perl
Executable File
1762 lines
53 KiB
Perl
Executable File
#!/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 (' '),
|
|
$q->td (' '));
|
|
|
|
# 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 (' '),
|
|
$q->td (' '));
|
|
|
|
# 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;
|
|
}
|
|
|