This file is indexed.

/usr/share/mod-gearman/mod_gearman_p1.pl is in mod-gearman-worker 1.5.5-1+b3.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
package Embed::Persistent;

# p1.pl for Mod-Gearman

use strict;
use Text::ParseWords qw(parse_line);

use constant LEAVE_MSG   => 1;
use constant CACHE_DUMP  => 2;
use constant PLUGIN_DUMP => 4;
use constant DEBUG_LEVEL => 0;
# use constant DEBUG_LEVEL => CACHE_DUMP ;
# use constant DEBUG_LEVEL => LEAVE_MSG ;
# use constant DEBUG_LEVEL => LEAVE_MSG | CACHE_DUMP ;
# use constant DEBUG_LEVEL => LEAVE_MSG | CACHE_DUMP | PLUGIN_DUMP ;

use constant DEBUG_LOG_PATH         => './';
use constant LEAVE_MSG_STREAM       => DEBUG_LOG_PATH . 'epn_leave-msgs.log';
use constant CACHE_DUMP_STREAM      => DEBUG_LOG_PATH . 'epn_cache-dump.log';
use constant PLUGIN_DUMP_STREAM     => DEBUG_LOG_PATH . 'epn_plugin-dump.log';
use constant NUMBER_OF_PERL_PLUGINS => 60;

# Cache will be dumped every Cache_Dump_Interval plugin compilations
use constant Cache_Dump_Interval    => 20;

( DEBUG_LEVEL & LEAVE_MSG ) && do {
    open LH, '>> ' . LEAVE_MSG_STREAM
        or die "Can't open " . LEAVE_MSG_STREAM . ": $!";
    # Unbuffer LH since this will be written by child processes.
    select( ( select(LH), $| = 1 )[0] );
};
( DEBUG_LEVEL & CACHE_DUMP ) && do {
    ( open CH, '>> ' . CACHE_DUMP_STREAM or die "Can't open " . CACHE_DUMP_STREAM . ": $!" );
    select( ( select(CH), $| = 1 )[0] );
};
( DEBUG_LEVEL & PLUGIN_DUMP )
    && ( open PH, '>> ' . PLUGIN_DUMP_STREAM or die "Can't open " . PLUGIN_DUMP_STREAM . ": $!" );

require Data::Dumper
    if DEBUG_LEVEL & CACHE_DUMP;

my( %Cache, $Current_Run );
keys %Cache = NUMBER_OF_PERL_PLUGINS;

# Offsets in %Cache{$filename}
use constant MTIME        => 0;
use constant PLUGIN_ARGS  => 1;
use constant PLUGIN_ERROR => 2;
use constant PLUGIN_HNDLR => 3;

package main;

use subs 'CORE::GLOBAL::exit';

sub CORE::GLOBAL::exit { die "ExitTrap: $_[0] (Redefine exit to trap plugin exit with eval BLOCK)" }

package OutputTrap;

# Methods for use by tied STDOUT in embedded PERL module.
# Simply ties STDOUT to a scalar and caches values written to it.
# NB No more than 4KB characters per line are kept.

sub TIEHANDLE {
    my($class) = @_;
    my $me = '';
    bless \$me, $class;
}

sub PRINT {
    my $self = shift;

    $$self .= substr( join( '', @_ ), 0, 4096 );
}

sub PRINTF {
    my $self = shift;
    my $fmt  = shift;

    $$self .= substr( sprintf( $fmt, @_ ), 0, 4096 );
}

sub READLINE {
    my $self = shift;
    return $$self;
}

sub CLOSE {
    my $self = shift;
    undef $self;
}

sub DESTROY {
    my $self = shift;
    undef $self;
}

package Embed::Persistent;

sub valid_package_name {
    local $_ = shift;
    s|([^A-Za-z0-9\/])|sprintf("_%2x",unpack("C",$1))|eg;

    # second pass only for words starting with a digit
    s|/(\d)|sprintf("/_%2x",unpack("C",$1))|eg;

    # Dress it up as a real package name
    s|/|::|g;
    return /^::/ ? "Embed$_" : "Embed::$_";
}

