File Coverage

lib/Apache/Config/Preproc/include.pm
Criterion Covered Total %
statement 89 116 76.7
branch 26 46 56.5
condition n/a
subroutine 18 20 90.0
pod 3 8 37.5
total 136 190 71.5


line stmt bran cond sub pod time code
1             package Apache::Config::Preproc::include;
2 9     9   62 use parent 'Apache::Config::Preproc::Expand';
  9         18  
  9         55  
3 9     9   442 use strict;
  9         16  
  9         170  
4 9     9   40 use warnings;
  9         16  
  9         330  
5 9     9   46 use Apache::Admin::Config;
  9         15  
  9         197  
6 9     9   39 use Apache::Config::Preproc;
  9         17  
  9         46  
7 9     9   66 use File::Spec;
  9         14  
  9         258  
8 9     9   57 use Cwd 'abs_path';
  9         12  
  9         609  
9 9     9   4897 use IPC::Open3;
  9         26183  
  9         515  
10 9     9   66 use Carp;
  9         26  
  9         8095  
11              
12             our $VERSION = '1.03';
13              
14             sub new {
15 9     9 0 21 my $class = shift;
16 9         17 my $conf = shift;
17 9         75 my $self = $class->SUPER::new($conf);
18 9         55 $self->{context} = [];
19 9         24 local %_ = @_;
20 9         21 $self->{server_root} = delete $_{server_root};
21 9 50       47 if (my $v = delete $_{probe}) {
22 0 0       0 if (ref($v) eq 'ARRAY') {
23 0         0 $self->probe(@$v);
24             } else {
25 0         0 $self->probe;
26             }
27             }
28 9 50       33 croak "unrecognized arguments" if keys(%_);
29 9 50       49 $self->{check_included} = $^O eq 'MSWin32'
30             ? \&_check_included_path
31             : \&_check_included_stat;
32 9         112 return $self;
33             }
34              
35             sub server_root {
36 28     28 1 111 my $self = shift;
37 28 100       68 if (my $v = shift) {
38 9         81 $self->{server_root} = $self->conf->dequote($v);
39             }
40 28         88 return $self->{server_root};
41             }
42              
43             sub context_string {
44 22     22 0 48 my ($self, $file) = @_;
45 22         334 my ($dev,$ino) = stat($file);
46 22         678 $file = abs_path($file);
47 22         330 return "\"$file\" $dev $ino";
48             }
49              
50             sub context_push {
51 22     22 0 103 my ($self,$file,$dev,$ino) = @_;
52 22         39 push @{$self->{context}}, { file => $file, dev => $dev, ino => $ino };
  22         176  
53             }
54              
55             sub context_pop {
56 19     19 0 29 my $self = shift;
57 19         24 pop @{$self->{context}};
  19         45  
58             }
59              
60             sub expand {
61 423     423 1 586 my ($self, $d, $repl) = @_;
62              
63 423 100       767 if ($d->type eq 'directive') {
64 370 100       1361 if (lc($d->name) eq 'serverroot') {
    100          
    100          
    100          
65 9         68 $self->server_root($d->value);
66             } elsif ($d->name =~ /^include(optional)?$/i) {
67 19         228 my $optional = $1;
68              
69 19         48 my $pat = $self->conf->dequote($d->value);
70 19 50       192 unless (File::Spec->file_name_is_absolute($pat)) {
71 19 50       88 if (my $d = $self->server_root) {
72 19         199 $pat = File::Spec->catfile($d, $pat);
73             }
74             }
75              
76 19 50       482 $pat = File::Spec->catfile($pat, '*') if -d $pat;
77 19         960 my @filelist = glob $pat;
78 19 100       81 if (@filelist) {
79 18         36 foreach my $file (@filelist) {
80 23 100       444 if ($self->check_included($file)) {
81 1         250 croak "file $file already included";
82             }
83 22 50       91 if (my $inc = new Apache::Admin::Config($file,
84             $self->conf->options)) {
85 22         10473 $inc->add('directive',
86             '$PUSH$' => $self->context_string($file),
87             '-ontop');
88 22         4736 $inc->add('directive',
89             '$POP$' => 0,
90             '-onbottom');
91             # NOTE: make sure each item is cloned
92 22         4009 push @$repl, map { $_->clone } $inc->select;
  86         6367  
93             } else {
94 0         0 croak $Apache::Admin::Config::ERROR;
95             }
96             }
97             }
98 18         1757 return 1;
99             } elsif ($d->name eq '$PUSH$') {
100 22 50       239 if ($d->value =~ /^\"(.+)\" (-?\d+) (-?\d+)$/) {
101 22         358 $self->context_push($1, $2, $3);
102             }
103 22         76 return 1;
104             } elsif ($d->name eq '$POP$') {
105 19         211 $self->context_pop;
106 19         68 return 1;
107             }
108             }
109            
110 363         3901 return 0;
111             }
112              
113             sub probe {
114 0     0 1 0 my ($self, @servlist) = @_;
115 0 0       0 unless (@servlist) {
116 0         0 @servlist = qw(/usr/sbin/httpd /usr/sbin/apache2);
117             }
118              
119 0         0 open(my $nullout, '>', File::Spec->devnull);
120 0         0 open(my $nullin, '<', File::Spec->devnull);
121 0         0 foreach my $serv (@servlist) {
122 9     9   74 use Symbol 'gensym';
  9         18  
  9         3577  
123 0         0 my $fd = gensym;
124 0         0 eval {
125 0 0       0 if (my $pid = open3($nullin, $fd, $nullout, $serv, '-V')) {
126 0         0 while (<$fd>) {
127 0         0 chomp;
128 0 0       0 if (/^\s+-D\s+HTTPD_ROOT=(.+)\s*$/) {
129 0         0 $self->server_root($1);
130 0         0 last;
131             }
132             }
133             }
134             };
135 0         0 close $fd;
136 0 0       0 last unless ($@)
137             }
138 0         0 close $nullin;
139 0         0 close $nullout;
140             }
141              
142             sub check_included {
143 23     23 0 49 my ($self, $file) = @_;
144 23         38 return $self->${ \ $self->{check_included} }($file);
  23         76  
145             }
146              
147             # Default included file table for unix-like OSes
148             sub _check_included_stat {
149 23     23   51 my ($self, $file) = @_;
150 23 50       395 my ($dev,$ino) = stat($file) or return 0;
151 23 50       77 return grep { $_->{dev} == $dev && $_->{ino} == $ino } @{$self->{context}};
  7         53  
  23         178  
152             }
153              
154             # Path-based file table, for defective OSes (MSWin32)
155             sub _check_included_path {
156 0     0     my ($self, $file) = @_;
157 0           my $path = abs_path($file);
158 0           return grep { $_->{file} eq $path } @{$self->{context}};
  0            
  0            
159             }
160              
161             1;
162              
163             __END__