This file is indexed.

/usr/share/perl5/Hook/WrapSub.pm is in libhook-wrapsub-perl 0.03-2.

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
package Hook::WrapSub;

use Exporter;
use Symbol;
use strict;
use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK );


$VERSION = '0.03';
@ISA = qw(Exporter);
@EXPORT = qw();
@EXPORT_OK = qw(
  wrap_subs
  unwrap_subs
);


=head1 NAME

Hook::WrapSub - wrap subs with pre- and post-call hooks

=head1 SYNOPSIS

  use Hook::WrapSub qw( wrap_subs unwrap_subs );

  wrap_subs \&before, 'some_func', 'another_func', \&after;

  unwrap_subs 'some_func';


=head1 DESCRIPTION

=head2 wrap_subs

This function enables intercepting a call to any named
function; handlers may be added both before and after
the call to the intercepted function.

For example:

  wrap_subs \&before, 'some_func', \&after;

In this case, whenever the sub named 'some_func' is called,
the &before sub is called first, and the &after sub is called
afterwards.  These are both optional.  If you only want
to intercept the call beforehand:

  wrap_subs \&before, 'some_func';

You may pass more than one sub name:

  wrap_subs \&before, 'foo', 'bar', 'baz', \&after;

and each one will have the same hooks applied.

The sub names may be qualified.  Any unqualified names
are assumed to reside in the package of the caller.

The &before sub and the &after sub are both passed the
argument list which is destined for the wrapped sub.
This can be inspected, and even altered, in the &before
sub:

  sub before {  
    ref($_[1]) && $_[1] =~ /\bARRAY\b/
      or croak "2nd arg must be an array-ref!";
    @_ or @_ = qw( default values );
    # if no args passed, insert some default values
  }

The &after sub is also passed this list.  Modifications
to it will (obviously) not be seen by the wrapped sub,
but the caller will see the changes, if it happens to
be looking.

Here's an example that causes a certain method call
to be redirected to a specific object.  (Note, we 
use splice to change $_[0], because assigning directly
to $_[0] would cause the change to be visible to the caller,
due to the magical aliasing nature of @_.)

  my $handler_object = new MyClass;

  Hook::WrapSub::wrap_subs
    sub { splice @_, 0, 1, $handler_object },
    'MyClass::some_method';
      
  my $other_object = new MyClass;
  $other_object->some_method;

  # even though the method is invoked on
  # $other_object, it will actually be executed
  # with a 0'th argument = $handler_obj,
  # as arranged by the pre-call hook sub.

=head2 Package Variables

There are some Hook::WrapSub package variables defined,
which the &before and &after subs may inspect.

=over 4

=item $Hook::WrapSub::name 

This is the fully qualified name of the wrapped sub.

=item @Hook::WrapSub::caller

This is a list which strongly resembles the result of a
call to the built-in function C<caller>; it is provided
because calling C<caller> will in fact produce confusing
results; if your sub is inclined to call C<caller>,
have it look at this variable instead.

=item @Hook::WrapSub::result

This contains the result of the call to the wrapped sub.
It is empty in the &before sub.  In the &after sub, it
will be empty if the sub was called in a void context,
it will contain one value if the sub was called in a
scalar context; otherwise, it may have any number of
elements.  Note that the &after function is not prevented
from modifying the contents of this array; any such
modifications will be seen by the caller!


=back

This simple example shows how Hook::WrapSub can be
used to log certain subroutine calls:

  sub before {
    print STDERR <<"    EOF";
      About to call $Hook::WrapSub::name( @_ );
      Wantarray=$Hook::WrapSub::caller[5]
    EOF
  }

  sub after {
    print STDERR <<"    EOF";
      Called $Hook::WrapSub::name( @_ );
      Result=( @Hook::WrapSub::result )
    EOF
    @Hook::WrapSub::result 
      or @Hook::WrapSub::result = qw( default return );
    # if the sub failed to return something...
  }

