<?xml version="1.0" encoding="windows-1252"?>
<node id="953939" title="Re^2: Implicitly file tying ..." created="2012-02-15 07:58:42" updated="2012-02-15 07:58:42">
<type id="11">
note</type>
<author id="607703">
clueless newbie</author>
<data>
<field name="doctext">
&lt;p&gt;Thanks to Eliya, I have the following which can eavesdrop on applications which perform simple io (NB: we are currently not eavesdropping on the DBI). It is intended that this module be used via perl's -M switch or via perl's PERL5OPT.&lt;/p&gt;
&lt;p&gt;This module has not yet been thoroughly tested. The errors in this code are mine.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;I ask forgiveness of all those giants whose toes I tripped on while coding this module.&lt;/i&gt;&lt;/p&gt;
&lt;c&gt;
package IOSnitch;

use 5.10.1;
use Carp;
use Data::Dumper;
use DBI;
use Params::Validate qw(:all);
use strict;
use warnings;
# Don't complain about ...
$Carp::CarpInternal{(__PACKAGE__)}++;

#=========== The following code should be altered to suit ones needs ============#
#                            Uses SQLite for logging
my $Logname="$0.SQLite";
my ($LOG_dbh,$LOG_sth);

    # Set the log's name
    sub import {
        my $package=shift();

        $Logname=$_[0]
            if (@_);
         }; # import:

    # Log a record
    sub log {
        @_=Params::Validate::validate_pos(@_,{ type=&gt;SCALAR|ARRAYREF|SCALARREF,optional=&gt;1 });
        local $Data::Dumper::Indent=0;
        if (@_ == 0) { # location only
            $LOG_sth-&gt;execute((caller(1))[3],''.Carp::longmess,undef);
             }
        elsif (ref $_[0] eq 'ARRAY') { # array content
            $LOG_sth-&gt;execute((caller(1))[3],''.Carp::longmess,''.Data::Dumper-&gt;Dump([\@{$_[0]}],[qw(*)]));
             }
        elsif (ref $_[0] eq 'SCALAR') { # scalar content
            $LOG_sth-&gt;execute((caller(1))[3],''.Carp::longmess,''.Data::Dumper-&gt;Dump([\${$_[0]}],[qw(*)]));
             }
        elsif (!ref $_[0]) { # String
            $LOG_sth-&gt;execute((caller(1))[3],''.Carp::longmess,$_[0]);
             }
        else {
            Carp::confess("IOSnitch::log was called with bad parameters!");
             };
         }; # log:

INIT {
    # Connect
    $LOG_dbh=DBI-&gt;connect("DBI:SQLite:$Logname",'','',{ AutoCommit=&gt;0,PrintError=&gt;1,RaiseError=&gt;1 });
    # Create the table if necessary
    $LOG_dbh-&gt;do(&lt;&lt;"__SQL__");
        create table if not exists IO (
            mode text,
            stacktrace text,
            message text
             );
__SQL__
    # Prepare an insert
    $LOG_sth=$LOG_dbh-&gt;prepare(&lt;&lt;"__SQL__");
        insert into IO (mode,stacktrace,message) values (?,?,?)
__SQL__
    # Tie STDERR, STDIN, STDOUT
    tie *STDERR,"TieSTDERR";
    tie *STDIN,"TieSTDIN";
    tie *STDOUT,"TieSTDOUT";
     };

END {
    # Commit the records
    $LOG_dbh-&gt;commit();
    # and disconnect
    $LOG_dbh-&gt;disconnect();
    # Email the resulting SQLite database to the user
    # ...
     };
#=========== The preceeding code should be altered to suit ones needs ===========#

package TieSTDERR;

use strict;
use warnings;
$Carp::CarpInternal{(__PACKAGE__)}++;

# Tie STDERR subs {

    sub CLOSE { };

    sub DESTROY { };

    sub OPEN { };

    sub PRINT {
        my $self_O=shift;
        my(@Arg_a)=@_;

        IOSnitch::log(@_ == 1 ? \$_[0] : [@_]);
        warn @Arg_a;
         }; # PRINT:

    sub PRINTF {
        my $self_O=shift;
        my($Format_s,@Arg_a)=@_;

        IOSnitch::log([@_]);#'
        warn sprintf($Format_s,@Arg_a);
         }; # PRINTF:

    sub TIEHANDLE {
        my $Class_C=shift;

        return bless [];
         }; # TIEHANDLE:

    sub UNTIE {
        my ($self_O,$count_S)=@_;

        return;
         }; # UNTIE:

#     }; # Internal (tie) Subs:

package TieSTDIN;

use strict;
use warnings;
$Carp::CarpInternal{(__PACKAGE__)}++;

# Tie STDIN subs {

my $stdin;
    sub CLOSE { };

    sub DESTROY { };

    sub OPEN { };

    sub READLINE {
        my $self_O=shift;

        if (wantarray()) {
            my @_a=&lt;$stdin&gt;;
            IOSnitch::log([@_a]);
            return @_a;
             } else {
            my $_s=&lt;$stdin&gt;;
            IOSnitch::log(\$_s);
            return $_s;
             };
         }; # READLINE:

    sub TIEHANDLE {
        my $Class_C=shift;

        # Point $stdin to the real thingie ...
        open($stdin, "&lt;&amp;STDIN");
        return bless [];
         }; # TIEHANDLE:

    sub UNTIE {
        my ($self_O,$count_S)=@_;

        return;
         }; # UNTIE:

