File manager - Edit - /usr/share/webmin/bin/webmin
Back
#!/usr/bin/env perl # Webmin CLI - Allows performing a variety of common Webmin-related # functions on the command line. use strict; use warnings; BEGIN { $Pod::Usage::Formatter = 'Pod::Text::Color'; } use Getopt::Long qw(:config no_ignore_case permute pass_through); use Term::ANSIColor qw(color); use Pod::Usage; # %ansi_specs # Map logical color names to preferred Term::ANSIColor specs and # compatibility fallbacks for older versions. my %ansi_specs = ( reset => [ 'reset' ], red => [ 'red' ], green => [ 'green' ], yellow => [ 'yellow' ], cyan => [ 'cyan' ], dark => [ 'dark', 'faint' ], bright_red => [ 'bright_red', 'bold red', 'red' ], bright_green => [ 'bright_green', 'bold green', 'green' ], bright_yellow => [ 'bright_yellow', 'bold yellow', 'yellow' ], ); my %ansi_cache; # ansi(name) # Resolve a named color to an ANSI escape sequence, with fallbacks # for older Term::ANSIColor versions that may not support newer names. sub ansi { my ($name) = @_; return $ansi_cache{$name} if (exists $ansi_cache{$name}); foreach my $spec (@{ $ansi_specs{$name} || [] }) { my $value = eval { color($spec) }; return $ansi_cache{$name} = $value if (defined($value)); } return $ansi_cache{$name} = ""; } # print_line(line) # Print a full line without relying on Perl's say syntax, # which is rejected by some older Perl parsers in this script. sub print_line { print @_; print "\n"; } # Check if root if ($> != 0) { die join("", ansi('bright_red'), "Error: ", ansi('reset'), ansi('bright_yellow'), "webmin", ansi('reset'), " command must be run as root\n"); exit 1; } my $a0 = $ARGV[0]; # main() # Parse global options and dispatch the requested Webmin CLI action. sub main { my ( %opt, $subcmd ); GetOptions( 'help|h' => \$opt{'help'}, 'config|c=s' => \$opt{'config'}, 'list-commands|l' => \$opt{'list'}, 'describe|d' => \$opt{'describe'}, 'man|m' => \$opt{'man'}, 'version|v' => \$opt{'version'}, 'versions|V' => \$opt{'versions'}, '<>' => sub { # Handle unrecognized options, inc. subcommands. my($arg) = @_; if ($arg =~ m{^-}) { print_line("Usage error: Unknown option $arg."); pod2usage(0); } else { # It must be a subcommand. $subcmd = $arg; die "!FINISH"; } } ); # Set defaults $opt{'config'} ||= "/etc/webmin"; $opt{'commands'} = $a0; # Load libs loadlibs(\%opt); my @remain = @ARGV; # List commands? if ($opt{'list'}) { list_commands(\%opt); exit 0; } elsif ($opt{'version'} || $opt{'versions'}) { # Load libs my $print_mod_vers = sub { my ($module_type, $modules_list, $prod_root, $prod_ver) = @_; return if (!ref($modules_list)); # Gather module info my @mods; foreach my $mod (@{$modules_list}) { my %mi; read_file($mod, \%mi); my $ver = $mi{'version'}; my ($dir) = $mod =~ m/$prod_root\/(.*?)\//; next if (!$ver || !$mi{'desc'} || !$dir); next if ($prod_ver =~ /^\Q$ver\E/); push(@mods, { desc => $mi{'desc'}, ver => $ver, dir => $dir }); } # Print sorted by description my $head; foreach my $m (sort { $a->{'desc'} cmp $b->{'desc'} } @mods) { my $mod_ver = $m->{'ver'}; if (-r "$prod_root/$m->{'dir'}/module.info") { eval { no warnings 'once'; local $main::error_must_die = 1; &foreign_require($m->{'dir'}) }; # Get module edition if available my $ed; $ed = eval { &foreign_call( $m->{'dir'}, "get_module_edition") } if (&foreign_defined($m->{'dir'}, "get_module_edition")); $mod_ver .= " $ed" if ($ed); } print_line(ansi('cyan'), " $module_type: ", ansi('reset')) if (!$head++); print_line(" $m->{'desc'}: ", ansi('green'), $mod_ver, ansi('reset'), ansi('dark'), " [$m->{'dir'}]", ansi('reset')); } }; my $root = root($opt{'config'}); if ($root && -d $root) { $ENV{'WEBMIN_CONFIG'} = $opt{'config'}; no warnings 'once'; @main::root_directories = ($root); $main::root_directory = $root; *unique = sub { my %seen; grep { !$seen{$_}++ } @_ } if (!defined(&unique)); use warnings; require("$root/web-lib-funcs.pl"); # Get Webmin version installed my $ver1 = "$root/version"; my $ver2 = "$opt{'config'}/version"; my $ver = read_file_contents($ver1) || read_file_contents($ver2); my $verrel_file = "$root/release"; my $verrel = -r $verrel_file ? read_file_contents($verrel_file) : ""; if ($verrel) { $verrel = ":@{[trim($verrel)]}"; } $ver = trim($ver); if ($ver) { if ($opt{'version'}) { print_line("$ver$verrel"); exit 0; } else { print_line(ansi('cyan'), "Webmin: ", ansi('reset'), ansi('green'), "$ver$verrel", ansi('reset'), ansi('dark'), " [$root]", ansi('reset')); } } else { print_line(ansi('red'), "Error: ", ansi('reset'), "Cannot determine Webmin version"); exit 1; } # Get other Webmin themes/modules versions if available my ($dir, @themes, @mods); if (opendir($dir, $root)) { while (my $file = readdir($dir)) { my $theme_info_file = "$root/$file/theme.info"; push(@themes, $theme_info_file) if (-r $theme_info_file); my $mod_info_file = "$root/$file/module.info"; push(@mods, $mod_info_file) if (-r $mod_info_file); } } closedir($dir); &$print_mod_vers('Themes', \@themes, $root, $ver); &$print_mod_vers('Modules', \@mods, $root, $ver); # Check for Usermin my $wmumconfig = "$opt{'config'}/usermin/config"; if (-r $wmumconfig) { my %wmumconfig; read_file($wmumconfig, \%wmumconfig); # Usermin config dir $wmumconfig = $wmumconfig{'usermin_dir'}; if ($wmumconfig) { my %uminiserv; read_file("$wmumconfig/miniserv.conf", \%uminiserv); my $uroot = $uminiserv{'root'}; # Get Usermin version installed if ($uroot && -d $uroot) { my $uver1 = "$uroot/version"; my $uver2 = "$wmumconfig/version"; my $uver = read_file_contents($uver1) || read_file_contents($uver2); my $uverrel_file = "$uroot/release"; my $uverrel = -r $uverrel_file ? read_file_contents($uverrel_file) : ""; $uverrel = ":@{[trim($uverrel)]}" if ($uverrel); $uver = trim($uver) . $uverrel; if ($uver) { print_line(ansi('cyan'), "Usermin: ", ansi('reset'), ansi('green'), $uver, ansi('reset'), ansi('dark'), " [$uroot]", ansi('reset')); my ($udir, @uthemes, @umods); if (opendir($udir, "$uroot")) { while (my $file = readdir($udir)) { my $theme_info_file = "$uroot/$file/theme.info"; push(@uthemes, $theme_info_file) if (-r $theme_info_file); my $mod_info_file = "$uroot/$file/module.info"; push(@umods, $mod_info_file) if (-r $mod_info_file); } } closedir($udir); &$print_mod_vers('Themes', \@uthemes, $uroot, $uver); &$print_mod_vers('Modules', \@umods, $uroot, $uver); } } } } } exit 0; } elsif ($opt{'man'} || $opt{'help'} || !defined($remain[0])) { # Show the full manual page man_command(\%opt, $subcmd); exit 0; } elsif ($subcmd) { run_command( \%opt, $subcmd, \@remain ); } exit 0; } exit main( \@ARGV ) if !caller(0); # run_command(optref, subcmd, remainref) # Run a subcommand with the resolved Webmin config and pass through # its exit status. sub run_command { my ( $optref, $subcmd, $remainref ) = @_; # Load libs loadlibs($optref); # Figure out the Webmin root directory my $root = root($optref->{'config'}); my (@commands) = list_commands($optref); if (! grep( /^$subcmd$/, @commands ) ) { print_line(ansi('red'), "Error: ", ansi('reset'), "Command \`$subcmd\` doesn't exist", ansi('reset')); exit 1; } my $command_path = get_command_path($root, $subcmd, $optref); # Merge the options my @allopts = ("--config", "$optref->{'config'}", @$remainref); # Run system($command_path, @allopts); # Try to exit with the passed through exit code (rarely used, but why not?) if ($? == -1) { print_line(ansi('red'), "Error: ", ansi('reset'), "Failed to execute \`$command_path\`: $!"); exit 1; } else { exit $? >> 8; } } # get_command_path(root, subcmd, optref) # Resolve a CLI command name to an executable path under Webmin's # global or module-specific bin directories. sub get_command_path { my ($root, $subcmd, $optref) = @_; # Load libs loadlibs($optref); # Check for a root-level command (in "$root/bin") my $command_path; if ($subcmd) { $command_path = File::Spec->catfile($root, 'bin', $subcmd); } else { $command_path = File::Spec->catfile($root, 'bin', 'webmin'); } my $module_name; my $command; if ( -x $command_path) { $command = $command_path; } else { # Try to extract a module name from the command # Get list of directories opendir (my $DIR, $root); my @module_dirs = grep { -d "$root/$_" } readdir($DIR); closedir($DIR); # See if any of them are a substring of $subcmd for my $dir (@module_dirs) { if (index($subcmd, $dir) == 0) { $module_name = $dir; my $barecmd = substr($subcmd, -(length($subcmd)-length($module_name)-1)); $command = File::Spec->catfile($root, $dir, 'bin', $barecmd); # Could be .pl or no extension if ( -x $command ) { last; } elsif ( -x $command . ".pl" ) { $command = $command . ".pl"; last; } } } } if ($optref->{'commands'} && $optref->{'commands'} =~ /^(stats|status|start|stop|restart|reload|force-restart|force-reload|kill)$/) { exit system("$0 server $optref->{'commands'}"); } elsif ($command) { return $command; } else { die join("", ansi('red'), "Unrecognized subcommand: $subcmd", ansi('reset'), "\n"); } } # list_commands(optref) # Enumerate available global and module CLI commands, optionally # rendering each command's DESCRIPTION section. sub list_commands { my ($optref) = @_; my $root = root($optref->{'config'}); my @commands; # Find and list global commands for my $command (glob ("$root/bin/*")) { my ($bin, $path) = fileparse($command); if ($bin =~ "webmin") { next; } if ($optref->{'describe'}) { # Display name and description print_line(ansi('yellow'), "$bin", ansi('reset')); pod2usage( -verbose => 99, -sections => [ qw(DESCRIPTION) ], -input => $command, -exitval => "NOEXIT"); } else { if (wantarray) { push(@commands, $bin); } else { # Just list the names print_line("$bin"); } } } my @modules; # Find all module directories with something in bin for my $command (glob ("$root/*/bin/*")) { my ($bin, $path) = fileparse($command); my $module = (split /\//, $path)[-2]; if ($optref->{'describe'}) { # Display name and description print_line(ansi('yellow'), "$module-$bin", ansi('reset')); pod2usage( -verbose => 99, -sections => [ qw(DESCRIPTION) ], -input => $command, -exitval => "NOEXIT"); } else { if (wantarray) { push(@modules, "$module-$bin"); } else { # Just list the names print_line("$module-$bin"); } } } if (wantarray) { return (@commands, @modules); } } # man_command(optref, subcmd) # Display usage message. sub man_command { my ($optref, $subcmd) = @_; my $root = root($optref->{'config'}); my $command_path = get_command_path($root, $subcmd, $optref); $ENV{'PAGER'} ||= "more"; open(my $PAGER, "|-", "$ENV{'PAGER'}"); if ($optref->{'help'}) { pod2usage( -input => $command_path ); } else { pod2usage( -verbose => 99, -input => $command_path, -output => $PAGER); } close($PAGER); } # root(config) # Read the configured Webmin installation root from miniserv.conf. sub root { my ($config) = @_; open(my $CONF, "<", "$config/miniserv.conf") || die join("", ansi('red'), "Failed to open $config/miniserv.conf", ansi('reset'), "\n"); my $root; while (<$CONF>) { if (/^root=(.*)/) { $root = $1; } } close($CONF); # Does the Webmin root exist? if ( $root ) { die "$root is not a directory. Is --config correct?\n" unless (-d $root); } else { die "Unable to determine Webmin installation directory ". "from $ENV{'WEBMIN_CONFIG'}\n"; } return $root; } # loadlibs(optref) # Load bundled libraries from the Webmin vendor dir when they are not # available from system package dependencies. sub loadlibs { my ($optref) = @_; $optref->{'config'} ||= "/etc/webmin"; my $root = root($optref->{'config'}); my $libroot = "$root/vendor_perl"; eval "use lib '$libroot'"; eval "use File::Basename"; eval "use File::Spec"; } 1; =pod =head1 NAME webmin =head1 DESCRIPTION Webmin CLI command to perform many common Webmin tasks from the command line or from scripts. =head1 SYNOPSIS webmin [options] subcommand [subcommand options] =head1 OPTIONS =over =item --help, -h Print this usage summary and exit. Subcommands may also have a usage summary. =item --config <path>, -c <path> Specify the full path to the Webmin configuration directory. Defaults to C</etc/webmin>. =item --list-commands, -l List available subcommands. =item --describe, -d When listing commands, briefly describe what they do. =item --man <command>, -m <command> Display the manual page for the given subcommand. =item --version, -v Returns current Webmin version installed =item --versions Returns Webmin and other modules and themes versions installed (only those for which version is available) =back =head1 EXIT CODES 0 on success ; non-0 on error =head1 LICENSE AND COPYRIGHT Copyright 2018 Jamie Cameron <jamie@webmin.com> Joe Cooper <joe@virtualmin.com> Ilia Ross <ilia@virtualmin.com>
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0.32 |
proxy
|
phpinfo
|
Settings