mirror of
https://github.com/webmin/webmin.git
synced 2025-07-23 00:30:33 +00:00
940 lines
23 KiB
Perl
Executable File
940 lines
23 KiB
Perl
Executable File
# cfengine-lib.pl
|
|
# Functions for parsing the cfengine config file
|
|
|
|
BEGIN { push(@INC, ".."); };
|
|
use WebminCore;
|
|
&init_config();
|
|
|
|
@known_sections = ( 'groups', 'control', 'homeservers', 'binservers',
|
|
'mailserver', 'mountables', 'broadcast', 'resolve',
|
|
'defaultroute', 'directories', 'miscmounts', 'files',
|
|
'ignore', 'tidy', 'required', 'links', 'disable',
|
|
'shellcommands', 'editfiles', 'processes', 'copy' );
|
|
@known_sections = sort { $text{"section_$a"} cmp $text{"section_$b"} }
|
|
@known_sections;
|
|
|
|
@known_cfd_sections = ( 'control', 'groups', 'admit', 'deny' );
|
|
@known_cfd_sections = sort { $text{"section_$a"} cmp $text{"section_$b"} }
|
|
@known_cfd_sections;
|
|
|
|
$cfengine_conf = $config{'cfengine_conf'} ? $config{'cfengine_conf'} :
|
|
"$config{'cfengine_dir'}/cfengine.conf";
|
|
$cfd_conf = $config{'cfd_conf'} ? $config{'cfd_conf'} :
|
|
"$config{'cfengine_dir'}/cfd.conf";
|
|
$cfrun_hosts = $config{'cfrun_hosts'} ? $config{'cfrun_hosts'} :
|
|
"$config{'cfengine_dir'}/cfrun.hosts";
|
|
|
|
# get_config()
|
|
# Parses the cfengine.conf file into a list of sections, each containing
|
|
# a list of classes, each containing options for the section type.
|
|
sub get_config
|
|
{
|
|
if (!scalar(@get_config_cache)) {
|
|
@get_config_cache = &get_config_file($cfengine_conf);
|
|
}
|
|
return \@get_config_cache;
|
|
}
|
|
|
|
# get_cfd_config()
|
|
# Parses the cfd.conf file
|
|
sub get_cfd_config
|
|
{
|
|
if (!scalar(@get_cfd_config_cache)) {
|
|
@get_cfd_config_cache = &get_config_file($cfd_conf);
|
|
}
|
|
return \@get_cfd_config_cache;
|
|
}
|
|
|
|
# get_config_file(file)
|
|
# Parses on specified cfengine config file
|
|
sub get_config_file
|
|
{
|
|
# Parse file into tokens
|
|
local $lnum = 0;
|
|
local @toks;
|
|
open(CONFIG, $_[0]);
|
|
while(<CONFIG>) {
|
|
s/\r|\n//g;
|
|
s/(^|\s+)#.*$//g;
|
|
local ($s, $q) = &split_str($_);
|
|
local $i;
|
|
for($i=0; $i<@$s; $i++) {
|
|
push(@toks, [ $s->[$i], $lnum, $q->[$i] ]);
|
|
}
|
|
$lnum++;
|
|
}
|
|
close(CONFIG);
|
|
|
|
# Parse tokens into the config
|
|
local (@rv, $sec, $cls, $i);
|
|
push(@rv, { 'type' => 'dummy', # dummy record so that config is never empty
|
|
'index' => 0,
|
|
'line' => -1,
|
|
'eline' => -1,
|
|
'file' => $_[0] } );
|
|
for($i=0; $i<@toks; $i++) {
|
|
local $t = $toks[$i];
|
|
if ($t->[0] =~ /^(\S+)::$/) {
|
|
# Start of a class
|
|
$cls = { 'name' => $1,
|
|
'type' => 'class',
|
|
'index' => scalar(@{$sec->{'cls'}}),
|
|
'line' => $t->[1],
|
|
'eline' => $t->[1],
|
|
'file' => $_[0] };
|
|
$sec->{'eline'} = $t->[1];
|
|
push(@{$sec->{'cls'}}, $cls);
|
|
}
|
|
elsif ($t->[0] =~ /^(\S+):$/) {
|
|
# Start of a section
|
|
$sec = { 'name' => $1,
|
|
'type' => 'section',
|
|
'index' => scalar(@rv),
|
|
'cls' => [ ],
|
|
'line' => $t->[1],
|
|
'eline' => $t->[1],
|
|
'file' => $_[0] };
|
|
undef($cls);
|
|
push(@rv, $sec);
|
|
}
|
|
else {
|
|
# Some kind of text within a class .. create all:: if needed
|
|
if (!$sec) {
|
|
&error("Unknown directive at line ",
|
|
($t->[1]+1)," in $_[0]");
|
|
}
|
|
if (!$cls) {
|
|
$cls = { 'name' => 'any',
|
|
'type' => 'class',
|
|
'implied' => 1,
|
|
'index' => scalar(@{$sec->{'cls'}}),
|
|
'line' => $t->[1],
|
|
'eline' => $t->[1],
|
|
'file' => $_[0] };
|
|
push(@{$sec->{'cls'}}, $cls);
|
|
}
|
|
|
|
if ($i+2 < @toks &&
|
|
$toks[$i+1]->[0] eq '=' &&
|
|
$toks[$i+2]->[0] eq '(') {
|
|
# A definition with multiple values
|
|
local $def = { 'name' => $t->[0],
|
|
'line' => $t->[1],
|
|
'file' => $_[0] };
|
|
$i += 3;
|
|
while($i < @toks && $toks[$i]->[0] ne ')') {
|
|
push(@{$def->{'values'}}, $toks[$i]->[0]);
|
|
push(@{$def->{'valuequotes'}}, $toks[$i]->[2]);
|
|
push(@{$def->{'valuequoted'}},
|
|
"e_str($toks[$i]->[0], $toks[$i]->[2]));
|
|
$i++;
|
|
}
|
|
$sec->{'eline'} = $cls->{'eline'} = $toks[$i]->[1];
|
|
push(@{$cls->{'defs'}}, $def);
|
|
}
|
|
elsif ($t->[0] eq '{') {
|
|
# A { } quoted list
|
|
local $list = { 'line' => $t->[1],
|
|
'file' => $_[0] };
|
|
$i++;
|
|
while($i < @toks && $toks[$i]->[0] ne '}') {
|
|
push(@{$list->{'values'}}, $toks[$i]->[0]);
|
|
push(@{$list->{'valuelines'}}, $toks[$i]->[1]);
|
|
push(@{$list->{'valuequotes'}}, $toks[$i]->[2]);
|
|
push(@{$list->{'valuequoted'}},
|
|
"e_str($toks[$i]->[0], $toks[$i]->[2]));
|
|
$i++;
|
|
}
|
|
$sec->{'eline'} = $cls->{'eline'} = $toks[$i]->[1];
|
|
push(@{$cls->{'lists'}}, $list);
|
|
}
|
|
else {
|
|
# A single value
|
|
push(@{$cls->{'values'}}, $t->[0]);
|
|
push(@{$cls->{'valuelines'}}, $t->[1]);
|
|
push(@{$cls->{'valuequotes'}}, $t->[2]);
|
|
push(@{$cls->{'valuequoted'}},
|
|
"e_str($t->[0], $t->[2]));
|
|
$sec->{'eline'} = $cls->{'eline'} = $t->[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
# Expand import: sections
|
|
local @imps = &find("import", \@rv);
|
|
foreach $i (@imps) {
|
|
foreach $c (@{$i->{'cls'}}) {
|
|
next if ($c->{'name'} ne 'any'); # XXX only do 'any::'
|
|
foreach $v (@{$c->{'values'}}) {
|
|
local $fn = $v;
|
|
if ($fn !~ /^\//) {
|
|
# Assume relative to current config file
|
|
$fn = "$config{'cfengine_dir'}/$fn";
|
|
}
|
|
local @inc = &get_config_file($fn);
|
|
map { $_->{'index'} += scalar(@rv) } @inc;
|
|
push(@rv, @inc);
|
|
}
|
|
}
|
|
}
|
|
|
|
return @rv;
|
|
}
|
|
|
|
# find(name, &config)
|
|
sub find
|
|
{
|
|
local ($c, @rv);
|
|
foreach $c (@{$_[1]}) {
|
|
push(@rv, $c) if ($c->{'name'} eq $_[0]);
|
|
}
|
|
return wantarray ? @rv : $rv[0];
|
|
}
|
|
|
|
# find_value(name, &config)
|
|
sub find_value
|
|
{
|
|
local @f = &find($_[0], $_[1]);
|
|
return wantarray ? () : undef if (!@f);
|
|
return wantarray ? @{$f[0]->{'values'}} : $f[0]->{'values'}->[0];
|
|
}
|
|
|
|
# save_directive(&config, &old, &new)
|
|
# Updates or adds an entire class or section to the config file
|
|
sub save_directive
|
|
{
|
|
local $file = $_[1] ? $_[1]->{'file'} : $_[0]->[0]->{'file'};
|
|
local $lref = &read_file_lines($file);
|
|
local @lines = &directive_lines($_[2]) if ($_[2]);
|
|
if ($_[1]) {
|
|
splice(@$lref, $_[1]->{'line'}, $_[1]->{'eline'} - $_[1]->{'line'} + 1,
|
|
@lines);
|
|
}
|
|
else {
|
|
splice(@$lref, $_[0]->[@{$_[0]}-1]->{'eline'}+1, 0, @lines);
|
|
}
|
|
}
|
|
|
|
# swap_directives(&config, &directive1, &directive2)
|
|
# Swaps two directives in the config file
|
|
sub swap_directives
|
|
{
|
|
local $lref = &read_file_lines($_[1]->{'file'});
|
|
local @lines1 = @$lref[$_[1]->{'line'} .. $_[1]->{'eline'}];
|
|
local @lines2 = @$lref[$_[2]->{'line'} .. $_[2]->{'eline'}];
|
|
if ($_[1]->{'line'} < $_[2]->{'line'}) {
|
|
splice(@$lref, $_[2]->{'line'}, scalar(@lines2), @lines1);
|
|
splice(@$lref, $_[1]->{'line'}, scalar(@lines1), @lines2);
|
|
}
|
|
elsif ($_[1]->{'line'} > $_[2]->{'line'}) {
|
|
splice(@$lref, $_[1]->{'line'}, scalar(@lines1), @lines2);
|
|
splice(@$lref, $_[2]->{'line'}, scalar(@lines2), @lines1);
|
|
}
|
|
}
|
|
|
|
# directive_lines(§ion|&class)
|
|
# Returns an array of the lines for some section or class
|
|
sub directive_lines
|
|
{
|
|
local (@rv, $d, $l, $i);
|
|
if ($_[0]->{'type'} eq 'section') {
|
|
push(@rv, "$_[0]->{'name'}:");
|
|
if (defined($_[0]->{'text'})) {
|
|
return (@rv, split(/\n/, $_[0]->{'text'}));
|
|
}
|
|
foreach $c (@{$_[0]->{'cls'}}) {
|
|
push(@rv, &directive_lines($c));
|
|
}
|
|
}
|
|
elsif ($_[0]->{'type'} eq 'class') {
|
|
local $id = $_[0]->{'implied'} ? "\t" : "\t\t";
|
|
push(@rv, "\t$_[0]->{'name'}::") if (!$_[0]->{'implied'});
|
|
if (defined($_[0]->{'text'})) {
|
|
return (@rv, split(/\n/, $_[0]->{'text'}));
|
|
}
|
|
foreach $d (@{$_[0]->{'defs'}}) {
|
|
local @v;
|
|
local $i;
|
|
for($i=0; $i<@{$d->{'values'}}; $i++) {
|
|
push(@v, "e_str($d->{'values'}->[$i],
|
|
$d->{'valuequotes'}->[$i]));
|
|
}
|
|
push(@rv, "$id$d->{'name'} = ( ".join(" ", @v)." )");
|
|
}
|
|
foreach $l (@{$_[0]->{'lists'}}) {
|
|
push(@rv, $id."{");
|
|
push(@rv, &value_lines($l->{'values'}, $l->{'valuelines'},
|
|
$l->{'valuequotes'}, $id));
|
|
push(@rv, $id."}");
|
|
}
|
|
push(@rv, &value_lines($_[0]->{'values'}, $_[0]->{'valuelines'},
|
|
$_[0]->{'valuequotes'}, $id));
|
|
}
|
|
return @rv;
|
|
}
|
|
|
|
# value_lines(&values, &lines, "es, indent)
|
|
sub value_lines
|
|
{
|
|
local @lines;
|
|
local $i;
|
|
for($i=0; $i<@{$_[0]}; $i++) {
|
|
local $l = $_[1]->[$i] -
|
|
$_[1]->[0];
|
|
if ($lines[$l] eq "") {
|
|
$lines[$l] = $_[3];
|
|
}
|
|
else {
|
|
$lines[$l] .= " ";
|
|
}
|
|
$lines[$l] .= "e_str($_[0]->[$i], $_[2]->[$i]);
|
|
}
|
|
return @lines;
|
|
}
|
|
|
|
# quote_str(string, quote)
|
|
sub quote_str
|
|
{
|
|
if (defined($_[1])) {
|
|
return $_[1].$_[0].$_[1];
|
|
}
|
|
elsif ($_[0] =~ /^\S+$/) {
|
|
return $_[0];
|
|
}
|
|
elsif ($_[0] !~ /"/) {
|
|
return "\"$_[0]\"";
|
|
}
|
|
elsif ($_[0] !~ /'/) {
|
|
return "'$_[0]'";
|
|
}
|
|
else {
|
|
return "`$_[0]`";
|
|
}
|
|
}
|
|
|
|
# split_str(string)
|
|
sub split_str
|
|
{
|
|
local (@rv, @qu);
|
|
local $str = $_[0];
|
|
while($str =~ /^\s*(")([^"]*)"(.*)$/s ||
|
|
$str =~ /^\s*(')([^"]*)'(.*)$/s ||
|
|
$str =~ /^\s*(`)([^"]*)`(.*)$/s ||
|
|
$str =~ /^\s*()(\S+)(.*)$/s) {
|
|
push(@qu, $1);
|
|
push(@rv, $2);
|
|
$str = $3;
|
|
}
|
|
return ( \@rv, \@qu );
|
|
}
|
|
|
|
# get_cfrun_hosts()
|
|
sub get_cfrun_hosts
|
|
{
|
|
local (@hosts, %opts);
|
|
open(HOSTS, $cfrun_hosts);
|
|
while(<HOSTS>) {
|
|
s/\r|\n//g;
|
|
s/#.*$//;
|
|
if (/^\s*(\S+)\s*=\s*(.*)/) {
|
|
$opts{$1} = $2;
|
|
}
|
|
elsif (/^\s*(\S+)\s*(.*)/) {
|
|
push(@hosts, [ $1, $2] );
|
|
}
|
|
}
|
|
close(HOSTS);
|
|
return ( \@hosts, \%opts );
|
|
}
|
|
|
|
# save_cfrun_hosts(&hosts, &opts)
|
|
sub save_cfrun_hosts
|
|
{
|
|
open(HOSTS, ">$cfrun_hosts");
|
|
foreach $o (keys %{$_[1]}) {
|
|
print HOSTS $o,"=".$_[1]->{$o},"\n";
|
|
}
|
|
foreach $h (@{$_[0]}) {
|
|
print HOSTS $h->[0]," ",$h->[1],"\n";
|
|
}
|
|
close(HOSTS);
|
|
}
|
|
|
|
# show_classes_table(&config, cfd, readonly)
|
|
sub show_classes_table
|
|
{
|
|
if (@{$_[0]}) {
|
|
&show_button($_[1]) if (!$_[2]);
|
|
print "<table border width=100%>\n";
|
|
print "<tr $tb> ",
|
|
($_[1] ? "" : "<td><b>$text{'index_active'}</b></td>"),
|
|
"<td><b>$text{'index_section'}</b></td> ",
|
|
"<td><b>$text{'index_classes'}</b></td> ",
|
|
"<td><b>$text{'index_details'}</b></td> </tr>\n";
|
|
local $s;
|
|
local %active;
|
|
foreach $s (@{$_[0]}) {
|
|
foreach $c (@{$s->{'cls'}}) {
|
|
if ($s->{'name'} eq 'control') {
|
|
local ($as) = &find("actionsequence",
|
|
$c->{'defs'});
|
|
local $cc = $c->{'name'} eq 'any' ? 2 : 1;
|
|
map { s/\..*$//; $active{$_} = $cc
|
|
if ($cc > $active{$_}) }
|
|
@{$as->{'values'}} if ($as);
|
|
}
|
|
}
|
|
}
|
|
foreach $s (@{$_[0]}) {
|
|
next if ($s->{'name'} =~ /^import/);
|
|
local (@clist, @dlist);
|
|
foreach $c (@{$s->{'cls'}}) {
|
|
push(@clist, $_[2] ? $c->{'name'} : &ui_link("edit_class.cgi?cfd=$_[1]&idx=$s->{'index'}&cidx=$c->{'index'}",$c->{'name'}));
|
|
local $desc;
|
|
if ($s->{'name'} eq 'links') {
|
|
local @l = &parse_links($c);
|
|
if (@l > 1) {
|
|
$desc = &text('index_links2',
|
|
scalar(@l));
|
|
}
|
|
elsif (@l) {
|
|
$desc = &text('index_links',
|
|
"<tt>$l[0]->{'_linkfrom'}</tt>",
|
|
"<tt>$l[0]->{'_linkto'}</tt>");
|
|
}
|
|
}
|
|
elsif ($s->{'name'} eq 'directories' ||
|
|
$s->{'name'} eq 'files' ||
|
|
$s->{'name'} eq 'disable' ||
|
|
$s->{'name'} eq 'shellcommands' ||
|
|
$s->{'name'} eq 'tidy' ||
|
|
$s->{'name'} eq 'required' ||
|
|
$s->{'name'} eq 'disks') {
|
|
local @dirs = &parse_directories($c);
|
|
if (@dirs > 1) {
|
|
$desc = &text('index_'.$s->{'name'}.'2',
|
|
scalar(@dirs));
|
|
}
|
|
elsif (@dirs) {
|
|
$desc = &text('index_'.$s->{'name'},
|
|
"<tt>$dirs[0]->{'_dir'}</tt>");
|
|
}
|
|
}
|
|
elsif ($s->{'name'} eq 'control' && $_[1]) {
|
|
local ($cmd) = &find("cfrunCommand",
|
|
$c->{'defs'});
|
|
if ($cmd) {
|
|
$desc = &text('index_cfrun',
|
|
"<tt>$cmd->{'values'}->[0]</tt>");
|
|
}
|
|
}
|
|
elsif ($s->{'name'} eq 'control' && !$_[1]) {
|
|
local ($as) = &find("actionsequence",
|
|
$c->{'defs'});
|
|
if ($as) {
|
|
local @v = @{$as->{'values'}};
|
|
if (@v > 1) {
|
|
$desc = &text('index_control2',
|
|
scalar(@v));
|
|
}
|
|
else {
|
|
$desc = &text('index_control',
|
|
"<tt>$v[0]</tt>");
|
|
}
|
|
}
|
|
}
|
|
elsif ($s->{'name'} eq 'editfiles') {
|
|
local @files = map { $_->{'values'}->[0] }
|
|
@{$c->{'lists'}};
|
|
if (@files > 1) {
|
|
$desc = &text('index_editfiles2',
|
|
scalar(@files));
|
|
}
|
|
elsif (@files) {
|
|
$desc = &text('index_editfiles',
|
|
"<tt>$files[0]</tt>");
|
|
}
|
|
}
|
|
elsif ($s->{'name'} eq 'grant' ||
|
|
$s->{'name'} eq 'admit' ||
|
|
$s->{'name'} eq 'deny') {
|
|
local @dirs = grep { /\// } @{$c->{'values'}};
|
|
if (@dirs > 1) {
|
|
$desc = &text('index_'.$s->{'name'}.'2',
|
|
scalar(@dirs));
|
|
}
|
|
elsif (@dirs) {
|
|
$desc = &text('index_'.$s->{'name'},
|
|
"<tt>$dirs[0]</tt>");
|
|
}
|
|
}
|
|
elsif ($s->{'name'} eq 'groups' ||
|
|
$s->{'name'} eq 'classes') {
|
|
local @grs = map { $_->{'name'} }
|
|
@{$c->{'defs'}};
|
|
if (@grs) {
|
|
$desc = &text('index_groups',
|
|
join(", ", map { "<tt>$_</tt>" }
|
|
@grs));
|
|
}
|
|
}
|
|
elsif ($s->{'name'} eq 'copy') {
|
|
local @copies = &parse_directories($c);
|
|
if (@copies > 1) {
|
|
$desc = &text('index_copy2',
|
|
scalar(@copies));
|
|
}
|
|
elsif (@copies) {
|
|
$desc = &text('index_copy',
|
|
"<tt>$copies[0]->{'_dir'}</tt>",
|
|
"<tt>$copies[0]->{'dest'}</tt>");
|
|
}
|
|
}
|
|
elsif ($s->{'name'} eq 'ignore') {
|
|
$desc = &text('index_ignore',
|
|
scalar(@{$c->{'values'}}));
|
|
}
|
|
elsif ($s->{'name'} eq "processes") {
|
|
local @procs = grep { !$_->{'_options'} }
|
|
&parse_processes($c);
|
|
if (@procs > 1) {
|
|
$desc = &text('index_procs2',
|
|
scalar(@procs));
|
|
}
|
|
elsif (@procs) {
|
|
$desc = &text('index_procs',
|
|
"<tt>$procs[0]->{'_match'}</tt>");
|
|
}
|
|
}
|
|
elsif ($s->{'name'} eq 'miscmounts') {
|
|
local @mnts = &parse_miscmounts($c);
|
|
if (@mnts > 1) {
|
|
$desc = &text('index_misc2',
|
|
scalar(@mnts));
|
|
}
|
|
elsif (@mnts) {
|
|
$desc = &text('index_misc',
|
|
"<tt>$mnts[0]->{'_src'}</tt>");
|
|
}
|
|
}
|
|
elsif ($s->{'name'} eq 'defaultroute') {
|
|
$desc = &text('index_route',
|
|
"<tt>$c->{'values'}->[0]</tt>");
|
|
}
|
|
$desc = " " if (!$desc);
|
|
push(@dlist, $desc);
|
|
}
|
|
next if (!@clist);
|
|
|
|
local $t = $text{"section_".$s->{'name'}."_".$_[1]};
|
|
$t = $text{"section_".$s->{'name'}} if (!$t);
|
|
print "<tr $cb>\n";
|
|
if (!$_[1]) {
|
|
printf "<td rowspan=%d valign=top>\n", scalar(@clist);
|
|
local $a = $active{$s->{'name'}};
|
|
print $s->{'name'} =~ /^control/ ? "<br>" : $a == 0 ? "<font color=#ff0000>$text{'no'}</font>" : $a == 1 ? "<font color=#333333>$text{'index_maybe'}</font>" : $text{'yes'};
|
|
print "</td>\n";
|
|
}
|
|
printf "<td rowspan=%d valign=top>\n", scalar(@clist);
|
|
print "<table cellpadding=0 cellspacing=0 width=100%><tr>\n";
|
|
print "<td>",$t ? "$t ($s->{'name'})" : $s->{'name'},"</td>\n";
|
|
print "<td align=right>\n";
|
|
#if ($s eq $_[0]->[@{$_[0]}-1]) {
|
|
# print "<img src=images/gap.gif>";
|
|
# }
|
|
#else {
|
|
# print "<a href='down.cgi?cfd=$_[1]&idx=$s->{'index'}'>",
|
|
# "<img src=images/down.gif border=0></a>";
|
|
# }
|
|
#if ($s eq $_[0]->[0]) {
|
|
# print "<img src=images/gap.gif>";
|
|
# }
|
|
#else {
|
|
# print "<a href='up.cgi?cfd=$_[1]&idx=$s->{'index'}'>",
|
|
# "<img src=images/up.gif border=0></a>";
|
|
# }
|
|
if (!$_[2]) {
|
|
print &ui_link("edit_class.cgi?cfd=$_[1]&idx=$s->{'index'}&new=1",$text{'index_cadd'}),"</td>\n";
|
|
}
|
|
print "</tr></table></td>\n";
|
|
|
|
for($i=0; $i<@clist; $i++) {
|
|
print "<tr $cb>\n" if ($i != 0);
|
|
print "<td>$clist[$i]</td>\n";
|
|
print "<td>$dlist[$i]</td>\n";
|
|
print "</tr>\n" if ($i == 0);
|
|
}
|
|
}
|
|
print "</table>\n";
|
|
}
|
|
elsif ($_[1]) {
|
|
print "<p><b>$text{'cfd_none'}</b><p>\n";
|
|
}
|
|
else {
|
|
print "<p><b>$text{'index_none'}</b><p>\n";
|
|
}
|
|
&show_button($_[1]) if (!$_[2]);
|
|
}
|
|
|
|
# show_button(cfd)
|
|
sub show_button
|
|
{
|
|
print "<form action=edit_class.cgi>\n";
|
|
print "<input type=hidden name=cfd value='$_[1]'>\n";
|
|
print "<input type=submit name=new value='$text{'index_add'}'>\n";
|
|
print "<select name=type>\n";
|
|
local $s;
|
|
foreach $s ($_[0] ? @known_cfd_sections : @known_sections) {
|
|
local $tt = $text{"type_".$s."_".$_[0]};
|
|
$tt = $text{"type_".$s} if (!$tt);
|
|
next if (!$tt);
|
|
local $t = $text{"section_".$s."_".$_[0]};
|
|
$t = $text{"section_".$s} if (!$t);
|
|
print "<option value=$s>$t ($s)</option>\n";
|
|
}
|
|
print "</select></form>\n";
|
|
|
|
}
|
|
|
|
# parse_links(&cls)
|
|
sub parse_links
|
|
{
|
|
local (@rv, $v);
|
|
foreach $v (@{$_[0]->{'values'}}) {
|
|
if ($v =~ /^(\S+)=(\S+)$/) {
|
|
if (defined($rv[$#rv]->{$1})) {
|
|
$rv[$#rv]->{$1} .= "\0$2";
|
|
}
|
|
else {
|
|
$rv[$#rv]->{$1} = $2;
|
|
}
|
|
}
|
|
elsif ($v =~ /^[\+\-]>!?$/) {
|
|
$rv[$#rv]->{'_linktype'} = $v;
|
|
}
|
|
else {
|
|
if (!@rv || $rv[$#rv]->{'_linkfrom'} && $rv[$#rv]->{'_linkto'}) {
|
|
push(@rv, { '_linkfrom' => $v } );
|
|
}
|
|
else {
|
|
$rv[$#rv]->{'_linkto'} = $v;
|
|
}
|
|
}
|
|
}
|
|
return @rv;
|
|
}
|
|
# unparse_links(&cls, link, ...)
|
|
sub unparse_links
|
|
{
|
|
local $cls = shift(@_);
|
|
local ($l, $vl = 0, @values, @valuelines);
|
|
foreach $l (@_) {
|
|
push(@values, $l->{'_linkfrom'}, $l->{'_linktype'}, $l->{'_linkto'});
|
|
push(@valuelines, $vl, $vl, $vl);
|
|
foreach $k (keys %$l) {
|
|
if ($k !~ /^_/) {
|
|
local $z;
|
|
foreach $z (split(/\0/, $l->{$k})) {
|
|
push(@values, "$k=$z");
|
|
push(@valuelines, $vl);
|
|
}
|
|
}
|
|
}
|
|
$vl++;
|
|
}
|
|
$cls->{'values'} = \@values;
|
|
$cls->{'valuelines'} = \@valuelines;
|
|
$cls->{'valuequotes'} = [ ];
|
|
}
|
|
|
|
# parse_directories(&cls)
|
|
sub parse_directories
|
|
{
|
|
local (@rv, $v);
|
|
foreach $v (@{$_[0]->{'values'}}) {
|
|
if ($v =~ /^(\S+)=(\S+)$/) {
|
|
if (defined($rv[$#rv]->{$1})) {
|
|
$rv[$#rv]->{$1} .= "\0$2";
|
|
}
|
|
else {
|
|
$rv[$#rv]->{$1} = $2;
|
|
}
|
|
}
|
|
else {
|
|
push(@rv, { '_dir' => $v } );
|
|
}
|
|
}
|
|
return @rv;
|
|
}
|
|
|
|
# unparse_directories(&cls, dir, ...)
|
|
sub unparse_directories
|
|
{
|
|
local $cls = shift(@_);
|
|
local ($d, $vl = 0, @values, @valuelines);
|
|
foreach $d (@_) {
|
|
push(@values, $d->{'_dir'});
|
|
push(@valuelines, $vl);
|
|
foreach $k (keys %$d) {
|
|
if ($k !~ /^_/) {
|
|
local $z;
|
|
foreach $z (split(/\0/, $d->{$k})) {
|
|
push(@values, "$k=$z");
|
|
push(@valuelines, $vl);
|
|
}
|
|
}
|
|
}
|
|
$vl++;
|
|
}
|
|
$cls->{'values'} = \@values;
|
|
$cls->{'valuelines'} = \@valuelines;
|
|
$cls->{'valuequotes'} = [ ];
|
|
return @rv;
|
|
}
|
|
|
|
# parse_processes(&cls, &optionstr)
|
|
sub parse_processes
|
|
{
|
|
local (@rv, $v, $i);
|
|
for($i=0; $i<@{$_[0]->{'values'}}; $i++) {
|
|
$v = $_[0]->{'values'}->[$i];
|
|
if ($v =~ /^(\S+)=(\S+)$/) {
|
|
if (defined($rv[$#rv]->{$1})) {
|
|
$rv[$#rv]->{$1} .= "\0$2";
|
|
}
|
|
else {
|
|
$rv[$#rv]->{$1} = $2;
|
|
}
|
|
}
|
|
elsif ($v eq "restart") {
|
|
$rv[$#rv]->{'_restart'} = $_[0]->{'values'}->[++$i];
|
|
}
|
|
elsif ($v eq "SetOptionString") {
|
|
push(@rv, { '_options' => $_[0]->{'values'}->[++$i] } );
|
|
}
|
|
else {
|
|
push(@rv, { '_match' => $v } );
|
|
}
|
|
}
|
|
return @rv;
|
|
}
|
|
|
|
# unparse_processes(&cls, match, ...)
|
|
sub unparse_processes
|
|
{
|
|
local $cls = shift(@_);
|
|
local ($d, $vl = 0, @values, @valuelines, @valuequotes);
|
|
foreach $d (@_) {
|
|
if ($d->{'_options'}) {
|
|
push(@values, "SetOptionString", $d->{'_options'});
|
|
push(@valuelines, $vl, $vl);
|
|
push(@valuequotes, "", '"');
|
|
}
|
|
else {
|
|
push(@values, $d->{'_match'});
|
|
push(@valuelines, $vl);
|
|
push(@valuequotes, '"');
|
|
foreach $k (keys %$d) {
|
|
if ($k !~ /^_/) {
|
|
local $z;
|
|
foreach $z (split(/\0/, $d->{$k})) {
|
|
push(@values, "$k=$z");
|
|
push(@valuelines, $vl);
|
|
push(@valuequotes, "");
|
|
}
|
|
}
|
|
}
|
|
if ($d->{'_restart'}) {
|
|
push(@values, "restart", $d->{'_restart'});
|
|
push(@valuelines, $vl, $vl);
|
|
push(@valuequotes, "", '"');
|
|
}
|
|
}
|
|
$vl++;
|
|
}
|
|
$cls->{'values'} = \@values;
|
|
$cls->{'valuelines'} = \@valuelines;
|
|
$cls->{'valuequotes'} = \@valuequotes;
|
|
return @rv;
|
|
}
|
|
|
|
# unparse_shellcommands(&cls, dir, ...)
|
|
sub unparse_shellcommands
|
|
{
|
|
local $cls = shift(@_);
|
|
local ($d, $vl = 0, @values, @valuelines, @valuequotes);
|
|
foreach $d (@_) {
|
|
push(@values, $d->{'_dir'});
|
|
push(@valuelines, $vl);
|
|
push(@valuequotes, $d->{'_dir'} !~ /"/ ? '"' :
|
|
$d->{'_dir'} !~ /'/ ? "'" : "`");
|
|
foreach $k (keys %$d) {
|
|
if ($k !~ /^_/) {
|
|
local $z;
|
|
foreach $z (split(/\0/, $d->{$k})) {
|
|
push(@values, "$k=$z");
|
|
push(@valuelines, $vl);
|
|
push(@valuequotes, undef);
|
|
}
|
|
}
|
|
}
|
|
$vl++;
|
|
}
|
|
$cls->{'values'} = \@values;
|
|
$cls->{'valuelines'} = \@valuelines;
|
|
$cls->{'valuequotes'} = \@valuequotes;
|
|
return @rv;
|
|
}
|
|
|
|
# parse_miscmounts(&cls)
|
|
sub parse_miscmounts
|
|
{
|
|
local (@rv, $v);
|
|
foreach $v (@{$_[0]->{'values'}}) {
|
|
if ($v =~ /^(\S+)=(\S+)$/) {
|
|
if (defined($rv[$#rv]->{$1})) {
|
|
$rv[$#rv]->{$1} .= "\0$2";
|
|
}
|
|
else {
|
|
$rv[$#rv]->{$1} = $2;
|
|
}
|
|
}
|
|
elsif ($v !~ /\//) {
|
|
$rv[$#rv]->{'mode'} = $v;
|
|
}
|
|
else {
|
|
if (@rv && $rv[$#rv]->{'_src'} && !$rv[$#rv]->{'_dest'}) {
|
|
$rv[$#rv]->{'_dest'} = $v;
|
|
}
|
|
else {
|
|
push(@rv, { '_src' => $v } );
|
|
}
|
|
}
|
|
}
|
|
return @rv;
|
|
}
|
|
|
|
# unparse_miscmounts(&cls, dir, ...)
|
|
sub unparse_miscmounts
|
|
{
|
|
local $cls = shift(@_);
|
|
local ($d, $vl = 0, @values, @valuelines);
|
|
foreach $d (@_) {
|
|
push(@values, $d->{'_src'}, $d->{'_dest'});
|
|
push(@valuelines, $vl, $vl);
|
|
foreach $k (keys %$d) {
|
|
if ($k !~ /^_/) {
|
|
local $z;
|
|
foreach $z (split(/\0/, $d->{$k})) {
|
|
push(@values, "$k=$z");
|
|
push(@valuelines, $vl);
|
|
}
|
|
}
|
|
}
|
|
$vl++;
|
|
}
|
|
$cls->{'values'} = \@values;
|
|
$cls->{'valuelines'} = \@valuelines;
|
|
$cls->{'valuequotes'} = [ ];
|
|
return @rv;
|
|
}
|
|
|
|
# list_cfengine_hosts()
|
|
# Returns a list of all webmin hosts running cfengine known to this module
|
|
sub list_cfengine_hosts
|
|
{
|
|
local (@rv, $f);
|
|
local $hdir = "$module_config_directory/hosts";
|
|
opendir(DIR, $hdir);
|
|
foreach $f (readdir(DIR)) {
|
|
if ($f =~ /^(\S+)\.host$/) {
|
|
local %host = ( 'id', $1 );
|
|
&read_file("$hdir/$f", \%host);
|
|
push(@rv, \%host);
|
|
}
|
|
}
|
|
closedir(DIR);
|
|
return @rv;
|
|
}
|
|
|
|
# list_servers()
|
|
# Returns a list of all servers from the webmin servers module that can be
|
|
# managed, plus this server
|
|
sub list_servers
|
|
{
|
|
local @servers = &foreign_call("servers", "list_servers");
|
|
return ( { 'id' => 0, 'desc' => $text{'this_server'}, 'type' => 'unknown' },
|
|
grep { $_->{'user'} } @servers );
|
|
}
|
|
|
|
# server_name(&server)
|
|
sub server_name
|
|
{
|
|
return $_[0]->{'desc'} ? $_[0]->{'desc'} : $_[0]->{'host'};
|
|
}
|
|
|
|
# save_cfengine_host(&host)
|
|
# Add or update a managed host
|
|
sub save_cfengine_host
|
|
{
|
|
local $hdir = "$module_config_directory/hosts";
|
|
mkdir($hdir, 0700);
|
|
&write_file("$hdir/$_[0]->{'id'}.host", $_[0]);
|
|
}
|
|
|
|
# delete_cfengine_host(&host)
|
|
sub delete_cfengine_host
|
|
{
|
|
unlink("$module_config_directory/hosts/$_[0]->{'id'}.host");
|
|
}
|
|
|
|
# cfengine_host_version(&server)
|
|
sub cfengine_host_version
|
|
{
|
|
local $out = &remote_eval($_[0]->{'host'}, "cfengine", '`$config{"cfengine"} -V 2>&1`');
|
|
return $out =~ /cfengine-(\S+)/ || $out =~ /GNU\s+(\S+)/ ? $1 : undef;
|
|
}
|
|
|
|
# show_run_form()
|
|
sub show_run_form
|
|
{
|
|
print "<tr> <td><b>$text{'run_dry'}</b></td>\n";
|
|
print "<td><input type=radio name=dry value=1> $text{'yes'}\n";
|
|
print "<td><input type=radio name=dry value=0 checked> $text{'no'}</td>\n";
|
|
|
|
print "<td><b>$text{'run_noifc'}</b></td>\n";
|
|
print "<td><input type=radio name=noifc value=0 checked> $text{'yes'}\n";
|
|
print "<td><input type=radio name=noifc value=1> $text{'no'}</td> </tr>\n";
|
|
|
|
print "<tr> <td><b>$text{'run_nomnt'}</b></td>\n";
|
|
print "<td><input type=radio name=nomnt value=0 checked> $text{'yes'}\n";
|
|
print "<td><input type=radio name=nomnt value=1> $text{'no'}</td>\n";
|
|
|
|
print "<td><b>$text{'run_nocmd'}</b></td>\n";
|
|
print "<td><input type=radio name=nocmd value=0 checked> $text{'yes'}\n";
|
|
print "<td><input type=radio name=nocmd value=1> $text{'no'}</td> </tr>\n";
|
|
|
|
print "<tr> <td><b>$text{'run_notidy'}</b></td>\n";
|
|
print "<td><input type=radio name=notidy value=0 checked> $text{'yes'}\n";
|
|
print "<td><input type=radio name=notidy value=1> $text{'no'}</td>\n";
|
|
|
|
print "<td><b>$text{'run_nolinks'}</b></td>\n";
|
|
print "<td><input type=radio name=nolinks value=0 checked> $text{'yes'}\n";
|
|
print "<td><input type=radio name=nolinks value=1> $text{'no'}</td> </tr>\n";
|
|
|
|
print "<tr> <td><b>$text{'run_verbose'}</b></td>\n";
|
|
print "<td><input type=radio name=verbose value=1 checked> $text{'yes'}\n";
|
|
print "<td><input type=radio name=verbose value=0> $text{'no'}</td>\n";
|
|
}
|
|
|
|
# get_cfengine_version(&dummy)
|
|
sub get_cfengine_version
|
|
{
|
|
local $out = `$config{'cfengine'} -V 2>&1`;
|
|
${$_[0]} = $out;
|
|
return $out =~ /cfengine-(\S+)/ || $out =~ /GNU\s+(\S+)/ ? $1 : undef;
|
|
}
|
|
|
|
1;
|
|
|