#     }; # Internal (tie) Subs:

package TieSTDOUT;

use strict;
use warnings;
$Carp::CarpInternal{(__PACKAGE__)}++;

# Tie STDOUT subs {

my $stdout;
    sub CLOSE { };

    sub DESTROY { };

    sub OPEN { };

    sub PRINT {
        my $self_O=shift;
        my(@Arg_a)=@_;

        # write on the log
        IOSnitch::log(@_ == 1 ? \$_[0] : [@_]);
        # write on the real thingie
        print $stdout @Arg_a;
         }; # PRINT:

    sub PRINTF {
        my $self_O=shift;
        my($Format_s,@Arg_a)=@_;

        # write on the log
        IOSnitch::log([@_]);
        # write on the real thingie
        print $stdout sprintf($Format_s,@Arg_a);
         }; # PRINTF:

    sub TIEHANDLE {
        my $Class_C=shift;

        # Point $stdout to the real thingie ...
        open($stdout, "&gt;&amp;STDOUT");
        return bless [];
         }; # TIEHANDLE:

    sub UNTIE {
        my ($self_O,$count_S)=@_;

        return;
         }; # UNTIE:

#     }; # Internal (tie) Subs:

package TieIO;

use Data::Dumper;
use strict;
use warnings;
$Carp::CarpInternal{(__PACKAGE__)}++;

# Tie IO subs {
my @IO;
    sub CLOSE {
        my $self_O=shift;
        my $fh=$IO[$self_O-&gt;{fhno}];
        close($fh);
        IOSnitch::log();
         }; # CLOSE:

    sub DESTROY { };

    sub OPEN { };

    sub PRINT {
        my $self_O=shift;
        my $fh=$IO[$self_O-&gt;{fhno}];
        my(@Arg_a)=@_;

        # write on the log
        IOSnitch::log(@_ == 1 ? \$_[0] : [@_]);
        # write on the real thingie
        print $fh @Arg_a;
         }; # PRINT:

    sub PRINTF {
        my $self_O=shift;
        my $fh=$IO[$self_O-&gt;{fhno}];
        my($Format_s,@Arg_a)=@_;

        # write on the log
        IOSnitch::log([@_]);
        # write on the real thingie
        print $fh sprintf($Format_s,@Arg_a);
         }; # PRINTF:

    sub READLINE {
        my $self_O=shift;
        my $fh=$IO[$self_O-&gt;{fhno}];
        if (wantarray()) {
            my @_a=&lt;$fh&gt;;
            IOSnitch::log([@_a]);
            return @_a;
             } else {
            my $_s=&lt;$fh&gt;;
            IOSnitch::log(\$_s);
            return $_s;
             };
         }; # READLINE:

    sub TIEHANDLE {
        my $Class_C=shift;
        # Point $fh to the real thingie ...
        open(my $IO,"+&gt;&amp;",$_[0]);
        IOSnitch::log();
        push(@IO,$IO);
        return bless { fhno=&gt;$#IO, name=&gt;$_[1] };
         }; # TIEHANDLE:

    sub UNTIE { #say __PACKAGE__."::UNTIE&lt;&gt;\n";
        my ($self_O,$count_S)=@_;
        return;
         }; # UNTIE:

#     }; # Internal (tie) Subs:

BEGIN {
    # Currently not checking to insure the file will be opened readonly
    *CORE::GLOBAL::open=sub (*;$@) { # Thanks to Eliya

        use Symbol();
        my $handle;
        if (defined $_[0]) {
            $handle = Symbol::qualify_to_ref($_[0], scalar caller);
             };

        if (@_ == 1) {
            CORE::open $handle
                or warn $! and return 0;
             }
        elsif (@_ == 2) {
            CORE::open $handle, $_[1]
                or warn $! and return 0;
             }
        elsif (@_ == 3) {
            if (defined $_[2]) {
                CORE::open $handle, $_[1], $_[2]
                    or warn $! and return 0;
                 }
            else {
                CORE::open $handle, $_[1], undef  # special case
                    or warn $! and return 0;
                 };
             }
        else {
            CORE::open $handle, $_[1], $_[2], @_[3..$#_]
                or warn $! and return 0;
             };
        $_[0]=$handle
            unless defined $_[0];  # pass up to caller
        tie *$handle,"TieIO",*$handle,$_[2]||'?'
         };
     };

    0**0

__END__
=head1 NAME

IOSnitch - eavesdrop on applications simple io

=head1 VERSION

This documentation refers to IOSnitch version 0.0.1.

=head1 SYNOPSIS

    perl -MIOSnitch &lt;application&gt; ...

    or

    export PERL5OPT='-MIOSnitch'

    sqlite3 &lt;application&gt;.SQLite

=head1 LICENSE AND COPYRIGHT

This software is Copyright (c) 2012 by Clueless Newbie.
&lt;/c&gt;</field>
<field name="root_node">
953722</field>
<field name="parent_node">
953731</field>
</data>
</node>
