parallel: Fixed security issue with -S + --fifo/--cat.

This commit is contained in:
Ole Tange 2015-05-14 17:17:02 +02:00
parent 53ebf4dcd0
commit cad4b15dab
6 changed files with 77 additions and 65 deletions

View file

@ -6263,24 +6263,29 @@ sub wrapped {
} }
} }
if($opt::cat) { if($opt::cat) {
# Prepend 'cat > {};' # Append 'unlink {} without affecting $?'
# Append 'unlink {} without affecting $?'
$command = $command =
$self->{'commandline'}->replace_placeholders(["cat > \257<\257>; "], 0, 0). $self->{'commandline'}->replace_placeholders(["cat > \257<\257>; "], 0, 0).
$command.";". postpone_exit_and_cleanup(). $command.";". postpone_exit_and_cleanup().
$self->{'commandline'}->replace_placeholders(["\257<\257>"], 0, 0); '$PARALLEL_TMP';
} elsif($opt::fifo) { } elsif($opt::fifo) {
# Prepend 'mkfifo {}; (' # Prepend 'mkfifo {}; ('
# Append ') & _PID=$!; cat > {}; wait $_PID; ' # Append ') & _PID=$!; cat > {}; wait $_PID; '
# (This makes it fail in csh, but give the correct exit code in bash) # (This makes it fail in csh, but give the correct exit code in bash)
# Append 'unlink {} without affecting $?' # Append 'unlink {} without affecting $?'
# Set $ENV{PARALLEL_TMP} when starting a job
# Set $ENV{PARALLEL_TMP} in the remote wrapper
# mkfifo $PARALLEL_TMP;
# {} = $PARALLEL_TMP;
# (...) &
# cat > $PARALLEL_TMP; wait \$_PID; cleanup $PARALLEL_TMP
# perl -e 'open($fifo,">",shift); while(read){print FIFO};unlink $fifo;waitpid($pid,0);exit $?' $! $PARALLEL_FIFO
$command = $command =
$self->{'commandline'}->replace_placeholders(["mkfifo \257<\257>;\n ("], 0, 0). "mkfifo \$PARALLEL_TMP\n (".
$command.";". $command.";".
$self->{'commandline'}->replace_placeholders([") & _PID=\$!; cat > \257<\257>; ", ') & _PID=$!; cat > $PARALLEL_TMP; wait $_PID; '.
"wait \$_PID; "]).
postpone_exit_and_cleanup(). postpone_exit_and_cleanup().
$self->{'commandline'}->replace_placeholders(["\257<\257>"], 0, 0); '$PARALLEL_TMP';
} }
# Wrap with ssh + tranferring of files # Wrap with ssh + tranferring of files
$command = $self->sshlogin_wrap($command); $command = $self->sshlogin_wrap($command);
@ -6401,7 +6406,13 @@ sub sshlogin_wrap {
$monitor_parent_sshd_script = $monitor_parent_sshd_script =
# This will be packed in ', so only use " # This will be packed in ', so only use "
::spacefree(0,'$shell = "'.($ENV{'PARALLEL_SHELL'} || '$ENV{SHELL}').'";'. ::spacefree(0,'$shell = "'.($ENV{'PARALLEL_SHELL'} || '$ENV{SHELL}').'";'.
'$tmpdir = "'.::perl_quote_scalar($ENV{'TMPDIR'}).'";'.
q{ q{
# Set $PARALLEL_TMP to a non-existent file name in $TMPDIR
do {
$ENV{PARALLEL_TMP} = $tmpdir."/par".
join"", map { (0..9,"a".."z","A".."Z")[rand(62)] } (1..5);
} while(-e $ENV{PARALLEL_TMP});
$SIG{CHLD} = sub { $done = 1; }; $SIG{CHLD} = sub { $done = 1; };
$pid = fork; $pid = fork;
unless($pid) { unless($pid) {
@ -6828,6 +6839,7 @@ sub start {
} }
$ENV{'PARALLEL_SEQ'} = $job->seq(); $ENV{'PARALLEL_SEQ'} = $job->seq();
$ENV{'PARALLEL_PID'} = $$; $ENV{'PARALLEL_PID'} = $$;
$ENV{'PARALLEL_TMP'} = ::tmpname("par");
::debug("run", $Global::total_running, " processes . Starting (", ::debug("run", $Global::total_running, " processes . Starting (",
$job->seq(), "): $command\n"); $job->seq(), "): $command\n");
if($opt::pipe) { if($opt::pipe) {
@ -6936,12 +6948,8 @@ sub print_dryrun_and_verbose {
my $self = shift; my $self = shift;
my $actual_command = shift; my $actual_command = shift;
# Temporary file name. Used for fifo to communicate exit val # Temporary file name. Used for fifo to communicate exit val
my ($fh, $tmpfifo) = ::tmpfile(SUFFIX => ".tmx"); my $tmpfifo=::tmpname("tmx");
$Global::unlink{$tmpfifo} = 1;
close $fh;
unlink $tmpfifo;
# # FIFO for communicating exit val
# my $tmpfifo = ::tmpfifo();
if(length($tmpfifo) >=100) { if(length($tmpfifo) >=100) {
::error("tmux does not support sockets with path > 100\n"); ::error("tmux does not support sockets with path > 100\n");
::wait_and_exit(255); ::wait_and_exit(255);
@ -6959,12 +6967,13 @@ sub print_dryrun_and_verbose {
my $l_act = length($actual_command); my $l_act = length($actual_command);
my $l_tit = length($title); my $l_tit = length($title);
my $l_fifo = length($tmpfifo);
# The line to run contains a 118 chars extra code + the title 2x # The line to run contains a 118 chars extra code + the title 2x
my $l_tot = 2 * $l_tit + $l_act + 30; my $l_tot = 2 * $l_tit + $l_act + $l_fifo;
while($l_tit < 1000 and while($l_tit < 1000 and
( (
(900 < $l_tot and $l_tot < 1300) (890 < $l_tot and $l_tot < 1350)
or or
(9250 < $l_tot and $l_tot < 9800) (9250 < $l_tot and $l_tot < 9800)
)) { )) {
@ -6977,7 +6986,7 @@ sub print_dryrun_and_verbose {
# 9331 < (title + whole command) < 9636 # 9331 < (title + whole command) < 9636
$title = $title.('\ 'x75); $title = $title.('\ 'x75);
$l_tit = length($title); $l_tit = length($title);
$l_tot = 2 * $l_tit + $l_act + 30; $l_tot = 2 * $l_tit + $l_act + $l_fifo;
} }
my $tmux; my $tmux;
@ -6994,7 +7003,7 @@ sub print_dryrun_and_verbose {
$Limits::Command::line_max_len, " tot ", $Limits::Command::line_max_len, " tot ",
$l_tot, "\n"); $l_tot, "\n");
return "mkfifo $tmpfifo; $tmux ". return "mkfifo $tmpfifo && $tmux ".
# Run in tmux # Run in tmux
::shell_quote_scalar ::shell_quote_scalar
( (
@ -7567,14 +7576,14 @@ sub populate {
my $max_len = $Global::minimal_command_line_length || Limits::Command::max_length(); my $max_len = $Global::minimal_command_line_length || Limits::Command::max_length();
if($opt::cat) { if($opt::cat) {
# Generate a tempfile name that will be used as {} # $PARALLEL_TMP will point to a tempfile that will be used as {}
$Global::JobQueue->{'commandlinequeue'}->{'arg_queue'}-> $Global::JobQueue->{'commandlinequeue'}->{'arg_queue'}->
unget([Arg->new(::tmpname("cat"))]); unget([Arg->new('$PARALLEL_TMP')]);
} }
if($opt::fifo) { if($opt::fifo) {
# Generate a tempfile name that will be used as {} # $PARALLEL_TMP will point to a tempfile that will be used as {}
$Global::JobQueue->{'commandlinequeue'}->{'arg_queue'}-> $Global::JobQueue->{'commandlinequeue'}->{'arg_queue'}->
unget([Arg->new(::tmpname("fif"))]); unget([Arg->new('$PARALLEL_TMP')]);
} }
while (not $self->{'arg_queue'}->empty()) { while (not $self->{'arg_queue'}->empty()) {
$next_arg = $self->{'arg_queue'}->get(); $next_arg = $self->{'arg_queue'}->get();
@ -7868,6 +7877,8 @@ sub replaced {
if(not defined $self->{'replaced'}) { if(not defined $self->{'replaced'}) {
# Don't quote arguments if the input is the full command line # Don't quote arguments if the input is the full command line
my $quote_arg = $Global::noquote ? 0 : not $Global::quoting; my $quote_arg = $Global::noquote ? 0 : not $Global::quoting;
# or if ($opt::cat or $opt::pipe) as they use $PARALLEL_TMP
$quote_arg = ($opt::cat || $opt::fifo) ? 0 : $quote_arg;
$self->{'replaced'} = $self-> $self->{'replaced'} = $self->
replace_placeholders($self->{'command'},$Global::quoting, replace_placeholders($self->{'command'},$Global::quoting,
$quote_arg); $quote_arg);

View file

@ -45,8 +45,8 @@ echo '2bug #43358: shellshock breaks exporting functions using --env'
echo '### bug #42999: --pipepart with remote does not work' echo '### bug #42999: --pipepart with remote does not work'
seq 100 > /tmp/bug42999; chmod 600 /tmp/bug42999; seq 100 > /tmp/bug42999; chmod 600 /tmp/bug42999;
parallel --sshdelay 0.3 --pipepart --block 31 -a /tmp/bug42999 -k -S parallel@lo wc; parallel --sshdelay 0.3 --pipepart --block 31 -a /tmp/bug42999 -k -S parallel@lo wc;
parallel --sshdelay 0.2 --pipepart --block 31 -a /tmp/bug42999 -k --fifo -S parallel@lo wc | perl -pe 's:(/tmp\S+fif)\S+:${1}XXXXX:' ; parallel --sshdelay 0.2 --pipepart --block 31 -a /tmp/bug42999 -k --fifo -S parallel@lo wc | perl -pe 's:(/tmp\S+par)\S+:${1}XXXXX:' ;
parallel --sshdelay 0.1 --pipepart --block 31 -a /tmp/bug42999 -k --cat -S parallel@lo wc | perl -pe 's:(/tmp\S+cat)\S+:${1}XXXXX:' ; parallel --sshdelay 0.1 --pipepart --block 31 -a /tmp/bug42999 -k --cat -S parallel@lo wc | perl -pe 's:(/tmp\S+par)\S+:${1}XXXXX:' ;
rm /tmp/bug42999 rm /tmp/bug42999
echo '### --cat gives incorrect exit value in csh' echo '### --cat gives incorrect exit value in csh'

View file

@ -46,8 +46,8 @@ echo '### bug #42041: Implement $PARALLEL_JOBSLOT'
echo '### bug #42363: --pipepart and --fifo/--cat does not work' echo '### bug #42363: --pipepart and --fifo/--cat does not work'
seq 100 > /tmp/bug42363; seq 100 > /tmp/bug42363;
parallel --pipepart --block 31 -a /tmp/bug42363 -k --fifo wc | perl -pe 's:(/tmp\S+fif).....:${1}XXXXX:'; parallel --pipepart --block 31 -a /tmp/bug42363 -k --fifo wc | perl -pe 's:(/tmp\S+par).....:${1}XXXXX:';
parallel --pipepart --block 31 -a /tmp/bug42363 -k --cat wc | perl -pe 's:(/tmp\S+cat).....:${1}XXXXX:'; parallel --pipepart --block 31 -a /tmp/bug42363 -k --cat wc | perl -pe 's:(/tmp\S+par).....:${1}XXXXX:';
rm /tmp/bug42363 rm /tmp/bug42363
echo '### bug #42055: --pipepart -a bigfile should not require sequential reading of bigfile' echo '### bug #42055: --pipepart -a bigfile should not require sequential reading of bigfile'

View file

@ -44,7 +44,7 @@ shellshock-hardened to non-shellshock-hardened
Function non-shellshock-hardened Function non-shellshock-hardened
echo '### bug #42999: --pipepart with remote does not work' echo '### bug #42999: --pipepart with remote does not work'
### bug #42999: --pipepart with remote does not work ### bug #42999: --pipepart with remote does not work
seq 100 > /tmp/bug42999; chmod 600 /tmp/bug42999; parallel --sshdelay 0.3 --pipepart --block 31 -a /tmp/bug42999 -k -S parallel@lo wc; parallel --sshdelay 0.2 --pipepart --block 31 -a /tmp/bug42999 -k --fifo -S parallel@lo wc | perl -pe 's:(/tmp\S+fif)\S+:${1}XXXXX:' ; parallel --sshdelay 0.1 --pipepart --block 31 -a /tmp/bug42999 -k --cat -S parallel@lo wc | perl -pe 's:(/tmp\S+cat)\S+:${1}XXXXX:' ; rm /tmp/bug42999 seq 100 > /tmp/bug42999; chmod 600 /tmp/bug42999; parallel --sshdelay 0.3 --pipepart --block 31 -a /tmp/bug42999 -k -S parallel@lo wc; parallel --sshdelay 0.2 --pipepart --block 31 -a /tmp/bug42999 -k --fifo -S parallel@lo wc | perl -pe 's:(/tmp\S+par)\S+:${1}XXXXX:' ; parallel --sshdelay 0.1 --pipepart --block 31 -a /tmp/bug42999 -k --cat -S parallel@lo wc | perl -pe 's:(/tmp\S+par)\S+:${1}XXXXX:' ; rm /tmp/bug42999
14 14 33 14 14 33
11 11 33 11 11 33
11 11 33 11 11 33
@ -54,24 +54,24 @@ echo '### bug #42999: --pipepart with remote does not work'
11 11 33 11 11 33
11 11 33 11 11 33
9 9 28 9 9 28
14 14 33 /tmp/parallel-local-ssh2/fifXXXXX 14 14 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/fifXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/fifXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/fifXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/fifXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/fifXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/fifXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/fifXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
9 9 28 /tmp/parallel-local-ssh2/fifXXXXX 9 9 28 /tmp/parallel-local-ssh2/parXXXXX
14 14 33 /tmp/parallel-local-ssh2/catXXXXX 14 14 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/catXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/catXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/catXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/catXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/catXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/catXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
11 11 33 /tmp/parallel-local-ssh2/catXXXXX 11 11 33 /tmp/parallel-local-ssh2/parXXXXX
9 9 28 /tmp/parallel-local-ssh2/catXXXXX 9 9 28 /tmp/parallel-local-ssh2/parXXXXX
echo '### --cat gives incorrect exit value in csh' echo '### --cat gives incorrect exit value in csh'
### --cat gives incorrect exit value in csh ### --cat gives incorrect exit value in csh
echo false | parallel --pipe --cat -Scsh@lo 'cat {}; false' ; echo $?; echo false | parallel --pipe --cat -Stcsh@lo 'cat {}; false' ; echo $?; echo true | parallel --pipe --cat -Scsh@lo 'cat {}; true' ; echo $?; echo true | parallel --pipe --cat -Stcsh@lo 'cat {}; true' ; echo $?; echo '### --cat and --fifo exit value in bash' echo false | parallel --pipe --cat -Scsh@lo 'cat {}; false' ; echo $?; echo false | parallel --pipe --cat -Stcsh@lo 'cat {}; false' ; echo $?; echo true | parallel --pipe --cat -Scsh@lo 'cat {}; true' ; echo $?; echo true | parallel --pipe --cat -Stcsh@lo 'cat {}; true' ; echo $?; echo '### --cat and --fifo exit value in bash'

View file

@ -43,25 +43,25 @@ echo '### bug #42041: Implement $PARALLEL_JOBSLOT'
2 2
echo '### bug #42363: --pipepart and --fifo/--cat does not work' echo '### bug #42363: --pipepart and --fifo/--cat does not work'
### bug #42363: --pipepart and --fifo/--cat does not work ### bug #42363: --pipepart and --fifo/--cat does not work
seq 100 > /tmp/bug42363; parallel --pipepart --block 31 -a /tmp/bug42363 -k --fifo wc | perl -pe 's:(/tmp\S+fif).....:${1}XXXXX:'; parallel --pipepart --block 31 -a /tmp/bug42363 -k --cat wc | perl -pe 's:(/tmp\S+cat).....:${1}XXXXX:'; rm /tmp/bug42363 seq 100 > /tmp/bug42363; parallel --pipepart --block 31 -a /tmp/bug42363 -k --fifo wc | perl -pe 's:(/tmp\S+par).....:${1}XXXXX:'; parallel --pipepart --block 31 -a /tmp/bug42363 -k --cat wc | perl -pe 's:(/tmp\S+par).....:${1}XXXXX:'; rm /tmp/bug42363
14 14 33 /tmp/parallel-local22/fifXXXXX 14 14 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/fifXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/fifXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/fifXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/fifXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/fifXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/fifXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/fifXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
9 9 28 /tmp/parallel-local22/fifXXXXX 9 9 28 /tmp/parallel-local22/parXXXXX
14 14 33 /tmp/parallel-local22/catXXXXX 14 14 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/catXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/catXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/catXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/catXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/catXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/catXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
11 11 33 /tmp/parallel-local22/catXXXXX 11 11 33 /tmp/parallel-local22/parXXXXX
9 9 28 /tmp/parallel-local22/catXXXXX 9 9 28 /tmp/parallel-local22/parXXXXX
echo '### bug #42055: --pipepart -a bigfile should not require sequential reading of bigfile' echo '### bug #42055: --pipepart -a bigfile should not require sequential reading of bigfile'
### bug #42055: --pipepart -a bigfile should not require sequential reading of bigfile ### bug #42055: --pipepart -a bigfile should not require sequential reading of bigfile
parallel --pipepart -a /etc/passwd -L 1 should not be run parallel --pipepart -a /etc/passwd -L 1 should not be run

View file

@ -637,6 +637,7 @@ ORACLE_SID
PARALLEL PARALLEL
PARALLEL_PID PARALLEL_PID
PARALLEL_SEQ PARALLEL_SEQ
PARALLEL_TMP
PATH PATH
PERL_MB_OPT PERL_MB_OPT
PERL_MM_OPT PERL_MM_OPT
@ -691,7 +692,7 @@ _
/bin/bash: my_func2: command not found /bin/bash: my_func2: command not found
parallel -vv -S $SERVER1 echo ::: bar parallel -vv -S $SERVER1 echo ::: bar
ssh parallel@lo exec perl\ -e\ \\\$ENV\\\{\\\"PARALLEL_PID\\\"\\\}=\\\"000000\\\"\\\;\\\$ENV\\\{\\\"PARALLEL_SEQ\\\"\\\}=\\\"1\\\"\\\;\\\$bashfunc\\\ =\\\ \\\"\\\"\\\;@ARGV=\\\"echo\\\ bar\\\"\\\;\\\$shell=\\\"\\\$ENV\\\{SHELL\\\}\\\"\\\;\\\$SIG\\\{CHLD\\\}=sub\\\{\\\$done=1\\\;\\\}\\\;\\\$pid=fork\\\;unless\\\(\\\$pid\\\)\\\{setpgrp\\\;exec\\\$shell,\\\"-c\\\",\\\(\\\$bashfunc.\\\"@ARGV\\\"\\\)\\\;die\\\"exec:\\\$\\\!\\\\n\\\"\\\;\\\}do\\\{\\\$s=\\\$s\\\<1\\\?0.001+\\\$s\\\*1.03:\\\$s\\\;select\\\(undef,undef,undef,\\\$s\\\)\\\;\\\}until\\\(\\\$done\\\|\\\|getppid==1\\\)\\\;kill\\\(SIGHUP,-\\\$\\\{pid\\\}\\\)unless\\\$done\\\;wait\\\;exit\\\(\\\$\\\?\\\&127\\\?128+\\\(\\\$\\\?\\\&127\\\):1+\\\$\\\?\\\>\\\>8\\\); ssh parallel@lo exec perl\ -e\ \\\$ENV\\\{\\\"PARALLEL_PID\\\"\\\}=\\\"000000\\\"\\\;\\\$ENV\\\{\\\"PARALLEL_SEQ\\\"\\\}=\\\"1\\\"\\\;\\\$bashfunc\\\ =\\\ \\\"\\\"\\\;@ARGV=\\\"echo\\\ bar\\\"\\\;\\\$shell=\\\"\\\$ENV\\\{SHELL\\\}\\\"\\\;\\\$tmpdir=\\\"/tmp/parallel-tutorial\\\"\\\;do\\\{\\\$ENV\\\{PARALLEL_TMP\\\}=\\\$tmpdir.\\\"/par\\\".join\\\"\\\",map\\\{\\\(0..9,\\\"a\\\"..\\\"z\\\",\\\"A\\\"..\\\"Z\\\"\\\)\\\[rand\\\(62\\\)\\\]\\\}\\\(1..5\\\)\\\;\\\}while\\\(-e\\\$ENV\\\{PARALLEL_TMP\\\}\\\)\\\;\\\$SIG\\\{CHLD\\\}=sub\\\{\\\$done=1\\\;\\\}\\\;\\\$pid=fork\\\;unless\\\(\\\$pid\\\)\\\{setpgrp\\\;exec\\\$shell,\\\"-c\\\",\\\(\\\$bashfunc.\\\"@ARGV\\\"\\\)\\\;die\\\"exec:\\\$\\\!\\\\n\\\"\\\;\\\}do\\\{\\\$s=\\\$s\\\<1\\\?0.001+\\\$s\\\*1.03:\\\$s\\\;select\\\(undef,undef,undef,\\\$s\\\)\\\;\\\}until\\\(\\\$done\\\|\\\|getppid==1\\\)\\\;kill\\\(SIGHUP,-\\\$\\\{pid\\\}\\\)unless\\\$done\\\;wait\\\;exit\\\(\\\$\\\?\\\&127\\\?128+\\\(\\\$\\\?\\\&127\\\):1+\\\$\\\?\\\>\\\>8\\\);
bar bar
my_func3() { my_func3() {
echo in my_func $1 > $1.out echo in my_func $1 > $1.out