This file is indexed.

/usr/share/perl5/IPC/Run/IO.pm is in libipc-run-perl 0.92-1.

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
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
package IPC::Run::IO;

=head1 NAME

IPC::Run::IO -- I/O channels for IPC::Run.

=head1 SYNOPSIS

B<NOT IMPLEMENTED YET ON Win32! Win32 does not allow select() on
normal file descriptors; IPC::RUN::IO needs to use IPC::Run::Win32Helper
to do this.>

   use IPC::Run qw( io );

   ## The sense of '>' and '<' is opposite of perl's open(),
   ## but agrees with IPC::Run.
   $io = io( "filename", '>',  \$recv );
   $io = io( "filename", 'r',  \$recv );

   ## Append to $recv:
   $io = io( "filename", '>>', \$recv );
   $io = io( "filename", 'ra', \$recv );

   $io = io( "filename", '<',  \$send );
   $io = io( "filename", 'w',  \$send );

   $io = io( "filename", '<<', \$send );
   $io = io( "filename", 'wa', \$send );

   ## Handles / IO objects that the caller opens:
   $io = io( \*HANDLE,   '<',  \$send );

   $f = IO::Handle->new( ... ); # Any subclass of IO::Handle
   $io = io( $f, '<', \$send );

   require IPC::Run::IO;
   $io = IPC::Run::IO->new( ... );

   ## Then run(), harness(), or start():
   run $io, ...;

   ## You can, of course, use io() or IPC::Run::IO->new() as an
   ## argument to run(), harness, or start():
   run io( ... );

=head1 DESCRIPTION

This class and module allows filehandles and filenames to be harnessed for
I/O when used IPC::Run, independent of anything else IPC::Run is doing
(except that errors & exceptions can affect all things that IPC::Run is
doing).

=head1 SUBCLASSING

INCOMPATIBLE CHANGE: due to the awkwardness introduced in ripping pseudohashes
out of Perl, this class I<no longer> uses the fields pragma.

=cut

## This class is also used internally by IPC::Run in a very initimate way,
## since this is a partial factoring of code from IPC::Run plus some code
## needed to do standalone channels.  This factoring process will continue
## at some point.  Don't know how far how fast.

use strict;
use Carp;
use Fcntl;
use Symbol;

use IPC::Run::Debug;
use IPC::Run qw( Win32_MODE );

use vars qw{$VERSION};
BEGIN {
	$VERSION = '0.90';
	if ( Win32_MODE ) {
		eval "use IPC::Run::Win32Helper; require IPC::Run::Win32IO; 1"
		or ( $@ && die ) or die "$!";
	}
}

sub _empty($);
*_empty = \&IPC::Run::_empty;

=head1 SUBROUTINES

=over 4

=item new

I think it takes >> or << along with some other data.

TODO: Needs more thorough documentation. Patches welcome.

=cut

sub new {
   my $class = shift;
   $class = ref $class || $class;

   my ( $external, $type, $internal ) = ( shift, shift, pop );

   croak "$class: '$_' is not a valid I/O operator"
      unless $type =~ /^(?:<<?|>>?)$/;

   my IPC::Run::IO $self = $class->_new_internal(
      $type, undef, undef, $internal, undef, @_
   );

   if ( ! ref $external ) {
      $self->{FILENAME} = $external;
   }
   elsif ( ref eq 'GLOB' || UNIVERSAL::isa( $external, 'IO::Handle' ) ) {
      $self->{HANDLE} = $external;
      $self->{DONT_CLOSE} = 1;
   }
   else {
      croak "$class: cannot accept " . ref( $external ) . " to do I/O with";
   }

   return $self;
}