Much more elaborate uses are possible.  Here's one
one way it could be used with database operations:

  my $dbh; # initialized elsewhere.

  wrap_subs
    sub {
      $dbh->checkpoint
    },

    'MyDb::update',
    'MyDb::delete',

    sub {
      # examine result of sub call:
      if ( $Hook::WrapSub::result[0] ) {
        # success
        $dbh->commit;
      }
      else {
        # failure
        $dbh->rollback;
      }
    };

=head2  unwrap_subs

This removes the most recent wrapping of the named subs.

NOTE: Any given sub may be wrapped an unlimited
number of times.  A "stack" of the wrappings is
maintained internally.  wrap_subs "pushes" a wrapping,
and unwrap_subs "pops".

=cut

sub wrap_subs(@) {
  my( $precall_cr, $postcall_cr );
  ref($_[0]) and $precall_cr = shift;
  ref($_[-1]) and $postcall_cr = pop;
  my @names = @_;

  my( $calling_package ) = caller;

  for my $name ( @names ) {

    my $fullname;
    my $sr = *{ qualify_to_ref($name,$calling_package) }{CODE};
    if ( defined $sr ) { 
      $fullname = qualify($name,$calling_package);
    }
    else {
      warn "Can't find subroutine named '$name'\n";
      next;
    }


    my $cr = sub {
      $Hook::WrapSub::UNWRAP and return $sr;

#
# this is a bunch of kludg to make a list of values
# that look like a "real" caller() result.
#
      my $up = 0;
      my @args = caller($up);
      while ( $args[0] =~ /Hook::WrapSub/ ) {
        $up++;
        @args = caller($up);
      }
      my @vargs = @args; # save temp
      while ( $args[3] =~ /Hook::WrapSub/ ) {
        $up++;
        @args = caller($up);
      }
      $vargs[3] = $args[3];
      # now @vargs looks right.

      local $Hook::WrapSub::name = $fullname;
      local @Hook::WrapSub::result = ();
      local @Hook::WrapSub::caller = @vargs;
      my $wantarray = $Hook::WrapSub::caller[5];
#
# try to supply the same calling context to the nested sub:
#

      unless ( defined $wantarray ) {
        # void context
        &$precall_cr  if $precall_cr;
        &$sr;
        &$postcall_cr if $postcall_cr;
        return();
      }

      unless ( $wantarray ) {
        # scalar context
        &$precall_cr  if $precall_cr;
        $Hook::WrapSub::result[0] = &$sr;
        &$postcall_cr if $postcall_cr;
        return $Hook::WrapSub::result[0];
      }

      # list context
      &$precall_cr  if $precall_cr;
      @Hook::WrapSub::result = &$sr;
      &$postcall_cr if $postcall_cr;
      return( @Hook::WrapSub::result );
    };

    $^W = 0;
    no strict 'refs';
    *{ $fullname } = $cr;
  }
}

sub unwrap_subs(@) {
  my @names = @_;

  my( $calling_package ) = caller;

  for my $name ( @names ) {
    my $fullname;
    my $sr = *{ qualify_to_ref($name,$calling_package) }{CODE};
    if ( defined $sr ) { 
      $fullname = qualify($name,$calling_package);
    }
    else {
      warn "Can't find subroutine named '$name'\n";
      next;
    }
    local $Hook::WrapSub::UNWRAP = 1;
    my $cr = $sr->();
    if ( defined $cr and $cr =~ /\bCODE\b/ ) {
      $^W = 0;
      no strict 'refs';
      *{ $fullname } = $cr;
    }
    else {
      warn "Subroutine '$fullname' not wrapped!";
    }
  }
}

1;

=head1 AUTHOR

jdporter@min.net (John Porter)

=head1 COPYRIGHT

This is free software.  This software may be modified and/or
distributed under the same terms as Perl itself.

=cut