#!/usr/local/bin/perl #-*- perl -*- # # Copyright (C) 1993-1998 Ken'ichi Fukamachi # All rights reserved. # 1993-1996 fukachan@phys.titech.ac.jp # 1996-1998 fukachan@sapporo.iij.ad.jp # # FML is free software; you can redistribute it and/or modify # it under the terms of GNU General Public License. # See the file COPYING for more details. # # $Id: config,v 2.10 2003/01/15 16:00:52 fukachan Exp $ # Init; $ERROR_LOG = "etc/motd.error"; unlink $ERROR_LOG if -f $ERROR_LOG; require 'getopts.pl'; &Getopts("m:hdDr:csnfrFiI:v"); $no_dns = $opt_n; $debug = $opt_d; $debug2 = $opt_D; $compat = $opt_c; $reverse = $opt_r; $install = $opt_i; $verbose = $rv'verbose = 1 if $opt_v; #'; $file_substitute = $opt_F; ############################################################################# $HEADER = q%# -*-Perl-*- # # FML Configuration File # # Copyright (C) 1993-2000 Ken'ichi Fukamachi # All rights reserved. # 1993-1996 fukachan@phys.titech.ac.jp # 1996-2000 fukachan@sapporo.iij.ad.jp # # FML is free software; you can redistribute it and/or modify # it under the terms of GNU General Public License. # See the file COPYING for more details. # %; &SetDefaults($opt_m); &SetIgnoredFields; if ($opt_r) { &reverse($opt_r); } elsif ($opt_c) { &SetIgnoredFields_Compat($opt_I); &compat_output; } elsif ($opt_s) { &show_entry; } elsif ($opt_f) { &FixEnv; } else { &readfile(@ARGV) unless $install; &output; } exit 0; ######################################################################## sub SetIgnoredFields { @Ignore = (PORT,TAR,UUENCODE,COMPRESS,ZCAT,HOST,LHA,ISH, 'MAIL_LIST', ML_FN, MAINTAINER, XML, 'PRECEDENCE', 'PROC_GEN'); for (@Ignore) { $skip_key .= $skip_key ? "|$_" : $_; } } sub SetIgnoredFields_Compat { local($file) = @_; local(@ignore); ($file && -f $file) || (die "cannot open $file\n"); if (open(F, $file)) { while () { chop; next if /^\s*$/; push(@ignore, $_); } close(F); } else { @ignore = (ML_MEMBER_CHECK,AUTO_REGISTERED_UNDELIVER_P, ERRORS_TO,REJECT_ADDR,SKIP_FIELDS,SENDMAIL, COMMAND_SYNTAX_EXTENSION,COMMAND_CHECK_LIMIT, GUIDE_CHECK_LIMIT,PROHIBIT_COMMAND_FOR_STRANGER, NEWSYSLOG_MAX,WHOIS_JCODE_P,CRON_NOTIFY, REMOTE_ADMINISTRATION_REQUIRE_PASSWORD); } for (@ignore) { $skip_key .= $skip_key ? "|$_" : $_;} } sub readfile { local($file) = @_; local(@local_order); ($file && open(F, $file)) || die "cannot open $file"; while () { /^LOCAL_CONFIG/ && ($local_config = 1) && next; if ($local_config) { $LOCAL .= $_; } else { next if /^\#/o; # skip "^# line" outside the LOCAL_... s/^\$//; # strip '$' of "$VARIABLE" if (/(\S+)\s+(.*)/) { # VARIABLE VALUE local($key, $str) = ($1, $2); $key =~ s/:$//; push(@local_order, $key); # SPECIAL FUNCTIONS if ($str =~ /^&path\((\S+)\)(.*)/) { local($opt) = $2; eval("\$str = &search_path($1);"); $str = "$str$opt"; } $str =~ s/@/\\@/g; while ($str =~ s/\\\\@/\\@/g) { 1;} # special handling of timezone if ($key eq 'TZone' || $key eq 'TZONE_DST' || $key eq 'BRACKET') { $str = "\"$str\""; # enforce "string" sytanx. } else { $str = ($str =~ /^(\-\d+|\d+)$/) ? $str : "\"$str\""; } # print STDERR # "Overwrite $key as $str\n\t(original $value{$key})\n"; $value{$key} = $str; $rewritten{$key} = 1; } } } close(F); # RESET if ($file_substitute) { @order = @local_order;} @CFDefiend = @local_order; } sub show_entry { for $k (sort keys %value) { next if $k =~ /^INFO:/; next if $k =~ /^LOCAL_/; printf "%-30s\t%s\n", $k, $value{$k}; printf "%s\n\n", $comment{$k}; } $k = "LOCAL_CONFIG"; printf "%-30s\n%s\n", $k, $value{$k}; } sub compat_output { print $HEADER; foreach $key (@order) { next if $key eq 'debug'; if ($value{$key} eq "\"\"" || $value{$key} eq "''" || $value{$key} eq "0") { next ; } if ($key eq 'LOCAL_CONFIG') { print "\n\#\#\#LOCAL_CONFIG\n"; print $value{"LOCAL_CONFIG"}; } elsif ($key !~ /^INFO:/ && (! ($value{$key} eq "0" || $value{$key} eq "\"\"")) ) { # non-nil variables next if $key =~ /$skip_key/; printf "%-20s || (%s = %s);\n", "\$$key", "\$$key", $value{$key}; } } print "\n1;\n"; } sub output { local($cf); # comment out flag; print $HEADER; foreach $key (@order) { #print STDERR "key\t$key => $value{$key}\n"; undef $cf; undef $ncr; undef $comment; next if $key eq "_SKIP_LINE_" && $prev_key eq "_SKIP_LINE_"; $prev_key = $key; if ($key eq "_SKIP_LINE_") { print "\n"; next; } # here may be overwritten! # patched by racsho@cpdc.canon.co.jp (96/11/14) if (!$install && !$rewritten{$key}) { $cf = '# '; } # dependent on keys in "cf" if (($key ne 'LOCAL_CONFIG') && (! $rewritten{$key})) { local($xkey); for $xkey (@CFDefiend) { next if $xkey =~ /^_/; next if $xkey =~ /^LOCAL_CONFIG/; if ($value{$key} =~ /\$${xkey}/) { printf STDERR " %-25s depends %s\n", $key, $xkey if $debug; undef $cf; } } } #print STDERR "[$cf]$key\t$value{$key}\n"; if ($key =~ /^INFO:/) { print "\n\n\n";} if ($_ = $comment{$key}) { $ncr = tr/\n/\n/; $add_n++;} if ($ncr <= 1) { $s = sprintf("%-30s = %s; %s\n", "${cf}\$${key}", $value{$key}, $_); $s = length($s); if ($s < 80) { $comment = "$_"; undef $add_n;} } if ($_ && (! $comment)) { # add \n? # $_ .= "\n"; # while (s/\n\n$/\n/) {;} print $_; ## print "\n"; # null line after the comments } if ($key eq "LOCAL_CONFIG") { print "\n"; print ('#' x 70); print "\n"; print "\# \#\#\# Section: LOCAL CONFIG \#\#\#\n"; print $value{$key}; print "\n"; } elsif ($key !~ /^INFO:/) { # printf "%-30s = %s;", "\$$key", $value{$key}; printf "%-30s = %s;", "${cf}\$$key", $value{$key}; print " $comment" if $comment; print "\n"; # print "\n" if $add_n; # cf version 3; not add "\n"; } } ##### LOCAL CONFIG ##### if ($LOCAL) { print "\n\n\n"; print ('#' x 35); print "\n"; print "\#\ LOCAL CONFIG YOU CONFIGURED\n"; # print ('#' x 35); print "\n"; print $LOCAL; } print "\n1;\n"; # fml-support: 04205; Masayuki FUKUI return if $file_substitute; for (keys %value) { print STDERR "WARNING: $ARGV[0]: invalid keyword \`$_\' (ignored)\n" unless $OrderHash{$_}; } } sub DNS { if ($no_dns) { print STDERR "No DNS Reconfigure\n"; $FQDN = 'aoi.domain.uja'; $DOMAINNAME = 'domain.uja'; return; } # fml 4.0 local($system) = $0; $system =~ s/config$//; $system .= ($ENV{'OS'} =~ /Windows_NT/) ? "..\\_fml\\" : "../.fml/"; $system .= 'system'; if (-f $system) { print STDERR "use system = $system\n" if $debug0; package __system; eval require $main::system; $main::HOSTNAME = $main::FQDN = $FQDN; $main::DOMAINNAME = $DOMAIN; package main; if ($@) { print STDERR $@; } else { return ; } } print STDERR "Verifying DNS...\n" if $debug; local(@n, $hostname, $list); chop($hostname = `hostname`); # beth or beth.domain may be possible $HOSTNAME = $FQDN = $hostname; @n = (gethostbyname($hostname))[0,1]; $list .= " @n "; @n = split(/\./, $hostname); $hostname = $n[0]; # beth.domain -> beth @n = (gethostbyname($hostname))[0,1]; $list .= " @n "; foreach (split(/\s+/, $list)) { /^$hostname\.\w+/ && ($FQDN = $_);} $FQDN =~ s/\.$//; # for e.g. NWS3865 $DOMAINNAME = $FQDN; $DOMAINNAME =~ s/^$hostname\.//; printf STDERR "%-10s %s\n", "HOSTNAME", $HOSTNAME if $debug; printf STDERR "%-10s %s\n", "DOMAINNAME", $DOMAINNAME if $debug; printf STDERR "%-10s %s\n", "FQDN", $FQDN if $debug; } sub host { $HOSTNAME;} sub dn { $DOMAINNAME;} sub fqdn { $FQDN;} sub SetDefaults { local($file) = @_; local($key, $local_config); foreach ($file, './cf/MANIFEST', './MANIFEST') { -f $_ && ($file = $_, last); } open(MANIFEST, $file) || die "CANNOT OPEN MANIFEST[$file]\n"; select(MANIFEST); $| = 1; select(STDOUT); print STDERR "MANIFEST: $file\n\n" if $debug2; &DNS; while () { next if /^\#C\s+/i; if (/MANIFEST,v ([\d\.]+) /) { $Manifest_Version = $1; } if (/\# \#\#\# Section:\s*(.*)\s*\#\#\#\s*$/) { $Index .= "\# $1\n"; } if (/^\s*$/) { undef $comment_key; push(@order, "_SKIP_LINE_"); } undef $local_config if /^(INFO|FML_CONFIG|LOCAL_CONFIG):/; if (/^LOCAL_CONFIG/) { $local_config = 1; push(@order, "LOCAL_CONFIG"); next; } if ($local_config) { $value{"LOCAL_CONFIG"} .= $_; next; } elsif (/^(\S+):\s*(.*)/) { # VARIABLE NAME: DEFAULT VALUE $key = $1; $str = $2; $attach++; # keyword print STDERR "define \$comment_key = $key;\n" if $verbose; $comment_key = $key; if ($str =~ /^&path\((\S+)\)(.*)/) { $str = &search_path($1); $FixError{$key} = 1 unless $str; $str = $str . $2; printf STDERR "%-10s %s\n", $key, $str if $opt_d; $FixPath{$key} = $str; } if ($str =~ /^&fix:(\S+)\s+(\S+)/) { $f = $1; $str = $org = $2; $str = &$f($str); local($fqdn, $dn, $hostname) = &CheckDNS; $FixDNS{'FQDN'} = $fqdn; $FixDNS{'DOMAINNAME'}= $dn; $FixError{$key} = 1 unless $str; } if ($str =~ /^&is_unix/) { $str = ($ENV{'OS'} =~ /Windows_NT/) ? 0 : 1; } if ($key eq 'INFO') { $INFO++; $key = "INFO:$INFO"; } push(@order, $key); $str =~ s/@/\\@/g; while ($str =~ s/\\\\@/\\@/g) { 1;} $value{$key} = ($str =~ /^\d+$/) ? $str : "\"$str\""; ## XXX 3.0B bug? ## It is needed to avoid default_config.ph overwrites ## config.ph definitions. For example $CONTROL_ADDRESS ## in default_config.ph overwrites config.ph commnted-out ## '# $CONTROL_ADDRESS' in config.ph ??? ## If $install mode (cf/config -i), WE SHOULD NOT ## load value like acct@domain form to default_config.ph. ## or SHOULD MODIFY cf/MANIFEST ??? # if ($install) { # if ($str =~ /\@/) { $value{$key} = "''";} # } # next; # not next for comments } # comments buffer supported for version 3 if ($comment_key) { if ($comment_buf) { #print STDERR "$comment_key < allcated \$comment_buf\n"; #print STDERR "\$comment_buf line=($_)\n"; $comment{$comment_key} .= "$comment_buf"; undef $comment_buf; } /^\s*(\#.*)/ && ($comment{$comment_key} .= "$1\n"); } else { print STDERR "alloc \$comment_buf($_)\n" if $_ && $verbose; /^\s*(\#.*)/ && ($comment_buf .= "$1\n"); } } # while; close(MANIFEST); # making the hash for (@order) { $OrderHash{$_} = 1;} print STDERR "SetDefaults Done.\n\n" if $verbose; $HEADER .= "\# Section Index (cf/MANIFEST $Manifest_Version)\n$Index\n"; } sub CheckDNS { local($fqdn, @fqdn, $hostname, $dn); chop($fqdn = `hostname`); if ($fqdn =~ /(\S+)\.(\S+)/) { # hostname gives FQDN @fqdn = split(/\./, $fqdn); $hostname = shift @fqdn; $dn = join('.', @fqdn); } else { $hostname = $fqdn; local($name, $aliases, @opt) = gethostbyname($fqdn); local($e) = "$name $aliases "; if ($e =~ /$hostname\.([\S+\.]+)\. / || $e =~ /$hostname\.([\S+\.]+) /) { $hostname = $hostname; $dn = $1; $fqdn = "$hostname\.$dn"; } } ($fqdn, $dn, $hostname); } sub FixEnv { while (<>) { chop; if (/^\$(\S+)(\s*=\s*)\"(.*)\"(;.*)/) { # VARIABLE NAME: DEFAULT VALUE $key = $1; $eq = $2; $str = $3; $pad = $4; if ($FixError{$key}) { printf STDERR "Hmm... %-10s %s\n", $key, "NOT FOUND"; printf STDERR " Please fix it manually if you need\n"; &ErrorLog("\t$key NOT FOUND"); } if ($newstr = ($FixPath{$key} || $FixDNS{$key})) { if ($newstr ne $str) { if ($newstr) { printf STDERR "Fixing %-10s => %s\n", $key, $newstr; } $_ = "\$$key$eq\"$newstr\"$pad"; } else { printf STDERR "O.K. %-10s %s\n", $key, $str; } } } print "$_\n"; } } sub search_path { local($f) = @_; local($path) = $ENV{'PATH'}; local($prog, $dir, $p); for $prog (split(/:/, $f)) { ($p) = split(/\\s/, $prog); $prog =~ s#\\s# #g; for $dir (split(/:/, $path)) { if (-f "$dir/$p") { return "$dir/$prog";} } print STDERR "search_prog; $prog is not found\n" if $debug; } ""; } sub ErrorLog { print STDERR "open(APP, >> $motd) < @_\n"; local($motd) = $ERROR_LOG || "etc/motd.error"; open(APP, ">> $motd") || retunr; select(APP); $| = 1; select(STDOUT); print APP "@_\n"; close(APP); 1; } package rv; sub main'reverse { local($file) = @_; # &PreScanConfigPH($file); ######################################################################## # TRICKY; (but why?) for (DIR, CACHE_DIR, FTP_DIR) { eval "\$$_ = '\$${_}';\n"; } print STDERR "=== do $file in 'rv' Name Space ===\n" if $verbose; do $file; for (DIR, CACHE_DIR, FTP_DIR) { eval "undef \$${_};"; } undef $rv'RM; undef $rv'CP; undef $rv'LOCKFILE; undef $rv'LOCKDIR; ######################################################################## if ($] =~ /5.\d\d\d/) { *stab = *{"rv::"}; } else { (*stab) = eval("*_rv"); } while (($key, $val) = each(%stab)) { if ($verbose) { print STDERR "\n".('-'x50); print STDERR "\nTRY\t$key\n"; print STDERR "\t$key != [A-Z0-9_]\n" if $key !~ /^[A-Z0-9\_]+$/; } next if $key !~ /^[A-Z0-9\_]+$/; local(*entry) = $val; if ($verbose) { if (defined $entry) { print STDERR "GO \$\t$key\n"; } elsif (defined @entry) { print STDERR "GO \@\t$key\n"; } elsif (defined %entry) { print STDERR "GO \%\t$key\n"; } elsif (defined &entry) { print STDERR "GO \&\t$key\n"; } else { print STDERR "GO !=\t$key\n"; } } if (defined($entry)) { print STDERR " ? $entry == $main'value{$key}\n" if $verbose;#'; next if "$entry" eq $main'value{$key}; next if "\"$entry\"" eq $main'value{$key}; print STDERR "\n\tDIFF $key\n\n" if $verbose; if ($key =~ /HOOK/) { if ($entry !~ /\#/) { $OUT'HOOK .= "\$$key = q\#$entry\#;\n"; #'; } elsif ($entry !~ /\%/) { $OUT'HOOK .= "\$$key = q%$entry%;\n"; #'; } elsif ($entry !~ /\@/) { $OUT'HOOK .= "\$$key = q@$entry@;\n"; #'; } else { print STDERR "CONVERSION ERROR: "; print STDERR "plaese define [$key]:\n$entry;\n"; } } else { $entry =~ s/\012/\\n/g; $value{$key} = $entry; $other_value{$key} = $entry; } next; } if (defined @entry) { undef $num; $OUT'LOCAL .= "\@$key = ("; foreach (@entry) { $OUT'LOCAL .= "," if $num++ > 0; $OUT'LOCAL .= "'$_'"; } $OUT'LOCAL .= ");\n"; next; } # Is there an associative array that isn't the one # we're currently iterating through? if ($key ne "_$package" && defined %entry) { $OUT'LOCAL .= "\%$key = (\n"; #'; foreach $key (sort keys(%entry)) { $OUT'LOCAL .= "'$key', '". $entry{$key} ."',\n";#'; } $OUT'LOCAL .= ");\n"; #'; next; } $OUT'UNMATCH .= "$key ;\n"; } # %stab; for $key (@main'order) { if ($key =~ /INFO:/) { print "\n" if $match; undef $match; next; } if (defined $value{$key}) { printf "%-20s %s\n", "$key", $value{$key}; $match++; } } undef $buffer; for (keys %other_value) { $v = $other_value{$_}; next if $main'OrderHash{$_}; #'; $buffer .= sprintf("\$%-20s = \"%s\";\n", $_, $v); } print "\n\nLOCAL_CONFIG\n\n"; print $OUT'HOOK; print "\n"; print $OUT'LOCAL; print "\n"; print "\#\#\# cf/config (reverse-mode) generates below \#\#\#\n"; print "\#\#\# NOT DEFINED ENTRIES in cf/MANIFEST ARE HERE \#\#\#\n"; print $buffer; } package dumpvar; sub rv'PreScanConfigPH #'; { local($file) = @_; do $file; if ($] =~ /5.\d\d\d/) { *stab = *{"dumpvar::"}; } else { (*stab) = eval("*_dumpvar"); } while (($key,$val) = each(%stab)) { next if @vars && !grep($key eq $_,@vars); local(*entry) = $val; if (defined $entry) { eval("$rv'\$$key = 1; undef $rv'\$$key"); } elsif (defined @entry) { eval("$rv'\@$key = 1; undef $rv'\@$key"); } elsif ($key ne "_$package" && $key ne "_DB" && defined %entry) { eval("$rv'\%$key = 1; undef $rv'\%$key"); } else { print STDERR "not match $key\n" if $verbose; } } } 1;