# Perl 5.005_03 only traps warnings for errors classed by perldiag
# as Fatal (eg 'Global symbol """"%s"""" requires explicit package name').
# Therefore treat all warnings as fatal.

sub throw_exception {
    die shift;
}

sub eval_file {
    my( $filename, $delete, undef, $plugin_args ) = @_;

    my $mtime = -M $filename;
    my $ts    = localtime( time() )
        if DEBUG_LEVEL;

    if(    exists( $Cache{$filename} )
        && $Cache{$filename}[MTIME]
        && $Cache{$filename}[MTIME] <= $mtime )
    {

        # We have compiled this plugin before and
        # it has not changed on disk; nothing to do except
        # 1 parse the plugin arguments and cache them (to save
        #   repeated parsing of the same args) - the same
        #   plugin could be called with different args.
        # 2 return the error from a former compilation
        #   if there was one.

        $Cache{$filename}[PLUGIN_ARGS]{$plugin_args} ||= [ parse_line( '\s+', 0, $plugin_args ) ]
            if $plugin_args;

        if( $Cache{$filename}[PLUGIN_ERROR] ) {
            print LH qq($ts eval_file: $filename failed compilation formerly and file has not changed; skipping compilation.\n)
                if DEBUG_LEVEL & LEAVE_MSG;
            die qq(**ePN failed to compile $filename: "$Cache{$filename}[PLUGIN_ERROR]");
        }
        else {
            print LH qq($ts eval_file: $filename already successfully compiled and file has not changed; skipping compilation.\n)
                if DEBUG_LEVEL & LEAVE_MSG;
            return $Cache{$filename}[PLUGIN_HNDLR];
        }
    }

    my $package = valid_package_name($filename);

    $Cache{$filename}[PLUGIN_ARGS]{$plugin_args} ||= [ parse_line( '\s+', 0, $plugin_args ) ]
        if $plugin_args;

    local *FH;

    # die will be trapped by caller (checking ERRSV)
    open FH, $filename
        or die qq(**ePN failed to open "$filename": "$!");

    my $sub;
    sysread FH, $sub, -s FH;
    close FH;

    # Cater for scripts that have embedded EOF symbols (__END__)
    # XXXX
    # Doesn't make sense to me.

    # $sub		=~ s/__END__/\;}\n__END__/;
    # Wrap the code into a subroutine inside our unique package
    # (using $_ here [to save a lexical] is not a good idea since
    # the definition of the package is visible to any other Perl
    # code that uses [non localised] $_).
    my $hndlr = <<EOSUB ;
package $package;

sub hndlr {
    \@ARGV = \@_;
    local \$^W = 1;
    \$ENV{NAGIOS_PLUGIN} = '$filename';

# <<< START of PLUGIN (first line of plugin is line 8 in the text) >>>
$sub
# <<< END of PLUGIN >>>
}
EOSUB

    $Cache{$filename}[MTIME] = $mtime
        unless $delete;

    # Suppress warning display.
    local $SIG{__WARN__} = \&throw_exception;

    # Following 3 lines added 10/18/07 by Larry Low to fix problem where
    # modified Perl plugins didn't get recached by the epn
    no strict 'refs';
    undef %{ $package . '::' };
    use strict 'refs';

    # Compile &$package::hndlr. Since non executable code is being eval'd
    # there is no need to protect lexicals in this scope.
    eval $hndlr;

    # $@ is set for any warning and error.
    # This guarantees that the plugin will not be run.
    if($@) {

        # Report error line number wrt to original plugin text (7 lines added by eval_file).
        # Error text looks like
        # 'Use of uninitialized ..' at (eval 23) line 186, <DATA> line 218
        # The error line number is 'line 186'
        chomp($@);
        $@ =~ s/line (\d+)[\.,]/'line ' . ($1 - 7) . ','/e;

        print LH qq($ts eval_file: syntax error in $filename: "$@".\n)
            if DEBUG_LEVEL & LEAVE_MSG;

        if( DEBUG_LEVEL & PLUGIN_DUMP ) {
            my $i = 1;
            $_ = $hndlr;
            s/^/sprintf('%10d  ', $i++)/meg;

            # Will only get here once (when a faulty plugin is compiled).
            # Therefore only _faulty_ plugins are dumped once each time the text changes.

            print PH qq($ts eval_file: transformed plugin "$filename" to ==>\n$_\n);
        }

        $@ = substr( $@, 0, 4096 )
            if length($@) > 4096;

        $Cache{$filename}[PLUGIN_ERROR] = $@;

        # If the compilation fails, leave nothing behind that may affect subsequent
        # compilations. This will be trapped by caller (checking ERRSV).
        die qq(**ePN failed to compile $filename: "$@");

    }
    else {
        $Cache{$filename}[PLUGIN_ERROR] = '';
    }

    print LH qq($ts eval_file: successfully compiled "$filename $plugin_args".\n)
        if DEBUG_LEVEL & LEAVE_MSG;

    print CH qq($ts eval_file: after $Current_Run compilations \%Cache =>\n), Data::Dumper->Dump( [ \%Cache ], [qw(*Cache)] ), "\n"
        if( ( DEBUG_LEVEL & CACHE_DUMP ) && ( ++$Current_Run % Cache_Dump_Interval == 0 ) );

    no strict 'refs';
    return $Cache{$filename}[PLUGIN_HNDLR] = *{ $package . '::hndlr' }{CODE};

}

