Getopt::Long is a huge, heavy perl module. So why use it?

This {gross,amazing} hack makes all wrapped uses of ikiwiki forgo any
option parsing at all. Options come in preparses via an env var from the
wrapper. As a bonus, Wrapper.pm no longer needs to be updated when command
line options are added to the program. Load time is sped up by around 10%.

ikiwikiwrap --params is no longer supported by this change. You will need
to rebuild your wrappers to take advantage of it.
master
joey 2006-03-23 07:37:16 +00:00
parent 6c8cf5dd57
commit b645dc5a41
4 changed files with 51 additions and 80 deletions

View File

@ -2,11 +2,12 @@
use warnings;
use strict;
use Cwd q{abs_path};
use Data::Dumper;
package IkiWiki;
sub gen_wrapper () { #{{{
eval q{use Cwd 'abs_path'};
$config{srcdir}=abs_path($config{srcdir});
$config{destdir}=abs_path($config{destdir});
my $this=abs_path($0);
@ -17,26 +18,8 @@ sub gen_wrapper () { #{{{
if ($config{setup}) {
error("cannot create a wrapper that uses a setup file");
}
my @params=($config{srcdir}, $config{destdir},
"--wikiname=$config{wikiname}",
"--templatedir=$config{templatedir}");
push @params, "--verbose" if $config{verbose};
push @params, "--rebuild" if $config{rebuild};
push @params, "--nosvn" if !$config{svn};
push @params, "--cgi" if $config{cgi};
push @params, "--url=$config{url}" if length $config{url};
push @params, "--cgiurl=$config{cgiurl}" if length $config{cgiurl};
push @params, "--historyurl=$config{historyurl}" if length $config{historyurl};
push @params, "--diffurl=$config{diffurl}" if length $config{diffurl};
push @params, "--anonok" if $config{anonok};
push @params, "--adminuser=$_" foreach @{$config{adminuser}};
my $params=join(" ", @params);
my $call='';
foreach my $p ($this, $this, @params) {
$call.=qq{"$p", };
}
$call.="NULL";
my $wrapper=possibly_foolish_untaint($config{wrapper});
delete $config{wrapper};
my @envsave;
push @envsave, qw{REMOTE_ADDR QUERY_STRING REQUEST_METHOD REQUEST_URI
@ -50,6 +33,11 @@ sub gen_wrapper () { #{{{
EOF
}
$Data::Dumper::Indent=0;
my $configstring=Data::Dumper->Dump([\%config], ['*config']);
$configstring=~s/\\/\\\\/g;
$configstring=~s/"/\\"/g;
open(OUT, ">ikiwiki-wrap.c") || error("failed to write ikiwiki-wrap.c: $!");;
print OUT <<"EOF";
/* A wrapper for ikiwiki, can be safely made suid. */
@ -64,33 +52,29 @@ extern char **environ;
int main (int argc, char **argv) {
/* Sanitize environment. */
char *s;
char *newenviron[$#envsave+3];
char *newenviron[$#envsave+4];
int i=0;
$envsave
newenviron[i++]="HOME=$ENV{HOME}";
newenviron[i++]="WRAPPED_OPTIONS=$configstring";
newenviron[i]=NULL;
environ=newenviron;
if (argc == 2 && strcmp(argv[1], "--params") == 0) {
printf("$params\\n");
exit(0);
}
execl($call);
execl("$this", "$this", NULL);
perror("failed to run $this");
exit(1);
}
EOF
close OUT;
if (system("gcc", "ikiwiki-wrap.c", "-o", possibly_foolish_untaint($config{wrapper})) != 0) {
if (system("gcc", "ikiwiki-wrap.c", "-o", $wrapper) != 0) {
error("failed to compile ikiwiki-wrap.c");
}
unlink("ikiwiki-wrap.c");
if (defined $config{wrappermode} &&
! chmod(oct($config{wrappermode}), possibly_foolish_untaint($config{wrapper}))) {
error("chmod $config{wrapper}: $!");
! chmod(oct($config{wrappermode}), $wrapper)) {
error("chmod $wrapper: $!");
}
print "successfully generated $config{wrapper}\n";
print "successfully generated $wrapper\n";
} #}}}
1

View File

@ -44,9 +44,7 @@ flags such as --verbose can be negated with --no-verbose.
The wrapper is designed to be safely made suid and be run by untrusted
users, as a [[Subversion]] [[post-commit]] hook, or as a [[CGI]].
Note that the generated wrapper will ignore all command line parameters
except for --params, which will make it print out the parameters it would
run ikiwiki with.
Note that the generated wrapper will ignore all command line parameters.
* --wrappermode mode

View File

@ -1,20 +0,0 @@
ikiwiki --wrapper can be used to generate a wrapper
program that runs ikiwiki with the specified parameters. This is used for
[[post-commit]] hooks, [[CGI]], etc, both for convenience and because these
things often need suid wrapper scripts to make ikiwiki run as the right
user.
The generated wrapper is a binary program. What if you want to regenerate
it with different parameters, or just run ikiwiki like it would but with
some parameter changed? To easily accomomplish this, the wrappers all
support being run with --params, which causes them to print out the
parameters they run ikiwiki with.
You can use this trick to regenerate a wrapper, adding or changing a
parameter:
ikiwiki $(./ikiwiki-wrap --params) --wikiname="newname" --wrapper
Or just to run ikiwiki like the wrapper would, and add a parameter:
ikiwiki $(./ikiwiki-wrap --params) --rebuild

59
ikiwiki
View File

@ -10,7 +10,6 @@ use strict;
use Memoize;
use File::Spec;
use HTML::Template;
use Getopt::Long;
use vars qw{%config %links %oldlinks %oldpagemtime %renderedfiles %pagesources};
@ -39,31 +38,41 @@ our %config=( #{{{
adminuser => undef,
); #}}}
GetOptions( #{{{
"setup|s=s" => \$config{setup},
"wikiname=s" => \$config{wikiname},
"verbose|v!" => \$config{verbose},
"rebuild!" => \$config{rebuild},
"wrapper:s" => sub { $config{wrapper}=$_[1] ? $_[1] : "ikiwiki-wrap" },
"wrappermode=i" => \$config{wrappermode},
"svn!" => \$config{svn},
"anonok!" => \$config{anonok},
"cgi!" => \$config{cgi},
"url=s" => \$config{url},
"cgiurl=s" => \$config{cgiurl},
"historyurl=s" => \$config{historyurl},
"diffurl=s" => \$config{diffurl},
"exclude=s@" => sub {
$config{wiki_file_prune_regexp}=qr/$config{wiki_file_prune_regexp}|$_[1]/;
},
"adminuser=s@" => sub { push @{$config{adminuser}}, $_[1] },
"templatedir=s" => sub { $config{templatedir}=possibly_foolish_untaint($_[1]) },
) || usage();
# option parsing #{{{
if (! exists $ENV{WRAPPED_OPTIONS}) {
eval q{use Getopt::Long};
GetOptions(
"setup|s=s" => \$config{setup},
"wikiname=s" => \$config{wikiname},
"verbose|v!" => \$config{verbose},
"rebuild!" => \$config{rebuild},
"wrapper:s" => sub { $config{wrapper}=$_[1] ? $_[1] : "ikiwiki-wrap" },
"wrappermode=i" => \$config{wrappermode},
"svn!" => \$config{svn},
"anonok!" => \$config{anonok},
"cgi!" => \$config{cgi},
"url=s" => \$config{url},
"cgiurl=s" => \$config{cgiurl},
"historyurl=s" => \$config{historyurl},
"diffurl=s" => \$config{diffurl},
"exclude=s@" => sub {
$config{wiki_file_prune_regexp}=qr/$config{wiki_file_prune_regexp}|$_[1]/;
},
"adminuser=s@" => sub { push @{$config{adminuser}}, $_[1] },
"templatedir=s" => sub { $config{templatedir}=possibly_foolish_untaint($_[1]) },
) || usage();
if (! $config{setup}) {
usage() unless @ARGV == 2;
$config{srcdir} = possibly_foolish_untaint(shift);
$config{destdir} = possibly_foolish_untaint(shift);
if (! $config{setup}) {
usage() unless @ARGV == 2;
$config{srcdir} = possibly_foolish_untaint(shift);
$config{destdir} = possibly_foolish_untaint(shift);
checkoptions();
}
}
else {
# wrapper passes a full config structure in the environment
# variable
eval possibly_foolish_untaint($ENV{WRAPPED_OPTIONS});
checkoptions();
}
#}}}