| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | #!/usr/bin/perl | 
| 2 | 1 |  |  | 1 |  | 20624 | use strict; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 48 |  | 
| 3 |  |  |  |  |  |  | #use warnings; | 
| 4 |  |  |  |  |  |  | #use diagnostics -verbose; | 
| 5 |  |  |  |  |  |  | ## no critic (TestingAndDebugging::RequireUseWarnings) | 
| 6 |  |  |  |  |  |  | package FCGI::Daemon; | 
| 7 |  |  |  |  |  |  | our $VERSION = '0.20151226'; | 
| 8 | 1 |  |  | 1 |  | 13 | use 5.14.2; | 
|  | 1 |  |  |  |  | 3 |  | 
| 9 | 1 |  |  | 1 |  | 10095 | use English '-no_match_vars'; | 
|  | 1 |  |  |  |  | 4611 |  | 
|  | 1 |  |  |  |  | 7 |  | 
| 10 | 1 |  |  | 1 |  | 1337 | use BSD::Resource;                      # on Debian available as libbsd-resource-perl | 
|  | 1 |  |  |  |  | 42523 |  | 
|  | 1 |  |  |  |  | 5 |  | 
| 11 | 1 |  |  | 1 |  | 1160 | use FCGI 0.71;                          # on Debian available as libfcgi-perl | 
|  | 1 |  |  |  |  | 1084 |  | 
|  | 1 |  |  |  |  | 31 |  | 
| 12 | 1 |  |  | 1 |  | 893 | use FCGI::ProcManager 0.18;             # on Debian available as libfcgi-procmanager-perl | 
|  | 1 |  |  |  |  | 12331 |  | 
|  | 1 |  |  |  |  | 52 |  | 
| 13 | 1 |  |  | 1 |  | 13099 | use Getopt::Std; | 
|  | 1 |  |  |  |  | 45 |  | 
|  | 1 |  |  |  |  | 75 |  | 
| 14 | 1 |  |  | 1 |  | 1372 | use autouse 'Pod::Usage'=>qw(pod2usage); | 
|  | 1 |  |  |  |  | 1032 |  | 
|  | 1 |  |  |  |  | 9 |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | =head1 NAME | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | FCGI::Daemon - Perl-aware Fast CGI daemon for use with nginx web server. | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | =head1 VERSION | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | Version 0.20111121 | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | =begin comment | 
| 25 |  |  |  |  |  |  | =cut | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | my %o; | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | __PACKAGE__->run() unless caller();     # modulino i.e. executable rather than module | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | =head2 help() | 
| 32 |  |  |  |  |  |  | print help screen extracted from POD | 
| 33 |  |  |  |  |  |  | =cut | 
| 34 | 0 | 0 |  | 0 | 1 |  | sub help { pod2usage(-verbose=>$ARG[0],-noperldoc=>1) and exit; }       ## no critic | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | =head2 dieif() | 
| 37 |  |  |  |  |  |  | exit handler | 
| 38 |  |  |  |  |  |  | =cut | 
| 39 |  |  |  |  |  |  | sub dieif { | 
| 40 | 0 | 0 |  | 0 | 1 |  | if($ARG[0]){ | 
| 41 | 0 |  |  |  |  |  | my $err=$ARG[1]; | 
| 42 | 0 |  |  |  |  |  | unlink @o{'pidfile','sockfile'}; | 
| 43 | 0 |  |  |  |  |  | print "Error - $err:\n",$ARG[0],"\n"; | 
| 44 | 0 |  |  |  |  |  | exit 1; | 
| 45 |  |  |  |  |  |  | } | 
| 46 |  |  |  |  |  |  | } | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | =head2 run() | 
| 49 |  |  |  |  |  |  | Modulino-style main routine | 
| 50 |  |  |  |  |  |  | =cut | 
| 51 |  |  |  |  |  |  | sub run { | 
| 52 | 0 | 0 |  | 0 | 1 |  | getopts('hde:f:q:p:s:g:u:m:c:l:w:',\%o) or help(0); | 
| 53 | 0 | 0 |  |  |  |  | help(2) if $o{'h'}; | 
| 54 |  |  |  |  |  |  |  | 
| 55 | 0 |  | 0 |  |  |  | $o{sockfile}=$o{'s'}||'/var/run/fcgi-daemon.sock'; | 
| 56 | 0 | 0 | 0 |  |  |  | $o{pidfile}=$o{'p'}||'/var/run/fcgi-daemon.pid' if $o{'d'}; | 
| 57 | 0 | 0 |  |  |  |  | $o{prefork}=defined $o{'w'} ? $o{'w'} : 1; | 
| 58 | 0 | 0 |  |  |  |  | $o{queue}=defined $o{'q'} ? $o{'q'} : 96; | 
| 59 | 0 |  | 0 |  |  |  | $o{rlimit_vmem}=($o{'m'}||512)*1024*1024; | 
| 60 | 0 |  | 0 |  |  |  | $o{rlimit_cpu}=$o{'c'}||32; | 
| 61 | 0 | 0 |  |  |  |  | $o{max_evals}=defined $o{'e'} ? $o{'e'} : 10240;   #max evals before exit - paranoid to free memory if leaks | 
| 62 | 0 |  | 0 |  |  |  | $o{file_pattern}=$o{'f'}||qr{\.pl}; | 
| 63 | 0 |  | 0 |  |  |  | $o{leak_threshold}=$o{'l'}||1.3; | 
| 64 |  |  |  |  |  |  |  | 
| 65 | 0 | 0 | 0 |  |  |  | if($REAL_USER_ID==$EFFECTIVE_USER_ID and $EFFECTIVE_USER_ID==0){        # if run as root | 
| 66 | 0 |  | 0 |  |  |  | $o{gid}=$o{g}||'www-data'; $o{gid_num}=scalar getgrnam($o{gid}); | 
|  | 0 |  |  |  |  |  |  | 
| 67 | 0 |  | 0 |  |  |  | $o{uid}=$o{u}||'www-data'; $o{uid_num}=scalar getpwnam($o{uid}); | 
|  | 0 |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | local $SIG{INT}= local $SIG{TERM}= sub{ | 
| 71 |  |  |  |  |  |  | # actually FCGI::ProcManager override our TERM handler so .sock and .pid files will be removed only by sysv script... :( | 
| 72 | 0 | 0 |  | 0 |  |  | $o{fcgi_pm}->pm_remove_pid_file() if $o{fcgi_pm}; | 
| 73 | 0 |  |  |  |  |  | unlink @o{'sockfile','pidfile'}; | 
| 74 | 0 | 0 |  |  |  |  | $o{fcgi_pm}->pm_die() if $o{fcgi_pm};   #pm_die() does not return | 
| 75 | 0 |  |  |  |  |  | exit 0; | 
| 76 | 0 |  |  |  |  |  | }; | 
| 77 |  |  |  |  |  |  |  | 
| 78 |  |  |  |  |  |  | # daemonize | 
| 79 | 0 | 0 |  |  |  |  | if($o{'d'}){ | 
| 80 | 0 |  |  |  |  |  | chdir '/';                              # this is good practice for unmounting | 
| 81 | 0 |  |  |  |  |  | local $PROGRAM_NAME='FCGI::Daemon'; | 
| 82 | 0 | 0 |  |  |  |  | defined(my $pid=fork) or die "Can't fork: $!"; | 
| 83 | 0 | 0 |  |  |  |  | exit if $pid; | 
| 84 | 1 | 0 |  | 1 |  | 644 | eval {use POSIX qw(setsid); POSIX::setsid();} or die q{Can't start a new session: }.$OS_ERROR; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 12 |  | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 85 | 0 |  |  |  |  |  | open *STDIN,'<','/dev/null'; | 
| 86 | 0 |  |  |  |  |  | open *STDOUT,'>>','/dev/null'; | 
| 87 | 0 |  |  |  |  |  | open *STDERR,'>>','/dev/null'; | 
| 88 | 0 |  |  |  |  |  | umask 022; | 
| 89 |  |  |  |  |  |  | } | 
| 90 |  |  |  |  |  |  |  | 
| 91 | 0 |  |  |  |  |  | my %req_env; | 
| 92 |  |  |  |  |  |  | $o{fcgi_pm}=FCGI::ProcManager->new({n_processes=>$o{prefork}, | 
| 93 |  |  |  |  |  |  | die_timeout=>28, | 
| 94 |  |  |  |  |  |  | pid_fname=>$o{pidfile} | 
| 95 | 0 |  |  |  |  |  | }); | 
| 96 | 0 |  |  |  |  |  | print "Opening socket $o{sockfile}\n"; | 
| 97 |  |  |  |  |  |  | my $rqst=FCGI::Request(\*STDIN,\*STDOUT,\*STDERR,\%req_env, | 
| 98 | 0 | 0 |  |  |  |  | FCGI::OpenSocket($o{sockfile},$o{prefork}*$o{queue}), | 
| 99 |  |  |  |  |  |  | FCGI::FAIL_ACCEPT_ON_INTR()) | 
| 100 |  |  |  |  |  |  | or die "Error: Unable to create FCGI::Request..."; | 
| 101 |  |  |  |  |  |  |  | 
| 102 | 0 | 0 | 0 |  |  |  | if(defined $o{gid_num} and defined $o{uid_num}){                # if run as root | 
| 103 |  |  |  |  |  |  | chown $o{uid_num},$o{gid_num},$o{sockfile}                  # chown SOCKfile | 
| 104 | 0 | 0 |  |  |  |  | or dieif($OS_ERROR,'Unable to chown SOCKfile'); | 
| 105 |  |  |  |  |  |  | } | 
| 106 |  |  |  |  |  |  |  | 
| 107 | 0 |  |  |  |  |  | $o{fcgi_pm}->pm_manage();   # from now on we are worker process | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | # drop privileges if run as root | 
| 110 | 0 | 0 | 0 |  |  |  | if(defined $o{gid_num} and defined $o{uid_num}){ | 
| 111 | 0 |  |  |  |  |  | local $REAL_GROUP_ID= local $EFFECTIVE_GROUP_ID= getgrnam($o{gid}); | 
| 112 | 0 |  |  |  |  |  | dieif($OS_ERROR,'Unable to change group_id to '.$o{gid}); | 
| 113 | 0 |  |  |  |  |  | local $REAL_USER_ID= local $EFFECTIVE_USER_ID= getpwnam($o{uid}); | 
| 114 | 0 |  |  |  |  |  | dieif($OS_ERROR,'Unable to change user_id to '.$o{uid}); | 
| 115 |  |  |  |  |  |  | } | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | ## set rlimit(s) | 
| 118 |  |  |  |  |  |  | setrlimit(RLIMIT_AS, $o{rlimit_vmem}, $o{rlimit_vmem}) | 
| 119 | 0 | 0 |  |  |  |  | or warn "Unable to set RLIMIT_AS.\n"; | 
| 120 |  |  |  |  |  |  | setrlimit(RLIMIT_CPU, $o{rlimit_cpu}, $o{rlimit_cpu}) | 
| 121 | 0 | 0 |  |  |  |  | or warn "Unable to set RLIMIT_CPU.\n"; | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | REQ_LOOP:   # main loop | 
| 124 | 0 |  |  |  |  |  | while($rqst->Accept()>=0){ | 
| 125 |  |  |  |  |  |  |  | 
| 126 | 0 |  |  |  |  |  | $req_env{'PATH_INFO'}=$req_env{'SCRIPT_FILENAME'}; | 
| 127 | 0 |  |  |  |  |  | $req_env{'SCRIPT_FILENAME'}=get_file_from_path($req_env{SCRIPT_FILENAME}); | 
| 128 | 0 |  |  |  |  |  | $req_env{'PATH_INFO'}=~s/$req_env{'SCRIPT_FILENAME'}//; | 
| 129 | 0 |  |  |  |  |  | $req_env{'SCRIPT_NAME'}=$req_env{'SCRIPT_FILENAME'}; | 
| 130 | 0 |  |  |  |  |  | $req_env{'SCRIPT_NAME'}=~s/$req_env{'DOCUMENT_ROOT'}//; | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | # check if script (exacutable, readable, non-zero size) | 
| 133 | 0 | 0 |  |  |  |  | unless(-x -s -r $req_env{'SCRIPT_FILENAME'}){ | 
| 134 | 0 |  |  |  |  |  | print "Content-type: text/plain\r\n\r\n"; | 
| 135 | 0 |  |  |  |  |  | $_="Error: No such CGI app - $req_env{SCRIPT_FILENAME} may not exist or is not executable by this process.\n"; | 
| 136 | 0 |  |  |  |  |  | print $_; | 
| 137 | 0 |  |  |  |  |  | print {*STDERR} $_; | 
|  | 0 |  |  |  |  |  |  | 
| 138 | 0 |  |  |  |  |  | next; | 
| 139 |  |  |  |  |  |  | } | 
| 140 |  |  |  |  |  |  |  | 
| 141 | 0 |  |  |  |  |  | local @ENV{keys %req_env}=values %req_env; | 
| 142 | 0 | 0 |  |  |  |  | chdir $1 if $req_env{'SCRIPT_FILENAME'}=~m{^(.*)\/};   # cd to the script's local directory | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | # Fast Perl-CGI processing | 
| 145 | 0 | 0 | 0 |  |  |  | if($o{max_evals}>0 and $req_env{'SCRIPT_FILENAME'}=~m{$o{file_pattern}\z}){   # detect if perl script | 
| 146 | 0 |  |  |  |  |  | my %allvars; | 
| 147 | 0 |  |  |  |  |  | @allvars{keys %main::}=(); | 
| 148 |  |  |  |  |  |  | { | 
| 149 | 0 |  |  | 0 |  |  | local *CORE::GLOBAL::exit=sub { die 'notr3a11yeXit' }; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 150 | 0 |  |  |  |  |  | local $0=$req_env{SCRIPT_FILENAME};     #fixes FindBin (in English $0 means $PROGRAM_NAME) | 
| 151 | 1 |  |  | 1 |  | 869 | no strict;                              ## no critic :: default for Perl5 | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 794 |  | 
| 152 | 0 |  |  |  |  |  | do $0;                                  # do $0; could be enough for strict scripts | 
| 153 | 0 | 0 |  |  |  |  | if($EVAL_ERROR){ | 
| 154 | 0 |  |  |  |  |  | $EVAL_ERROR=~s{\n+\z}{}; | 
| 155 | 0 | 0 |  |  |  |  | print {*STDERR} "$0\n$EVAL_ERROR\n\b" unless $EVAL_ERROR =~ m{^notr3a11yeXit}; | 
|  | 0 |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  | } | 
| 158 |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | #untested experimental callback to execute on script exit | 
| 160 |  |  |  |  |  |  | #$_{$req_env{SCRIPT_FILENAME}}->{SIGTERM}() if defined $_{$req_env{SCRIPT_FILENAME}}->{SIGTERM}; | 
| 161 |  |  |  |  |  |  | #Perl scripts can cache persistent data in $_{$0}->{mydata} | 
| 162 |  |  |  |  |  |  | #However if you store too much data it may trigger termination by rlimit | 
| 163 |  |  |  |  |  |  | #After DO/EVAL $_{$0}->{'SIGTERM'} is being called so termination handler | 
| 164 |  |  |  |  |  |  | #can be used to close DB connections etc. | 
| 165 |  |  |  |  |  |  | #$_{$0}->{'SIGTERM'}=sub { print "I closed my handles"; }; | 
| 166 |  |  |  |  |  |  |  | 
| 167 | 0 |  |  |  |  |  | foreach(keys %main::){                      # cleanup garbage after do() | 
| 168 | 0 | 0 |  |  |  |  | next if exists $allvars{$_}; | 
| 169 | 0 | 0 |  |  |  |  | next if m{::$}; | 
| 170 | 0 | 0 |  |  |  |  | next if m{^_}; | 
| 171 | 0 |  |  |  |  |  | delete $main::{$_}; | 
| 172 |  |  |  |  |  |  | } | 
| 173 |  |  |  |  |  |  |  | 
| 174 | 0 | 0 |  |  |  |  | if(open my $STAT,'<',"/proc/$$/status"){ | 
| 175 | 0 |  |  |  |  |  | my %stat; | 
| 176 | 0 |  |  |  |  |  | while(my ($k,$v)=split /\:\s+/,<$STAT>){ | 
| 177 | 0 |  |  |  |  |  | chop $v; | 
| 178 | 0 |  |  |  |  |  | $stat{$k}=$v; | 
| 179 |  |  |  |  |  |  | } | 
| 180 | 0 |  |  |  |  |  | close $STAT; | 
| 181 |  |  |  |  |  |  | # check if child takes too much resident memory and terminate if necessary | 
| 182 | 0 | 0 |  |  |  |  | if($stat{VmSize}/$stat{VmRSS}<$o{leak_threshold}){ | 
| 183 | 0 |  |  |  |  |  | print {*STDERR} 'fcgi-daemon :: terminating child - memory leak? ' | 
| 184 | 0 |  |  |  |  |  | ."VmSize:$stat{VmSize}; VmRSS:$stat{VmRSS}; Ratio:".$stat{VmSize}/$stat{VmRSS}; | 
| 185 | 0 |  |  |  |  |  | exit; | 
| 186 |  |  |  |  |  |  | } | 
| 187 |  |  |  |  |  |  | } | 
| 188 | 0 | 0 |  |  |  |  | exit unless --$o{max_evals}; | 
| 189 | 0 |  |  |  |  |  | next REQ_LOOP; | 
| 190 |  |  |  |  |  |  | } | 
| 191 |  |  |  |  |  |  |  | 
| 192 |  |  |  |  |  |  | # Normal CGI processing | 
| 193 | 0 |  |  |  |  |  | $o{fcgi_pm}->pm_pre_dispatch(); | 
| 194 | 0 |  |  |  |  |  | local $OUTPUT_AUTOFLUSH=1;  # select below is equivalent of: my $oldfh=select($CERR); $|=1; select($oldfh); | 
| 195 | 0 |  |  |  |  |  | pipe my($PERR),my($CERR);   select((select($CERR),$OUTPUT_AUTOFLUSH=1)[0]);    #prepare child-to-parent pipe and swith off buffering | 
|  | 0 |  |  |  |  |  |  | 
| 196 | 0 |  |  |  |  |  | pipe my($CIN),my($PIN);     select((select($PIN),$OUTPUT_AUTOFLUSH=1)[0]);     #prepare parent-to-child pipe and swith off buffering | 
|  | 0 |  |  |  |  |  |  | 
| 197 |  |  |  |  |  |  |  | 
| 198 | 0 |  |  |  |  |  | my $pid=open my($COUT),"-|";     ## fork and pipe to us | 
| 199 | 0 | 0 |  |  |  |  | unless(defined $pid){ | 
| 200 | 0 |  |  |  |  |  | print "Content-type: text/plain\r\n\r\n" | 
| 201 |  |  |  |  |  |  | ."Error: CGI app returned no output - Executing $req_env{SCRIPT_FILENAME} failed !\n"; | 
| 202 | 0 |  |  |  |  |  | next; | 
| 203 |  |  |  |  |  |  | } | 
| 204 | 0 |  |  |  |  |  | $rqst->Detach();         # needed to restore original STDIN,STDOUT,STDERR | 
| 205 |  |  |  |  |  |  |  | 
| 206 | 0 | 0 |  |  |  |  | unless($pid){   #### Child #### | 
| 207 | 0 |  |  |  |  |  | close $PIN;     # <--perhaps not really necessary | 
| 208 | 0 | 0 |  |  |  |  | open *STDIN,'<&=',$CIN   or die 'unable to reopen STDIN'; | 
| 209 | 0 | 0 |  |  |  |  | open *STDERR,'>&=',$CERR or die 'unable to reopen STDERR'; | 
| 210 | 0 | 0 |  |  |  |  | exec $req_env{'SCRIPT_FILENAME'} or die "exec failed";     # running the cgi app (exec does not return so child terminates here) | 
| 211 |  |  |  |  |  |  | }else{          #### Parent #### | 
| 212 | 0 |  |  |  |  |  | close $CIN;             # <--perhaps not really necessary | 
| 213 | 0 |  |  |  |  |  | close $CERR;            # *must* close child's file handle to avoid deadlock | 
| 214 | 0 |  |  |  |  |  | $rqst->Attach();        #reattach FCGI's STDIN,STDOUT,STDERR | 
| 215 |  |  |  |  |  |  |  | 
| 216 |  |  |  |  |  |  | ## send STDIN to child | 
| 217 | 0 |  |  |  |  |  | my $buffer; | 
| 218 |  |  |  |  |  |  | #print {$PIN} $buffer while (read *STDIN,$buffer,$ENV{'CONTENT_LENGTH'});   ## longer version below may be safer for very long input. | 
| 219 | 0 | 0 | 0 |  |  |  | if($req_env{'REQUEST_METHOD'} eq 'POST' and $req_env{'CONTENT_LENGTH'}!=0){ | 
| 220 | 0 |  |  |  |  |  | my $bytes=0; | 
| 221 | 0 |  |  |  |  |  | while ($bytes<$req_env{'CONTENT_LENGTH'}){ | 
| 222 | 0 |  |  |  |  |  | $bytes+=read *STDIN,$buffer,($req_env{'CONTENT_LENGTH'}-$bytes); | 
| 223 | 0 | 0 | 0 |  |  |  | last if ($bytes==0 or not defined $bytes); | 
| 224 | 0 |  |  |  |  |  | print {$PIN} $buffer; | 
|  | 0 |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | }   } | 
| 226 | 0 |  |  |  |  |  | close $PIN; | 
| 227 |  |  |  |  |  |  |  | 
| 228 | 1 |  |  | 1 |  | 1670 | use IO::Select;     # non-blocking read from child's redirected STDOUT and STDERR | 
|  | 1 |  |  |  |  | 2253 |  | 
|  | 1 |  |  |  |  | 730 |  | 
| 229 | 0 |  |  |  |  |  | my $sel = IO::Select->new($COUT,$PERR); | 
| 230 | 0 |  |  |  |  |  | while(my @ready=$sel->can_read){ | 
| 231 | 0 |  |  |  |  |  | for my $FH (@ready){ | 
| 232 | 0 | 0 |  |  |  |  | if(0==sysread $FH,$buffer,4096){ | 
| 233 | 0 |  |  |  |  |  | $sel->remove($FH); | 
| 234 | 0 |  |  |  |  |  | close $FH; | 
| 235 |  |  |  |  |  |  | }else{ | 
| 236 | 0 | 0 |  |  |  |  | print {$FH==$COUT ? *STDOUT:*STDERR} $buffer; | 
|  | 0 |  |  |  |  |  |  | 
| 237 |  |  |  |  |  |  | }  }    } | 
| 238 | 0 |  |  |  |  |  | waitpid $pid,0; | 
| 239 | 0 |  |  |  |  |  | $rqst->Finish(); | 
| 240 |  |  |  |  |  |  | } | 
| 241 | 0 |  |  |  |  |  | $o{fcgi_pm}->pm_post_dispatch(); | 
| 242 |  |  |  |  |  |  | } | 
| 243 | 0 |  |  |  |  |  | return; | 
| 244 |  |  |  |  |  |  | } | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | # overriding process names | 
| 247 |  |  |  |  |  |  | sub FCGI::ProcManager::pm_change_process_name { | 
| 248 | 0 |  |  | 0 | 1 |  | my ($self,$name)=@_; | 
| 249 | 0 |  |  |  |  |  | my %p=( 'perl-fcgi-pm'  =>'FCGI::Daemon', | 
| 250 |  |  |  |  |  |  | 'perl-fcgi'     =>'FCGI::Daemon-worker', | 
| 251 |  |  |  |  |  |  | ); | 
| 252 | 0 | 0 |  |  |  |  | $0=$p{$name} if $p{$name} ne '';                                    ## no critic | 
| 253 | 0 |  |  |  |  |  | return; | 
| 254 |  |  |  |  |  |  | } | 
| 255 |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | =head2 get_file_from_path() | 
| 257 |  |  |  |  |  |  | Find first file in path | 
| 258 |  |  |  |  |  |  | =cut | 
| 259 |  |  |  |  |  |  | sub get_file_from_path { | 
| 260 | 0 |  |  | 0 | 1 |  | local $_=shift; | 
| 261 | 0 |  |  |  |  |  | my $file=''; | 
| 262 | 0 |  |  |  |  |  | for(split '/',$_){ | 
| 263 | 0 | 0 |  |  |  |  | next if $_ eq ''; | 
| 264 | 0 |  |  |  |  |  | $file.='/'.$_; | 
| 265 | 0 | 0 |  |  |  |  | last if -f -s $file; | 
| 266 |  |  |  |  |  |  | } | 
| 267 | 0 |  |  |  |  |  | return $file; | 
| 268 |  |  |  |  |  |  | } | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | 1; | 
| 271 |  |  |  |  |  |  | __END__ |