ACC SHELL
Path : /usr/lib/YaST2/bin/ |
|
Current File : //usr/lib/YaST2/bin/parse_configs.pl |
#!/usr/bin/perl -w
#
# File:
# parse_configs.pl
#
# Module:
# Sysconfig editor
#
# Authors:
# Ladislav Slezak <lslezak@suse.cz>
#
# Description:
# This script parses configuration files and generates YCP list
# with values:
# - list of items for tree widget
# - map with node descriptions
#
# This script is used by YaST2 sysconfig editor to speedup
# module start.
#
# $Id: parse_configs.pl 33337 2006-10-12 08:29:28Z lslezak $
#
# used modules:
# module for wild card file name expansion
use File::Glob ':glob';
use ycp;
use strict;
# global variable - normal or powertweak mode flag
# used at tree widget content generation as opened/closed flag
my $powertweak_mode = "false";
# convert list of variable identifications to list of items
# required by Yast2 Tree widget
sub ids_to_item($$)
{
my ($string, $location) = @_;
my $result = "";
my @list = split(/,/, $string);
# sort list of IDs
#@list = sort(@list); # should be sorted from yast2
my $first = 1;
for my $var (@list) {
my $varname = $var;
if ($varname =~ /(.*)\$.*/)
{
$varname = $1;
}
if ($first == 0)
{
$result .= ", ";
}
else
{
$first = 0;
}
$result .= "`item(`id(\"$var\"), \"$varname\", $powertweak_mode)";
}
return $result;
}
sub convert(@);
# recursively create Tree widget content
# paramter: list which contains pairs (location string, variables id string),
# last item in the list is prefix of all variables
sub convert(@)
{
my (@list) = @_;
my $node = pop(@list);
my $size = @list;
my $index = 0;
my $current_prefix = "";
# array used for recursive converting
my @recurse = ();
my $result = "";
my $first = 1;
while ($index < $size)
{
my $location = $list[$index++];
my $id = $list[$index++];
# location is empty - stop recursion and return list of leaf-node items
if ($location eq "")
{
if ($first != 1)
{
$result .= ", ";
}
else
{
$first = 0;
}
$result .= ids_to_item($id, $node);
}
else
{
# get prefix of current location
my $prefix = $location;
my $postfix = "";
# split location to prefix and remaining part
if ($prefix =~ /(.*?[^\\])\/(.*)/)
{
$prefix = $1;
$postfix = $2;
}
# at start is current prefix empty
if ($current_prefix eq "")
{
$current_prefix = $prefix;
}
# if prefix is same as previous one just push remaining part of path and variable id to list
if ($prefix eq $current_prefix)
{
push(@recurse, $postfix);
push(@recurse, $id);
}
else
{
# if prefix is different we collected all variables with same prefix
# proces it recursively
my $new_node = ($node eq "") ? $current_prefix : $node.'/'.$current_prefix;
push(@recurse, $new_node);
my $x = convert(@recurse);
if ($first != 1)
{
$result .= ", ";
}
else
{
$first = 0;
}
$result .= "`item(`id(\"$new_node\"), \"$current_prefix\", $powertweak_mode, [ $x ])";
# store new prefix and new id
$current_prefix = $prefix;
@recurse = ();
push(@recurse, $postfix);
push(@recurse, $id);
}
}
}
# recursively process remaining values
if (@recurse > 0)
{
my $new_node = ($node eq "") ? $current_prefix : $node.'/'.$current_prefix;
push(@recurse, $new_node);
my $x = convert(@recurse);
if ($first != 1)
{
$result .= ", ";
}
$result .= "`item(`id(\"$new_node\"), \"$current_prefix\", $powertweak_mode, [ $x ])";
}
return $result;
}
sub flip_hash(%)
{
my %input = @_;
my %ret;
for my $location (keys(%input))
{
my $var = $input{$location};
my @vars = split(',', $var);
for my $v (@vars)
{
$ret{$v} = $location;
}
}
return %ret;
}
# convert perl hash to YCP map (in string form)
sub hash_to_map(%)
{
my (%desc) = @_;
my $first = 1;
my $result = '$[ ';
# each hash pair convert to string
for my $path (keys(%desc))
{
if ($first != 1)
{
$result .= ', ';
}
else
{
$first = 0;
}
my $description = $desc{$path};
if (defined($description))
{
$description =~ s/([^\\])"/$1\\"/g;
}
# escape double quote characters
my $n = 1;
while($n)
{
$n = $path =~ s/([^\\])"/$1\\"/go;
}
# output nil if value is undefined
$result .= (defined($description)) ? "\"$path\" : \"$description\"" : "\"$path\" : nil";
}
$result .= ' ]';
return $result;
}
# remove variable identification from string
sub remove_variable($$)
{
my ($string, $var) = @_;
my $result = "";
my @list = split(/,/, $string);
for my $v (@list)
{
if ($v ne $var)
{
if (length($result) > 0)
{
$result .= ",";
}
$result .= $v;
}
}
return $result;
}
# read multiline tag from sysconfig file
sub ReadMulti()
{
my $ret = "\\";
while ($ret =~ /(.*)\\$/)
{
# remove trailing backslash
$ret = $1;
my $line = <CONFIGFILE>;
# break cycle when EOF is reached
if (!defined($line))
{
last;
}
if ($line =~ /^##(.*)/)
{
$line = $1;
}
chomp($line);
$ret .= $line;
}
return $ret;
}
# list of files to process
my @list = ();
# collect all files
for my $arg (@ARGV)
{
if ($arg eq "--powertweak")
{
$powertweak_mode = "true";
}
else
{
my @files = bsd_glob($arg);
# ignore *.bak, *~ files
my @source_files = ();
for my $f (@files)
{
if (!($f =~ /\.bak$/) && !($f =~ /~$/))
{
push(@source_files, $f);
}
else
{
y2milestone("Ignoring backup file $f");
}
}
# merge lists
@list = (@list, @source_files);
}
}
# hash: key = location, value = string containig variables identifications
my %locations = ();
# hash: key = location, value = node description (string)
my %descriptions = ();
# report redefined variables
my %redefined_vars = ();
# actions started when variable is changed: key = variableID,
# value = hash 'Config','ServiceRestart', 'ServiceReload','Command' =>
my %actions = ();
# collect pairs (location, variables definition) from all configuration files
for my $fname (@list)
{
my $stat = open(CONFIGFILE, $fname);
if (!defined $stat)
{
print STDERR "Cannot open file $fname\n";
next;
}
my $location = "Other".$fname;
my $description = "";
my $Config = undef;
my $ServiceRestart = undef;
my $ServiceReload = undef;
my $Command = undef;
my $PreSaveCommand = undef;
my $Meta_found = 0;
# hack for /etc/sysconfig/network/ifcfg-* files
if ($fname =~ '^/etc/sysconfig/network/ifcfg-(.*)')
{
$location = "Hardware/Network/$1";
$descriptions{$location} = "Configuration of network device $1";
}
# remember all variables from config file
# used for redefinition check
my %found_vars = ();
while(my $line = <CONFIGFILE>)
{
chomp($line);
# path metadata definition
if ($line =~ /^##\s*Path\s*:\s*((\s*\S+)*)\s*$/)
{
$location = $1;
# read multiline metadata
if ($location =~ /(.*)\\$/)
{
# Read multiline metadata value
$location .= ReadMulti();
}
}
elsif ($line =~ /^##\s*Description\s*:\s*((\s*\S+)*)\s*$/)
{
my $descr = $1;
# read multiline metadata
if ($descr =~ /(.*)\\$/)
{
# Read multiline metadata value
$descr .= ReadMulti();
}
$descriptions{$location} = $descr;
}
# variable definition
elsif ($line =~ /^\s*([-\w\/:]*)\s*=.*/)
{
if (defined($found_vars{$1}))
{
# add to redefined vars
$redefined_vars{$1.'$'.$fname} = 1;
# variable was already found
# remove it from previous location
my $prev_location = $found_vars{$1};
my $new_val = remove_variable($locations{$prev_location}, $1.'$'.$fname);
if ($new_val eq "")
{
# remove location if it is empty
delete($locations{$prev_location});
}
else
{
# update location
$locations{$prev_location} = $new_val;
}
}
my $existing_vars = $locations{$location};
if (defined($existing_vars))
{
$existing_vars .= ",";
}
$existing_vars .= $1.'$'.$fname;
$locations{$location} = $existing_vars;
# remember location of variable
$found_vars{$1} = $location;
# reset metadata flag for the next variable
$Meta_found = 0;
# add action commands to the variable if they are defined
my %tmp = ();
if (defined($Config))
{
$tmp{'Cfg'} = $Config;
}
if (defined($ServiceReload))
{
$tmp{'Reld'} = $ServiceReload;
}
if (defined($ServiceRestart))
{
$tmp{'Rest'} = $ServiceRestart;
}
if (defined($Command))
{
$tmp{'Cmd'} = $Command;
}
if (defined($PreSaveCommand))
{
$tmp{'Pre'} = $PreSaveCommand;
}
$actions{$1.'$'.$fname} = \%tmp;
# check whether single quotes are used,
# values in single quotes won't be escaped by yast
if ($line =~ /^\s*([-\w\/:]*)\s*=\s*'.*'/)
{
$tmp{'SingleQt'} = 1;
}
}
# SuSEconfig script specification
elsif ($line =~ /^##\s*Config\s*:\s*((\s*\S+)*)\s*$/)
{
if ($Meta_found == 0)
{
# reset all other action tag values
$ServiceReload = $ServiceRestart = $Command = $PreSaveCommand = undef;
}
$Config = $1;
# read multiline metadata
if ($Config =~ /(.*)\\$/)
{
# Read multiline metadata value
$Config .= ReadMulti();
}
if ($Config eq '""')
{
$Config = '';
}
$Meta_found = 1;
}
# services to restart
elsif ($line =~ /^##\s*ServiceRestart\s*:\s*((\s*\S+)*)\s*$/)
{
if ($Meta_found == 0)
{
# reset all other action tag values
$ServiceReload = $Config = $Command = $PreSaveCommand = undef;
}
$ServiceRestart = $1;
# read multiline metadata
if ($ServiceRestart =~ /(.*)\\$/)
{
# Read multiline metadata value
$ServiceRestart .= ReadMulti();
}
if ($ServiceRestart eq '""')
{
$ServiceRestart = '';
}
$Meta_found = 1;
}
# services to reload
elsif ($line =~ /^##\s*ServiceReload\s*:\s*((\s*\S+)*)\s*$/)
{
if ($Meta_found == 0)
{
# reset all other action tag values
$ServiceRestart = $Config = $Command = $PreSaveCommand = undef;
}
$ServiceReload = $1;
# read multiline metadata
if ($ServiceReload =~ /(.*)\\$/)
{
# Read multiline metadata value
$ServiceReload .= ReadMulti();
}
if ($ServiceReload eq '""')
{
$ServiceReload = '';
}
$Meta_found = 1;
}
# generic command
elsif ($line =~ /^##\s*Command\s*:\s*((\s*\S+)*)\s*$/)
{
if ($Meta_found == 0)
{
# reset all other action tag values
$ServiceRestart = $Config = $ServiceReload = $PreSaveCommand = undef;
}
$Command = $1;
# read multiline metadata
if ($Command =~ /(.*)\\$/)
{
# Read multiline metadata value
$Command .= ReadMulti();
}
if ($Command eq '""')
{
$Command = '';
}
$Meta_found = 1;
}
# generic command started before changed variable is saved
elsif ($line =~ /^##\s*PreSaveCommand\s*:\s*((\s*\S+)*)\s*$/)
{
if ($Meta_found == 0)
{
# reset all other action tag values
$ServiceRestart = $Config = $Command = $ServiceReload = undef;
}
$PreSaveCommand = $1;
# read multiline metadata
if ($PreSaveCommand =~ /(.*)\\$/)
{
# Read multiline metadata value
$PreSaveCommand .= ReadMulti();
}
if ($PreSaveCommand eq '""')
{
$PreSaveCommand = '';
}
$Meta_found = 1;
}
# other lines (comments, empty lines) are ignored
}
close(CONFIGFILE);
}
# create sorted list of locations
my @sorted_locations = sort(keys(%locations));
my @rec = ();
for my $loc (@sorted_locations)
{
push(@rec, $loc);
push(@rec, $locations{$loc});
}
# initialize to empty prefix
push (@rec, "");
# start conversion
print "[\n";
print '['.convert(@rec)."],\n";
print hash_to_map(%descriptions).",\n";
print hash_to_map(flip_hash(%locations)).",\n";
print hash_to_map(%redefined_vars).",\n";
# print action commands for each variable
print "\$[\n";
my @keys = keys(%actions);
for my $var (@keys)
{
print "\"$var\" : ".hash_to_map(%{$actions{$var}}).",\n";
}
print "]\n";
print "]\n";
ACC SHELL 2018