sub run_package {
    my( $filename, undef, $plugin_hndlr_cr, $plugin_args ) = @_;

    # Second parm (after $filename) _may_ be used to wallop stashes.

    my $has_exit = 0;
    my $res      = 3;
    my $ts       = localtime( time() ) if DEBUG_LEVEL;

    local $SIG{__WARN__} = \&throw_exception;
    my $stdout = tie( *STDOUT, 'OutputTrap' );
    my @plugin_args = $plugin_args ? @{ $Cache{$filename}[PLUGIN_ARGS]{$plugin_args} } : ();

    # If the plugin has args, they have been cached by eval_file.
    # ( cannot cache @plugin_args here because run_package() is
    #   called by child processes so cannot update %Cache.)

    eval { $plugin_hndlr_cr->(@plugin_args) };

    if($@) {

        # Error => normal plugin termination (exit) || run time error.
        $_ = $@;
        /^ExitTrap: (-?\d+)/ ? do {$has_exit = 1; $res = $1} :

            # For normal plugin exit, $@ will  always match /^ExitTrap: (-?\d+)/
            /^ExitTrap:  / ? do { $has_exit = 1; $res = 0 } : do {

            # Run time error/abnormal plugin termination.

            chomp;

            # Report error line number wrt to original plugin text (7 lines added by eval_file).
            s/line (\d+)[\.,]/'line ' . ($1 - 7) . ','/e;
            print STDOUT qq(**ePN $filename: "$_".\n);
            };

        ( $@, $_ ) = ( '', '' );
    }

    # ! Error => Perl code is not a plugin (fell off the end; no exit)

    # !! (read any output from the tied file handle.)
    my $plugin_output = <STDOUT>;

    undef $stdout;
    untie *STDOUT;

    $plugin_output = "**ePN $filename: plugin did not call exit()\n".$plugin_output if $has_exit == 0;

    print LH qq($ts run_package: "$filename $plugin_args" returning ($res, "$plugin_output").\n)
        if DEBUG_LEVEL & LEAVE_MSG;

    return ( $res, $plugin_output );
}

1;

=head1 SEE ALSO

=over 4

=item * perlembed (section on maintaining a persistent interpreter)

=back

=head1 AUTHOR

Originally by Stephen Davies.

Now maintained by Stanley Hopcroft <hopcrofts@cpan.org> who retains responsibility for the 'bad bits'.

=head1 COPYRIGHT

Copyright (c) 2004 Stanley Hopcroft. All rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

=cut