]> git.sur5r.net Git - bacula/bacula/blob - regress/scripts/regress-win32.pl
regress: fix extract_resource
[bacula/bacula] / regress / scripts / regress-win32.pl
1 #!/usr/bin/perl -w
2
3 =head1 NAME
4
5     regress-win32.pl -- Helper for Windows regression tests
6
7 =head2 DESCRIPTION
8
9     This perl script permits to run test Bacula Client Daemon on Windows.
10     It allows to:
11        - stop/start/upgrade the Bacula Client Daemon
12        - compare to subtree with checksums, attribs and ACL
13        - create test environments
14
15 =head2 USAGE
16
17   X:\> regress-win32.pl [-b basedir] [-i ip_address] [-p c:/bacula]
18    or
19   X:\> perl regress-win32.pl ...
20
21     -b|--base=path      Where to find regress and bacula directories
22     -i|--ip=ip          Restrict access to this tool to this ip address
23     -p|--prefix=path    Path to the windows installation
24     -h|--help           Print this help
25
26 =head2 EXAMPLE
27
28     regress-win32.pl -b z:/git         # will find z:/git/regress z:/git/bacula
29
30     regress-win32.pl -i 192.168.0.1 -b z:
31
32 =head2 INSTALL
33
34     This perl script needs a Perl distribution on the Windows Client
35     (http://strawberryperl.com)
36
37     You need to have the following subtree on x:
38     x:/
39       bacula/
40       regress/
41
42 =cut
43
44 use strict;
45 use HTTP::Daemon;
46 use HTTP::Status;
47 use HTTP::Response;
48 use HTTP::Headers;
49 use File::Copy;
50 use Pod::Usage;
51 use Cwd 'chdir';
52 use File::Find;
53 use Digest::MD5;
54 use Getopt::Long ;
55
56 my $base = 'x:';
57 my $src_ip = '';
58 my $help;
59 my $bacula_prefix="c:/Program Files/Bacula";
60 my $conf = "C:/Documents and Settings/All Users/Application Data/Bacula";
61 GetOptions("base=s"   => \$base,
62            "help"     => \$help,
63            "prefix=s" => \$bacula_prefix,
64            "ip=s"     => \$src_ip);
65
66 if ($help) {
67     pod2usage(-verbose => 2, 
68               -exitval => 0);
69 }
70
71 if (! -d $bacula_prefix) {
72     print "Could not find Bacula installation dir $bacula_prefix\n";
73     print "Won't be able to upgrade the version or modify the configuration\n";
74 }
75
76 if (-f "$bacula_prefix/bacula-fd.conf" and -f "$conf/bacula-fd.conf") {
77     print "Unable to determine bacula-fd location $bacula_prefix or $conf ?\n";
78
79 } elsif (-f "$bacula_prefix/bacula-fd.conf") {
80     $conf = $bacula_prefix;
81 }
82
83 #if (! -d "$base/bacula" || ! -d "$base/regress") {
84 #    pod2usage(-verbose => 2, 
85 #              -exitval => 1,
86 #              -message => "Can't find bacula or regress dir on $base\n");
87 #} 
88
89 # stop the fd service
90 sub stop_fd
91 {
92     return `net stop bacula-fd`;
93 }
94
95 # copy binaries for a new fd
96 sub install_fd
97 {
98     copy("$base/bacula/src/win32/release32/bacula-fd.exe", 
99          "c:/Program Files/bacula/bacula-fd.exe"); 
100
101     copy("$base/bacula/src/win32/release32/bacula.dll", 
102          "c:/Program Files/bacula/bacula.dll"); 
103 }
104
105 # start the fd service
106 sub start_fd
107 {
108     return `net start bacula-fd`;
109 }
110
111 # initialize the weird directory for runscript test
112 sub init_weird_runscript_test
113 {
114     my ($r) = shift;
115
116     if ($r->url !~ m!^/init_weird_runscript_test\?source=(\w:/[\w/]+)$!) {
117         return "ERR\nIncorrect url\n";
118     }
119     my $source = $1;
120
121     if (!chdir($source)) {
122         return "ERR\nCan't access to $source $!\n";
123     }
124     
125     if (-d "weird_runscript") {
126         system("rmdir /Q /S weird_runscript");
127     }
128
129     mkdir("weird_runscript");
130     if (!chdir("weird_runscript")) {
131         return "ERR\nCan't access to $source $!\n";
132     }
133    
134     open(FP, ">test.bat")                 or return "ERR\n";
135     print FP "\@echo off\n";
136     print FP "echo hello \%1\n";
137     close(FP);
138     
139     copy("test.bat", "test space.bat")    or return "ERR\n";
140     copy("test.bat", "test2 space.bat")   or return "ERR\n";
141     copy("test.bat", "testé.bat")         or return "ERR\n";
142
143     mkdir("dir space")                    or return "ERR\n";
144     copy("test.bat", "dir space")         or return "ERR\n";
145     copy("testé.bat","dir space")         or return "ERR\n"; 
146     copy("test2 space.bat", "dir space")  or return "ERR\n";
147
148     mkdir("Évoilà")                       or return "ERR\n";
149     copy("test.bat", "Évoilà")            or return "ERR\n";
150     copy("testé.bat","Évoilà")            or return "ERR\n"; 
151     copy("test2 space.bat", "Évoilà")     or return "ERR\n";
152
153     mkdir("Éwith space")                  or return "ERR\n";
154     copy("test.bat", "Éwith space")       or return "ERR\n";
155     copy("testé.bat","Éwith space")       or return "ERR\n"; 
156     copy("test2 space.bat", "Éwith space") or return "ERR\n";
157     return "OK\n";
158 }
159
160 # init the Attrib test by creating some files and settings attributes
161 sub init_attrib_test
162 {
163     my ($r) = shift;
164
165     if ($r->url !~ m!^/init_attrib_test\?source=(\w:/[\w/]+)$!) {
166         return "ERR\nIncorrect url\n";
167     }
168   
169     my $source = $1;
170  
171     if (!chdir($source)) {
172         return "ERR\nCan't access to $source $!\n";
173     }
174
175     # cleanup the old directory if any
176     if (-d "attrib_test") {
177         system("rmdir /Q /S attrib_test");
178     }
179
180     mkdir("attrib_test");
181     chdir("attrib_test");
182     
183     mkdir("hidden");
184     mkdir("hidden/something");
185     system("attrib +H hidden");
186
187     mkdir("readonly");
188     mkdir("readonly/something");
189     system("attrib +R readonly");
190
191     mkdir("normal");
192     mkdir("normal/something");
193     system("attrib -R -H -S normal");
194
195     mkdir("system");
196     mkdir("system/something");
197     system("attrib +S system");
198
199     mkdir("readonly_hidden");
200     mkdir("readonly_hidden/something");
201     system("attrib +R +H readonly_hidden");
202
203     my $ret = `attrib /S /D`;
204     $ret = strip_base($ret, $source);
205
206     return "OK\n$ret\n";
207 }
208
209 sub md5sum
210 {
211     my $file = shift;
212     open(FILE, $file) or return "Can't open $file $!";
213     binmode(FILE);
214     return Digest::MD5->new->addfile(*FILE)->hexdigest;
215 }
216
217 # set $src and $dst before using Find call
218 my ($src, $dst);
219 my $error="";
220 sub wanted
221 {
222     my $f = $File::Find::name;
223     $f =~ s!^\Q$src\E/?!!i;
224     
225     if (-f "$src/$f") {
226         if (! -f "$dst/$f") {
227             $error .= "$dst/$f is missing\n";
228         } else {
229             my $a = md5sum("$src/$f");
230             my $b = md5sum("$dst/$f");
231             if ($a ne $b) {
232                 $error .= "$src/$f $a\n$dst/$f $b\n";
233             }
234         }
235     }
236 }
237
238 sub set_director_name
239 {
240     my ($r) = shift;
241
242     if ($r->url !~ m!^/set_director_name\?name=([\w\d\.\-]+);pass=([\w\d+]+)$!)
243     {
244         return "ERR\nIncorrect url\n";
245     }
246
247     my ($name, $pass) = ($1, $2);
248
249     open(ORG, "$conf/bacula-fd.conf") or return "ERR\nORG $!\n";
250     open(NEW, ">$conf/bacula-fd.conf.new") or return "ERR\nNEW $!\n";
251     
252     my $in_dir=0;
253     while (my $l = <ORG>)
254     {
255         if ($l =~ /^\s*Director\s+{/i) {
256             print NEW $l; 
257             $in_dir = 1;
258         } elsif ($l =~ /^(\s*)Name\s*=/ and $in_dir) {
259             print NEW "${1}Name=$name\n";
260         } elsif ($l =~ /^(\s*)Password\s*=/ and $in_dir) {
261             print NEW "${1}Password=$pass\n";
262         } elsif ($l =~ /\s*}/ and $in_dir) {
263             print NEW $l; 
264             $in_dir = 0;
265         } elsif (!$in_dir) {
266             print NEW $l;
267         }
268     }
269
270     close(ORG);
271     close(NEW);
272     move("$conf/bacula-fd.conf.new", "$conf/bacula-fd.conf")
273         and return "OK\n";
274
275     return "ERR\n";
276
277
278 # convert \ to / and strip the path
279 sub strip_base
280 {
281     my ($data, $path) = @_;
282     $data =~ s!\\!/!sg;
283     $data =~ s!\Q$path!!sig;
284     return $data;
285 }
286
287 # Compare two directories, make checksums, compare attribs and ACLs
288 sub compare
289 {
290     my ($r) = shift;
291
292     if ($r->url !~ m!^/compare\?source=(\w:/[\w/]+);dest=(\w:/[\w/]+)$!) {
293         return "ERR\nIncorrect url\n";
294     }
295
296     my ($source, $dest) = ($1, $2);
297     
298     if (!Cwd::chdir($source)) {
299         return "ERR\nCan't access to $source $!\n";
300     }
301     
302     my $src_attrib = `attrib /D /S`;
303     $src_attrib = strip_base($src_attrib, $source);
304
305     if (!Cwd::chdir($dest)) {
306         return "ERR\nCan't access to $dest $!\n";
307     }
308     
309     my $dest_attrib = `attrib /D /S`;
310     $dest_attrib = strip_base($dest_attrib, $dest);
311
312     if (lc($src_attrib) ne lc($dest_attrib)) {
313         return "ERR\n$src_attrib\n=========\n$dest_attrib\n";
314     } 
315
316     ($src, $dst, $error) = ($source, $dest, '');
317     find(\&wanted, $source);
318     if ($error) {
319         return "ERR\n$error";
320     } else {
321         return "OK\n";
322     }
323 }
324
325 sub cleandir
326 {
327     my ($r) = shift;
328
329     if ($r->url !~ m!^/cleandir\?source=(\w:/[\w/]+)/restore$!) {
330         return "ERR\nIncorrect url\n";
331     }
332
333     my $source = $1;
334  
335     if (! -d "$source/restore") {
336         return "ERR\nIncorrect path\n";
337     }
338
339     if (!chdir($source)) {
340         return "ERR\nCan't access to $source $!\n";
341     }
342
343     system("rmdir /Q /S restore");
344
345     return "OK\n";
346 }
347
348 # When adding an action, fill this hash with the right function
349 my %action_list = (
350     stop    => \&stop_fd,
351     start   => \&start_fd,
352     install => \&install_fd,
353     compare => \&compare,
354     init_attrib_test => \&init_attrib_test,
355     init_weird_runscript_test => \&init_weird_runscript_test,
356     set_director_name => \&set_director_name,
357     cleandir => \&cleandir,
358     );
359
360 # handle client request
361 sub handle_client
362 {
363     my ($c, $ip) = @_ ;
364     my $action;
365     my $r = $c->get_request ;
366
367     if (!$r) {
368         $c->send_error(RC_FORBIDDEN) ;
369         return;
370     }
371     if ($r->url->path !~ m!^/(\w+)!) {
372         $c->send_error(RC_NOT_FOUND) ;
373         return;
374     }
375     $action = $1;
376
377     if (($r->method eq 'GET') 
378         and $action_list{$action})       
379     {
380         my $ret = $action_list{$action}($r);
381         my $h = HTTP::Headers->new('Content-Type' => 'text/plain') ;
382         my $r = HTTP::Response->new(HTTP::Status::RC_OK,
383                                     'OK', $h, $ret) ;
384
385         $c->send_response($r) ;
386     } else {
387         $c->send_error(RC_NOT_FOUND) ;
388     }
389
390     $c->close;
391 }
392
393 my $d = HTTP::Daemon->new ( LocalPort =>  8091,
394                             ReuseAddr => 1) 
395     || die "E : Can't bind $!" ;
396
397 my $olddir = Cwd::cwd();
398 while (1) {
399     my $c = $d->accept ;
400     my $ip = $c->peerhost;
401     if (!$ip) {
402         $c->send_error(RC_FORBIDDEN) ;
403     } elsif ($src_ip && $ip ne $src_ip) {
404         $c->send_error(RC_FORBIDDEN) ;
405     } elsif ($c) {
406         handle_client($c, $ip) ;
407     } else {
408         $c->send_error(RC_FORBIDDEN) ;
409     }
410     close($c) ;
411     chdir($olddir);
412 }