line  
 stmt  
 bran  
 cond  
 sub  
 pod  
 time  
 code  
 
1 
 
  
 
   
 
 
 
 
 
 
 
 
 
 
 
 #  
 
2 
 
 
 
 
 
 
 
 
 
 
 
 
 
 # (c) Jan Gehring    
 
3 
 
 
 
 
 
 
 
 
 
 
 
 
 
 #  
 
4 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
5 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 NAME  
 
6 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
7 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Rex::Commands::File - Transparent File Manipulation  
 
8 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
9 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 DESCRIPTION  
 
10 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
11 
 
 
 
 
 
 
 
 
 
 
 
 
 
 With this module you can manipulate files.  
 
12 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
13 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 SYNOPSIS  
 
14 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
15 
 
 
 
 
 
 
 
 
 
 
 
 
 
  task "read_passwd", "server01", sub {  
 
16 
 
 
 
 
 
 
 
 
 
 
 
 
 
    my $fh = file_read "/etc/passwd";  
 
17 
 
 
 
 
 
 
 
 
 
 
 
 
 
    for my $line ($fh->read_all) {  
 
18 
 
 
 
 
 
 
 
 
 
 
 
 
 
      print $line;  
 
19 
 
 
 
 
 
 
 
 
 
 
 
 
 
    }  
 
20 
 
 
 
 
 
 
 
 
 
 
 
 
 
    $fh->close;  
 
21 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
22 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
23 
 
 
 
 
 
 
 
 
 
 
 
 
 
  task "read_passwd2", "server01", sub {  
 
24 
 
 
 
 
 
 
 
 
 
 
 
 
 
    say cat "/etc/passwd";  
 
25 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
26 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
27 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
28 
 
 
 
 
 
 
 
 
 
 
 
 
 
  task "write_passwd", "server01", sub {  
 
29 
 
 
 
 
 
 
 
 
 
 
 
 
 
    my $fh = file_write "/etc/passwd";  
 
30 
 
 
 
 
 
 
 
 
 
 
 
 
 
    $fh->write("root:*:0:0:root user:/root:/bin/sh\n");  
 
31 
 
 
 
 
 
 
 
 
 
 
 
 
 
    $fh->close;  
 
32 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
33 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
34 
 
 
 
 
 
 
 
 
 
 
 
 
 
  delete_lines_matching "/var/log/auth.log", matching => "root";  
 
35 
 
 
 
 
 
 
 
 
 
 
 
 
 
  delete_lines_matching "/var/log/auth.log", matching => qr{Failed};  
 
36 
 
 
 
 
 
 
 
 
 
 
 
 
 
  delete_lines_matching "/var/log/auth.log",  
 
37 
 
 
 
 
 
 
 
 
 
 
 
 
 
                 matching => "root", qr{Failed}, "nobody";  
 
38 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
39 
 
 
 
 
 
 
 
 
 
 
 
 
 
  file "/path/on/the/remote/machine",  
 
40 
 
 
 
 
 
 
 
 
 
 
 
 
 
    source => "/path/on/local/machine";  
 
41 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
42 
 
 
 
 
 
 
 
 
 
 
 
 
 
  file "/path/on/the/remote/machine",  
 
43 
 
 
 
 
 
 
 
 
 
 
 
 
 
    content => "foo bar";  
 
44 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
45 
 
 
 
 
 
 
 
 
 
 
 
 
 
  file "/path/on/the/remote/machine",  
 
46 
 
 
 
 
 
 
 
 
 
 
 
 
 
    source => "/path/on/local/machine",  
 
47 
 
 
 
 
 
 
 
 
 
 
 
 
 
    owner  => "root",  
 
48 
 
 
 
 
 
 
 
 
 
 
 
 
 
    group  => "root",  
 
49 
 
 
 
 
 
 
 
 
 
 
 
 
 
    mode  => 400,  
 
50 
 
 
 
 
 
 
 
 
 
 
 
 
 
    on_change => sub { say shift, " was changed."; },  
 
51 
 
 
 
 
 
 
 
 
 
 
 
 
 
    on_no_change => sub { say shift, " wasn't changed."; };  
 
52 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
53 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
54 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 EXPORTED FUNCTIONS  
 
55 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
56 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
57 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
58 
 
 
 
 
 
 
 
 
 
 
 
 
 
 package Rex::Commands::File;  
 
59 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
60 
 
45
 
 
 
 
 
  
45
   
 
 
 
269103
 
 use v5.12.5;  
 
  
 
45
 
 
 
 
 
 
 
 
 
552
 
    
 
61 
 
45
 
 
 
 
 
  
45
   
 
 
 
245
 
 use warnings;  
 
  
 
45
 
 
 
 
 
 
 
 
 
142
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
1295
 
    
 
62 
 
45
 
 
 
 
 
  
45
   
 
 
 
222
 
 use Fcntl;  
 
  
 
45
 
 
 
 
 
 
 
 
 
98
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
11403
 
    
 
63 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
64 
 
 
 
 
 
 
 
 
 
 
 
 
 
 our $VERSION = '1.14.2.3'; # TRIAL VERSION  
 
65 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
66 
 
 
 
 
 
 
 
 
 
 
 
 
 
 require Rex::Exporter;  
 
67 
 
45
 
 
 
 
 
  
45
   
 
 
 
2251
 
 use Data::Dumper;  
 
  
 
45
 
 
 
 
 
 
 
 
 
21019
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
2275
 
    
 
68 
 
45
 
 
 
 
 
  
45
   
 
 
 
2432
 
 use Rex::Config;  
 
  
 
45
 
 
 
 
 
 
 
 
 
104
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
398
 
    
 
69 
 
45
 
 
 
 
 
  
45
   
 
 
 
3235
 
 use Rex::FS::File;  
 
  
 
45
 
 
 
 
 
 
 
 
 
130
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
456
 
    
 
70 
 
45
 
 
 
 
 
  
45
   
 
 
 
1594
 
 use Rex::Commands::Upload;  
 
  
 
45
 
 
 
 
 
 
 
 
 
222
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
362
 
    
 
71 
 
45
 
 
 
 
 
  
45
   
 
 
 
299
 
 use Rex::Commands::MD5;  
 
  
 
45
 
 
 
 
 
 
 
 
 
110
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
251
 
    
 
72 
 
45
 
 
 
 
 
  
45
   
 
 
 
514
 
 use Rex::File::Parser::Data;  
 
  
 
45
 
 
 
 
 
 
 
 
 
139
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
570
 
    
 
73 
 
45
 
 
 
 
 
  
45
   
 
 
 
1377
 
 use Rex::Helper::File::Spec;  
 
  
 
45
 
 
 
 
 
 
 
 
 
97
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
263
 
    
 
74 
 
45
 
 
 
 
 
  
45
   
 
 
 
1072
 
 use Rex::Helper::System;  
 
  
 
45
 
 
 
 
 
 
 
 
 
117
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
394
 
    
 
75 
 
45
 
 
 
 
 
  
45
   
 
 
 
1238
 
 use Rex::Helper::Path;  
 
  
 
45
 
 
 
 
 
 
 
 
 
111
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
2603
 
    
 
76 
 
45
 
 
 
 
 
  
45
   
 
 
 
261
 
 use Rex::Hook;  
 
  
 
45
 
 
 
 
 
 
 
 
 
89
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
1609
 
    
 
77 
 
45
 
 
 
 
 
  
45
   
 
 
 
281
 
 use Carp;  
 
  
 
45
 
 
 
 
 
 
 
 
 
107
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
2310
 
    
 
78 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
79 
 
45
 
 
 
 
 
  
45
   
 
 
 
276
 
 use Rex::Interface::Exec;  
 
  
 
45
 
 
 
 
 
 
 
 
 
116
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
589
 
    
 
80 
 
45
 
 
 
 
 
  
45
   
 
 
 
1172
 
 use Rex::Interface::File;  
 
  
 
45
 
 
 
 
 
 
 
 
 
86
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
244
 
    
 
81 
 
45
 
 
 
 
 
  
45
   
 
 
 
1110
 
 use Rex::Interface::Fs;  
 
  
 
45
 
 
 
 
 
 
 
 
 
115
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
293
 
    
 
82 
 
 
 
 
 
 
 
 
 
 
 
 
 
 require Rex::CMDB;  
 
83 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
84 
 
45
 
 
 
 
 
  
45
   
 
 
 
1981
 
 use File::Basename qw(dirname basename);  
 
  
 
45
 
 
 
 
 
 
 
 
 
93
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
2356
 
    
 
85 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
86 
 
45
 
 
 
 
 
  
45
   
 
 
 
274
 
 use vars qw(@EXPORT);  
 
  
 
45
 
 
 
 
 
 
 
 
 
116
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
2022
 
    
 
87 
 
45
 
 
 
 
 
  
45
   
 
 
 
307
 
 use base qw(Rex::Exporter);  
 
  
 
45
 
 
 
 
 
 
 
 
 
117
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
4815
 
    
 
88 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
89 
 
 
 
 
 
 
 
 
 
 
 
 
 
 @EXPORT = qw(file_write file_read file_append  
 
90 
 
 
 
 
 
 
 
 
 
 
 
 
 
   cat sed  
 
91 
 
 
 
 
 
 
 
 
 
 
 
 
 
   delete_lines_matching append_if_no_such_line delete_lines_according_to  
 
92 
 
 
 
 
 
 
 
 
 
 
 
 
 
   file template append_or_amend_line  
 
93 
 
 
 
 
 
 
 
 
 
 
 
 
 
   extract);  
 
94 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
95 
 
45
 
 
 
 
 
  
45
   
 
 
 
324
 
 use vars qw(%file_handles);  
 
  
 
45
 
 
 
 
 
 
 
 
 
131
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
180696
 
    
 
96 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
97 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 template($file [, %params])  
 
98 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
99 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Parse a template and return the content.  
 
100 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
101 
 
 
 
 
 
 
 
 
 
 
 
 
 
 By default, it uses L. If any of the L or L<1.3|Rex#1.3> (or newer) feature flag is enabled, then L is used instead of this module (recommended).     
 
102 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
103 
 
 
 
 
 
 
 
 
 
 
 
 
 
 For more advanced functionality, you may use your favorite template engine via the L configuration option.   
 
104 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
105 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Template variables may be passed either as hash or a hash reference. The following calls are equivalent:  
 
106 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
107 
 
 
 
 
 
 
 
 
 
 
 
 
 
  template( $template, variable => value );  
 
108 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
109 
 
 
 
 
 
 
 
 
 
 
 
 
 
  template( $template, { variable => value } );  
 
110 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
111 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head3 List of exposed template variables  
 
112 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
113 
 
 
 
 
 
 
 
 
 
 
 
 
 
 The following template variables are passed to the underlying templating engine, in order of precedence from low to high (variables of the same name are overridden by the next level aka "last one wins"):  
 
114 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
115 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =over 4  
 
116 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
117 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item task parameters  
 
118 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
119 
 
 
 
 
 
 
 
 
 
 
 
 
 
 All task parameters coming from the command line via C>, or from calling a task as a function, like C value } )>>.    
 
120 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
121 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item resource parameters  
 
122 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
123 
 
 
 
 
 
 
 
 
 
 
 
 
 
 All resource parameters as returned by Cget_current_resource()-Eget_all_parameters>, when called inside a resource.    
 
124 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
125 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item explicit template variables  
 
126 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
127 
 
 
 
 
 
 
 
 
 
 
 
 
 
 All manually specified, explicit template variables passed to C.   
 
128 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
129 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item system information  
 
130 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
131 
 
 
 
 
 
 
 
 
 
 
 
 
 
 The results from all available L modules as returned by Cget('All')>.    
 
132 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
133 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Pass C<__no_sys_info__ =E TRUE> as a template variable to disable including system information:   
 
134 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
135 
 
 
 
 
 
 
 
 
 
 
 
 
 
  my $content = template( $template, __no_sys_info__ => TRUE );  
 
136 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
137 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =back  
 
138 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
139 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head3 Embedded templates  
 
140 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
141 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Use C<__DATA__> to embed templates at the end of the file. Prefix embedded template names with C<@>. If embedding multiple templates, mark their end with C<@end>.  
 
142 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
143 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head4 Single template  
 
144 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
145 
 
 
 
 
 
 
 
 
 
 
 
 
 
  my $content = template( '@hello', name => 'world' ); # Hello, world!  
 
146 
 
 
 
 
 
 
 
 
 
 
 
 
 
  __DATA__  
 
147 
 
 
 
 
 
 
 
 
 
 
 
 
 
  @hello  
 
148 
 
 
 
 
 
 
 
 
 
 
 
 
 
  Hello, <%= $name -%>!  
 
149 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
150 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head4 Multiple templates  
 
151 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
152 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Use C<@end> to separate multiple templates inside C<__DATA__>.  
 
153 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
154 
 
 
 
 
 
 
 
 
 
 
 
 
 
  my $content     = template( '@hello', name => 'world' ); # Hello, world!  
 
155 
 
 
 
 
 
 
 
 
 
 
 
 
 
  my $alternative = template( '@hi',    name => 'world' ); # Hi, world!  
 
156 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
157 
 
 
 
 
 
 
 
 
 
 
 
 
 
  __DATA__  
 
158 
 
 
 
 
 
 
 
 
 
 
 
 
 
  @hello  
 
159 
 
 
 
 
 
 
 
 
 
 
 
 
 
  Hello, <%= $name -%>!  
 
160 
 
 
 
 
 
 
 
 
 
 
 
 
 
  @end  
 
161 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
162 
 
 
 
 
 
 
 
 
 
 
 
 
 
  @hi  
 
163 
 
 
 
 
 
 
 
 
 
 
 
 
 
  Hi, <%= $name -%>!  
 
164 
 
 
 
 
 
 
 
 
 
 
 
 
 
  @end  
 
165 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
166 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head3 File templates  
 
167 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
168 
 
 
 
 
 
 
 
 
 
 
 
 
 
  my $content = template("/files/templates/vhosts.tpl",  
 
169 
 
 
 
 
 
 
 
 
 
 
 
 
 
                name      => "test.lan",  
 
170 
 
 
 
 
 
 
 
 
 
 
 
 
 
                webmaster => 'webmaster@test.lan');  
 
171 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
172 
 
 
 
 
 
 
 
 
 
 
 
 
 
 The file name specified is subject to "path_map" processing as documented  
 
173 
 
 
 
 
 
 
 
 
 
 
 
 
 
 under the file() function to resolve to a physical file name.  
 
174 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
175 
 
 
 
 
 
 
 
 
 
 
 
 
 
 In addition to the "path_map" processing, if the B<-E> command line switch  
 
176 
 
 
 
 
 
 
 
 
 
 
 
 
 
 is used to specify an environment name, existence of a file ending with  
 
177 
 
 
 
 
 
 
 
 
 
 
 
 
 
 '.' is checked and has precedence over the file without one, if it   
 
178 
 
 
 
 
 
 
 
 
 
 
 
 
 
 exists. E.g. if rex is started as:  
 
179 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
180 
 
 
 
 
 
 
 
 
 
 
 
 
 
  $ rex -E prod task1  
 
181 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
182 
 
 
 
 
 
 
 
 
 
 
 
 
 
 then in task1 defined as:  
 
183 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
184 
 
 
 
 
 
 
 
 
 
 
 
 
 
  task "task1", sub {  
 
185 
 
 
 
 
 
 
 
 
 
 
 
 
 
     say template("files/etc/ntpd.conf");  
 
186 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
187 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
188 
 
 
 
 
 
 
 
 
 
 
 
 
 
 will print the content of 'files/etc/ntpd.conf.prod' if it exists.  
 
189 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
190 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Note: the appended environment mechanism is always applied, after  
 
191 
 
 
 
 
 
 
 
 
 
 
 
 
 
 the 'path_map' mechanism, if that is configured.  
 
192 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
193 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
194 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
195 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub template {  
 
196 
 
19
 
 
 
 
 
  
19
   
 
  
1
   
 
6425
 
   my ( $file, @params ) = @_;  
 
197 
 
19
 
 
 
 
 
 
 
 
 
82
 
   my $param;  
 
198 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
199 
 
19
 
  
100
   
 
 
 
 
 
 
 
120
 
   if ( ref $params[0] eq "HASH" ) {  
 
200 
 
3
 
 
 
 
 
 
 
 
 
10
 
     $param = $params[0];  
 
201 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
202 
 
 
 
 
 
 
 
 
 
 
 
 
 
   else {  
 
203 
 
16
 
 
 
 
 
 
 
 
 
96
 
     $param = {@params};  
 
204 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
205 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
206 
 
19
 
  
 50
   
 
 
 
 
 
 
 
128
 
   if ( !exists $param->{server} ) {  
 
207 
 
19
 
 
 
 
 
 
 
 
 
159
 
     $param->{server} = Rex::Commands::connection()->server;  
 
208 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
209 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
210 
 
19
 
 
 
 
 
 
 
 
 
67
 
   my $content;  
 
211 
 
19
 
  
100
   
 
  
 66
   
 
 
 
 
 
261
 
   if ( ref $file && ref $file eq 'SCALAR' ) {  
 
212 
 
16
 
 
 
 
 
 
 
 
 
50
 
     $content = ${$file};  
 
  
 
16
 
 
 
 
 
 
 
 
 
82
 
    
 
213 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
214 
 
 
 
 
 
 
 
 
 
 
 
 
 
   else {  
 
215 
 
3
 
 
 
 
 
 
 
 
 
10
 
     $file = resolv_path($file);  
 
216 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
217 
 
3
 
  
100
   
 
  
 66
   
 
 
 
 
 
21
 
     unless ( $file =~ m/^\// || $file =~ m/^\@/ ) {  
 
218 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
219 
 
 
 
 
 
 
 
 
 
 
 
 
 
       # path is relative and no template  
 
220 
 
1
 
 
 
 
 
 
 
 
 
8
 
       Rex::Logger::debug("Relativ path $file");  
 
221 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
222 
 
1
 
 
 
 
 
 
 
 
 
45
 
       $file = Rex::Helper::Path::get_file_path( $file, caller() );  
 
223 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
224 
 
1
 
 
 
 
 
 
 
 
 
6
 
       Rex::Logger::debug("New filename: $file");  
 
225 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
226 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
227 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # if there is a file called filename.environment then use this file  
 
228 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # ex:  
 
229 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # $content = template("files/hosts.tpl");  
 
230 
 
 
 
 
 
 
 
 
 
 
 
 
 
     #  
 
231 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # rex -E live ...  
 
232 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # will first look if files/hosts.tpl.live is available, if not it will  
 
233 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # use files/hosts.tpl  
 
234 
 
3
 
  
 50
   
 
 
 
 
 
 
 
19
 
     if ( -f "$file." . Rex::Config->get_environment ) {  
 
235 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
       $file = "$file." . Rex::Config->get_environment;  
 
236 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
237 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
238 
 
3
 
  
100
   
 
 
 
 
 
 
 
61
 
     if ( -f $file ) {  
 
  
 
 
 
  
 50
   
 
 
 
 
 
 
 
 
 
    
 
239 
 
1
 
 
 
 
 
 
 
 
 
3
 
       $content = eval { local ( @ARGV, $/ ) = ($file); <>; };  
 
  
 
1
 
 
 
 
 
 
 
 
 
8
 
    
 
  
 
1
 
 
 
 
 
 
 
 
 
106
 
    
 
240 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
241 
 
 
 
 
 
 
 
 
 
 
 
 
 
     elsif ( $file =~ m/^\@/ ) {  
 
242 
 
2
 
 
 
 
 
 
 
 
 
21
 
       my @caller = caller(0);  
 
243 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
244 
 
2
 
 
 
 
 
 
 
 
 
10
 
       my $file_path = Rex::get_module_path( $caller[0] );  
 
245 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
246 
 
2
 
  
 50
   
 
 
 
 
 
 
 
18
 
       if ( !-f $file_path ) {  
 
247 
 
2
 
 
 
 
 
 
 
 
 
7
 
         my ($mod_name) = ( $caller[0] =~ m/^.*::(.*?)$/ );  
 
248 
 
2
 
  
 50
   
 
  
 33
   
 
 
 
 
 
99
 
         if ( $mod_name && -f "$file_path/$mod_name.pm" ) {  
 
  
 
 
 
  
 50
   
 
 
 
 
 
 
 
 
 
    
 
  
 
 
 
  
 50
   
 
 
 
 
 
 
 
 
 
    
 
  
 
 
 
  
 50
   
 
 
 
 
 
 
 
 
 
    
 
  
 
 
 
  
  0
   
 
 
 
 
 
 
 
 
 
    
 
249 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
           $file_path = "$file_path/$mod_name.pm";  
 
250 
 
 
 
 
 
 
 
 
 
 
 
 
 
         }  
 
251 
 
 
 
 
 
 
 
 
 
 
 
 
 
         elsif ( -f "$file_path/__module__.pm" ) {  
 
252 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
           $file_path = "$file_path/__module__.pm";  
 
253 
 
 
 
 
 
 
 
 
 
 
 
 
 
         }  
 
254 
 
 
 
 
 
 
 
 
 
 
 
 
 
         elsif ( -f "$file_path/Module.pm" ) {  
 
255 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
           $file_path = "$file_path/Module.pm";  
 
256 
 
 
 
 
 
 
 
 
 
 
 
 
 
         }  
 
257 
 
 
 
 
 
 
 
 
 
 
 
 
 
         elsif ( -f $caller[1] ) {  
 
258 
 
2
 
 
 
 
 
 
 
 
 
9
 
           $file_path = $caller[1];  
 
259 
 
 
 
 
 
 
 
 
 
 
 
 
 
         }  
 
260 
 
 
 
 
 
 
 
 
 
 
 
 
 
         elsif ( $caller[1] =~ m|^/loader/[^/]+/__Rexfile__.pm$| ) {  
 
261 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
           $file_path = $INC{"__Rexfile__.pm"};  
 
262 
 
 
 
 
 
 
 
 
 
 
 
 
 
         }  
 
263 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
264 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
265 
 
2
 
 
 
 
 
 
 
 
 
5
 
       my $file_content = eval { local ( @ARGV, $/ ) = ($file_path); <>; };  
 
  
 
2
 
 
 
 
 
 
 
 
 
11
 
    
 
  
 
2
 
 
 
 
 
 
 
 
 
133
 
    
 
266 
 
2
 
 
 
 
 
 
 
 
 
20
 
       my ($data)       = ( $file_content =~ m/.*__DATA__(.*)/ms );  
 
267 
 
2
 
 
 
 
 
 
 
 
 
26
 
       my $fp = Rex::File::Parser::Data->new( data => [ split( /\n/, $data ) ] );  
 
268 
 
2
 
 
 
 
 
 
 
 
 
5
 
       my $snippet_to_read = substr( $file, 1 );  
 
269 
 
2
 
 
 
 
 
 
 
 
 
8
 
       $content = $fp->read($snippet_to_read);  
 
270 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
271 
 
 
 
 
 
 
 
 
 
 
 
 
 
     else {  
 
272 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
       die("$file not found");  
 
273 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
274 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
275 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
276 
 
19
 
 
 
 
 
 
 
 
 
70
 
   my %template_vars;  
 
277 
 
19
 
  
100
   
 
 
 
 
 
 
 
86
 
   if ( !exists $param->{__no_sys_info__} ) {  
 
278 
 
13
 
 
 
 
 
 
 
 
 
48
 
     %template_vars = _get_std_template_vars($param);  
 
279 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
280 
 
 
 
 
 
 
 
 
 
 
 
 
 
   else {  
 
281 
 
6
 
 
 
 
 
 
 
 
 
19
 
     delete $param->{__no_sys_info__};  
 
282 
 
6
 
 
 
 
 
 
 
 
 
16
 
     %template_vars = %{$param};  
 
  
 
6
 
 
 
 
 
 
 
 
 
37
 
    
 
283 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
284 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
285 
 
 
 
 
 
 
 
 
 
 
 
 
 
   # configuration variables  
 
286 
 
19
 
 
 
 
 
 
 
 
 
276
 
   my $config_values = Rex::Config->get_all;  
 
287 
 
19
 
 
 
 
 
 
 
 
 
45
 
   for my $key ( keys %{$config_values} ) {  
 
  
 
19
 
 
 
 
 
 
 
 
 
224
 
    
 
288 
 
26
 
  
100
   
 
 
 
 
 
 
 
135
 
     if ( !exists $template_vars{$key} ) {  
 
289 
 
25
 
 
 
 
 
 
 
 
 
166
 
       $template_vars{$key} = $config_values->{$key};  
 
290 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
291 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
292 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
293 
 
19
 
  
100
   
 
  
 66
   
 
 
 
 
 
204
 
   if ( Rex::CMDB::cmdb_active() && Rex::Config->get_register_cmdb_template ) {  
 
294 
 
4
 
 
 
 
 
 
 
 
 
18
 
     my $data = Rex::CMDB::cmdb();  
 
295 
 
4
 
 
 
 
 
 
 
 
 
26
 
     for my $key ( keys %{ $data->{value} } ) {  
 
  
 
4
 
 
 
 
 
 
 
 
 
38
 
    
 
296 
 
28
 
  
100
   
 
 
 
 
 
 
 
61
 
       if ( !exists $template_vars{$key} ) {  
 
297 
 
26
 
 
 
 
 
 
 
 
 
109
 
         $template_vars{$key} = $data->{value}->{$key};  
 
298 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
299 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
300 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
301 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
302 
 
19
 
 
 
 
 
 
 
 
 
329
 
   return Rex::Config->get_template_function()->( $content, \%template_vars );  
 
303 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
304 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
305 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub _get_std_template_vars {  
 
306 
 
13
 
 
 
 
 
  
13
   
 
 
 
31
 
   my ($param) = @_;  
 
307 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
308 
 
13
 
  
 50
   
 
 
 
 
 
 
 
41
 
   my %merge1 = %{ $param || {} };  
 
  
 
13
 
 
 
 
 
 
 
 
 
78
 
    
 
309 
 
13
 
 
 
 
 
 
 
 
 
31
 
   my %merge2;  
 
310 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
311 
 
13
 
  
 50
   
 
 
 
 
 
 
 
55
 
   if ( Rex::get_cache()->valid("system_information_info") ) {  
 
312 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     %merge2 = %{ Rex::get_cache()->get("system_information_info") };  
 
  
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
    
 
313 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
314 
 
 
 
 
 
 
 
 
 
 
 
 
 
   else {  
 
315 
 
13
 
 
 
 
 
 
 
 
 
60
 
     %merge2 = Rex::Helper::System::info();  
 
316 
 
13
 
 
 
 
 
 
 
 
 
137
 
     Rex::get_cache()->set( "system_information_info", \%merge2 );  
 
317 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
318 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
319 
 
13
 
 
 
 
 
 
 
 
 
405
 
   my %template_vars = ( %merge1, %merge2 );  
 
320 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
321 
 
13
 
 
 
 
 
 
 
 
 
491
 
   return %template_vars;  
 
322 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
323 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
324 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 file($file_name [, %options])  
 
325 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
326 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This function is the successor of I. Please use this function to upload files to your server.   
 
327 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
328 
 
 
 
 
 
 
 
 
 
 
 
 
 
  task "prepare", "server1", "server2", sub {  
 
329 
 
 
 
 
 
 
 
 
 
 
 
 
 
    file "/file/on/remote/machine",  
 
330 
 
 
 
 
 
 
 
 
 
 
 
 
 
      source => "/file/on/local/machine";  
 
331 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
332 
 
 
 
 
 
 
 
 
 
 
 
 
 
    file "/etc/hosts",  
 
333 
 
 
 
 
 
 
 
 
 
 
 
 
 
      content => template("templates/etc/hosts.tpl"),  
 
334 
 
 
 
 
 
 
 
 
 
 
 
 
 
      owner  => "user",  
 
335 
 
 
 
 
 
 
 
 
 
 
 
 
 
      group  => "group",  
 
336 
 
 
 
 
 
 
 
 
 
 
 
 
 
      mode   => 700,  
 
337 
 
 
 
 
 
 
 
 
 
 
 
 
 
      on_change => sub { say "Something was changed." },  
 
338 
 
 
 
 
 
 
 
 
 
 
 
 
 
      on_no_change => sub { say "Nothing has changed." };  
 
339 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
340 
 
 
 
 
 
 
 
 
 
 
 
 
 
    file "/etc/motd",  
 
341 
 
 
 
 
 
 
 
 
 
 
 
 
 
      content => `fortune`;  
 
342 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
343 
 
 
 
 
 
 
 
 
 
 
 
 
 
    file "/etc/named.conf",  
 
344 
 
 
 
 
 
 
 
 
 
 
 
 
 
      content    => template("templates/etc/named.conf.tpl"),  
 
345 
 
 
 
 
 
 
 
 
 
 
 
 
 
      no_overwrite => TRUE;  # this file will not be overwritten if already exists.  
 
346 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
347 
 
 
 
 
 
 
 
 
 
 
 
 
 
    file "/etc/httpd/conf/httpd.conf",  
 
348 
 
 
 
 
 
 
 
 
 
 
 
 
 
      source => "/files/etc/httpd/conf/httpd.conf",  
 
349 
 
 
 
 
 
 
 
 
 
 
 
 
 
      on_change => sub { service httpd => "restart"; };  
 
350 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
351 
 
 
 
 
 
 
 
 
 
 
 
 
 
    file "/etc/named.d",  
 
352 
 
 
 
 
 
 
 
 
 
 
 
 
 
      ensure => "directory",  # this will create a directory  
 
353 
 
 
 
 
 
 
 
 
 
 
 
 
 
      owner  => "root",  
 
354 
 
 
 
 
 
 
 
 
 
 
 
 
 
      group  => "root";  
 
355 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
356 
 
 
 
 
 
 
 
 
 
 
 
 
 
    file "/etc/motd",  
 
357 
 
 
 
 
 
 
 
 
 
 
 
 
 
      ensure => "absent";   # this will remove the file or directory  
 
358 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
359 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
360 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
361 
 
 
 
 
 
 
 
 
 
 
 
 
 
 The first parameter is either a string or an array reference. In the latter case the  
 
362 
 
 
 
 
 
 
 
 
 
 
 
 
 
 function is called for all strings in the array. Therefore, the following constructs  
 
363 
 
 
 
 
 
 
 
 
 
 
 
 
 
 are equivalent:  
 
364 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
365 
 
 
 
 
 
 
 
 
 
 
 
 
 
   file '/tmp/test1', ensure => 'directory';  
 
366 
 
 
 
 
 
 
 
 
 
 
 
 
 
   file '/tmp/test2', ensure => 'directory';  
 
367 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
368 
 
 
 
 
 
 
 
 
 
 
 
 
 
   file [ qw( /tmp/test1 /tmp/test2 ) ], ensure => 'directory'; # use array ref  
 
369 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
370 
 
 
 
 
 
 
 
 
 
 
 
 
 
   file [ glob('/tmp/test{1,2}') ], ensure => 'directory'; # explicit glob call for array contents  
 
371 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
372 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Use the glob carefully as B (e.g. when using wildcards).   
 
373 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
374 
 
 
 
 
 
 
 
 
 
 
 
 
 
 The I is subject to a path resolution algorithm. This algorithm   
 
375 
 
 
 
 
 
 
 
 
 
 
 
 
 
 can be configured using the I function to set the value of the   
 
376 
 
 
 
 
 
 
 
 
 
 
 
 
 
 I variable to a hash containing path prefixes as its keys.   
 
377 
 
 
 
 
 
 
 
 
 
 
 
 
 
 The associated values are arrays listing the prefix replacements in order  
 
378 
 
 
 
 
 
 
 
 
 
 
 
 
 
 of (decreasing) priority.  
 
379 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
380 
 
 
 
 
 
 
 
 
 
 
 
 
 
   set "path_map", {  
 
381 
 
 
 
 
 
 
 
 
 
 
 
 
 
     "files/" => [ "files/{environment}/{hostname}/_root_/",  
 
382 
 
 
 
 
 
 
 
 
 
 
 
 
 
                   "files/{environment}/_root_/" ]  
 
383 
 
 
 
 
 
 
 
 
 
 
 
 
 
   };  
 
384 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
385 
 
 
 
 
 
 
 
 
 
 
 
 
 
 With this configuration, the file "files/etc/ntpd.conf" will be probed for  
 
386 
 
 
 
 
 
 
 
 
 
 
 
 
 
 in the following locations:  
 
387 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
388 
 
 
 
 
 
 
 
 
 
 
 
 
 
  - files/{environment}/{hostname}/_root_/etc/ntpd.conf  
 
389 
 
 
 
 
 
 
 
 
 
 
 
 
 
  - files/{environment}/_root_/etc/ntpd.conf  
 
390 
 
 
 
 
 
 
 
 
 
 
 
 
 
  - files/etc/ntpd.conf  
 
391 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
392 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Furthermore, if a path prefix matches multiple prefix entries in 'path_map',  
 
393 
 
 
 
 
 
 
 
 
 
 
 
 
 
 e.g. "files/etc/ntpd.conf" matching both "files/" and "files/etc/", the  
 
394 
 
 
 
 
 
 
 
 
 
 
 
 
 
 longer matching prefix(es) have precedence over shorter ones. Note that  
 
395 
 
 
 
 
 
 
 
 
 
 
 
 
 
 keys without a trailing slash (i.e. "files/etc") will be treated as having  
 
396 
 
 
 
 
 
 
 
 
 
 
 
 
 
 a trailing slash when matching the prefix ("files/etc/").  
 
397 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
398 
 
 
 
 
 
 
 
 
 
 
 
 
 
 If no file is found using the above procedure and I is relative,   
 
399 
 
 
 
 
 
 
 
 
 
 
 
 
 
 it will search from the location of your I or the I<.pm> file if   
 
400 
 
 
 
 
 
 
 
 
 
 
 
 
 
 you use Perl packages.  
 
401 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
402 
 
 
 
 
 
 
 
 
 
 
 
 
 
 All the possible variables ('{environment}', '{hostname}', ...) are documented  
 
403 
 
 
 
 
 
 
 
 
 
 
 
 
 
 in the CMDB YAML documentation.  
 
404 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
405 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head3 Hooks  
 
406 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
407 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This function supports the following L:   
 
408 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
409 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =over 4  
 
410 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
411 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item before  
 
412 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
413 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This gets executed before anything is done. All original parameters are passed to it, including the applied defaults (C 'present'>, resolved path for C).    
 
414 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
415 
 
 
 
 
 
 
 
 
 
 
 
 
 
 The return value of this hook overwrites the original parameters of the function call.  
 
416 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
417 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item before_change  
 
418 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
419 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This gets executed right before the new file is written. All original parameters are passed to it, including the applied defaults (C 'present'>, resolved path for C).    
 
420 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
421 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item after_change  
 
422 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
423 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This gets executed right after the file is written. All original parameters, including the applied defaults (C 'present'>, resolved path for C), and any returned results are passed to it.    
 
424 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
425 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item after  
 
426 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
427 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This gets executed right before the C function returns. All original parameters, including the applied defaults (C 'present'>, resolved path for C), and any returned results are passed to it.     
 
428 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
429 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =back  
 
430 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
431 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
432 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
433 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub file {  
 
434 
 
53
 
 
 
 
 
  
53
   
 
  
1
   
 
68086
 
   my ( $file, @options ) = @_;  
 
435 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
436 
 
53
 
  
 50
   
 
 
 
 
 
 
 
419
 
   if ( ref $file eq "ARRAY" ) {  
 
437 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     my @ret;  
 
438 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
439 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # $file is an array, so iterate over these files  
 
440 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     for my $f ( @{$file} ) {  
 
  
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
    
 
441 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
       push( @ret, file( $f, @options ) );  
 
442 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
443 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
444 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     return \@ret;  
 
445 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
446 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
447 
 
53
 
 
 
 
 
 
 
 
 
572
 
   my $option = {@options};  
 
448 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
449 
 
53
 
 
 
 
 
 
 
 
 
438
 
   $file = resolv_path($file);  
 
450 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
451 
 
53
 
 
 
 
 
 
 
 
 
242
 
   my ($is_directory);  
 
452 
 
53
 
  
100
   
 
  
100
   
 
 
 
 
 
536
 
   if ( exists $option->{ensure} && $option->{ensure} eq "directory" ) {  
 
453 
 
2
 
 
 
 
 
 
 
 
 
13
 
     $is_directory = 1;  
 
454 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
455 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
456 
 
53
 
  
100
   
 
  
 66
   
 
 
 
 
 
325
 
   if ( exists $option->{source} && !$is_directory ) {  
 
457 
 
3
 
 
 
 
 
 
 
 
 
28
 
     $option->{source} = resolv_path( $option->{source} );  
 
458 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
459 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
460 
 
 
 
 
 
 
 
 
 
 
 
 
 
   # default: ensure = present  
 
461 
 
53
 
 
 
  
100
   
 
 
 
 
 
1119
 
   $option->{ensure} ||= "present";  
 
462 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
463 
 
53
 
 
 
 
 
 
 
 
 
1121
 
   my $fs = Rex::Interface::Fs->create;  
 
464 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
465 
 
53
 
  
100
   
 
  
100
   
 
 
 
 
 
1315
 
   if ( $option->{ensure} ne 'absent' && $fs->is_symlink($file) ) {  
 
466 
 
4
 
 
 
 
 
 
 
 
 
111
 
     my $original_file = $file;  
 
467 
 
4
 
 
 
 
 
 
 
 
 
123
 
     $file = resolve_symlink($file);  
 
468 
 
4
 
 
 
 
 
 
 
 
 
262
 
     Rex::Logger::info(  
 
469 
 
 
 
 
 
 
 
 
 
 
 
 
 
       "$original_file is a symlink, operating on $file instead", 'warn' );  
 
470 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
471 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
472 
 
 
 
 
 
 
 
 
 
 
 
 
 
   #### check and run before hook  
 
473 
 
 
 
 
 
 
 
 
 
 
 
 
 
   eval {  
 
474 
 
53
 
 
 
 
 
 
 
 
 
212
 
     my @new_args = Rex::Hook::run_hook( file => "before", $file, %{$option} );  
 
  
 
53
 
 
 
 
 
 
 
 
 
2062
 
    
 
475 
 
53
 
  
100
   
 
 
 
 
 
 
 
416
 
     if (@new_args) {  
 
476 
 
3
 
 
 
 
 
 
 
 
 
42
 
       ( $file, @options ) = @new_args;  
 
477 
 
3
 
 
 
 
 
 
 
 
 
21
 
       $option = {@options};  
 
478 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
479 
 
53
 
 
 
 
 
 
 
 
 
273
 
     1;  
 
480 
 
53
 
  
 50
   
 
 
 
 
 
 
 
584
 
   } or do {  
 
481 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     die("Before hook failed. Cancelling file() action: $@");  
 
482 
 
 
 
 
 
 
 
 
 
 
 
 
 
   };  
 
483 
 
 
 
 
 
 
 
 
 
 
 
 
 
   ##############################  
 
484 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
485 
 
 
 
 
 
 
 
 
 
 
 
 
 
   Rex::get_current_connection()->{reporter}  
 
486 
 
53
 
 
 
 
 
 
 
 
 
262
 
     ->report_resource_start( type => "file", name => $file );  
 
487 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
488 
 
53
 
  
100
   
 
  
100
   
 
 
 
 
 
499
 
   my $need_md5     = ( $option->{"on_change"} && !$is_directory ? 1 : 0 );  
 
489 
 
53
 
 
 
  
100
   
 
  
40
   
 
 
 
1519
 
   my $on_change    = $option->{"on_change"}    || sub { };  
 
490 
 
53
 
 
 
  
 50
   
 
  
12
   
 
 
 
884
 
   my $on_no_change = $option->{"on_no_change"} || sub { };  
 
491 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
492 
 
53
 
 
 
 
 
 
 
 
 
296
 
   my $__ret = { changed => 0 };  
 
493 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
494 
 
53
 
 
 
 
 
 
 
 
 
142
 
   my ( $new_md5, $old_md5 );  
 
495 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
496 
 
53
 
  
 50
   
 
  
 33
   
 
 
 
 
 
1044
 
   if ( exists $option->{no_overwrite}  
 
  
 
 
 
  
100
   
 
  
  0
   
 
 
 
 
 
 
 
    
 
  
 
 
 
 
 
  
100
   
 
 
 
 
 
 
 
    
 
  
 
 
 
 
 
  
 66
   
 
 
 
 
 
 
 
    
 
497 
 
 
 
 
 
 
 
 
 
 
 
 
 
     && $option->{no_overwrite}  
 
498 
 
 
 
 
 
 
 
 
 
 
 
 
 
     && $fs->is_file($file) )  
 
499 
 
 
 
 
 
 
 
 
 
 
 
 
 
   {  
 
500 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     Rex::Logger::debug(  
 
501 
 
 
 
 
 
 
 
 
 
 
 
 
 
       "File already exists and no_overwrite option given. Doing nothing.");  
 
502 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $__ret = { changed => 0 };  
 
503 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
504 
 
 
 
 
 
 
 
 
 
 
 
 
 
     Rex::get_current_connection()->{reporter}->report(  
 
505 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
       changed => 0,  
 
506 
 
 
 
 
 
 
 
 
 
 
 
 
 
       message =>  
 
507 
 
 
 
 
 
 
 
 
 
 
 
 
 
         "File already exists and no_overwrite option given. Doing nothing."  
 
508 
 
 
 
 
 
 
 
 
 
 
 
 
 
     );  
 
509 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
510 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
511 
 
 
 
 
 
 
 
 
 
 
 
 
 
   elsif ( ( exists $option->{content} || exists $option->{source} )  
 
512 
 
 
 
 
 
 
 
 
 
 
 
 
 
     && !$is_directory )  
 
513 
 
 
 
 
 
 
 
 
 
 
 
 
 
   {  
 
514 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
515 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # first upload file to tmp location, to get md5 sum.  
 
516 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # than we can decide if we need to replace the current (old) file.  
 
517 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
518 
 
42
 
 
 
 
 
 
 
 
 
670
 
     my $tmp_file_name = get_tmp_file_name($file);  
 
519 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
520 
 
42
 
  
100
   
 
 
 
 
 
 
 
282
 
     if ( exists $option->{content} ) {  
 
  
 
 
 
  
 50
   
 
 
 
 
 
 
 
 
 
    
 
521 
 
39
 
 
 
 
 
 
 
 
 
251
 
       my $fh    = file_write($tmp_file_name);  
 
522 
 
39
 
 
 
 
 
 
 
 
 
1443
 
       my @lines = split( qr{$/}, $option->{"content"} );  
 
523 
 
39
 
 
 
 
 
 
 
 
 
422
 
       for my $line (@lines) {  
 
524 
 
240
 
 
 
 
 
 
 
 
 
1321
 
         $fh->write( $line . $/ );  
 
525 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
526 
 
39
 
 
 
 
 
 
 
 
 
433
 
       $fh->close;  
 
527 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
528 
 
 
 
 
 
 
 
 
 
 
 
 
 
     elsif ( exists $option->{source} ) {  
 
529 
 
 
 
 
 
 
 
 
 
 
 
 
 
       $option->{source} =  
 
530 
 
3
 
 
 
 
 
 
 
 
 
93
 
         Rex::Helper::Path::get_file_path( $option->{source}, caller );  
 
531 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
532 
 
3
 
 
 
 
 
 
 
 
 
47
 
       upload $option->{source}, $tmp_file_name;  
 
533 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
534 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
535 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # now get md5 sums  
 
536 
 
42
 
 
 
 
 
 
 
 
 
206
 
     eval { $old_md5 = md5($file); };  
 
  
 
42
 
 
 
 
 
 
 
 
 
782
 
    
 
537 
 
42
 
 
 
 
 
 
 
 
 
378
 
     $new_md5 = md5($tmp_file_name);  
 
538 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
539 
 
42
 
  
100
   
 
  
 66
   
 
 
 
 
 
1562
 
     if ( $new_md5 && $old_md5 && $new_md5 eq $old_md5 ) {  
 
  
 
 
 
 
 
  
100
   
 
 
 
 
 
 
 
    
 
540 
 
4
 
 
 
 
 
 
 
 
 
161
 
       Rex::Logger::debug(  
 
541 
 
 
 
 
 
 
 
 
 
 
 
 
 
         "No need to overwrite existing file. Old and new files are the same. $old_md5 eq $new_md5."  
 
542 
 
 
 
 
 
 
 
 
 
 
 
 
 
       );  
 
543 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
544 
 
 
 
 
 
 
 
 
 
 
 
 
 
       # md5 sums are the same, delete tmp.  
 
545 
 
4
 
 
 
 
 
 
 
 
 
155
 
       $fs->unlink($tmp_file_name);  
 
546 
 
4
 
 
 
 
 
 
 
 
 
33
 
       $need_md5 = 0; # we don't need to execute on_change hook  
 
547 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
548 
 
 
 
 
 
 
 
 
 
 
 
 
 
       Rex::get_current_connection()->{reporter}->report(  
 
549 
 
4
 
 
 
 
 
 
 
 
 
94
 
         changed => 0,  
 
550 
 
 
 
 
 
 
 
 
 
 
 
 
 
         message =>  
 
551 
 
 
 
 
 
 
 
 
 
 
 
 
 
           "No need to overwrite existing file. Old and new files are the same. $old_md5 eq $new_md5."  
 
552 
 
 
 
 
 
 
 
 
 
 
 
 
 
       );  
 
553 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
554 
 
 
 
 
 
 
 
 
 
 
 
 
 
     else {  
 
555 
 
38
 
 
 
  
100
   
 
 
 
 
 
449
 
       $old_md5 ||= "";  
 
556 
 
38
 
 
 
 
 
 
 
 
 
718
 
       Rex::Logger::debug(  
 
557 
 
 
 
 
 
 
 
 
 
 
 
 
 
         "Need to use the new file. md5 sums are different. <<$old_md5>> = <<$new_md5>>"  
 
558 
 
 
 
 
 
 
 
 
 
 
 
 
 
       );  
 
559 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
560 
 
 
 
 
 
 
 
 
 
 
 
 
 
       #### check and run before_change hook  
 
561 
 
38
 
 
 
 
 
 
 
 
 
189
 
       Rex::Hook::run_hook( file => "before_change", $file, %{$option} );  
 
  
 
38
 
 
 
 
 
 
 
 
 
1681
 
    
 
562 
 
 
 
 
 
 
 
 
 
 
 
 
 
       ##############################  
 
563 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
564 
 
38
 
  
 50
   
 
 
 
 
 
 
 
444
 
       if (Rex::is_sudo) {  
 
565 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         my $current_options =  
 
566 
 
 
 
 
 
 
 
 
 
 
 
 
 
           Rex::get_current_connection_object()->get_current_sudo_options;  
 
567 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         Rex::get_current_connection_object()->push_sudo_options( {} );  
 
568 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
569 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
0
 
         if ( exists $current_options->{user} ) {  
 
570 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
           $fs->chown( "$current_options->{user}:", $tmp_file_name );  
 
571 
 
 
 
 
 
 
 
 
 
 
 
 
 
         }  
 
572 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
573 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
574 
 
38
 
 
 
 
 
 
 
 
 
1018
 
       $fs->rename( $tmp_file_name, $file );  
 
575 
 
38
 
  
 50
   
 
 
 
 
 
 
 
596
 
       Rex::get_current_connection_object()->pop_sudo_options()  
 
576 
 
 
 
 
 
 
 
 
 
 
 
 
 
         if (Rex::is_sudo);  
 
577 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
578 
 
38
 
 
 
 
 
 
 
 
 
1244
 
       $__ret = { changed => 1 };  
 
579 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
580 
 
 
 
 
 
 
 
 
 
 
 
 
 
       Rex::get_current_connection()->{reporter}->report(  
 
581 
 
38
 
 
 
 
 
 
 
 
 
446
 
         changed => 1,  
 
582 
 
 
 
 
 
 
 
 
 
 
 
 
 
         message => "File updated. old md5: $old_md5, new md5: $new_md5"  
 
583 
 
 
 
 
 
 
 
 
 
 
 
 
 
       );  
 
584 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
585 
 
 
 
 
 
 
 
 
 
 
 
 
 
       #### check and run after_change hook  
 
586 
 
38
 
 
 
 
 
 
 
 
 
240
 
       Rex::Hook::run_hook( file => "after_change", $file, %{$option}, $__ret );  
 
  
 
38
 
 
 
 
 
 
 
 
 
1471
 
    
 
587 
 
 
 
 
 
 
 
 
 
 
 
 
 
       ##############################  
 
588 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
589 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
590 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
591 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
592 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
593 
 
53
 
  
 50
   
 
 
 
 
 
 
 
325
 
   if ( exists $option->{"ensure"} ) {  
 
594 
 
53
 
  
100
   
 
 
 
 
 
 
 
430
 
     if ( $option->{ensure} eq "present" ) {  
 
  
 
 
 
  
100
   
 
 
 
 
 
 
 
 
 
    
 
  
 
 
 
  
 50
   
 
 
 
 
 
 
 
 
 
    
 
595 
 
49
 
  
100
   
 
 
 
 
 
 
 
641
 
       if ( !$fs->is_file($file) ) {  
 
  
 
 
 
  
100
   
 
 
 
 
 
 
 
 
 
    
 
596 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
597 
 
 
 
 
 
 
 
 
 
 
 
 
 
         #### check and run before_change hook  
 
598 
 
1
 
 
 
 
 
 
 
 
 
7
 
         Rex::Hook::run_hook( file => "before_change", $file, %{$option} );  
 
  
 
1
 
 
 
 
 
 
 
 
 
10
 
    
 
599 
 
 
 
 
 
 
 
 
 
 
 
 
 
         ##############################  
 
600 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
601 
 
1
 
 
 
 
 
 
 
 
 
16
 
         my $fh = file_write($file);  
 
602 
 
1
 
 
 
 
 
 
 
 
 
11
 
         $fh->write("");  
 
603 
 
1
 
 
 
 
 
 
 
 
 
10
 
         $fh->close;  
 
604 
 
1
 
 
 
 
 
 
 
 
 
6
 
         $__ret = { changed => 1 };  
 
605 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
606 
 
 
 
 
 
 
 
 
 
 
 
 
 
         Rex::get_current_connection()->{reporter}->report(  
 
607 
 
1
 
 
 
 
 
 
 
 
 
5
 
           changed => 1,  
 
608 
 
 
 
 
 
 
 
 
 
 
 
 
 
           message => "file is now present, with no content",  
 
609 
 
 
 
 
 
 
 
 
 
 
 
 
 
         );  
 
610 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
611 
 
 
 
 
 
 
 
 
 
 
 
 
 
         #### check and run after_change hook  
 
612 
 
 
 
 
 
 
 
 
 
 
 
 
 
         Rex::Hook::run_hook(  
 
613 
 
 
 
 
 
 
 
 
 
 
 
 
 
           file => "after_change",  
 
614 
 
1
 
 
 
 
 
 
 
 
 
5
 
           $file, %{$option}, $__ret  
 
  
 
1
 
 
 
 
 
 
 
 
 
12
 
    
 
615 
 
 
 
 
 
 
 
 
 
 
 
 
 
         );  
 
616 
 
 
 
 
 
 
 
 
 
 
 
 
 
         ##############################  
 
617 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
618 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
619 
 
 
 
 
 
 
 
 
 
 
 
 
 
       elsif ( !$__ret->{changed} ) {  
 
620 
 
10
 
 
 
 
 
 
 
 
 
149
 
         $__ret = { changed => 0 };  
 
621 
 
10
 
 
 
 
 
 
 
 
 
173
 
         Rex::get_current_connection()->{reporter}->report( changed => 0, );  
 
622 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
623 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
624 
 
 
 
 
 
 
 
 
 
 
 
 
 
     elsif ( $option->{ensure} eq "absent" ) {  
 
625 
 
2
 
 
 
 
 
 
 
 
 
41
 
       $need_md5 = 0;  
 
626 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
627 
 
 
 
 
 
 
 
 
 
 
 
 
 
       #### check and run before_change hook  
 
628 
 
2
 
 
 
 
 
 
 
 
 
13
 
       Rex::Hook::run_hook( file => "before_change", $file, %{$option} );  
 
  
 
2
 
 
 
 
 
 
 
 
 
31
 
    
 
629 
 
 
 
 
 
 
 
 
 
 
 
 
 
       ##############################  
 
630 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
631 
 
2
 
  
 50
   
 
 
 
 
 
 
 
34
 
       if ( $fs->is_file($file) ) {  
 
  
 
 
 
  
  0
   
 
 
 
 
 
 
 
 
 
    
 
632 
 
2
 
 
 
 
 
 
 
 
 
185
 
         $fs->unlink($file);  
 
633 
 
2
 
 
 
 
 
 
 
 
 
13
 
         $__ret = { changed => 1 };  
 
634 
 
 
 
 
 
 
 
 
 
 
 
 
 
         Rex::get_current_connection()->{reporter}->report(  
 
635 
 
2
 
 
 
 
 
 
 
 
 
24
 
           changed => 1,  
 
636 
 
 
 
 
 
 
 
 
 
 
 
 
 
           message => "File removed."  
 
637 
 
 
 
 
 
 
 
 
 
 
 
 
 
         );  
 
638 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
639 
 
 
 
 
 
 
 
 
 
 
 
 
 
       elsif ( $fs->is_dir($file) ) {  
 
640 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         $fs->rmdir($file);  
 
641 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         $__ret = { changed => 1 };  
 
642 
 
 
 
 
 
 
 
 
 
 
 
 
 
         Rex::get_current_connection()->{reporter}->report(  
 
643 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
           changed => 1,  
 
644 
 
 
 
 
 
 
 
 
 
 
 
 
 
           message => "Directory removed.",  
 
645 
 
 
 
 
 
 
 
 
 
 
 
 
 
         );  
 
646 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
647 
 
 
 
 
 
 
 
 
 
 
 
 
 
       else {  
 
648 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         $__ret = { changed => 0 };  
 
649 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         Rex::get_current_connection()->{reporter}->report( changed => 0, );  
 
650 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
651 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
652 
 
 
 
 
 
 
 
 
 
 
 
 
 
       #### check and run after_change hook  
 
653 
 
2
 
 
 
 
 
 
 
 
 
10
 
       Rex::Hook::run_hook( file => "after_change", $file, %{$option}, $__ret );  
 
  
 
2
 
 
 
 
 
 
 
 
 
15
 
    
 
654 
 
 
 
 
 
 
 
 
 
 
 
 
 
       ##############################  
 
655 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
656 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
657 
 
 
 
 
 
 
 
 
 
 
 
 
 
     elsif ( $option->{ensure} eq "directory" ) {  
 
658 
 
2
 
 
 
 
 
 
 
 
 
66
 
       Rex::Logger::debug("file() should be a directory");  
 
659 
 
2
 
 
 
 
 
 
 
 
 
15
 
       my %dir_option;  
 
660 
 
2
 
  
 50
   
 
 
 
 
 
 
 
23
 
       if ( exists $option->{owner} ) {  
 
661 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         $dir_option{owner} = $option->{owner};  
 
662 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
663 
 
2
 
  
 50
   
 
 
 
 
 
 
 
25
 
       if ( exists $option->{group} ) {  
 
664 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         $dir_option{group} = $option->{group};  
 
665 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
666 
 
2
 
  
 50
   
 
 
 
 
 
 
 
17
 
       if ( exists $option->{mode} ) {  
 
667 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         $dir_option{mode} = $option->{mode};  
 
668 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
669 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
670 
 
2
 
 
 
 
 
 
 
 
 
46
 
       Rex::Commands::Fs::mkdir( $file, %dir_option, on_change => $on_change );  
 
671 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
672 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
673 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
674 
 
53
 
  
100
   
 
  
100
   
 
 
 
 
 
696
 
   if ( !exists $option->{content}  
 
  
 
 
 
 
 
  
100
   
 
 
 
 
 
 
 
    
 
675 
 
 
 
 
 
 
 
 
 
 
 
 
 
     && !exists $option->{source}  
 
676 
 
 
 
 
 
 
 
 
 
 
 
 
 
     && $option->{ensure} ne "absent" )  
 
677 
 
 
 
 
 
 
 
 
 
 
 
 
 
   {  
 
678 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
679 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # no content and no source, so just verify that the file is present  
 
680 
 
9
 
  
 50
   
 
  
 66
   
 
 
 
 
 
63
 
     if ( !$fs->is_file($file) && !$is_directory ) {  
 
681 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
682 
 
 
 
 
 
 
 
 
 
 
 
 
 
       #### check and run before_change hook  
 
683 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
       Rex::Hook::run_hook( file => "before_change", $file, %{$option} );  
 
  
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
    
 
684 
 
 
 
 
 
 
 
 
 
 
 
 
 
       ##############################  
 
685 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
686 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
       my $fh = file_write($file);  
 
687 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
       $fh->write("");  
 
688 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
       $fh->close;  
 
689 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
690 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
       my $f_type = "file is now present, with no content";  
 
691 
 
  
0
   
 
  
  0
   
 
  
  0
   
 
 
 
 
 
0
 
       if ( exists $option->{ensure} && $option->{ensure} eq "directory" ) {  
 
692 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         $f_type = "directory is now present";  
 
693 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
694 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
695 
 
 
 
 
 
 
 
 
 
 
 
 
 
       Rex::get_current_connection()->{reporter}->report(  
 
696 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         changed => 1,  
 
697 
 
 
 
 
 
 
 
 
 
 
 
 
 
         message => $f_type,  
 
698 
 
 
 
 
 
 
 
 
 
 
 
 
 
       );  
 
699 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
700 
 
 
 
 
 
 
 
 
 
 
 
 
 
       #### check and run after_change hook  
 
701 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
       Rex::Hook::run_hook( file => "after_change", $file, %{$option}, $__ret );  
 
  
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
    
 
702 
 
 
 
 
 
 
 
 
 
 
 
 
 
       ##############################  
 
703 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
704 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
705 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
706 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
707 
 
53
 
  
100
   
 
 
 
 
 
 
 
439
 
   if ( $option->{ensure} ne "absent" ) {  
 
708 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
709 
 
51
 
  
100
   
 
 
 
 
 
 
 
225
 
     if ($need_md5) {  
 
710 
 
2
 
 
 
 
 
 
 
 
 
25
 
       eval { $new_md5 = md5($file); };  
 
  
 
2
 
 
 
 
 
 
 
 
 
51
 
    
 
711 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
712 
 
51
 
 
 
 
 
 
 
 
 
453
 
     my %stat_old = $fs->stat($file);  
 
713 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
714 
 
51
 
  
100
   
 
 
 
 
 
 
 
537
 
     if ( exists $option->{"mode"} ) {  
 
715 
 
28
 
 
 
 
 
 
 
 
 
1044
 
       $fs->chmod( $option->{"mode"}, $file );  
 
716 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
717 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
718 
 
51
 
  
100
   
 
 
 
 
 
 
 
919
 
     if ( exists $option->{"group"} ) {  
 
719 
 
25
 
 
 
 
 
 
 
 
 
781
 
       $fs->chgrp( $option->{"group"}, $file );  
 
720 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
721 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
722 
 
51
 
  
100
   
 
 
 
 
 
 
 
844
 
     if ( exists $option->{"owner"} ) {  
 
723 
 
25
 
 
 
 
 
 
 
 
 
758
 
       $fs->chown( $option->{"owner"}, $file );  
 
724 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
725 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
726 
 
51
 
 
 
 
 
 
 
 
 
1289
 
     my %stat_new = $fs->stat($file);  
 
727 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
728 
 
51
 
  
100
   
 
  
 33
   
 
 
 
 
 
1432
 
     if ( %stat_old && %stat_new && $stat_old{mode} ne $stat_new{mode} ) {  
 
  
 
 
 
 
 
  
 66
   
 
 
 
 
 
 
 
    
 
729 
 
 
 
 
 
 
 
 
 
 
 
 
 
       Rex::get_current_connection()->{reporter}->report(  
 
730 
 
15
 
 
 
 
 
 
 
 
 
111
 
         changed => 1,  
 
731 
 
 
 
 
 
 
 
 
 
 
 
 
 
         message =>  
 
732 
 
 
 
 
 
 
 
 
 
 
 
 
 
           "File-System permissions changed from $stat_old{mode} to $stat_new{mode}.",  
 
733 
 
 
 
 
 
 
 
 
 
 
 
 
 
       );  
 
734 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
735 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
736 
 
51
 
  
 50
   
 
  
 33
   
 
 
 
 
 
1353
 
     if ( %stat_old && %stat_new && $stat_old{uid} ne $stat_new{uid} ) {  
 
  
 
 
 
 
 
  
 33
   
 
 
 
 
 
 
 
    
 
737 
 
 
 
 
 
 
 
 
 
 
 
 
 
       Rex::get_current_connection()->{reporter}->report(  
 
738 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         changed => 1,  
 
739 
 
 
 
 
 
 
 
 
 
 
 
 
 
         message => "Owner changed from $stat_old{uid} to $stat_new{uid}.",  
 
740 
 
 
 
 
 
 
 
 
 
 
 
 
 
       );  
 
741 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
742 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
743 
 
51
 
  
 50
   
 
  
 33
   
 
 
 
 
 
1500
 
     if ( %stat_old && %stat_new && $stat_old{gid} ne $stat_new{gid} ) {  
 
  
 
 
 
 
 
  
 33
   
 
 
 
 
 
 
 
    
 
744 
 
 
 
 
 
 
 
 
 
 
 
 
 
       Rex::get_current_connection()->{reporter}->report(  
 
745 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         changed => 1,  
 
746 
 
 
 
 
 
 
 
 
 
 
 
 
 
         message => "Group changed from $stat_old{gid} to $stat_new{gid}.",  
 
747 
 
 
 
 
 
 
 
 
 
 
 
 
 
       );  
 
748 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
749 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
750 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
751 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
752 
 
53
 
 
 
 
 
 
 
 
 
283
 
   my $on_change_done = 0;  
 
753 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
754 
 
53
 
  
100
   
 
 
 
 
 
 
 
225
 
   if ($need_md5) {  
 
755 
 
2
 
  
  0
   
 
  
 33
   
 
 
 
 
 
49
 
     unless ( $old_md5 && $new_md5 && $old_md5 eq $new_md5 ) {  
 
  
 
 
 
 
 
  
 33
   
 
 
 
 
 
 
 
    
 
756 
 
2
 
 
 
  
 50
   
 
 
 
 
 
54
 
       $old_md5 ||= "";  
 
757 
 
2
 
 
 
  
 50
   
 
 
 
 
 
22
 
       $new_md5 ||= "";  
 
758 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
759 
 
2
 
 
 
 
 
 
 
 
 
36
 
       Rex::Logger::debug("File $file has been changed... Running on_change");  
 
760 
 
2
 
 
 
 
 
 
 
 
 
25
 
       Rex::Logger::debug("old: $old_md5");  
 
761 
 
2
 
 
 
 
 
 
 
 
 
30
 
       Rex::Logger::debug("new: $new_md5");  
 
762 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
763 
 
2
 
 
 
 
 
 
 
 
 
38
 
       &$on_change($file);  
 
764 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
765 
 
2
 
 
 
 
 
 
 
 
 
31
 
       $on_change_done = 1;  
 
766 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
767 
 
 
 
 
 
 
 
 
 
 
 
 
 
       Rex::get_current_connection()->{reporter}->report(  
 
768 
 
2
 
 
 
 
 
 
 
 
 
28
 
         changed => 1,  
 
769 
 
 
 
 
 
 
 
 
 
 
 
 
 
         message => "Content changed.",  
 
770 
 
 
 
 
 
 
 
 
 
 
 
 
 
       );  
 
771 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
772 
 
2
 
 
 
 
 
 
 
 
 
24
 
       $__ret = { changed => 1 };  
 
773 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
774 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
775 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
776 
 
53
 
  
100
   
 
  
100
   
 
 
 
 
 
743
 
   if ( $__ret->{changed} == 1 && $on_change_done == 0 ) {  
 
  
 
 
 
  
100
   
 
 
 
 
 
 
 
 
 
    
 
777 
 
39
 
 
 
 
 
 
 
 
 
429
 
     &$on_change($file);  
 
778 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
779 
 
 
 
 
 
 
 
 
 
 
 
 
 
   elsif ( $__ret->{changed} == 0 ) {  
 
780 
 
12
 
 
 
 
 
 
 
 
 
332
 
     Rex::Logger::debug(  
 
781 
 
 
 
 
 
 
 
 
 
 
 
 
 
       "File $file has not been changed... Running on_no_change");  
 
782 
 
12
 
 
 
 
 
 
 
 
 
155
 
     &$on_no_change($file);  
 
783 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
784 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
785 
 
 
 
 
 
 
 
 
 
 
 
 
 
   #### check and run after hook  
 
786 
 
53
 
 
 
 
 
 
 
 
 
201
 
   Rex::Hook::run_hook( file => "after", $file, %{$option}, $__ret );  
 
  
 
53
 
 
 
 
 
 
 
 
 
1376
 
    
 
787 
 
 
 
 
 
 
 
 
 
 
 
 
 
   ##############################  
 
788 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
789 
 
 
 
 
 
 
 
 
 
 
 
 
 
   Rex::get_current_connection()->{reporter}  
 
790 
 
53
 
 
 
 
 
 
 
 
 
264
 
     ->report_resource_end( type => "file", name => $file );  
 
791 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
792 
 
53
 
 
 
 
 
 
 
 
 
3378
 
   return $__ret->{changed};  
 
793 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
794 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
795 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub get_tmp_file_name {  
 
796 
 
44
 
 
 
 
 
  
44
   
 
  
0
   
 
2513
 
   my $file = shift;  
 
797 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
798 
 
44
 
 
 
 
 
 
 
 
 
6254
 
   my $dirname  = dirname($file);  
 
799 
 
44
 
 
 
 
 
 
 
 
 
1989
 
   my $filename = ".rex.tmp." . basename($file);  
 
800 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
801 
 
44
 
  
100
   
 
 
 
 
 
 
 
1958
 
   my $tmp_file_name =  
 
802 
 
 
 
 
 
 
 
 
 
 
 
 
 
       $dirname eq '.'  
 
803 
 
 
 
 
 
 
 
 
 
 
 
 
 
     ? $filename  
 
804 
 
 
 
 
 
 
 
 
 
 
 
 
 
     : Rex::Helper::File::Spec->catfile( $dirname, $filename );  
 
805 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
806 
 
44
 
 
 
 
 
 
 
 
 
316
 
   return $tmp_file_name;  
 
807 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
808 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
809 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 file_write($file_name)  
 
810 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
811 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This function opens a file for writing (it will truncate the file if it already exists). It returns a Rex::FS::File object on success.  
 
812 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
813 
 
 
 
 
 
 
 
 
 
 
 
 
 
 On failure it will die.  
 
814 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
815 
 
 
 
 
 
 
 
 
 
 
 
 
 
  my $fh;  
 
816 
 
 
 
 
 
 
 
 
 
 
 
 
 
  eval {  
 
817 
 
 
 
 
 
 
 
 
 
 
 
 
 
    $fh = file_write("/etc/groups");  
 
818 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
819 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
820 
 
 
 
 
 
 
 
 
 
 
 
 
 
  # catch an error  
 
821 
 
 
 
 
 
 
 
 
 
 
 
 
 
  if($@) {  
 
822 
 
 
 
 
 
 
 
 
 
 
 
 
 
    print "An error occurred. $@.\n";  
 
823 
 
 
 
 
 
 
 
 
 
 
 
 
 
  }  
 
824 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
825 
 
 
 
 
 
 
 
 
 
 
 
 
 
  # work with the filehandle  
 
826 
 
 
 
 
 
 
 
 
 
 
 
 
 
  $fh->write("...");  
 
827 
 
 
 
 
 
 
 
 
 
 
 
 
 
  $fh->close;  
 
828 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
829 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
830 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
831 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub file_write {  
 
832 
 
42
 
 
 
 
 
  
42
   
 
  
1
   
 
3100
 
   my ($file) = @_;  
 
833 
 
42
 
 
 
 
 
 
 
 
 
705
 
   $file = resolv_path($file);  
 
834 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
835 
 
42
 
 
 
 
 
 
 
 
 
986
 
   Rex::Logger::debug("Opening file: $file for writing.");  
 
836 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
837 
 
42
 
 
 
 
 
 
 
 
 
1182
 
   my $fh = Rex::Interface::File->create;  
 
838 
 
42
 
  
 50
   
 
 
 
 
 
 
 
449
 
   if ( !$fh->open( ">", $file ) ) {  
 
839 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     Rex::Logger::debug("Can't open $file for writing.");  
 
840 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     die("Can't open $file for writing.");  
 
841 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
842 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
843 
 
42
 
 
 
 
 
 
 
 
 
968
 
   return Rex::FS::File->new( fh => $fh );  
 
844 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
845 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
846 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 file_append($file_name)  
 
847 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
848 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
849 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
850 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub file_append {  
 
851 
 
1
 
 
 
 
 
  
1
   
 
  
1
   
 
2181
 
   my ($file) = @_;  
 
852 
 
1
 
 
 
 
 
 
 
 
 
50
 
   $file = resolv_path($file);  
 
853 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
854 
 
1
 
 
 
 
 
 
 
 
 
47
 
   Rex::Logger::debug("Opening file: $file for appending.");  
 
855 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
856 
 
1
 
 
 
 
 
 
 
 
 
57
 
   my $fh = Rex::Interface::File->create;  
 
857 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
858 
 
1
 
  
 50
   
 
 
 
 
 
 
 
41
 
   if ( !$fh->open( ">>", $file ) ) {  
 
859 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     Rex::Logger::debug("Can't open $file for appending.");  
 
860 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     die("Can't open $file for appending.");  
 
861 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
862 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
863 
 
1
 
 
 
 
 
 
 
 
 
51
 
   return Rex::FS::File->new( fh => $fh );  
 
864 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
865 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
866 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 file_read($file_name)  
 
867 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
868 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This function opens a file for reading. It returns a Rex::FS::File object on success.  
 
869 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
870 
 
 
 
 
 
 
 
 
 
 
 
 
 
 On failure it will die.  
 
871 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
872 
 
 
 
 
 
 
 
 
 
 
 
 
 
  my $fh;  
 
873 
 
 
 
 
 
 
 
 
 
 
 
 
 
  eval {  
 
874 
 
 
 
 
 
 
 
 
 
 
 
 
 
    $fh = file_read("/etc/groups");  
 
875 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
876 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
877 
 
 
 
 
 
 
 
 
 
 
 
 
 
  # catch an error  
 
878 
 
 
 
 
 
 
 
 
 
 
 
 
 
  if($@) {  
 
879 
 
 
 
 
 
 
 
 
 
 
 
 
 
    print "An error occurred. $@.\n";  
 
880 
 
 
 
 
 
 
 
 
 
 
 
 
 
  }  
 
881 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
882 
 
 
 
 
 
 
 
 
 
 
 
 
 
  # work with the filehandle  
 
883 
 
 
 
 
 
 
 
 
 
 
 
 
 
  my $content = $fh->read_all;  
 
884 
 
 
 
 
 
 
 
 
 
 
 
 
 
  $fh->close;  
 
885 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
886 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
887 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
888 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub file_read {  
 
889 
 
137
 
 
 
 
 
  
137
   
 
  
1
   
 
1262
 
   my ($file) = @_;  
 
890 
 
137
 
 
 
 
 
 
 
 
 
1247
 
   $file = resolv_path($file);  
 
891 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
892 
 
137
 
 
 
 
 
 
 
 
 
3015
 
   Rex::Logger::debug("Opening file: $file for reading.");  
 
893 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
894 
 
137
 
 
 
 
 
 
 
 
 
4680
 
   my $fh = Rex::Interface::File->create;  
 
895 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
896 
 
137
 
  
 50
   
 
 
 
 
 
 
 
1188
 
   if ( !$fh->open( "<", $file ) ) {  
 
897 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     Rex::Logger::debug("Can't open $file for reading.");  
 
898 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     die("Can't open $file for reading.");  
 
899 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
900 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
901 
 
137
 
 
 
 
 
 
 
 
 
3665
 
   return Rex::FS::File->new( fh => $fh );  
 
902 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
903 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
904 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 cat($file_name)  
 
905 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
906 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This function returns the complete content of $file_name as a string.  
 
907 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
908 
 
 
 
 
 
 
 
 
 
 
 
 
 
  print cat "/etc/passwd";  
 
909 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
910 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
911 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
912 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub cat {  
 
913 
 
86
 
 
 
 
 
  
86
   
 
  
1
   
 
14769
 
   my ($file) = @_;  
 
914 
 
86
 
 
 
 
 
 
 
 
 
1119
 
   $file = resolv_path($file);  
 
915 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
916 
 
86
 
 
 
 
 
 
 
 
 
939
 
   my $fh = file_read($file);  
 
917 
 
86
 
  
 50
   
 
 
 
 
 
 
 
367
 
   unless ($fh) {  
 
918 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     die("Can't open $file for reading");  
 
919 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
920 
 
86
 
 
 
 
 
 
 
 
 
757
 
   my $content = $fh->read_all;  
 
921 
 
86
 
 
 
 
 
 
 
 
 
704
 
   $fh->close;  
 
922 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
923 
 
86
 
 
 
 
 
 
 
 
 
944
 
   return $content;  
 
924 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
925 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
926 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 delete_lines_matching($file, $regexp)  
 
927 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
928 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Delete lines that match $regexp in $file.  
 
929 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
930 
 
 
 
 
 
 
 
 
 
 
 
 
 
  task "clean-logs", sub {  
 
931 
 
 
 
 
 
 
 
 
 
 
 
 
 
     delete_lines_matching "/var/log/auth.log" => "root";  
 
932 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
933 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
934 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
935 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
936 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub delete_lines_matching {  
 
937 
 
1
 
 
 
 
 
  
1
   
 
  
1
   
 
1764
 
   my ( $file, @m ) = @_;  
 
938 
 
1
 
 
 
 
 
 
 
 
 
31
 
   $file = resolv_path($file);  
 
939 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
940 
 
 
 
 
 
 
 
 
 
 
 
 
 
   Rex::get_current_connection()->{reporter}  
 
941 
 
1
 
 
 
 
 
 
 
 
 
24
 
     ->report_resource_start( type => "delete_lines_matching", name => $file );  
 
942 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
943 
 
1
 
 
 
 
 
 
 
 
 
12
 
   for (@m) {  
 
944 
 
1
 
  
 50
   
 
 
 
 
 
 
 
19
 
     if ( ref($_) ne "Regexp" ) {  
 
945 
 
1
 
 
 
 
 
 
 
 
 
49
 
       $_ = qr{\Q$_\E};  
 
946 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
947 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
948 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
949 
 
1
 
 
 
 
 
 
 
 
 
46
 
   my $fs = Rex::Interface::Fs->create;  
 
950 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
951 
 
1
 
 
 
 
 
 
 
 
 
25
 
   my %stat = $fs->stat($file);  
 
952 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
953 
 
1
 
  
 50
   
 
 
 
 
 
 
 
26
 
   if ( !$fs->is_file($file) ) {  
 
954 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     Rex::Logger::info("File: $file not found.");  
 
955 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     die("$file not found");  
 
956 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
957 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
958 
 
1
 
  
 50
   
 
 
 
 
 
 
 
21
 
   if ( !$fs->is_writable($file) ) {  
 
959 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     Rex::Logger::info("File: $file not writable.");  
 
960 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     die("$file not writable");  
 
961 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
962 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
963 
 
1
 
 
 
 
 
 
 
 
 
11
 
   my $nl      = $/;  
 
964 
 
1
 
 
 
 
 
 
 
 
 
36
 
   my @content = split( /$nl/, cat($file) );  
 
965 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
966 
 
1
 
 
 
 
 
 
 
 
 
13
 
   my $old_md5 = "";  
 
967 
 
1
 
 
 
 
 
 
 
 
 
7
 
   eval { $old_md5 = md5($file); };  
 
  
 
1
 
 
 
 
 
 
 
 
 
27
 
    
 
968 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
969 
 
1
 
 
 
 
 
 
 
 
 
38
 
   my @new_content;  
 
970 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
971 
 
 
 
 
 
 
 
 
 
 
 
 
 
 OUT:  
 
972 
 
1
 
 
 
 
 
 
 
 
 
20
 
   for my $line (@content) {  
 
973 
 
 
 
 
 
 
 
 
 
 
 
 
 
   IN:  
 
974 
 
1
 
 
 
 
 
 
 
 
 
14
 
     for my $match (@m) {  
 
975 
 
1
 
  
 50
   
 
 
 
 
 
 
 
62
 
       if ( $line =~ $match ) {  
 
976 
 
1
 
 
 
 
 
 
 
 
 
24
 
         next OUT;  
 
977 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
978 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
979 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
980 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     push @new_content, $line;  
 
981 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
982 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
983 
 
 
 
 
 
 
 
 
 
 
 
 
 
   file $file,  
 
984 
 
 
 
 
 
 
 
 
 
 
 
 
 
     content => join( $nl, @new_content ),  
 
985 
 
 
 
 
 
 
 
 
 
 
 
 
 
     owner   => $stat{uid},  
 
986 
 
 
 
 
 
 
 
 
 
 
 
 
 
     group   => $stat{gid},  
 
987 
 
1
 
 
 
 
 
 
 
 
 
55
 
     mode    => $stat{mode};  
 
988 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
989 
 
1
 
 
 
 
 
 
 
 
 
21
 
   my $new_md5 = "";  
 
990 
 
1
 
 
 
 
 
 
 
 
 
20
 
   eval { $new_md5 = md5($file); };  
 
  
 
1
 
 
 
 
 
 
 
 
 
41
 
    
 
991 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
992 
 
1
 
  
 50
   
 
 
 
 
 
 
 
55
 
   if ( $new_md5 ne $old_md5 ) {  
 
993 
 
 
 
 
 
 
 
 
 
 
 
 
 
     Rex::get_current_connection()->{reporter}->report(  
 
994 
 
1
 
 
 
 
 
 
 
 
 
52
 
       changed => 1,  
 
995 
 
 
 
 
 
 
 
 
 
 
 
 
 
       message => "Content changed.",  
 
996 
 
 
 
 
 
 
 
 
 
 
 
 
 
     );  
 
997 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
998 
 
 
 
 
 
 
 
 
 
 
 
 
 
   else {  
 
999 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     Rex::get_current_connection()->{reporter}->report( changed => 0, );  
 
1000 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1001 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1002 
 
 
 
 
 
 
 
 
 
 
 
 
 
   Rex::get_current_connection()->{reporter}  
 
1003 
 
1
 
 
 
 
 
 
 
 
 
26
 
     ->report_resource_end( type => "delete_lines_matching", name => $file );  
 
1004 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
1005 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1006 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 delete_lines_according_to($search, $file [, @options])  
 
1007 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1008 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This is the successor of the delete_lines_matching() function. This function also allows the usage of on_change and on_no_change hooks.  
 
1009 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1010 
 
 
 
 
 
 
 
 
 
 
 
 
 
 It will search for $search in $file and remove the found lines. If on_change hook is present it will execute this if the file was changed.  
 
1011 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1012 
 
 
 
 
 
 
 
 
 
 
 
 
 
  task "cleanup", "server1", sub {  
 
1013 
 
 
 
 
 
 
 
 
 
 
 
 
 
    delete_lines_according_to qr{^foo:}, "/etc/passwd",  
 
1014 
 
 
 
 
 
 
 
 
 
 
 
 
 
     on_change => sub {  
 
1015 
 
 
 
 
 
 
 
 
 
 
 
 
 
       say "removed user foo.";  
 
1016 
 
 
 
 
 
 
 
 
 
 
 
 
 
     };  
 
1017 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
1018 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1019 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
1020 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1021 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub delete_lines_according_to {  
 
1022 
 
  
0
   
 
 
 
 
 
  
0
   
 
  
1
   
 
0
 
   my ( $search, $file, @options ) = @_;  
 
1023 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   $file = resolv_path($file);  
 
1024 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1025 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   my $option       = {@options};  
 
1026 
 
  
0
   
 
 
 
  
  0
   
 
 
 
 
 
0
 
   my $on_change    = $option->{on_change}    || undef;  
 
1027 
 
  
0
   
 
 
 
  
  0
   
 
 
 
 
 
0
 
   my $on_no_change = $option->{on_no_change} || undef;  
 
1028 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1029 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   my ( $old_md5, $new_md5 );  
 
1030 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1031 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
0
 
   if ($on_change) {  
 
1032 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $old_md5 = md5($file);  
 
1033 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1034 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1035 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   delete_lines_matching( $file, $search );  
 
1036 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1037 
 
  
0
   
 
  
  0
   
 
  
  0
   
 
 
 
 
 
0
 
   if ( $on_change || $on_no_change ) {  
 
1038 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $new_md5 = md5($file);  
 
1039 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1040 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
0
 
     if ( $old_md5 ne $new_md5 ) {  
 
1041 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
0
 
       &$on_change($file) if $on_change;  
 
1042 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
1043 
 
 
 
 
 
 
 
 
 
 
 
 
 
     else {  
 
1044 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
0
 
       &$on_no_change($file) if $on_no_change;  
 
1045 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
1046 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1047 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1048 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
1049 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1050 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 append_if_no_such_line($file, $new_line [, @regexp])  
 
1051 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1052 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Append $new_line to $file if none in @regexp is found. If no regexp is  
 
1053 
 
 
 
 
 
 
 
 
 
 
 
 
 
 supplied, the line is appended unless there is already an identical line  
 
1054 
 
 
 
 
 
 
 
 
 
 
 
 
 
 in $file.  
 
1055 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1056 
 
 
 
 
 
 
 
 
 
 
 
 
 
  task "add-group", sub {  
 
1057 
 
 
 
 
 
 
 
 
 
 
 
 
 
    append_if_no_such_line "/etc/groups", "mygroup:*:100:myuser1,myuser2", on_change => sub { service sshd => "restart"; };  
 
1058 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
1059 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1060 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Since 0.42 you can use named parameters as well  
 
1061 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1062 
 
 
 
 
 
 
 
 
 
 
 
 
 
  task "add-group", sub {  
 
1063 
 
 
 
 
 
 
 
 
 
 
 
 
 
    append_if_no_such_line "/etc/groups",  
 
1064 
 
 
 
 
 
 
 
 
 
 
 
 
 
      line  => "mygroup:*:100:myuser1,myuser2",  
 
1065 
 
 
 
 
 
 
 
 
 
 
 
 
 
      regexp => qr{^mygroup},  
 
1066 
 
 
 
 
 
 
 
 
 
 
 
 
 
      on_change => sub {  
 
1067 
 
 
 
 
 
 
 
 
 
 
 
 
 
                 say "file was changed, do something.";  
 
1068 
 
 
 
 
 
 
 
 
 
 
 
 
 
               };  
 
1069 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1070 
 
 
 
 
 
 
 
 
 
 
 
 
 
    append_if_no_such_line "/etc/groups",  
 
1071 
 
 
 
 
 
 
 
 
 
 
 
 
 
      line  => "mygroup:*:100:myuser1,myuser2",  
 
1072 
 
 
 
 
 
 
 
 
 
 
 
 
 
      regexp => [qr{^mygroup:}, qr{^ourgroup:}]; # this is an OR  
 
1073 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
1074 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1075 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
1076 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1077 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub append_if_no_such_line {  
 
1078 
 
14
 
 
 
 
 
  
14
   
 
  
1
   
 
29230
 
   _append_or_update( 'append_if_no_such_line', @_ );  
 
1079 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
1080 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1081 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 append_or_amend_line($file, $line [, @regexp])  
 
1082 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1083 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Similar to L, but if the line in the regexp is   
 
1084 
 
 
 
 
 
 
 
 
 
 
 
 
 
 found, it will be updated. Otherwise, it will be appended.  
 
1085 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1086 
 
 
 
 
 
 
 
 
 
 
 
 
 
  task "update-group", sub {  
 
1087 
 
 
 
 
 
 
 
 
 
 
 
 
 
    append_or_amend_line "/etc/groups",  
 
1088 
 
 
 
 
 
 
 
 
 
 
 
 
 
      line  => "mygroup:*:100:myuser3,myuser4",  
 
1089 
 
 
 
 
 
 
 
 
 
 
 
 
 
      regexp => qr{^mygroup},  
 
1090 
 
 
 
 
 
 
 
 
 
 
 
 
 
      on_change => sub {  
 
1091 
 
 
 
 
 
 
 
 
 
 
 
 
 
        say "file was changed, do something.";  
 
1092 
 
 
 
 
 
 
 
 
 
 
 
 
 
      },  
 
1093 
 
 
 
 
 
 
 
 
 
 
 
 
 
      on_no_change => sub {  
 
1094 
 
 
 
 
 
 
 
 
 
 
 
 
 
        say "file was not changed, do something.";  
 
1095 
 
 
 
 
 
 
 
 
 
 
 
 
 
      };  
 
1096 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
1097 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1098 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
1099 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1100 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub append_or_amend_line {  
 
1101 
 
5
 
 
 
 
 
  
5
   
 
  
1
   
 
11829
 
   _append_or_update( 'append_or_amend_line', @_ );  
 
1102 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
1103 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1104 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub _append_or_update {  
 
1105 
 
19
 
 
 
 
 
  
19
   
 
 
 
182
 
   my $action = shift;  
 
1106 
 
19
 
 
 
 
 
 
 
 
 
69
 
   my $file   = shift;  
 
1107 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1108 
 
19
 
 
 
 
 
 
 
 
 
118
 
   $file = resolv_path($file);  
 
1109 
 
19
 
 
 
 
 
 
 
 
 
124
 
   my ( $new_line, @m );  
 
1110 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1111 
 
 
 
 
 
 
 
 
 
 
 
 
 
   # check if parameters are in key => value format  
 
1112 
 
19
 
 
 
 
 
 
 
 
 
0
 
   my ( $option, $on_change, $on_no_change );  
 
1113 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1114 
 
 
 
 
 
 
 
 
 
 
 
 
 
   Rex::get_current_connection()->{reporter}  
 
1115 
 
19
 
 
 
 
 
 
 
 
 
103
 
     ->report_resource_start( type => $action, name => $file );  
 
1116 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1117 
 
 
 
 
 
 
 
 
 
 
 
 
 
   eval {  
 
1118 
 
45
 
 
 
 
 
  
45
   
 
 
 
489
 
     no warnings;  
 
  
 
45
 
 
 
 
 
 
 
 
 
119
 
    
 
  
 
45
 
 
 
 
 
 
 
 
 
74446
 
    
 
1119 
 
19
 
 
 
 
 
 
 
 
 
207
 
     $option = {@_};  
 
1120 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1121 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # if there is no line parameter, it is the old parameter format  
 
1122 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # so go dieing  
 
1123 
 
19
 
  
100
   
 
 
 
 
 
 
 
130
 
     if ( !exists $option->{line} ) {  
 
1124 
 
4
 
 
 
 
 
 
 
 
 
73
 
       die;  
 
1125 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
1126 
 
15
 
 
 
 
 
 
 
 
 
67
 
     $new_line = $option->{line};  
 
1127 
 
15
 
  
100
   
 
  
100
   
 
 
 
 
 
357
 
     if ( exists $option->{regexp} && ref $option->{regexp} eq "Regexp" ) {  
 
  
 
 
 
  
100
   
 
 
 
 
 
 
 
 
 
    
 
1128 
 
10
 
 
 
 
 
 
 
 
 
57
 
       @m = ( $option->{regexp} );  
 
1129 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
1130 
 
 
 
 
 
 
 
 
 
 
 
 
 
     elsif ( ref $option->{regexp} eq "ARRAY" ) {  
 
1131 
 
2
 
 
 
 
 
 
 
 
 
9
 
       @m = @{ $option->{regexp} };  
 
  
 
2
 
 
 
 
 
 
 
 
 
20
 
    
 
1132 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
1133 
 
15
 
 
 
  
 50
   
 
 
 
 
 
196
 
     $on_change    = $option->{on_change}    || undef;  
 
1134 
 
15
 
 
 
  
 50
   
 
 
 
 
 
135
 
     $on_no_change = $option->{on_no_change} || undef;  
 
1135 
 
15
 
 
 
 
 
 
 
 
 
226
 
     1;  
 
1136 
 
19
 
  
100
   
 
 
 
 
 
 
 
90
 
   } or do {  
 
1137 
 
4
 
 
 
 
 
 
 
 
 
30
 
     ( $new_line, @m ) = @_;  
 
1138 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1139 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # check if something in @m (the regexpes) is named on_change or on_no_change  
 
1140 
 
4
 
 
 
 
 
 
 
 
 
62
 
     for my $option ( [ on_change => \$on_change ],  
 
1141 
 
 
 
 
 
 
 
 
 
 
 
 
 
       [ on_no_change => \$on_no_change ] )  
 
1142 
 
 
 
 
 
 
 
 
 
 
 
 
 
     {  
 
1143 
 
8
 
 
 
 
 
 
 
 
 
33
 
       for ( my $i = 0 ; $i < $#m ; $i++ ) {  
 
1144 
 
8
 
  
100
   
 
  
 66
   
 
 
 
 
 
70
 
         if ( $m[$i] eq $option->[0] && ref( $m[ $i + 1 ] ) eq "CODE" ) {  
 
1145 
 
5
 
 
 
 
 
 
 
 
 
11
 
           ${ $option->[1] } = $m[ $i + 1 ];  
 
  
 
5
 
 
 
 
 
 
 
 
 
10
 
    
 
1146 
 
5
 
 
 
 
 
 
 
 
 
11
 
           splice( @m, $i, 2 );  
 
1147 
 
5
 
 
 
 
 
 
 
 
 
17
 
           last;  
 
1148 
 
 
 
 
 
 
 
 
 
 
 
 
 
         }  
 
1149 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
1150 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
1151 
 
 
 
 
 
 
 
 
 
 
 
 
 
   };  
 
1152 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1153 
 
19
 
  
 50
   
 
 
 
 
 
 
 
101
 
   unless ( defined $new_line ) {  
 
1154 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     my ( undef, undef, undef, $subroutine ) = caller(1);  
 
1155 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $subroutine =~ s/^.*:://;  
 
1156 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     die "Undefined new line while trying to run $subroutine on $file";  
 
1157 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1158 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1159 
 
19
 
 
 
 
 
 
 
 
 
558
 
   my $fs = Rex::Interface::Fs->create;  
 
1160 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1161 
 
19
 
 
 
 
 
 
 
 
 
136
 
   my %stat = $fs->stat($file);  
 
1162 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1163 
 
19
 
 
 
 
 
 
 
 
 
96
 
   my ( $old_md5, $ret );  
 
1164 
 
19
 
 
 
 
 
 
 
 
 
127
 
   $old_md5 = md5($file);  
 
1165 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1166 
 
 
 
 
 
 
 
 
 
 
 
 
 
   # slow but secure way  
 
1167 
 
19
 
 
 
 
 
 
 
 
 
213
 
   my $content;  
 
1168 
 
 
 
 
 
 
 
 
 
 
 
 
 
   eval {  
 
1169 
 
19
 
 
 
 
 
 
 
 
 
466
 
     $content = [ split( /\n/, cat($file) ) ];  
 
1170 
 
19
 
 
 
 
 
 
 
 
 
173
 
     1;  
 
1171 
 
19
 
  
 50
   
 
 
 
 
 
 
 
259
 
   } or do {  
 
1172 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $ret = 1;  
 
1173 
 
 
 
 
 
 
 
 
 
 
 
 
 
   };  
 
1174 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1175 
 
19
 
  
100
   
 
 
 
 
 
 
 
180
 
   if ( !@m ) {  
 
1176 
 
5
 
 
 
 
 
 
 
 
 
315
 
     push @m, qr{\Q$new_line\E};  
 
1177 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1178 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1179 
 
19
 
 
 
 
 
 
 
 
 
88
 
   my $found;  
 
1180 
 
19
 
 
 
 
 
 
 
 
 
68
 
   for my $line ( 0 .. $#{$content} ) {  
 
  
 
19
 
 
 
 
 
 
 
 
 
250
 
    
 
1181 
 
129
 
 
 
 
 
 
 
 
 
321
 
     for my $match (@m) {  
 
1182 
 
144
 
  
 50
   
 
 
 
 
 
 
 
497
 
       if ( ref($match) ne "Regexp" ) {  
 
1183 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
         $match = qr{$match};  
 
1184 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
1185 
 
144
 
  
100
   
 
 
 
 
 
 
 
1122
 
       if ( $content->[$line] =~ $match ) {  
 
1186 
 
9
 
 
 
 
 
 
 
 
 
94
 
         $found = 1;  
 
1187 
 
9
 
  
100
   
 
 
 
 
 
 
 
125
 
         last if $action eq 'append_if_no_such_line';  
 
1188 
 
3
 
 
 
 
 
 
 
 
 
40
 
         $content->[$line] = "$new_line";  
 
1189 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
1190 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
1191 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1192 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1193 
 
19
 
 
 
 
 
 
 
 
 
78
 
   my $new_md5;  
 
1194 
 
19
 
  
100
   
 
  
100
   
 
 
 
 
 
355
 
   if ( $action eq 'append_if_no_such_line' && $found ) {  
 
1195 
 
6
 
 
 
 
 
 
 
 
 
69
 
     $new_md5 = $old_md5;  
 
1196 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1197 
 
 
 
 
 
 
 
 
 
 
 
 
 
   else {  
 
1198 
 
13
 
  
100
   
 
 
 
 
 
 
 
169
 
     push @$content, "$new_line" unless $found;  
 
1199 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1200 
 
 
 
 
 
 
 
 
 
 
 
 
 
     file $file,  
 
1201 
 
 
 
 
 
 
 
 
 
 
 
 
 
       content => join( "\n", @$content ),  
 
1202 
 
 
 
 
 
 
 
 
 
 
 
 
 
       owner   => $stat{uid},  
 
1203 
 
 
 
 
 
 
 
 
 
 
 
 
 
       group   => $stat{gid},  
 
1204 
 
13
 
 
 
 
 
 
 
 
 
437
 
       mode    => $stat{mode};  
 
1205 
 
13
 
 
 
 
 
 
 
 
 
389
 
     $new_md5 = md5($file);  
 
1206 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1207 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1208 
 
19
 
  
100
   
 
  
 66
   
 
 
 
 
 
768
 
   if ( $on_change || $on_no_change ) {  
 
1209 
 
3
 
  
100
   
 
  
 33
   
 
 
 
 
 
223
 
     if ( $old_md5 && $new_md5 && $old_md5 ne $new_md5 ) {  
 
  
 
 
 
  
 50
   
 
  
 66
   
 
 
 
 
 
 
 
    
 
1210 
 
1
 
  
 50
   
 
 
 
 
 
 
 
32
 
       if ($on_change) {  
 
1211 
 
1
 
 
 
  
 50
   
 
 
 
 
 
38
 
         $old_md5 ||= "";  
 
1212 
 
1
 
 
 
  
 50
   
 
 
 
 
 
29
 
         $new_md5 ||= "";  
 
1213 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1214 
 
1
 
 
 
 
 
 
 
 
 
98
 
         Rex::Logger::debug("File $file has been changed... Running on_change");  
 
1215 
 
1
 
 
 
 
 
 
 
 
 
34
 
         Rex::Logger::debug("old: $old_md5");  
 
1216 
 
1
 
 
 
 
 
 
 
 
 
26
 
         Rex::Logger::debug("new: $new_md5");  
 
1217 
 
1
 
 
 
 
 
 
 
 
 
64
 
         &$on_change($file);  
 
1218 
 
 
 
 
 
 
 
 
 
 
 
 
 
       }  
 
1219 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
1220 
 
 
 
 
 
 
 
 
 
 
 
 
 
     elsif ($on_no_change) {  
 
1221 
 
2
 
 
 
  
 50
   
 
 
 
 
 
31
 
       $new_md5 ||= "";  
 
1222 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1223 
 
2
 
 
 
 
 
 
 
 
 
29
 
       Rex::Logger::debug(  
 
1224 
 
 
 
 
 
 
 
 
 
 
 
 
 
         "File $file has not been changed (md5 $new_md5)... Running on_no_change"  
 
1225 
 
 
 
 
 
 
 
 
 
 
 
 
 
       );  
 
1226 
 
2
 
 
 
 
 
 
 
 
 
33
 
       &$on_no_change($file);  
 
1227 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
1228 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1229 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1230 
 
19
 
  
100
   
 
  
 33
   
 
 
 
 
 
729
 
   if ( $old_md5 && $new_md5 && $old_md5 ne $new_md5 ) {  
 
  
 
 
 
 
 
  
 66
   
 
 
 
 
 
 
 
    
 
1231 
 
 
 
 
 
 
 
 
 
 
 
 
 
     Rex::get_current_connection()->{reporter}->report(  
 
1232 
 
13
 
 
 
 
 
 
 
 
 
138
 
       changed => 1,  
 
1233 
 
 
 
 
 
 
 
 
 
 
 
 
 
       message => "Content changed.",  
 
1234 
 
 
 
 
 
 
 
 
 
 
 
 
 
     );  
 
1235 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1236 
 
 
 
 
 
 
 
 
 
 
 
 
 
   else {  
 
1237 
 
6
 
 
 
 
 
 
 
 
 
60
 
     Rex::get_current_connection()->{reporter}->report( changed => 0, );  
 
1238 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1239 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1240 
 
 
 
 
 
 
 
 
 
 
 
 
 
   Rex::get_current_connection()->{reporter}  
 
1241 
 
19
 
 
 
 
 
 
 
 
 
184
 
     ->report_resource_end( type => $action, name => $file );  
 
1242 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
1243 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1244 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 extract($file [, %options])  
 
1245 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1246 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This function extracts a file. The target directory optionally specified with the `to` option will be created automatically.  
 
1247 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1248 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Supported formats are .box, .tar, .tar.gz, .tgz, .tar.Z, .tar.bz2, .tbz2, .zip, .gz, .bz2, .war, .jar.  
 
1249 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1250 
 
 
 
 
 
 
 
 
 
 
 
 
 
  task prepare => sub {  
 
1251 
 
 
 
 
 
 
 
 
 
 
 
 
 
    extract "/tmp/myfile.tar.gz",  
 
1252 
 
 
 
 
 
 
 
 
 
 
 
 
 
     owner => "root",  
 
1253 
 
 
 
 
 
 
 
 
 
 
 
 
 
     group => "root",  
 
1254 
 
 
 
 
 
 
 
 
 
 
 
 
 
     to   => "/etc";  
 
1255 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1256 
 
 
 
 
 
 
 
 
 
 
 
 
 
    extract "/tmp/foo.tgz",  
 
1257 
 
 
 
 
 
 
 
 
 
 
 
 
 
     type => "tgz",  
 
1258 
 
 
 
 
 
 
 
 
 
 
 
 
 
     mode => "g+rwX";  
 
1259 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
1260 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1261 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Can use the type=> option if the file suffix has been changed. (types are tar, tgz, tbz, zip, gz, bz2)  
 
1262 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1263 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
1264 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1265 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub extract {  
 
1266 
 
  
0
   
 
 
 
 
 
  
0
   
 
  
1
   
 
0
 
   my ( $file, %option ) = @_;  
 
1267 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   $file = resolv_path($file);  
 
1268 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1269 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   my $pre_cmd = "";  
 
1270 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   my $to      = ".";  
 
1271 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   my $type    = "";  
 
1272 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1273 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
0
 
   if ( $option{chdir} ) {  
 
1274 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $to = $option{chdir};  
 
1275 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1276 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1277 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
0
 
   if ( $option{to} ) {  
 
1278 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $to = $option{to};  
 
1279 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1280 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   $to = resolv_path($to);  
 
1281 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1282 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
0
 
   if ( $option{type} ) {  
 
1283 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $type = $option{type};  
 
1284 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1285 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1286 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   Rex::Commands::Fs::mkdir($to);  
 
1287 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   $pre_cmd = "cd $to; ";  
 
1288 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1289 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   my $exec = Rex::Interface::Exec->create;  
 
1290 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   my $cmd  = "";  
 
1291 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1292 
 
  
0
   
 
  
  0
   
 
  
  0
   
 
 
 
 
 
0
 
   if ( $type eq 'tgz'  
 
  
 
 
 
  
  0
   
 
  
  0
   
 
 
 
 
 
 
 
    
 
  
 
 
 
  
  0
   
 
  
  0
   
 
 
 
 
 
 
 
    
 
  
 
 
 
  
  0
   
 
  
  0
   
 
 
 
 
 
 
 
    
 
  
 
 
 
  
  0
   
 
  
  0
   
 
 
 
 
 
 
 
    
 
  
 
 
 
  
  0
   
 
  
  0
   
 
 
 
 
 
 
 
    
 
  
 
 
 
 
 
  
  0
   
 
 
 
 
 
 
 
    
 
  
 
 
 
 
 
  
  0
   
 
 
 
 
 
 
 
    
 
  
 
 
 
 
 
  
  0
   
 
 
 
 
 
 
 
    
 
1293 
 
 
 
 
 
 
 
 
 
 
 
 
 
     || $file =~ m/\.tar\.gz$/  
 
1294 
 
 
 
 
 
 
 
 
 
 
 
 
 
     || $file =~ m/\.tgz$/  
 
1295 
 
 
 
 
 
 
 
 
 
 
 
 
 
     || $file =~ m/\.tar\.Z$/ )  
 
1296 
 
 
 
 
 
 
 
 
 
 
 
 
 
   {  
 
1297 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $cmd = "${pre_cmd}gunzip -c $file | tar -xf -";  
 
1298 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1299 
 
 
 
 
 
 
 
 
 
 
 
 
 
   elsif ( $type eq 'tbz' || $file =~ m/\.tar\.bz2/ || $file =~ m/\.tbz2/ ) {  
 
1300 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $cmd = "${pre_cmd}bunzip2 -c $file | tar -xf -";  
 
1301 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1302 
 
 
 
 
 
 
 
 
 
 
 
 
 
   elsif ( $type eq 'tar' || $file =~ m/\.(tar|box)/ ) {  
 
1303 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $cmd = "${pre_cmd}tar -xf $file";  
 
1304 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1305 
 
 
 
 
 
 
 
 
 
 
 
 
 
   elsif ( $type eq 'zip' || $file =~ m/\.(zip|war|jar)$/ ) {  
 
1306 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $cmd = "${pre_cmd}unzip -o $file";  
 
1307 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1308 
 
 
 
 
 
 
 
 
 
 
 
 
 
   elsif ( $type eq 'gz' || $file =~ m/\.gz$/ ) {  
 
1309 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $cmd = "${pre_cmd}gunzip -f $file";  
 
1310 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1311 
 
 
 
 
 
 
 
 
 
 
 
 
 
   elsif ( $type eq 'bz2' || $file =~ m/\.bz2$/ ) {  
 
1312 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $cmd = "${pre_cmd}bunzip2 -f $file";  
 
1313 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1314 
 
 
 
 
 
 
 
 
 
 
 
 
 
   else {  
 
1315 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     Rex::Logger::info("File not supported.");  
 
1316 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     die("File ($file) not supported.");  
 
1317 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1318 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1319 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   $exec->exec($cmd);  
 
1320 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1321 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
   my $fs = Rex::Interface::Fs->create;  
 
1322 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
0
 
   if ( $option{owner} ) {  
 
1323 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $fs->chown( $option{owner}, $to, recursive => 1 );  
 
1324 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1325 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1326 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
0
 
   if ( $option{group} ) {  
 
1327 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $fs->chgrp( $option{group}, $to, recursive => 1 );  
 
1328 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1329 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1330 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
0
 
   if ( $option{mode} ) {  
 
1331 
 
  
0
   
 
 
 
 
 
 
 
 
 
0
 
     $fs->chmod( $option{mode}, $to, recursive => 1 );  
 
1332 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1333 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1334 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
1335 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1336 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 sed($search, $replace, $file [, %options])  
 
1337 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1338 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Search some string in a file and replace it.  
 
1339 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1340 
 
 
 
 
 
 
 
 
 
 
 
 
 
  task sar => sub {  
 
1341 
 
 
 
 
 
 
 
 
 
 
 
 
 
    # this will work line by line  
 
1342 
 
 
 
 
 
 
 
 
 
 
 
 
 
    sed qr{search}, "replace", "/var/log/auth.log";  
 
1343 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1344 
 
 
 
 
 
 
 
 
 
 
 
 
 
    # to use it in a multiline way  
 
1345 
 
 
 
 
 
 
 
 
 
 
 
 
 
    sed qr{search}, "replace", "/var/log/auth.log",  
 
1346 
 
 
 
 
 
 
 
 
 
 
 
 
 
     multiline => TRUE;  
 
1347 
 
 
 
 
 
 
 
 
 
 
 
 
 
  };  
 
1348 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1349 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Like similar file management commands, it also supports C and C hooks.    
 
1350 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1351 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
1352 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1353 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub sed {  
 
1354 
 
11
 
 
 
 
 
  
11
   
 
  
1
   
 
17806
 
   my ( $search, $replace, $file, @option ) = @_;  
 
1355 
 
11
 
 
 
 
 
 
 
 
 
185
 
   $file = resolv_path($file);  
 
1356 
 
11
 
 
 
 
 
 
 
 
 
50
 
   my $options = {};  
 
1357 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1358 
 
 
 
 
 
 
 
 
 
 
 
 
 
   Rex::get_current_connection()->{reporter}  
 
1359 
 
11
 
 
 
 
 
 
 
 
 
74
 
     ->report_resource_start( type => "sed", name => $file );  
 
1360 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1361 
 
11
 
  
 50
   
 
 
 
 
 
 
 
75
 
   if ( ref( $option[0] ) ) {  
 
1362 
 
0
 
 
 
 
 
 
 
 
 
0
 
     $options = $option[0];  
 
1363 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1364 
 
 
 
 
 
 
 
 
 
 
 
 
 
   else {  
 
1365 
 
11
 
 
 
 
 
 
 
 
 
59
 
     $options = {@option};  
 
1366 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1367 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1368 
 
11
 
 
 
  
 50
   
 
 
 
 
 
175
 
   my $on_change    = $options->{"on_change"}    || undef;  
 
1369 
 
11
 
 
 
  
 50
   
 
 
 
 
 
134
 
   my $on_no_change = $options->{"on_no_change"} || undef;  
 
1370 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1371 
 
11
 
 
 
 
 
 
 
 
 
44
 
   my @content;  
 
1372 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1373 
 
11
 
  
100
   
 
 
 
 
 
 
 
54
 
   if ( exists $options->{multiline} ) {  
 
1374 
 
1
 
 
 
 
 
 
 
 
 
31
 
     $content[0] = cat($file);  
 
1375 
 
1
 
 
 
 
 
 
 
 
 
33
 
     $content[0] =~ s/$search/$replace/gms;  
 
1376 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1377 
 
 
 
 
 
 
 
 
 
 
 
 
 
   else {  
 
1378 
 
10
 
 
 
 
 
 
 
 
 
81
 
     @content = split( /\n/, cat($file) );  
 
1379 
 
10
 
 
 
 
 
 
 
 
 
64
 
     for (@content) {  
 
1380 
 
109
 
 
 
 
 
 
 
 
 
481
 
       s/$search/$replace/;  
 
1381 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
1382 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
1383 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1384 
 
11
 
 
 
 
 
 
 
 
 
297
 
   my $fs   = Rex::Interface::Fs->create;  
 
1385 
 
11
 
 
 
 
 
 
 
 
 
66
 
   my %stat = $fs->stat($file);  
 
1386 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1387 
 
 
 
 
 
 
 
 
 
 
 
 
 
   my $ret = file(  
 
1388 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $file,  
 
1389 
 
 
 
 
 
 
 
 
 
 
 
 
 
     content      => join( "\n", @content ),  
 
1390 
 
 
 
 
 
 
 
 
 
 
 
 
 
     on_change    => $on_change,  
 
1391 
 
 
 
 
 
 
 
 
 
 
 
 
 
     on_no_change => $on_no_change,  
 
1392 
 
 
 
 
 
 
 
 
 
 
 
 
 
     owner        => $stat{uid},  
 
1393 
 
 
 
 
 
 
 
 
 
 
 
 
 
     group        => $stat{gid},  
 
1394 
 
 
 
 
 
 
 
 
 
 
 
 
 
     mode         => $stat{mode}  
 
1395 
 
11
 
 
 
 
 
 
 
 
 
180
 
   );  
 
1396 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1397 
 
 
 
 
 
 
 
 
 
 
 
 
 
   Rex::get_current_connection()->{reporter}  
 
1398 
 
11
 
 
 
 
 
 
 
 
 
209
 
     ->report_resource_end( type => "sed", name => $file );  
 
1399 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1400 
 
11
 
 
 
 
 
 
 
 
 
680
 
   return $ret;  
 
1401 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
1402 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
1403 
 
 
 
 
 
 
 
 
 
 
 
 
 
 1;