2006-03-23 07:51:15 +01:00
|
|
|
#!/usr/bin/perl
|
|
|
|
|
2008-07-11 12:07:48 +02:00
|
|
|
package IkiWiki;
|
|
|
|
|
2006-03-23 07:51:15 +01:00
|
|
|
use warnings;
|
|
|
|
use strict;
|
2008-07-22 00:26:14 +02:00
|
|
|
use File::Spec;
|
2008-07-11 11:40:18 +02:00
|
|
|
use Data::Dumper;
|
2006-05-02 08:53:33 +02:00
|
|
|
use IkiWiki;
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2010-07-24 23:33:59 +02:00
|
|
|
sub gen_wrappers () {
|
|
|
|
debug(gettext("generating wrappers.."));
|
|
|
|
my %origconfig=(%config);
|
|
|
|
foreach my $wrapper (@{$config{wrappers}}) {
|
|
|
|
%config=(%origconfig, %{$wrapper});
|
|
|
|
$config{verbose}=$config{setupverbose}
|
|
|
|
if exists $config{setupverbose};
|
|
|
|
$config{syslog}=$config{setupsyslog}
|
|
|
|
if exists $config{setupsyslog};
|
|
|
|
delete @config{qw(setupsyslog setupverbose wrappers genwrappers rebuild)};
|
|
|
|
checkconfig();
|
|
|
|
if (! $config{cgi} && ! $config{post_commit} &&
|
|
|
|
! $config{test_receive}) {
|
|
|
|
$config{post_commit}=1;
|
|
|
|
}
|
|
|
|
gen_wrapper();
|
|
|
|
}
|
|
|
|
%config=(%origconfig);
|
|
|
|
}
|
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub gen_wrapper () {
|
2008-07-22 00:26:14 +02:00
|
|
|
$config{srcdir}=File::Spec->rel2abs($config{srcdir});
|
|
|
|
$config{destdir}=File::Spec->rel2abs($config{destdir});
|
|
|
|
my $this=File::Spec->rel2abs($0);
|
2006-03-23 07:51:15 +01:00
|
|
|
if (! -x $this) {
|
2006-12-29 05:38:40 +01:00
|
|
|
error(sprintf(gettext("%s doesn't seem to be executable"), $this));
|
2006-03-23 07:51:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($config{setup}) {
|
2006-12-29 05:38:40 +01:00
|
|
|
error(gettext("cannot create a wrapper that uses a setup file"));
|
2006-03-23 07:51:15 +01:00
|
|
|
}
|
2006-03-23 08:37:16 +01:00
|
|
|
my $wrapper=possibly_foolish_untaint($config{wrapper});
|
2006-04-20 15:34:11 +02:00
|
|
|
if (! defined $wrapper || ! length $wrapper) {
|
2006-12-29 05:38:40 +01:00
|
|
|
error(gettext("wrapper filename not specified"));
|
2006-04-20 15:34:11 +02:00
|
|
|
}
|
2006-03-23 08:37:16 +01:00
|
|
|
delete $config{wrapper};
|
2006-03-23 07:51:15 +01:00
|
|
|
|
|
|
|
my @envsave;
|
|
|
|
push @envsave, qw{REMOTE_ADDR QUERY_STRING REQUEST_METHOD REQUEST_URI
|
|
|
|
CONTENT_TYPE CONTENT_LENGTH GATEWAY_INTERFACE
|
2009-01-31 19:06:44 +01:00
|
|
|
HTTP_COOKIE REMOTE_USER HTTPS REDIRECT_STATUS
|
2011-06-16 02:02:14 +02:00
|
|
|
HTTP_HOST SERVER_PORT HTTPS HTTP_ACCEPT
|
2009-01-31 19:06:44 +01:00
|
|
|
REDIRECT_URL} if $config{cgi};
|
2006-03-23 07:51:15 +01:00
|
|
|
my $envsave="";
|
|
|
|
foreach my $var (@envsave) {
|
do no-op post_commit test in wrapper
This speeds up web commits by 1/4th of a second or so, since perl does
not have to start up for the post commit hook.
perl's locking is completly FuBar, since it's impossible to tell what perl
flock() really does, and thus difficult to write code in other languages
that interoperates with perl's locking. (Let alone interoperating with
existing fcntl locking from perl...)
In this particular case, I think I was able to find a way to avoid the
insanity, mostly. The C code does a true flock(2), and if perl is using an
incompatable lock method that does not use the same locking primative at
the kernel level, then the C code's test will fail, and it will go ahead
and run the perl code. Then the perl code's test will test the right thing.
On Debian, at least lately, perl's flock() does a true flock(2), so the
optimisation does work.
2008-10-26 20:13:04 +01:00
|
|
|
$envsave.=<<"EOF";
|
2006-03-23 07:51:15 +01:00
|
|
|
if ((s=getenv("$var")))
|
2007-07-09 02:39:55 +02:00
|
|
|
addenv("$var", s);
|
2006-03-23 07:51:15 +01:00
|
|
|
EOF
|
|
|
|
}
|
2009-09-10 20:04:46 +02:00
|
|
|
|
|
|
|
my @wrapper_hooks;
|
|
|
|
run_hooks(genwrapper => sub { push @wrapper_hooks, shift->() });
|
2008-10-26 19:03:18 +01:00
|
|
|
|
do no-op post_commit test in wrapper
This speeds up web commits by 1/4th of a second or so, since perl does
not have to start up for the post commit hook.
perl's locking is completly FuBar, since it's impossible to tell what perl
flock() really does, and thus difficult to write code in other languages
that interoperates with perl's locking. (Let alone interoperating with
existing fcntl locking from perl...)
In this particular case, I think I was able to find a way to avoid the
insanity, mostly. The C code does a true flock(2), and if perl is using an
incompatable lock method that does not use the same locking primative at
the kernel level, then the C code's test will fail, and it will go ahead
and run the perl code. Then the perl code's test will test the right thing.
On Debian, at least lately, perl's flock() does a true flock(2), so the
optimisation does work.
2008-10-26 20:13:04 +01:00
|
|
|
my $check_commit_hook="";
|
2008-11-11 21:40:04 +01:00
|
|
|
my $pre_exec="";
|
do no-op post_commit test in wrapper
This speeds up web commits by 1/4th of a second or so, since perl does
not have to start up for the post commit hook.
perl's locking is completly FuBar, since it's impossible to tell what perl
flock() really does, and thus difficult to write code in other languages
that interoperates with perl's locking. (Let alone interoperating with
existing fcntl locking from perl...)
In this particular case, I think I was able to find a way to avoid the
insanity, mostly. The C code does a true flock(2), and if perl is using an
incompatable lock method that does not use the same locking primative at
the kernel level, then the C code's test will fail, and it will go ahead
and run the perl code. Then the perl code's test will test the right thing.
On Debian, at least lately, perl's flock() does a true flock(2), so the
optimisation does work.
2008-10-26 20:13:04 +01:00
|
|
|
if ($config{post_commit}) {
|
|
|
|
# Optimise checking !commit_hook_enabled() ,
|
|
|
|
# so that ikiwiki does not have to be started if the
|
|
|
|
# hook is disabled.
|
|
|
|
#
|
|
|
|
# Note that perl's flock may be implemented using fcntl
|
|
|
|
# or lockf on some systems. If so, and if there is no
|
|
|
|
# interop between the locking systems, the true C flock will
|
|
|
|
# always succeed, and this optimisation won't work.
|
|
|
|
# The perl code will later correctly check the lock,
|
|
|
|
# so the right thing will still happen, though without
|
|
|
|
# the benefit of this optimisation.
|
|
|
|
$check_commit_hook=<<"EOF";
|
|
|
|
{
|
2008-11-11 21:53:55 +01:00
|
|
|
int fd=open("$config{wikistatedir}/commitlock", O_CREAT | O_RDWR, 0666);
|
do no-op post_commit test in wrapper
This speeds up web commits by 1/4th of a second or so, since perl does
not have to start up for the post commit hook.
perl's locking is completly FuBar, since it's impossible to tell what perl
flock() really does, and thus difficult to write code in other languages
that interoperates with perl's locking. (Let alone interoperating with
existing fcntl locking from perl...)
In this particular case, I think I was able to find a way to avoid the
insanity, mostly. The C code does a true flock(2), and if perl is using an
incompatable lock method that does not use the same locking primative at
the kernel level, then the C code's test will fail, and it will go ahead
and run the perl code. Then the perl code's test will test the right thing.
On Debian, at least lately, perl's flock() does a true flock(2), so the
optimisation does work.
2008-10-26 20:13:04 +01:00
|
|
|
if (fd != -1) {
|
|
|
|
if (flock(fd, LOCK_SH | LOCK_NB) != 0)
|
|
|
|
exit(0);
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EOF
|
|
|
|
}
|
2008-11-11 21:40:04 +01:00
|
|
|
elsif ($config{cgi}) {
|
|
|
|
# Avoid more than one ikiwiki cgi running at a time by
|
|
|
|
# taking a cgi lock. Since ikiwiki uses several MB of
|
|
|
|
# memory, a pile up of processes could cause thrashing
|
2008-11-12 02:48:02 +01:00
|
|
|
# otherwise. The fd of the lock is stored in
|
|
|
|
# IKIWIKI_CGILOCK_FD so unlockwiki can close it.
|
2008-11-11 21:40:04 +01:00
|
|
|
$pre_exec=<<"EOF";
|
2010-07-01 22:20:03 +02:00
|
|
|
lockfd=open("$config{wikistatedir}/cgilock", O_CREAT | O_RDWR, 0666);
|
|
|
|
if (lockfd != -1 && flock(lockfd, LOCK_EX) == 0) {
|
|
|
|
char *fd_s=malloc(8);
|
|
|
|
sprintf(fd_s, "%i", lockfd);
|
|
|
|
setenv("IKIWIKI_CGILOCK_FD", fd_s, 1);
|
2008-11-11 21:40:04 +01:00
|
|
|
}
|
|
|
|
EOF
|
|
|
|
}
|
do no-op post_commit test in wrapper
This speeds up web commits by 1/4th of a second or so, since perl does
not have to start up for the post commit hook.
perl's locking is completly FuBar, since it's impossible to tell what perl
flock() really does, and thus difficult to write code in other languages
that interoperates with perl's locking. (Let alone interoperating with
existing fcntl locking from perl...)
In this particular case, I think I was able to find a way to avoid the
insanity, mostly. The C code does a true flock(2), and if perl is using an
incompatable lock method that does not use the same locking primative at
the kernel level, then the C code's test will fail, and it will go ahead
and run the perl code. Then the perl code's test will test the right thing.
On Debian, at least lately, perl's flock() does a true flock(2), so the
optimisation does work.
2008-10-26 20:13:04 +01:00
|
|
|
|
2010-07-01 22:20:03 +02:00
|
|
|
my $set_background_command='';
|
|
|
|
if (defined $config{wrapper_background_command} &&
|
|
|
|
length $config{wrapper_background_command}) {
|
|
|
|
my $background_command=delete $config{wrapper_background_command};
|
|
|
|
$set_background_command=~s/"/\\"/g;
|
|
|
|
$set_background_command='#define BACKGROUND_COMMAND "'.$background_command.'"';
|
|
|
|
}
|
|
|
|
|
2006-03-23 08:42:24 +01:00
|
|
|
$Data::Dumper::Indent=0; # no newlines
|
2006-03-23 08:37:16 +01:00
|
|
|
my $configstring=Data::Dumper->Dump([\%config], ['*config']);
|
|
|
|
$configstring=~s/\\/\\\\/g;
|
|
|
|
$configstring=~s/"/\\"/g;
|
2007-06-03 18:24:22 +02:00
|
|
|
$configstring=~s/\n/\\n/g;
|
2006-03-23 08:37:16 +01:00
|
|
|
|
2009-02-09 21:13:12 +01:00
|
|
|
writefile(basename("$wrapper.c"), dirname($wrapper), <<"EOF");
|
2006-03-23 07:51:15 +01:00
|
|
|
/* A wrapper for ikiwiki, can be safely made suid. */
|
|
|
|
#include <stdio.h>
|
2006-09-04 05:50:27 +02:00
|
|
|
#include <sys/types.h>
|
do no-op post_commit test in wrapper
This speeds up web commits by 1/4th of a second or so, since perl does
not have to start up for the post commit hook.
perl's locking is completly FuBar, since it's impossible to tell what perl
flock() really does, and thus difficult to write code in other languages
that interoperates with perl's locking. (Let alone interoperating with
existing fcntl locking from perl...)
In this particular case, I think I was able to find a way to avoid the
insanity, mostly. The C code does a true flock(2), and if perl is using an
incompatable lock method that does not use the same locking primative at
the kernel level, then the C code's test will fail, and it will go ahead
and run the perl code. Then the perl code's test will test the right thing.
On Debian, at least lately, perl's flock() does a true flock(2), so the
optimisation does work.
2008-10-26 20:13:04 +01:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2006-03-23 07:51:15 +01:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
do no-op post_commit test in wrapper
This speeds up web commits by 1/4th of a second or so, since perl does
not have to start up for the post commit hook.
perl's locking is completly FuBar, since it's impossible to tell what perl
flock() really does, and thus difficult to write code in other languages
that interoperates with perl's locking. (Let alone interoperating with
existing fcntl locking from perl...)
In this particular case, I think I was able to find a way to avoid the
insanity, mostly. The C code does a true flock(2), and if perl is using an
incompatable lock method that does not use the same locking primative at
the kernel level, then the C code's test will fail, and it will go ahead
and run the perl code. Then the perl code's test will test the right thing.
On Debian, at least lately, perl's flock() does a true flock(2), so the
optimisation does work.
2008-10-26 20:13:04 +01:00
|
|
|
#include <sys/file.h>
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2010-03-29 00:27:23 +02:00
|
|
|
extern char **environ;
|
2010-09-27 04:27:46 +02:00
|
|
|
char *newenviron[$#envsave+7];
|
2007-07-09 02:39:55 +02:00
|
|
|
int i=0;
|
|
|
|
|
2010-03-18 22:35:59 +01:00
|
|
|
void addenv(char *var, char *val) {
|
2007-07-09 02:39:55 +02:00
|
|
|
char *s=malloc(strlen(var)+1+strlen(val)+1);
|
|
|
|
if (!s)
|
|
|
|
perror("malloc");
|
|
|
|
sprintf(s, "%s=%s", var, val);
|
|
|
|
newenviron[i++]=s;
|
|
|
|
}
|
2006-03-23 07:51:15 +01:00
|
|
|
|
|
|
|
int main (int argc, char **argv) {
|
2010-07-01 22:20:03 +02:00
|
|
|
int lockfd=-1;
|
2006-03-23 07:51:15 +01:00
|
|
|
char *s;
|
2008-10-26 19:03:18 +01:00
|
|
|
|
do no-op post_commit test in wrapper
This speeds up web commits by 1/4th of a second or so, since perl does
not have to start up for the post commit hook.
perl's locking is completly FuBar, since it's impossible to tell what perl
flock() really does, and thus difficult to write code in other languages
that interoperates with perl's locking. (Let alone interoperating with
existing fcntl locking from perl...)
In this particular case, I think I was able to find a way to avoid the
insanity, mostly. The C code does a true flock(2), and if perl is using an
incompatable lock method that does not use the same locking primative at
the kernel level, then the C code's test will fail, and it will go ahead
and run the perl code. Then the perl code's test will test the right thing.
On Debian, at least lately, perl's flock() does a true flock(2), so the
optimisation does work.
2008-10-26 20:13:04 +01:00
|
|
|
$check_commit_hook
|
2009-09-10 20:04:46 +02:00
|
|
|
@wrapper_hooks
|
2006-03-23 07:51:15 +01:00
|
|
|
$envsave
|
|
|
|
newenviron[i++]="HOME=$ENV{HOME}";
|
2010-09-27 04:27:46 +02:00
|
|
|
newenviron[i++]="PATH=$ENV{PATH}";
|
2006-03-23 08:37:16 +01:00
|
|
|
newenviron[i++]="WRAPPED_OPTIONS=$configstring";
|
2010-03-18 22:44:46 +01:00
|
|
|
|
2010-03-29 00:27:23 +02:00
|
|
|
#ifdef __TINYC__
|
2010-05-05 00:41:55 +02:00
|
|
|
/* old tcc versions do not support modifying environ directly */
|
2010-03-18 22:44:46 +01:00
|
|
|
if (clearenv() != 0) {
|
|
|
|
perror("clearenv");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
for (; i>0; i--)
|
|
|
|
putenv(newenviron[i-1]);
|
2010-03-29 00:27:23 +02:00
|
|
|
#else
|
|
|
|
newenviron[i]=NULL;
|
|
|
|
environ=newenviron;
|
|
|
|
#endif
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2008-01-02 00:48:34 +01:00
|
|
|
if (setregid(getegid(), -1) != 0 &&
|
|
|
|
setregid(getegid(), -1) != 0) {
|
|
|
|
perror("failed to drop real gid");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (setreuid(geteuid(), -1) != 0 &&
|
|
|
|
setreuid(geteuid(), -1) != 0) {
|
|
|
|
perror("failed to drop real uid");
|
2006-09-04 05:38:02 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2008-11-11 21:40:04 +01:00
|
|
|
$pre_exec
|
2010-07-01 22:20:03 +02:00
|
|
|
|
|
|
|
$set_background_command
|
|
|
|
#ifdef BACKGROUND_COMMAND
|
|
|
|
if (lockfd != -1) {
|
|
|
|
close(lockfd);
|
|
|
|
}
|
|
|
|
|
|
|
|
pid_t pid=fork();
|
|
|
|
if (pid == -1) {
|
|
|
|
perror("fork");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
else if (pid == 0) {
|
|
|
|
execl("$this", "$this", NULL);
|
|
|
|
perror("exec $this");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
waitpid(pid, NULL, 0);
|
|
|
|
|
|
|
|
if (daemon(1, 0) == 0) {
|
|
|
|
system(BACKGROUND_COMMAND);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
perror("daemon");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2009-08-24 00:25:02 +02:00
|
|
|
execl("$this", "$this", NULL);
|
2007-07-09 02:39:55 +02:00
|
|
|
perror("exec $this");
|
2006-03-23 07:51:15 +01:00
|
|
|
exit(1);
|
2010-07-01 22:20:03 +02:00
|
|
|
#endif
|
2006-03-23 07:51:15 +01:00
|
|
|
}
|
|
|
|
EOF
|
2007-11-25 21:50:31 +01:00
|
|
|
|
2009-10-21 22:27:44 +02:00
|
|
|
my @cc=exists $ENV{CC} ? possibly_foolish_untaint($ENV{CC}) : 'cc';
|
|
|
|
push @cc, possibly_foolish_untaint($ENV{CFLAGS}) if exists $ENV{CFLAGS};
|
|
|
|
if (system(@cc, "$wrapper.c", "-o", "$wrapper.new") != 0) {
|
2007-01-04 13:00:23 +01:00
|
|
|
#translators: The parameter is a C filename.
|
2006-12-29 05:38:40 +01:00
|
|
|
error(sprintf(gettext("failed to compile %s"), "$wrapper.c"));
|
2006-03-23 07:51:15 +01:00
|
|
|
}
|
2006-03-26 04:30:44 +02:00
|
|
|
unlink("$wrapper.c");
|
2007-11-14 15:27:11 +01:00
|
|
|
if (defined $config{wrappergroup}) {
|
|
|
|
my $gid=(getgrnam($config{wrappergroup}))[2];
|
|
|
|
if (! defined $gid) {
|
|
|
|
error(sprintf("bad wrappergroup"));
|
|
|
|
}
|
|
|
|
if (! chown(-1, $gid, "$wrapper.new")) {
|
|
|
|
error("chown $wrapper.new: $!");
|
|
|
|
}
|
|
|
|
}
|
2006-03-23 07:51:15 +01:00
|
|
|
if (defined $config{wrappermode} &&
|
2007-11-14 15:27:11 +01:00
|
|
|
! chmod(oct($config{wrappermode}), "$wrapper.new")) {
|
|
|
|
error("chmod $wrapper.new: $!");
|
|
|
|
}
|
|
|
|
if (! rename("$wrapper.new", $wrapper)) {
|
|
|
|
error("rename $wrapper.new $wrapper: $!");
|
2006-03-23 07:51:15 +01:00
|
|
|
}
|
2007-01-04 13:00:23 +01:00
|
|
|
#translators: The parameter is a filename.
|
2011-04-21 00:10:33 +02:00
|
|
|
debug(sprintf(gettext("successfully generated %s"), $wrapper));
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-03-23 07:51:15 +01:00
|
|
|
|
|
|
|
1
|