## IPC::Run uses this ctor, since it preparses things and needs more
## smarts.
sub _new_internal {
   my $class = shift;
   $class = ref $class || $class;

   $class = "IPC::Run::Win32IO"
      if Win32_MODE && $class eq "IPC::Run::IO";

   my IPC::Run::IO $self;
   $self = bless {}, $class;

   my ( $type, $kfd, $pty_id, $internal, $binmode, @filters ) = @_;

   # Older perls (<=5.00503, at least) don't do list assign to
   # psuedo-hashes well.
   $self->{TYPE}    = $type;
   $self->{KFD}     = $kfd;
   $self->{PTY_ID}  = $pty_id;
   $self->binmode( $binmode );
   $self->{FILTERS} = [ @filters ];

   ## Add an adapter to the end of the filter chain (which is usually just the
   ## read/writer sub pushed by IPC::Run) to the DEST or SOURCE, if need be.
   if ( $self->op =~ />/ ) {
      croak "'$_' missing a destination" if _empty $internal;
      $self->{DEST} = $internal;
      if ( UNIVERSAL::isa( $self->{DEST}, 'CODE' ) ) {
         ## Put a filter on the end of the filter chain to pass the
         ## output on to the CODE ref.  For SCALAR refs, the last
         ## filter in the chain writes directly to the scalar itself.  See
         ## _init_filters().  For CODE refs, however, we need to adapt from
         ## the SCALAR to calling the CODE.
         unshift( 
            @{$self->{FILTERS}},
            sub {
               my ( $in_ref ) = @_;

               return IPC::Run::input_avail() && do {
        	  $self->{DEST}->( $$in_ref );
        	  $$in_ref = '';
        	  1;
               }
            }
         );
      }
   }
   else {
      croak "'$_' missing a source" if _empty $internal;
      $self->{SOURCE} = $internal;
      if ( UNIVERSAL::isa( $internal, 'CODE' ) ) {
         push(
            @{$self->{FILTERS}},
            sub {
               my ( $in_ref, $out_ref ) = @_;
               return 0 if length $$out_ref;

               return undef
        	  if $self->{SOURCE_EMPTY};

               my $in = $internal->();
               unless ( defined $in ) {
        	  $self->{SOURCE_EMPTY} = 1;
        	  return undef 
               }
               return 0 unless length $in;
               $$out_ref = $in;

               return 1;
            }
         );
      }
      elsif ( UNIVERSAL::isa( $internal, 'SCALAR' ) ) {
         push(
            @{$self->{FILTERS}},
            sub {
               my ( $in_ref, $out_ref ) = @_;
               return 0 if length $$out_ref;

               ## pump() clears auto_close_ins, finish() sets it.
               return $self->{HARNESS}->{auto_close_ins} ? undef : 0
        	  if IPC::Run::_empty ${$self->{SOURCE}}
        	     || $self->{SOURCE_EMPTY};

               $$out_ref = $$internal;
               eval { $$internal = '' }
        	  if $self->{HARNESS}->{clear_ins};

               $self->{SOURCE_EMPTY} = $self->{HARNESS}->{auto_close_ins};

               return 1;
            }
         );
      }
   }

   return $self;
}

=item filename

Gets/sets the filename.  Returns the value after the name change, if
any.

=cut

sub filename {
   my IPC::Run::IO $self = shift;
   $self->{FILENAME} = shift if @_;
   return $self->{FILENAME};
}

=item init

Does initialization required before this can be run.  This includes open()ing
the file, if necessary, and clearing the destination scalar if necessary.

=cut

sub init {
   my IPC::Run::IO $self = shift;

   $self->{SOURCE_EMPTY} = 0;
   ${$self->{DEST}} = ''
      if $self->mode =~ /r/ && ref $self->{DEST} eq 'SCALAR';

   $self->open if defined $self->filename;
   $self->{FD} = $self->fileno;

   if ( ! $self->{FILTERS} ) {
      $self->{FBUFS} = undef;
   }
   else {
      @{$self->{FBUFS}} = map {
         my $s = "";
         \$s;
      } ( @{$self->{FILTERS}}, '' );

      $self->{FBUFS}->[0] = $self->{DEST}
         if $self->{DEST} && ref $self->{DEST} eq 'SCALAR';
      push @{$self->{FBUFS}}, $self->{SOURCE};
   }

   return undef;
}


=item open

If a filename was passed in, opens it.  Determines if the handle is open
via fileno().  Throws an exception on error.

=cut

