* [PATCH 0/2] more spawn improvements
@ 2019-12-30 5:04 Eric Wong
2019-12-30 5:04 ` [PATCH 1/2] spawn: support chdir via -C option Eric Wong
2019-12-30 5:04 ` [PATCH 2/2] spawn: better error handling Eric Wong
0 siblings, 2 replies; 3+ messages in thread
From: Eric Wong @ 2019-12-30 5:04 UTC (permalink / raw)
To: meta
Less code overall and improved git compatibility. Maybe one day
posix_spawn(3) can get rlimit support and we can just use that:
http://austingroupbugs.net/view.php?id=603
Eric Wong (2):
spawn: support chdir via -C option
spawn: better error handling
lib/PublicInbox/Admin.pm | 31 +++++++----------------
lib/PublicInbox/SolverGit.pm | 6 ++---
lib/PublicInbox/Spawn.pm | 48 ++++++++++++++++--------------------
lib/PublicInbox/SpawnPP.pm | 7 ++++--
4 files changed, 38 insertions(+), 54 deletions(-)
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/2] spawn: support chdir via -C option
2019-12-30 5:04 [PATCH 0/2] more spawn improvements Eric Wong
@ 2019-12-30 5:04 ` Eric Wong
2019-12-30 5:04 ` [PATCH 2/2] spawn: better error handling Eric Wong
1 sibling, 0 replies; 3+ messages in thread
From: Eric Wong @ 2019-12-30 5:04 UTC (permalink / raw)
To: meta
This simplifies our admin module a bit and allows solver to be
used with v1 inboxes using git versions prior to v1.8.5 (but
still >= git v1.8.0).
---
lib/PublicInbox/Admin.pm | 31 +++++++++----------------------
lib/PublicInbox/SolverGit.pm | 6 +++---
lib/PublicInbox/Spawn.pm | 8 ++++++--
lib/PublicInbox/SpawnPP.pm | 7 +++++--
4 files changed, 23 insertions(+), 29 deletions(-)
diff --git a/lib/PublicInbox/Admin.pm b/lib/PublicInbox/Admin.pm
index 5a3554cf..44b44b6e 100644
--- a/lib/PublicInbox/Admin.pm
+++ b/lib/PublicInbox/Admin.pm
@@ -10,6 +10,7 @@ use Cwd 'abs_path';
use base qw(Exporter);
our @EXPORT_OK = qw(resolve_repo_dir);
require PublicInbox::Config;
+use PublicInbox::Spawn qw(popen_rd);
sub resolve_repo_dir {
my ($cd, $ver) = @_;
@@ -18,28 +19,14 @@ sub resolve_repo_dir {
$$ver = 2 if $ver;
return abs_path($prefix);
}
-
- my @cmd = qw(git rev-parse --git-dir);
- my $cmd = join(' ', @cmd);
- my $pid = open my $fh, '-|';
- defined $pid or die "forking $cmd failed: $!\n";
- if ($pid == 0) {
- if (defined $cd) {
- chdir $cd or die "chdir $cd failed: $!\n";
- }
- exec @cmd;
- die "Failed to exec $cmd: $!\n";
- } else {
- my $dir = eval {
- local $/;
- <$fh>;
- };
- close $fh or die "error in $cmd (cwd:$cd): $!\n";
- chomp $dir;
- $$ver = 1 if $ver;
- return abs_path($cd) if ($dir eq '.' && defined $cd);
- abs_path($dir);
- }
+ my $cmd = [ qw(git rev-parse --git-dir) ];
+ my $fh = popen_rd($cmd, undef, {-C => $cd});
+ my $dir = do { local $/; <$fh> };
+ close $fh or die "error in ".join(' ', @$cmd)." (cwd:$cd): $!\n";
+ chomp $dir;
+ $$ver = 1 if $ver;
+ return abs_path($cd) if ($dir eq '.' && defined $cd);
+ abs_path($dir);
}
# for unconfigured inboxes
diff --git a/lib/PublicInbox/SolverGit.pm b/lib/PublicInbox/SolverGit.pm
index 03666646..c57fb4c6 100644
--- a/lib/PublicInbox/SolverGit.pm
+++ b/lib/PublicInbox/SolverGit.pm
@@ -472,7 +472,7 @@ sub do_git_apply ($) {
my $patches = $self->{patches};
# we need --ignore-whitespace because some patches are CRLF
- my @cmd = (qw(git -C), $dn, qw(apply --cached --ignore-whitespace
+ my @cmd = (qw(git apply --cached --ignore-whitespace
--unidiff-zero --whitespace=warn --verbose));
my $len = length(join(' ', @cmd));
my $total = $self->{tot};
@@ -491,8 +491,8 @@ sub do_git_apply ($) {
} while (@$patches && $len < $ARG_SIZE_MAX &&
!oids_same_ish($patches->[0]->{oid_b}, $prv_oid_b));
- my $rdr = { 2 => 1 };
- my $qsp = PublicInbox::Qspawn->new(\@cmd, $self->{git_env}, $rdr);
+ my $opt = { 2 => 1, -C => $dn };
+ my $qsp = PublicInbox::Qspawn->new(\@cmd, $self->{git_env}, $opt);
$self->{-cur_di} = $di;
$self->{-qsp} = $qsp;
$qsp->psgi_qx($self->{psgi_env}, undef, \&apply_result, $self);
diff --git a/lib/PublicInbox/Spawn.pm b/lib/PublicInbox/Spawn.pm
index 6d42d5bc..d624c521 100644
--- a/lib/PublicInbox/Spawn.pm
+++ b/lib/PublicInbox/Spawn.pm
@@ -84,7 +84,8 @@ static void xerr(const char *msg)
* whatever we'll need in the future.
* Be sure to update PublicInbox::SpawnPP if this changes
*/
-int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref)
+int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref,
+ const char *cd)
{
AV *redir = (AV *)SvRV(redirref);
AV *cmd = (AV *)SvRV(cmdref);
@@ -118,6 +119,8 @@ int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref)
}
for (sig = 1; sig < NSIG; sig++)
signal(sig, SIG_DFL); /* ignore errors on signals */
+ if (*cd && chdir(cd) < 0)
+ xerr("chdir");
max = av_len(rlim);
for (i = 0; i < max; i += 3) {
@@ -216,7 +219,8 @@ sub spawn ($;$$) {
}
push @$rlim, $r, @$v;
}
- my $pid = pi_fork_exec($redir, $f, $cmd, \@env, $rlim);
+ my $cd = $opts->{'-C'} // ''; # undef => NULL mapping doesn't work?
+ my $pid = pi_fork_exec($redir, $f, $cmd, \@env, $rlim, $cd);
$pid < 0 ? undef : $pid;
}
diff --git a/lib/PublicInbox/SpawnPP.pm b/lib/PublicInbox/SpawnPP.pm
index 2ac02c56..cd682a6b 100644
--- a/lib/PublicInbox/SpawnPP.pm
+++ b/lib/PublicInbox/SpawnPP.pm
@@ -9,8 +9,8 @@ use warnings;
use POSIX qw(dup2 :signal_h);
# Pure Perl implementation for folks that do not use Inline::C
-sub pi_fork_exec ($$$$$) {
- my ($redir, $f, $cmd, $env, $rlim) = @_;
+sub pi_fork_exec ($$$$$$) {
+ my ($redir, $f, $cmd, $env, $rlim, $cd) = @_;
my $old = POSIX::SigSet->new();
my $set = POSIX::SigSet->new();
$set->fillset or die "fillset failed: $!";
@@ -33,6 +33,9 @@ sub pi_fork_exec ($$$$$) {
dup2($parent_fd, $child_fd) or
die "dup2($parent_fd, $child_fd): $!\n";
}
+ if ($cd ne '') {
+ chdir $cd or die "chdir $cd: $!";
+ }
if ($ENV{MOD_PERL}) {
exec which('env'), '-i', @$env, @$cmd;
die "exec env -i ... $cmd->[0] failed: $!\n";
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/2] spawn: better error handling
2019-12-30 5:04 [PATCH 0/2] more spawn improvements Eric Wong
2019-12-30 5:04 ` [PATCH 1/2] spawn: support chdir via -C option Eric Wong
@ 2019-12-30 5:04 ` Eric Wong
1 sibling, 0 replies; 3+ messages in thread
From: Eric Wong @ 2019-12-30 5:04 UTC (permalink / raw)
To: meta
Since vfork always shares memory between the child and parent,
we can propagate errors to the parent errno using shared memory
instead of just dumping to stderr and hoping somebody sees it.
---
lib/PublicInbox/Spawn.pm | 42 +++++++++++++++-------------------------
1 file changed, 16 insertions(+), 26 deletions(-)
diff --git a/lib/PublicInbox/Spawn.pm b/lib/PublicInbox/Spawn.pm
index d624c521..6eea2b9c 100644
--- a/lib/PublicInbox/Spawn.pm
+++ b/lib/PublicInbox/Spawn.pm
@@ -56,26 +56,10 @@ my $vfork_spawn = <<'VFORK_SPAWN';
dst[real_len] = 0; \
} while (0)
-static void *deconst(const char *s)
-{
- union { const char *in; void *out; } u;
- u.in = s;
- return u.out;
-}
-
/* needs to be safe inside a vfork'ed process */
-static void xerr(const char *msg)
+static void exit_err(int *cerrnum)
{
- struct iovec iov[3];
- const char *err = strerror(errno); /* should be safe in practice */
-
- iov[0].iov_base = deconst(msg);
- iov[0].iov_len = strlen(msg);
- iov[1].iov_base = deconst(err);
- iov[1].iov_len = strlen(err);
- iov[2].iov_base = deconst("\n");
- iov[2].iov_len = 1;
- writev(2, iov, 3);
+ *cerrnum = errno;
_exit(1);
}
@@ -95,7 +79,7 @@ int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref,
pid_t pid;
char **argv, **envp;
sigset_t set, old;
- int ret, errnum;
+ int ret, perrnum, cerrnum = 0;
AV2C_COPY(argv, cmd);
AV2C_COPY(envp, env);
@@ -115,12 +99,12 @@ int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref,
if (parent_fd == child_fd)
continue;
if (dup2(parent_fd, child_fd) < 0)
- xerr("dup2");
+ exit_err(&cerrnum);
}
for (sig = 1; sig < NSIG; sig++)
signal(sig, SIG_DFL); /* ignore errors on signals */
if (*cd && chdir(cd) < 0)
- xerr("chdir");
+ exit_err(&cerrnum);
max = av_len(rlim);
for (i = 0; i < max; i += 3) {
@@ -132,7 +116,7 @@ int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref,
rl.rlim_cur = SvIV(*soft);
rl.rlim_max = SvIV(*hard);
if (setrlimit(SvIV(*res), &rl) < 0)
- xerr("sertlimit");
+ exit_err(&cerrnum);
}
/*
@@ -140,13 +124,19 @@ int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref,
* to the group taking out a subprocess
*/
execve(filename, argv, envp);
- xerr("execve failed");
+ exit_err(&cerrnum);
}
- errnum = errno;
+ perrnum = errno;
ret = sigprocmask(SIG_SETMASK, &old, NULL);
assert(ret == 0 && "BUG calling sigprocmask to restore");
- errno = errnum;
-
+ if (cerrnum) {
+ if (pid > 0)
+ waitpid(pid, NULL, 0);
+ pid = -1;
+ errno = cerrnum;
+ } else if (perrnum) {
+ errno = perrnum;
+ }
return (int)pid;
}
VFORK_SPAWN
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2019-12-30 5:04 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-30 5:04 [PATCH 0/2] more spawn improvements Eric Wong
2019-12-30 5:04 ` [PATCH 1/2] spawn: support chdir via -C option Eric Wong
2019-12-30 5:04 ` [PATCH 2/2] spawn: better error handling Eric Wong
Code repositories for project(s) associated with this public inbox
https://80x24.org/public-inbox.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).