File Coverage

blib/lib/Sys/Trace.pm
Criterion Covered Total %
statement 6 32 18.7
branch 0 16 0.0
condition n/a
subroutine 2 6 33.3
pod 4 4 100.0
total 12 58 20.6


line stmt bran cond sub pod time code
1             package Sys::Trace;
2 3     3   95415 use strict;
  3         7  
  3         117  
3 3     3   1401 use Sys::Trace::Results;
  3         7  
  3         1712  
4              
5             our $VERSION = "0.03";
6              
7             =head1 NAME
8              
9             Sys::Trace - Interface to system call tracing interfaces
10              
11             =head1 SYNOPSIS
12              
13             use Sys::Trace;
14              
15             my $trace = Sys::Trace->new(exec => [qw(ls foo)]);
16              
17             $trace->start; # Returns a PID which you can watch
18             $trace->wait; # Alternatively call this to wait on the PID
19              
20             my $result = $trace->results; # Returns a Sys::Trace::Results object
21              
22             use Cwd;
23             print $result->files(getcwd . "/"); # Should show an attempt to look at "foo"
24             # in the current directory (i.e. "ls
25             # foo", above)
26              
27             =head1 DESCRIPTION
28              
29             Provides a way to programmatically run or trace a program and see the system
30             calls it makes.
31              
32             This can be useful during testing as a way to ensure a particular file is
33             actually opened, or another hard to test interaction actually occurs.
34              
35             Currently supported tracing mechanisms are ktrace, strace and truss.
36              
37             =head1 METHODS
38              
39             =cut
40              
41             our @INTERFACES = qw(
42             Sys::Trace::Impl::Strace
43             Sys::Trace::Impl::Ktrace
44             Sys::Trace::Impl::Truss
45             );
46              
47             our @ISA;
48              
49             my $interface_class = "";
50              
51             =head2 new(%args)
52              
53             Keys in C<%args> can be:
54              
55             =over 4
56              
57             =item *
58              
59             B: Program and arguments to execute
60              
61             =item *
62              
63             B: PID of program to trace
64              
65             =item *
66              
67             B: Follow child processes too (default is 1, set to 0 to disable)
68              
69             =back
70              
71             Only one of exec or pid must be provided.
72              
73             =cut
74              
75             sub new {
76 0     0 1   my($class, %args) = @_;
77              
78 0 0         if(!$interface_class) {
79 0           for my $interface(@INTERFACES) {
80 0           my $file = $interface;
81 0           $file =~ s{::}{/}g;
82 0           $file .= ".pm";
83 0 0         eval { require $file } or next;
  0            
84              
85 0 0         if($interface->usable) {
86 0           $interface_class = $interface;
87 0           @ISA = $interface_class;
88 0           last;
89             }
90             }
91             }
92              
93 0 0         if(!$interface_class) {
94 0           require Carp;
95 0           Carp::croak("No interface for system call tracing is available on this platform");
96             }
97              
98             # Default to following forks
99 0 0         $args{follow_forks} = 1 unless exists $args{follow_forks};
100              
101 0           return $class->SUPER::new(%args);
102             }
103              
104             =head2 start
105              
106             Start running the trace.
107              
108             =cut
109              
110             sub start {
111 0     0 1   my($self) = @_;
112              
113 0 0         if(!defined $self->pid(fork)) {
114 0           die "Unable to fork: $!";
115             }
116              
117 0 0         return $self->pid if $self->pid; # parent
118 0           $self->run;
119             }
120              
121             =head2 wait
122              
123             Wait for the trace to finish
124              
125             =cut
126              
127             sub wait {
128 0     0 1   my($self) = @_;
129              
130 0 0         $? if waitpid $self->pid, 0;
131             }
132              
133             =head2 results
134              
135             Return a L object populated with the results of the trace.
136              
137             =cut
138              
139             sub results {
140 0     0 1   my($self) = @_;
141              
142 0           return Sys::Trace::Results->new($self);
143             }
144              
145             1;
146              
147             __END__