my %open_flags = (
   '>'  => O_RDONLY,
   '>>' => O_RDONLY,
   '<'  => O_WRONLY | O_CREAT | O_TRUNC,
   '<<' => O_WRONLY | O_CREAT | O_APPEND,
);

sub open {
   my IPC::Run::IO $self = shift;

   croak "IPC::Run::IO: Can't open() a file with no name"
      unless defined $self->{FILENAME};
   $self->{HANDLE} = gensym unless $self->{HANDLE};

   _debug
      "opening '", $self->filename, "' mode '", $self->mode, "'"
   if _debugging_data;
   sysopen(
      $self->{HANDLE},
      $self->filename,
      $open_flags{$self->op},
   ) or croak
         "IPC::Run::IO: $! opening '$self->{FILENAME}', mode '" . $self->mode . "'";

   return undef;
}


=item open_pipe

If this is a redirection IO object, this opens the pipe in a platform
independent manner.

=cut

sub _do_open {
   my $self = shift;
   my ( $child_debug_fd, $parent_handle ) = @_;


   if ( $self->dir eq "<" ) {
      ( $self->{TFD}, $self->{FD} ) = IPC::Run::_pipe_nb;
      if ( $parent_handle ) {
         CORE::open $parent_handle, ">&=$self->{FD}"
            or croak "$! duping write end of pipe for caller";
      }
   }
   else {
      ( $self->{FD}, $self->{TFD} ) = IPC::Run::_pipe;
      if ( $parent_handle ) {
         CORE::open $parent_handle, "<&=$self->{FD}"
            or croak "$! duping read end of pipe for caller";
      }
   }
}

sub open_pipe {
   my IPC::Run::IO $self = shift;

   ## Hmmm, Maybe allow named pipes one day.  But until then...
   croak "IPC::Run::IO: Can't pipe() when a file name has been set"
      if defined $self->{FILENAME};

   $self->_do_open( @_ );

   ## return ( child_fd, parent_fd )
   return $self->dir eq "<"
      ? ( $self->{TFD}, $self->{FD} )
      : ( $self->{FD}, $self->{TFD} );
}


sub _cleanup { ## Called from Run.pm's _cleanup
   my $self = shift;
   undef $self->{FAKE_PIPE};
}


=item close

Closes the handle.  Throws an exception on failure.


=cut

sub close {
   my IPC::Run::IO $self = shift;

   if ( defined $self->{HANDLE} ) {
      close $self->{HANDLE}
         or croak(  "IPC::Run::IO: $! closing "
            . ( defined $self->{FILENAME}
               ? "'$self->{FILENAME}'"
               : "handle"
            )
         );
   }
   else {
      IPC::Run::_close( $self->{FD} );
   }

   $self->{FD} = undef;

   return undef;
}

=item fileno

Returns the fileno of the handle.  Throws an exception on failure.


=cut

sub fileno {
   my IPC::Run::IO $self = shift;

   my $fd = fileno $self->{HANDLE};
   croak(  "IPC::Run::IO: $! "
         . ( defined $self->{FILENAME}
            ? "'$self->{FILENAME}'"
            : "handle"
         )
      ) unless defined $fd;

   return $fd;
}

=item mode

Returns the operator in terms of 'r', 'w', and 'a'.  There is a state
'ra', unlike Perl's open(), which indicates that data read from the
handle or file will be appended to the output if the output is a scalar.
This is only meaningful if the output is a scalar, it has no effect if
the output is a subroutine.

The redirection operators can be a little confusing, so here's a reference
table:

   >      r      Read from handle in to process
   <      w      Write from process out to handle
   >>     ra     Read from handle in to process, appending it to existing
                 data if the destination is a scalar.
   <<     wa     Write from process out to handle, appending to existing
                 data if IPC::Run::IO opened a named file.

=cut

sub mode {
   my IPC::Run::IO $self = shift;

   croak "IPC::Run::IO: unexpected arguments for mode(): @_" if @_;

   ## TODO: Optimize this
   return ( $self->{TYPE} =~ /</     ? 'w' : 'r' ) . 
          ( $self->{TYPE} =~ /<<|>>/ ? 'a' : ''  );
}


