Index: lib/TWiki.pm =================================================================== --- lib/TWiki.pm (revision 3241) +++ lib/TWiki.pm (working copy) @@ -2439,6 +2439,41 @@ return $text; } +# {{{ run_process + +=pod + +=head2 run_process + + $lines=&run_process('command','option_1','option_2'); + + or + + $lines=&run_process(@command_args); + + Starts the job without invoking the shell. Each option has to be a + single element of the list passed. + +=cut + +sub run_process { + my (@command_args)=@_; + my(@result)=(); + if (open(JOB, "-|")) { + while () { + #chomp; + push(@result, $_); + } + close JOB; + } else { + exec { $command_args[0] } @command_args; + } + + #warn "start_job args \n" . join " ",@command_args; + #warn "start_job res @result, error code $?\n"; + @result; +} + =end twiki =cut Index: lib/TWiki.cfg =================================================================== --- lib/TWiki.cfg (revision 3241) +++ lib/TWiki.cfg (working copy) @@ -48,22 +48,22 @@ # 'c:\foo'. # URL for TWiki host (e.g. "http://myhost.com:123") -$defaultUrlHost = "http://your.domain.com"; +$defaultUrlHost = "http://localhost"; # %SCRIPTURLPATH% : cgi-bin URL path for TWiki: -$scriptUrlPath = "/twiki/bin"; +$scriptUrlPath = "/DEVELOP/bin"; # %PUBURLPATH% : Public data URL path for TWiki (root of attachments) : -$pubUrlPath = "/twiki/pub"; +$pubUrlPath = "/DEVELOP/pub"; # Public data directory (file path not URL), must match $pubUrlPath : -$pubDir = "/home/httpd/twiki/pub"; +$pubDir = "/usr/local/twiki/DEVELOP/pub"; # Template directory : -$templateDir = "/home/httpd/twiki/templates"; +$templateDir = "/usr/local/twiki/DEVELOP/templates"; # Data (topic files) root directory (file path not URL): -$dataDir = "/home/httpd/twiki/data"; +$dataDir = "/usr/local/twiki/DEVELOP/data"; # Log directory for log files, debug and warning files. Default "$dataDir" : $logDir = "$dataDir"; @@ -195,7 +195,7 @@ $useRcsDir = "0"; # This should enable gathering of extra error information on most OSes. However, won't work on NT4 unless unix like shell is used $endRcsCmd = ""; -$endRcsCmd = " 2>&1" if( $OS eq "UNIX" ); +#$endRcsCmd = " 2>&1" if( $OS eq "UNIX" ); # Command quote ' for unix, \" for Windows $cmdQuote = "'"; $cmdQuote = "\"" if( $OS eq "WINDOWS" ); @@ -308,19 +308,19 @@ useRcsDir => $TWiki::useRcsDir, # Rcs only - initBinaryCmd => "$rcsDir/rcs $rcsArg -q -i -t-none -kb %FILENAME% $endRcsCmd", - tmpBinaryCmd => "$rcsDir/rcs $rcsArg -q -kb %FILENAME% $endRcsCmd", - ciCmd => "$rcsDir/ci $rcsArg -q -l -m$cmdQuote%COMMENT%$cmdQuote -t-none -w$cmdQuote%USERNAME%$cmdQuote %FILENAME% $endRcsCmd", - coCmd => "$rcsDir/co $rcsArg -q -p%REVISION% $keywordMode %FILENAME% $endRcsCmd", - histCmd => "$rcsDir/rlog $rcsArg -h %FILENAME% $endRcsCmd", - infoCmd => "$rcsDir/rlog $rcsArg -r%REVISION% %FILENAME% $endRcsCmd", - diffCmd => "$rcsDir/rcsdiff $rcsArg -q -w -B -r%REVISION1% -r%REVISION2% $keywordMode --unified=%CONTEXT% %FILENAME% $endRcsCmd", - breakLockCmd => "$rcsDir/rcs $rcsArg -q -l -M %FILENAME% $endRcsCmd", - ciDateCmd => "$rcsDir/ci -l $rcsArg -q -mnone -t-none -d$cmdQuote%DATE%$cmdQuote -w$cmdQuote%USERNAME%$cmdQuote %FILENAME% $endRcsCmd", - delRevCmd => "$rcsDir/rcs $rcsArg -q -o%REVISION% %FILENAME% $endRcsCmd", - unlockCmd => "$rcsDir/rcs $rcsArg -q -u %FILENAME% $endRcsCmd", - lockCmd => "$rcsDir/rcs $rcsArg -q -l %FILENAME% $endRcsCmd", - tagCmd => "$rcsDir/rcs $rcsArg -N%TAG%:%REVISION% %FILENAME% $endRcsCmd", + initBinaryCmd => ["$rcsDir/rcs", "$rcsArg", "-q", "-i","-t-none","-kb","%FILENAME%", "$endRcsCmd"], + tmpBinaryCmd => ["$rcsDir/rcs","$rcsArg","-q","-kb","%FILENAME%","$endRcsCmd"], + ciCmd => ["$rcsDir/ci","$rcsArg","-q","-l","-m%COMMENT%","-t-none","-w%USERNAME%","%FILENAME%", "$endRcsCmd"], + coCmd => ["$rcsDir/co","$rcsArg","-q","-p%REVISION%","$keywordMode","%FILENAME%","$endRcsCmd]", + histCmd => ["$rcsDir/rlog","$rcsArg","-h","%FILENAME%","$endRcsCmd"], + infoCmd => ["$rcsDir/rlog","$rcsArg","-r%REVISION%","%FILENAME%","$endRcsCmd"], + diffCmd => ["$rcsDir/rcsdiff","$rcsArg","-q","-w","-B","-r%REVISION1%","-r%REVISION2%","$keywordMode","--unified=%CONTEXT%","%FILENAME%","$endRcsCmd"], + breakLockCmd => ["$rcsDir/rcs","$rcsArg","-q","-l","-M","%FILENAME%","$endRcsCmd"], + ciDateCmd => ["$rcsDir/ci","-l","$rcsArg","-q","-mnone","-t-none","-d$cmdQuote%DATE%$cmdQuote","-w$cmdQuote%USERNAME%$cmdQuote","%FILENAME%","$endRcsCmd"], + delRevCmd => ["$rcsDir/rcs","$rcsArg","-q","-o%REVISION%","%FILENAME%","$endRcsCmd"], + unlockCmd => ["$rcsDir/rcs","$rcsArg","-q","-u","%FILENAME%","$endRcsCmd"], + lockCmd => ["$rcsDir/rcs","$rcsArg","-q","-l","%FILENAME%","$endRcsCmd"], + tagCmd => ["$rcsDir/rcs","$rcsArg","-N%TAG%:%REVISION%","%FILENAME%","$endRcsCmd"], ); # Regex security filter for web name, topic name, user name : Index: lib/TWiki/Search.pm =================================================================== --- lib/TWiki/Search.pm (revision 3241) +++ lib/TWiki/Search.pm (working copy) @@ -960,6 +960,8 @@ $tempVal =~ s/\$formfield\(\s*([^\)]*)\s*\)/getMetaFormField( $meta, $1 )/geos; $tempVal =~ s/\$formname/_getMetaFormName( $meta )/geos; $tempVal =~ s/\$pattern\((.*?\s*\.\*)\)/getTextPattern( $text, $1 )/geos; + TWiki::writeLog( "XX pattern","<<$1>>","<<$text>>" ); + $tempVal =~ s/\r?\n/$newLine/gos if( $newLine ); if( $theSeparator ) { $tempVal .= $theSeparator; Index: lib/TWiki/Store/RcsWrap.pm =================================================================== --- lib/TWiki/Store/RcsWrap.pm (revision 3241) +++ lib/TWiki/Store/RcsWrap.pm (working copy) @@ -105,14 +105,18 @@ sub _binaryChange { my( $self ) = @_; + my (@ncmd,$cmd); + if( $self->getBinary() ) { # Can only do something when changing to binary - my $cmd = $self->{"initBinaryCmd"}; + # $rcsDir/rcs $rcsArg -q -i -t-none -kb %FILENAME% $endRcsCmd + my @cmd = @{$self->{"initBinaryCmd"}}; my $file = $self->file(); - $cmd =~ s/%FILENAME%/$cmdQuote$file$cmdQuote/go; - $cmd =~ /(.*)/; - $cmd = "$1"; # safe, so untaint variable - my $rcsOutput = `$cmd`; + foreach $cmd (@cmd) { + $cmd =~ s/%FILENAME%/$file/go; + push @ncmd,$cmd; + } + my $rcsOutput = TWiki::run_process(@ncmd); my $exit = $? >> 8; #_traceExec( $cmd, $rcsOutput, $exit ); if( $exit && $rcsOutput ) { @@ -163,9 +167,10 @@ my $rev = $self->numRevisions(); my $file = $self->{file}; my $rcsFile = $self->{rcsFile}; - my $cmd; + my @cmd; my $rcsOut; - + my (@ncmd,$cmd); + # update repository with same userName and date if( $rev == 1 ) { # initial revision, so delete repository file and start again @@ -174,21 +179,29 @@ $self->_deleteRevision( $rev ); } $self->_saveFile( $self->file(), $text ); - $cmd = $self->{ciDateCmd}; + @cmd = @{$self->{ciDateCmd}}; $date = TWiki::formatTime( $date , "\$rcs", "gmtime"); - $cmd =~ s/%DATE%/$date/; - $cmd =~ s/%USERNAME%/$user/; + $file =~ s/$TWiki::securityFilter//go; $rcsFile =~ s/$TWiki::securityFilter//go; - $cmd =~ s/%FILENAME%/$cmdQuote$file$cmdQuote $cmdQuote$rcsFile$cmdQuote/; - $cmd =~ /(.*)/; - $cmd = $1; # safe, so untaint variable - $rcsOut = `$cmd`; + foreach $cmd (@cmd) { + $cmd =~ s/%DATE%/$date/; + $cmd =~ s/%USERNAME%/$user/; + if ($cmd =~ m/%FILENAME%/ ) { + push @ncmd,$file; + push @ncmd,$rcsFile; + next; + } + push @ncmd,$cmd; + } + + $rcsOut = TWiki::run_process(@cmd); + # FJH FIXME $? should contain exit code of last child process my $exit = $? >> 8; #_traceExec( $cmd, $rcsOut, $exit ); #$rcsOut =~ s/^Warning\: missing newline.*//os; # forget warning if( $exit ) { - $rcsOut = "$cmd\n$rcsOut"; + $rcsOut = "@ncmd\n$rcsOut"; return $rcsOut; } return ""; @@ -215,28 +228,44 @@ sub _deleteRevision { my( $self, $rev ) = @_; - + my (@ncmd,$cmd); + # delete latest revision (unlock, delete revision, lock) my $file = $self->{file}; my $rcsFile = $self->{rcsFile}; - my $cmd= $self->{unlockCmd}; - $cmd =~ s/%FILENAME%/$cmdQuote$file$cmdQuote $cmdQuote$rcsFile$cmdQuote/go; - $cmd =~ /(.*)/; - $cmd = $1; # safe, so untaint - my $rcsOut = `$cmd`; # capture stderr + my @cmd= @{$self->{unlockCmd}}; + foreach $cmd (@cmd) { + if ($cmd =~ m/%FILENAME%/ ) { + push @ncmd,$file; + push @ncmd,$rcsFile; + next; + } + push @ncmd,$cmd; + } + # FJH FIXME: what does # capture stderr mean + my $rcsOut = TWiki::run_process(@ncmd); # capture stderr my $exit = $? >> 8; #_traceExec( $cmd, $rcsOut, $exit ); #$rcsOut =~ s/^Warning\: missing newline.*//os; # forget warning if( $exit ) { - $rcsOut = "$cmd\n$rcsOut"; + $rcsOut = "@ncmd\n$rcsOut"; return $rcsOut; } - $cmd= $self->{delRevCmd}; - $cmd =~ s/%REVISION%/1.$rev/go; - $cmd =~ s/%FILENAME%/$cmdQuote$file$cmdQuote $cmdQuote$rcsFile$cmdQuote/go; - $cmd =~ /(.*)/; - $cmd = $1; # safe, so untaint variable - $rcsOut = `$cmd`; + + @cmd= @{$self->{delRevCmd}}; + @ncmd =(); + foreach $cmd (@cmd) { + $cmd =~ s/%REVISION%/1.$rev/go; + if ($cmd =~ m/%FILENAME%/ ) { + push @ncmd,$file; + push @ncmd,$rcsFile; + next; + } + push @ncmd,$cmd; + } + + + $rcsOut = TWiki::run_process( @ncmd); $exit = $? >> 8; #_traceExec( $cmd, $rcsOut, $exit ); #$rcsOut =~ s/^Warning\: missing newline.*//os; # forget warning @@ -244,16 +273,23 @@ $rcsOut = "$cmd\n$rcsOut"; return $rcsOut; } - $cmd= $self->{lockCmd}; - $cmd =~ s/%REVISION%/$rev/go; - $cmd =~ s/%FILENAME%/$cmdQuote$file$cmdQuote $cmdQuote$rcsFile$cmdQuote/go; - $cmd =~ /(.*)/; - $cmd = $1; # safe, so untaint variable - $rcsOut = `$cmd`; + @cmd= @{$self->{lockCmd}}; + @ncmd =(); + foreach $cmd (@cmd) { + $cmd =~ s/%REVISION%/$rev/go; + if ($cmd =~ m/%FILENAME%/ ) { + push @ncmd,$file; + push @ncmd,$rcsFile; + next; + } + push @ncmd,$cmd; + } + + $rcsOut = TWiki::run_process(@ncmd); #_traceExec( $cmd, $rcsOut, $exit ); #$rcsOut =~ s/^Warning\: missing newline.*//os; # forget warning if( $exit ) { - $rcsOut = "$cmd\n$rcsOut"; + $rcsOut = "@ncmd\n$rcsOut"; return $rcsOut; } } @@ -270,10 +306,11 @@ sub getRevision { my( $self, $version ) = @_; + my (@ncmd,$cmd); my $tmpfile = ""; my $tmpRevFile = ""; - my $cmd = $self->{"coCmd"}; + my @cmd = @{$self->{"coCmd"}}; my $file = $self->file(); if( $TWiki::OS eq "WINDOWS" ) { # Need to take temporary copy of topic, check it out to file, then read that @@ -282,20 +319,25 @@ $tmpfile = $self->_mkTmpFilename(); $tmpRevFile = "$tmpfile,v"; copy( $self->rcsFile(), $tmpRevFile ); - my $cmd1 = $self->{tmpBinaryCmd}; - $cmd1 =~ s/%FILENAME%/$cmdQuote$tmpRevFile$cmdQuote/; - $cmd1 =~ /(.*)/; - $cmd1 = "$1"; - my $tmp = `$cmd1`; + my @cmd1 = @{$self->{tmpBinaryCmd}}; + foreach $cmd (@cmd1) { + $cmd =~ s/%FILENAME%/$cmdQuote$tmpRevFile$cmdQuote/; + push @ncmd,$cmd; + } + + my $tmp = TWiki::run_process( @ncmd); #_traceExec( $cmd1, $tmp ); $file = $tmpfile; - $cmd =~ s/-p%REVISION%/-r%REVISION%/; + #$cmd =~ s/-p%REVISION%/-r%REVISION%/; } - $cmd =~ s/%REVISION%/1.$version/; - $cmd =~ s/%FILENAME%/$cmdQuote$file$cmdQuote/; - $cmd =~ /(.*)/; - $cmd = "$1"; # untaint - my $text = `$cmd`; + foreach $cmd (@cmd) { + $cmd =~ s/-p%REVISION%/-r%REVISION%/ if( $TWiki::OS eq "WINDOWS" ); + $cmd =~ s/%REVISION%/1.$version/; + $cmd =~ s/%FILENAME%/$cmdQuote$file$cmdQuote/; + push @ncmd,$cmd; + } + + my $text = TWiki::run_process( TWiki::split_job(@ncmd)); if( $tmpfile ) { $text = $self->_readFile( $tmpfile ); $tmpfile =~ /(.*)/; @@ -321,21 +363,24 @@ sub numRevisions { my( $self ) = @_; - my $cmd= $self->{"histCmd"}; + my (@ncmd,$cmd); + + my @cmd= @{$self->{"histCmd"}}; my $rcsFile = $self->rcsFile(); if( ! -e $rcsFile ) { return ""; } + foreach $cmd (@cmd) { + $cmd =~ s/%FILENAME%/$rcsFile/; + push @ncmd,$cmd; + } - $cmd =~ s/%FILENAME%/$cmdQuote$rcsFile$cmdQuote/; - $cmd =~ /(.*)/; - $cmd = $1; # now safe, so untaint variable - my $rcsOutput = `$cmd`; + my $rcsOutput = TWiki::run_process(@ncmd); #_traceExec( $cmd, $rcsOutput ); if( $rcsOutput =~ /head:\s+\d+\.(\d+)\n/ ) { return $1; } else { - return ""; # Note this hides possible errors + return ""; # Note this hides possible errors FIXME } } @@ -370,11 +415,14 @@ my $rcsError = ""; my( $dummy, $rev, $date, $user, $comment ); if ( -e $rcsFile ) { - my $cmd= $self->{infoCmd}; - $cmd =~ s/%REVISION%/$version/; - $cmd =~ s/%FILENAME%/$cmdQuote$rcsFile$cmdQuote/; - $cmd =~ /(.*)/; $cmd = $1; # Untaint - my $rcsOut = `$cmd`; + my @cmd= @{$self->{infoCmd}}; + my (@ncmd,$cmd); + foreach $cmd (@cmd) { + $cmd =~ s/%REVISION%/$version/; + $cmd =~ s/%FILENAME%/$rcsFile/; + push @ncmd,$cmd; + } + my $rcsOut = TWiki::run_process(@ncmd); my $exit = $? >> 8; #_traceExec( $cmd, $cmd, $exit ); $rcsError = "Error with $cmd, output: $rcsOut" if( $exit ); @@ -410,7 +458,8 @@ sub revisionDiff { my( $self, $rev1, $rev2, $contextLines ) = @_; - + my (@ncmd,$cmd,@tmp); + my $error = ""; my $tmp= ""; @@ -421,17 +470,18 @@ $tmp = "$tmp> $_\n"; } } else { - $tmp= $self->{"diffCmd"}; - $tmp =~ s/%REVISION1%/1.$rev1/; - $tmp =~ s/%REVISION2%/1.$rev2/; + @tmp= @{$self->{"diffCmd"}}; my $rcsFile = $self->rcsFile(); $rcsFile =~ s/$TWiki::securityFilter//go; - $tmp =~ s/%FILENAME%/$cmdQuote$rcsFile$cmdQuote/; $contextLines = "" unless defined($contextLines); - $tmp =~ s/%CONTEXT%/$contextLines/; - $tmp =~ /(.*)/; - my $cmd = $1; # now safe, so untaint variable - $tmp = `$cmd`; + foreach $tmp (@tmp) { + $tmp =~ s/%REVISION1%/1.$rev1/; + $tmp =~ s/%REVISION2%/1.$rev2/; + $tmp =~ s/%FILENAME%/$rcsFile/; + $tmp =~ s/%CONTEXT%/$contextLines/; + push @ncmd,$tmp; + } + $tmp = TWiki::run_process(@ncmd); my $exit = $? >> 8; $error = "Error $exit when runing $cmd"; #_traceExec( $cmd, $tmp, $exit ); @@ -521,29 +571,39 @@ # on directory tree) return "$file is not writable" unless ( -w $file ); - my $cmd = $self->{"ciCmd"}; + my @cmd = @{ $self->{"ciCmd"} }; + my (@ncmd,$cmd); my $rcsOutput = ""; - $cmd =~ s/%USERNAME%/$userName/; $file =~ s/$TWiki::securityFilter//go; - $cmd =~ s/%FILENAME%/$cmdQuote$file$cmdQuote/; $comment = "none" unless( $comment ); $comment =~ s/[\"\'\`\;]//go; # security, Codev.NoShellCharacterEscapingInFileAttachComment, MikeSmith - $cmd =~ s/%COMMENT%/$comment/; - $cmd =~ /(.*)/; - $cmd = $1; # safe, so untaint variable - $rcsOutput = `$cmd`; # capture stderr (S.Knutson) + foreach $cmd (@cmd) { + $cmd =~ s/%COMMENT%/$comment/; + $cmd =~ s/%USERNAME%/$userName/; + $cmd =~ s/%FILENAME%/$file/; + push @ncmd,$cmd; + } + + # FJH FIXME capture stderr (S.Knutson) what does this mean? + $rcsOutput = TWiki::run_process( @ncmd ); # capture stderr (S.Knutson) + # FJH FIXME check if exit code works my $exit = $? >> 8; #_traceExec( $cmd, $rcsOutput ); if( $exit && $rcsOutput =~ /no lock set by/ ) { # Try and break lock, setting new one and doing ci again - my $cmd = $self->{"breakLockCmd"}; - $cmd =~ s/%FILENAME%/$cmdQuote$file$cmdQuote/go; - $cmd =~ /(.*)/; - my $out = `$cmd`; + my @cmd = @{$self->{"breakLockCmd"}}; + @ncmd=(); + foreach $cmd (@cmd) { + $cmd =~ s/%FILENAME%/$file/go; + push @ncmd,$cmd; + } + my $out = TWiki::run_process(@ncmd); #_traceExec( $cmd, $out ); # Assume it worked, as not sure how to trap failure - $rcsOutput = `$cmd`; # capture stderr (S.Knutson) + # FJH FIXME the line above looks brave! Why is the breakLockCmd executed twice? + # FJH FIXME 'capture stderr' what does this mean? + $rcsOutput = TWiki::run_process(@ncmd );# capture stderr (S.Knutson) $exit = $? >> 8; #_traceExec( $cmd, $rcsOutput ); if( ! $exit ) { @@ -578,13 +638,18 @@ my $file = $self->{file}; if ( -e $file ) { - my $cmd= $self->{tagCmd}; - $cmd =~ s/%REVISION%/$rev/; - $cmd =~ s/%FILENAME%/$cmdQuote$file$cmdQuote/; - $cmd =~ s/%TAG%/$tag/; - $cmd = $cmd." 2>> $TWiki::warningFilename"; - $cmd =~ /(.*)/; $cmd = $1; # Untaint - my $rcsOut = `$cmd`; + my @cmd= @{$self->{tagCmd}}; + my (@ncmd ,$cmd); + @ncmd=(); + foreach $cmd (@cmd) { + $cmd =~ s/%REVISION%/$rev/; + $cmd =~ s/%FILENAME%/$file/; + $cmd =~ s/%TAG%/$tag/; + #$cmd = $cmd." 2>> $TWiki::warningFilename"; FIXME IO REDIRECTION + push @ncmd,$cmd; + } + + my $rcsOut = TWiki::run_process( @ncmd); my $exit = $? >> 8; #_traceExec( $cmd, $cmd, $exit ); if( $exit && $rcsOut ) { # oops, stderr was not empty, return error @@ -592,7 +657,7 @@ TWiki:writeDebug("RCSWrap::setTopicRevisionTag error - $rcsOut"); return 0; } - } + } return 1; }