=item op

Returns the operation: '<', '>', '<<', '>>'.  See L</mode> if you want
to spell these 'r', 'w', etc.

=cut

sub op {
   my IPC::Run::IO $self = shift;

   croak "IPC::Run::IO: unexpected arguments for op(): @_" if @_;

   return $self->{TYPE};
}

=item binmode

Sets/gets whether this pipe is in binmode or not.  No effect off of Win32
OSs, of course, and on Win32, no effect after the harness is start()ed.

=cut

sub binmode {
   my IPC::Run::IO $self = shift;

   $self->{BINMODE} = shift if @_;

   return $self->{BINMODE};
}


=item dir

Returns the first character of $self->op.  This is either "<" or ">".

=cut

sub dir {
   my IPC::Run::IO $self = shift;

   croak "IPC::Run::IO: unexpected arguments for dir(): @_" if @_;

   return substr $self->{TYPE}, 0, 1;
}


##
## Filter Scaffolding
##
#my $filter_op ;        ## The op running a filter chain right now
#my $filter_num;        ## Which filter is being run right now.

use vars (
'$filter_op',        ## The op running a filter chain right now
'$filter_num'        ## Which filter is being run right now.
);

sub _init_filters {
   my IPC::Run::IO $self = shift;

confess "\$self not an IPC::Run::IO" unless UNIVERSAL::isa( $self, "IPC::Run::IO" );
   $self->{FBUFS} = [];

   $self->{FBUFS}->[0] = $self->{DEST}
      if $self->{DEST} && ref $self->{DEST} eq 'SCALAR';

   return unless $self->{FILTERS} && @{$self->{FILTERS}};

   push @{$self->{FBUFS}}, map {
      my $s = "";
      \$s;
   } ( @{$self->{FILTERS}}, '' );

   push @{$self->{FBUFS}}, $self->{SOURCE};
}

=item poll

TODO: Needs confirmation that this is correct. Was previously undocumented.

I believe this is polling the IO for new input and then returns undef if there will never be any more input, 0 if there is none now, but there might be in the future, and TRUE if more input was gotten.

=cut

sub poll {
   my IPC::Run::IO $self = shift;
   my ( $harness ) = @_;

   if ( defined $self->{FD} ) {
      my $d = $self->dir;
      if ( $d eq "<" ) {
         if ( vec $harness->{WOUT}, $self->{FD}, 1 ) {
            _debug_desc_fd( "filtering data to", $self )
               if _debugging_details;
            return $self->_do_filters( $harness );
         }
      }
      elsif ( $d eq ">" ) {
         if ( vec $harness->{ROUT}, $self->{FD}, 1 ) {
            _debug_desc_fd( "filtering data from", $self )
               if _debugging_details;
            return $self->_do_filters( $harness );
         }
      }
   }
   return 0;
}


sub _do_filters {
   my IPC::Run::IO $self = shift;

   ( $self->{HARNESS} ) = @_;

   my ( $saved_op, $saved_num ) =($IPC::Run::filter_op,$IPC::Run::filter_num);
   $IPC::Run::filter_op = $self;
   $IPC::Run::filter_num = -1;
   my $redos = 0;
   my $r;
   {
	   $@ = '';
	   $r = eval { IPC::Run::get_more_input(); };

	   # Detect Resource temporarily unavailable and re-try 200 times (2 seconds),  assuming select behaves (which it doesn't always? need ref)
	   if(($@||'') =~ $IPC::Run::_EAGAIN && $redos++ < 200) {
	       select(undef, undef, undef, 0.01);
	       redo;
	   }
   }
   ( $IPC::Run::filter_op, $IPC::Run::filter_num ) = ( $saved_op, $saved_num );
   $self->{HARNESS} = undef;
   die "ack ", $@ if $@;
   return $r;
}

=back

=head1 AUTHOR

Barrie Slaymaker <barries@slaysys.com>

=head1 TODO

Implement bidirectionality.

=cut

1;