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 Bareos Client Daemon on Windows. 10 It allows to: 11 - stop/start/upgrade the Bareos 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:/bareos] 18 or 19 X:\> perl regress-win32.pl ... 20 21 -b|--base=path Where to find regress and bareos 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/bareos 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 bareos/ 40 regress/ 41 42 This script requires perl to work (http://strawberryperl.com), and by default 43 it assumes that Bareos is installed in the standard location. Once it's 44 started on the windows, you can do remote commands like: 45 - start the service 46 - stop the service 47 - edit the bareos-fd.conf to change the director and password setting 48 - install a new binary version (not tested, no plugin support) 49 - create weird files and directories 50 - create files with windows attributes 51 - compare two directories (with md5) 52 53 54 To test it, you can follow this procedure 55 On the windows box: 56 - install perl from http://strawberryperl.com on windows 57 - copy or export regress directory somewhere on your windows 58 You can use a network share to your regress directory on linux 59 Then, copy a link to this script to your desktop 60 And double-click on it, and always open .pl file with perl.exe 61 62 - If you export the regress directory to your windows box and you 63 make windows binaries available, this script can update bareos version. 64 You need to put your binaries on: 65 regress/release32 and regress/release64 66 or 67 regress/build/src/win32/release32 and regress/build/src/win32/release64 68 69 - start the regress/scripts/regress-win32.pl (open it with perl.exe) 70 - create $WIN32_FILE 71 - make sure that the firewall is well configured or just disabled (needs 72 bareos and 8091/tcp) 73 74 On Linux box: 75 - edit config file to fill the following variables 76 77 WIN32_CLIENT="win2008-fd" 78 # Client FQDN or IP address 79 WIN32_ADDR="192.168.0.6" 80 # File or Directory to backup. This is put in the "File" directive 81 # in the FileSet 82 WIN32_FILE="c:/tmp" 83 # Port of Win32 client 84 WIN32_PORT=9102 85 # Win32 Client password 86 WIN32_PASSWORD="xxx" 87 # will be the ip address of the linux box 88 WIN32_STORE_ADDR="192.168.0.1" 89 # set for autologon 90 WIN32_USER=Administrator 91 WIN32_PASS=password 92 # set for MSSQL 93 WIN32_MSSQL_USER=sa 94 WIN32_MSSQL_PASS=pass 95 - type make setup 96 - run ./tests/backup-bareos-test to be sure that everything is ok 97 - start ./tests/win32-fd-test 98 99 I'm not very happy with this script, but it works :) 100 101=cut 102 103use strict; 104use HTTP::Daemon; 105use HTTP::Status; 106use HTTP::Response; 107use HTTP::Headers; 108use File::Copy; 109use Pod::Usage; 110use Cwd 'chdir'; 111use File::Find; 112use Digest::MD5; 113use Getopt::Long ; 114use POSIX; 115use File::Basename qw/dirname/; 116 117my $base = 'x:'; 118my $src_ip = ''; 119my $help; 120my $bareos_prefix="c:/Program Files/Bareos"; 121my $conf = "C:/Documents and Settings/All Users/Application Data/Bareos"; 122GetOptions("base=s" => \$base, 123 "help" => \$help, 124 "prefix=s" => \$bareos_prefix, 125 "ip=s" => \$src_ip); 126 127if ($help) { 128 pod2usage(-verbose => 2, 129 -exitval => 0); 130} 131 132if (! -d $bareos_prefix) { 133 print "regress-win32.pl: Could not find Bareos installation dir $bareos_prefix\n"; 134 print "regress-win32.pl: Won't be able to upgrade the version or modify the configuration\n"; 135} 136 137if (-f "$bareos_prefix/bareos-fd.conf" and -f "$conf/bareos-fd.conf") { 138 print "regress-win32.pl: Unable to determine bareos-fd location $bareos_prefix or $conf ?\n"; 139 140} elsif (-f "$bareos_prefix/bareos-fd.conf") { 141 $conf = $bareos_prefix; 142} 143 144#if (! -d "$base/bareos" || ! -d "$base/regress") { 145# pod2usage(-verbose => 2, 146# -exitval => 1, 147# -message => "Can't find bareos or regress dir on $base\n"); 148#} 149 150# stop the fd service 151sub stop_fd 152{ 153 return `net stop bareos-fd`; 154} 155 156my $arch; 157my $bin_path; 158sub find_binaries 159{ 160 if ($_ =~ /bareos-fd.exe/i) { 161 if ($File::Find::dir =~ /release$arch/) { 162 $bin_path = $File::Find::dir; 163 } 164 } 165} 166 167# copy binaries for a new fd 168# to work, you need to mount the regress directory 169sub install_fd 170{ 171 my ($r) = shift; 172 if ($r->url !~ m!^/install$!) { 173 return "ERR\nIncorrect url: " . $r->url . "\n"; 174 } 175 176 if (-d "c:/Program Files (x86)") { 177 $arch = "64"; 178 } else { 179 $arch = "32"; 180 } 181 182 # X:/regress/scripts/regress-win32.pl 183 # X:/scripts/regress-win32.pl 184 # perl script location 185 186 my $dir = dirname(dirname($0)); 187 print "searching bareos-fd.exe in $dir\n"; 188 find(\&find_binaries, ("$dir\\build\\src\\win32\\release$arch", 189 "$dir\\release$arch")); 190 191 if (!$bin_path) { 192 return "ERR\nCan't find bareos-fd.exe in $dir\n"; 193 } 194 195 print "Found binaries in $bin_path\n"; 196 197 stop_fd(); 198 199 system("del \"c:\\Program Files\\bareos\\bareos.dll\""); 200 system("del \"c:\\Program Files\\bareos\\bareos-fd.exe\""); 201 system("del \"c:\\Program Files\\bareos\\plugins\\vss-fd.dll\""); 202 203 my $ret="Ok\n"; 204 205 copy("$bin_path/bareos-fd.exe", 206 "c:/Program Files/bareos/bareos-fd.exe") or $ret="ERR\n$!\n"; 207 208 copy("$bin_path/bareos.dll", 209 "c:/Program Files/bareos/bareos.dll") or $ret="ERR\n$!\n"; 210 211 copy("$bin_path/vss-fd.dll", 212 "c:/Program Files/bareos/plugins/vss-fd.dll") or $ret="ERR\n$!\n"; 213 214 start_fd(); 215 return "OK\n"; 216} 217 218# start the fd service 219sub start_fd 220{ 221 return `net start bareos-fd`; 222} 223 224# initialize the weird directory for runscript test 225sub init_weird_runscript_test 226{ 227 my ($r) = shift; 228 229 if ($r->url !~ m!^/init_weird_runscript_test\?source=(\w:/[\w\d\-\./]+)$!) { 230 return "ERR\nIncorrect url: ". $r->url . "\n"; 231 } 232 my $source = $1; 233 234 # Create $source if needed 235 my $tmp = $source; 236 $tmp =~ s:/:\\:g; 237 system("mkdir $tmp"); 238 239 if (!chdir($source)) { 240 return "ERR\nCan't access to $source $!\n"; 241 } 242 243 if (-d "weird_runscript") { 244 system("rmdir /Q /S weird_runscript"); 245 } 246 247 mkdir("weird_runscript"); 248 if (!chdir("weird_runscript")) { 249 return "ERR\nCan't access to $source $!\n"; 250 } 251 252 open(FP, ">test.bat") or return "ERR\n"; 253 print FP "\@echo off\n"; 254 print FP "echo hello \%1\n"; 255 close(FP); 256 257 copy("test.bat", "test space.bat") or return "ERR\n"; 258 copy("test.bat", "test2 space.bat") or return "ERR\n"; 259 copy("test.bat", "test�.bat") or return "ERR\n"; 260 261 mkdir("dir space") or return "ERR\n"; 262 copy("test.bat", "dir space") or return "ERR\n"; 263 copy("test�.bat","dir space") or return "ERR\n"; 264 copy("test2 space.bat", "dir space") or return "ERR\n"; 265 266 mkdir("�voil�") or return "ERR\n"; 267 copy("test.bat", "�voil�") or return "ERR\n"; 268 copy("test�.bat","�voil�") or return "ERR\n"; 269 copy("test2 space.bat", "�voil�") or return "ERR\n"; 270 271 mkdir("�with space") or return "ERR\n"; 272 copy("test.bat", "�with space") or return "ERR\n"; 273 copy("test�.bat","�with space") or return "ERR\n"; 274 copy("test2 space.bat", "�with space") or return "ERR\n"; 275 mkdir("a"x200); 276 copy("test.bat", "a"x200); 277 system("mklink /J junc " . "a"x200); # TODO: need something for win2003 278 link("test.bat", "link.bat"); 279 return "OK\n"; 280} 281 282# init the Attrib test by creating some files and settings attributes 283sub init_attrib_test 284{ 285 my ($r) = shift; 286 287 if ($r->url !~ m!^/init_attrib_test\?source=(\w:/[\w/]+)$!) { 288 return "ERR\nIncorrect url: " . $r->url . "\n"; 289 } 290 291 my $source = $1; 292 system("mkdir $source"); 293 294 if (!chdir($source)) { 295 return "ERR\nCan't access to $source $!\n"; 296 } 297 298 # cleanup the old directory if any 299 if (-d "attrib_test") { 300 system("rmdir /Q /S attrib_test"); 301 } 302 303 mkdir("attrib_test"); 304 chdir("attrib_test"); 305 306 mkdir("hidden"); 307 mkdir("hidden/something"); 308 system("attrib +H hidden"); 309 310 mkdir("readonly"); 311 mkdir("readonly/something"); 312 system("attrib +R readonly"); 313 314 mkdir("normal"); 315 mkdir("normal/something"); 316 system("attrib -R -H -S normal"); 317 318 mkdir("system"); 319 mkdir("system/something"); 320 system("attrib +S system"); 321 322 mkdir("readonly_hidden"); 323 mkdir("readonly_hidden/something"); 324 system("attrib +R +H readonly_hidden"); 325 326 my $ret = `attrib /S /D`; 327 $ret = strip_base($ret, $source); 328 329 return "OK\n$ret\n"; 330} 331 332sub md5sum 333{ 334 my $file = shift; 335 open(FILE, $file) or return "Can't open $file $!"; 336 binmode(FILE); 337 return Digest::MD5->new->addfile(*FILE)->hexdigest; 338} 339 340# set $src and $dst before using Find call 341my ($src, $dst); 342my $error=""; 343sub wanted 344{ 345 my $f = $File::Find::name; 346 $f =~ s!^\Q$src\E/?!!i; 347 348 if (-f "$src/$f") { 349 if (! -f "$dst/$f") { 350 $error .= "$dst/$f is missing\n"; 351 } else { 352 my $a = md5sum("$src/$f"); 353 my $b = md5sum("$dst/$f"); 354 if ($a ne $b) { 355 $error .= "$src/$f $a\n$dst/$f $b\n"; 356 } 357 } 358 } 359} 360 361sub create_schedtask 362{ 363 my ($r) = shift; 364 if ($r->url !~ m!^/create_schedtask\?name=([\w\d\-.]+)$!) { 365 return "ERR\nIncorrect url: " . $r->url . "\n"; 366 } 367 my $ret=''; 368 my ($task,$pass) = ($1, $2); 369 my (undef, undef, $version, undef) = POSIX::uname(); 370 if ($version < 6) { # win2003 371 $ret = `echo pass | SCHTASKS /Create /TN $task /SC ONLOGON /TR C:\\windows\\system32\\calc.exe /F 2>&1`; 372 } else { 373 $ret=`SCHTASKS /Create /TN $task /SC ONLOGON /F /TR C:\\windows\\system32\\calc.exe`; 374 } 375 376 if ($ret =~ /SUCCESS|has been created/) { 377 return "OK\n$ret"; 378 } else { 379 return "ERR\n$ret"; 380 } 381# 382# SCHTASKS /Create [/S system [/U username [/P [password]]]] 383# [/RU username [/RP password]] /SC schedule [/MO modifier] [/D day] 384# [/M months] [/I idletime] /TN taskname /TR taskrun [/ST starttime] 385# [/RI interval] [ {/ET endtime | /DU duration} [/K] [/XML xmlfile] [/V1]] 386# [/SD startdate] [/ED enddate] [/IT | /NP] [/Z] [/F] 387} 388 389sub del_schedtask 390{ 391 my ($r) = shift; 392 if ($r->url !~ m!^/del_schedtask\?name=([\w\d\-.]+)$!) { 393 return "ERR\nIncorrect url: " . $r->url . "\n"; 394 } 395 my ($task) = ($1); 396 my $ret=`SCHTASKS /Delete /TN $task /F`; 397 398 if ($ret =~ /SUCCESS/) { 399 return "OK\n$ret"; 400 } else { 401 return "ERR\n$ret"; 402 } 403} 404 405sub check_schedtask 406{ 407 my ($r) = shift; 408 if ($r->url !~ m!^/check_schedtask\?name=([\w\d\-.]+)$!) { 409 return "ERR\nIncorrect url: " . $r->url . "\n"; 410 } 411 412 my ($task) = ($1); 413 my (undef, undef, $version, undef) = POSIX::uname(); 414 my $ret; 415 if ($version < 6) { # win2003 416 $ret=`SCHTASKS /Query`; 417 } else { 418 $ret=`SCHTASKS /Query /TN $task`; 419 } 420 421 if ($ret =~ /^($task .+)$/m) { 422 return "OK\n$1\n"; 423 } else { 424 return "ERR\n$ret"; 425 } 426} 427 428sub set_director_name 429{ 430 my ($r) = shift; 431 432 if ($r->url !~ m!^/set_director_name\?name=([\w\d\.\-]+);pass=([\w\d+\-\.*]+)$!) 433 { 434 return "ERR\nIncorrect url: " . $r->url . "\n"; 435 } 436 437 my ($name, $pass) = ($1, $2); 438 439 open(ORG, "$conf/bareos-fd.conf") or return "ERR\nORG $!\n"; 440 open(NEW, ">$conf/bareos-fd.conf.new") or return "ERR\nNEW $!\n"; 441 442 my $in_dir=0; # don't use monitoring section 443 my $nb_dir=""; 444 while (my $l = <ORG>) 445 { 446 if ($l =~ /^\s*Director\s+{/i) { 447 print NEW $l; 448 $in_dir = 1; 449 } elsif ($l =~ /^(\s*)Name\s*=/ and $in_dir) { 450 print NEW "${1}Name=$name$nb_dir\n"; 451 } elsif ($l =~ /^(\s*)Password\s*=/ and $in_dir) { 452 print NEW "${1}Password=$pass\n"; 453 } elsif ($l =~ /#(\s*Plugin.*)$/) { 454 print NEW $1; 455 } elsif ($l =~ /\s*}/ and $in_dir) { 456 print NEW $l; 457 $in_dir = 0; 458 $nb_dir++; 459 } else { 460 print NEW $l; 461 } 462 } 463 464 close(ORG); 465 close(NEW); 466 move("$conf/bareos-fd.conf.new", "$conf/bareos-fd.conf") 467 and return "OK\n"; 468 469 return "ERR\nCan't set the director name\n"; 470} 471 472# convert \ to / and strip the path 473sub strip_base 474{ 475 my ($data, $path) = @_; 476 $data =~ s!\\!/!sg; 477 $data =~ s!\Q$path!!sig; 478 return $data; 479} 480 481# Compare two directories, make checksums, compare attribs and ACLs 482sub compare 483{ 484 my ($r) = shift; 485 486 if ($r->url !~ m!^/compare\?source=(\w:/[\w/]+);dest=(\w:/[\w/]+)$!) { 487 return "ERR\nIncorrect url: " . $r->url . "\n"; 488 } 489 490 my ($source, $dest) = ($1, $2); 491 492 if (!Cwd::chdir($source)) { 493 return "ERR\nCan't access to $source $!\n"; 494 } 495 496 my $src_attrib = `attrib /D /S`; 497 $src_attrib = strip_base($src_attrib, $source); 498 499 if (!Cwd::chdir($dest)) { 500 return "ERR\nCan't access to $dest $!\n"; 501 } 502 503 my $dest_attrib = `attrib /D /S`; 504 $dest_attrib = strip_base($dest_attrib, $dest); 505 506 if (lc($src_attrib) ne lc($dest_attrib)) { 507 print "ERR\n$src_attrib\n=========\n$dest_attrib\n"; 508 return "ERR\n$src_attrib\n=========\n$dest_attrib\n"; 509 } 510 511 ($src, $dst, $error) = ($source, $dest, ''); 512 find(\&wanted, $source); 513 if ($error) { 514 return "ERR\n$error"; 515 } else { 516 return "OK\n"; 517 } 518} 519 520sub cleandir 521{ 522 my ($r) = shift; 523 524 if ($r->url !~ m!^/cleandir\?source=(\w:/[\w/]+)/restore$!) { 525 return "ERR\nIncorrect url: " . $r->url . "\n"; 526 } 527 528 my $source = $1; 529 530 if (! -d "$source/restore") { 531 return "ERR\nIncorrect path\n"; 532 } 533 534 if (!chdir($source)) { 535 return "ERR\nCan't access to $source $!\n"; 536 } 537 538 system("rmdir /Q /S restore"); 539 540 return "OK\n"; 541} 542 543sub reboot 544{ 545 Win32::InitiateSystemShutdown('', "\nSystem will now Reboot\!", 2, 0, 1 ); 546 exit 0; 547} 548 549# boot disabled auto 550sub set_service 551{ 552 my ($r) = shift; 553 554 if ($r->url !~ m!^/set_service\?srv=([\w-]+);action=(\w+)$!) { 555 return "ERR\nIncorrect url: " . $r->url . "\n"; 556 } 557 my $out = `sc config $1 start= $2`; 558 if ($out !~ /SUCCESS/) { 559 return "ERR\n$out"; 560 } 561 return "OK\n"; 562} 563 564# RUNNING, STOPPED 565sub get_service 566{ 567 my ($r) = shift; 568 569 if ($r->url !~ m!^/get_service\?srv=([\w-]+);state=(\w+)$!) { 570 return "ERR\nIncorrect url: " . $r->url . "\n"; 571 } 572 my $out = `sc query $1`; 573 if ($out !~ /$2/) { 574 return "ERR\n$out"; 575 } 576 return "OK\n"; 577} 578 579sub add_registry_key 580{ 581 my ($r) = shift; 582 if ($r->url !~ m!^/add_registry_key\?key=(\w+);val=(\w+)$!) { 583 return "ERR\nIncorrect url: " . $r->url . "\n"; 584 } 585 my ($k, $v) = ($1,$2); 586 my $ret = "ERR"; 587 open(FP, ">tmp.reg") 588 or return "ERR\nCan't open tmp.reg $!\n"; 589 590 print FP "Windows Registry Editor Version 5.00 591 592[HKEY_LOCAL_MACHINE\\SOFTWARE\\Bareos] 593\"$k\"=\"$v\" 594 595"; 596 close(FP); 597 system("regedit /s tmp.reg"); 598 599 unlink("tmp2.reg"); 600 system("regedit /e tmp2.reg HKEY_LOCAL_MACHINE\\SOFTWARE\\Bareos"); 601 602 open(FP, "<:encoding(UTF-16LE)", "tmp2.reg") 603 or return "ERR\nCan't open tmp2.reg $!\n"; 604 while (my $l = <FP>) { 605 if ($l =~ /"$k"="$v"/) { 606 $ret = "OK"; 607 } 608 } 609 close(FP); 610 unlink("tmp.reg"); 611 unlink("tmp2.reg"); 612 return "$ret\n"; 613} 614 615sub set_auto_logon 616{ 617 my ($r) = shift; 618 my $self = $0; # perl script location 619 $self =~ s/\\/\\\\/g; 620 my $p = $^X; # perl.exe location 621 $p =~ s/\\/\\\\/g; 622 if ($r->url !~ m!^/set_auto_logon\?user=([\w\d\-+\.]+);pass=([\w\d\.\,:*+%\-]*)$!) { 623 return "ERR\nIncorrect url: " . $r->url . "\n"; 624 } 625 my $k = $1; 626 my $v = $2 || ''; # password can be empty 627 my $ret = "ERR\nCan't find AutoAdminLogon key\n"; 628 open(FP, ">c:/autologon.reg") 629 or return "ERR\nCan't open autologon.reg $!\n"; 630 print FP "Windows Registry Editor Version 5.00 631 632[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon] 633\"DefaultUserName\"=\"$k\" 634\"DefaultPassword\"=\"$v\" 635\"AutoAdminLogon\"=\"1\" 636 637[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run] 638\"regress\"=\"$p $self\" 639 640[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Reliability] 641\"ShutdownReasonUI\"=dword:00000000 642 643[HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\Windows NT\\Reliability] 644\"ShutdownReasonOn\"=dword:00000000 645"; 646 close(FP); 647 system("regedit /s c:\\autologon.reg"); 648 649 unlink("tmp2.reg"); 650 system("regedit /e tmp2.reg \"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\""); 651 652 open(FP, "<:encoding(UTF-16LE)", "tmp2.reg") 653 or return "ERR\nCan't open tmp2.reg $!\n"; 654 while (my $l = <FP>) { 655 if ($l =~ /"AutoAdminLogon"="1"/) { 656 $ret = "OK\n"; 657 } 658 } 659 close(FP); 660 unlink("tmp2.reg"); 661 return $ret; 662} 663 664sub del_registry_key 665{ 666 my ($r) = shift; 667 if ($r->url !~ m!^/del_registry_key\?key=(\w+)$!) { 668 return "ERR\nIncorrect url: " . $r->url . "\n"; 669 } 670 my $k = $1; 671 my $ret = "OK\n"; 672 673 unlink("tmp2.reg"); 674 open(FP, ">tmp.reg") 675 or return "ERR\nCan't open tmp.reg $!\n"; 676 print FP "Windows Registry Editor Version 5.00 677 678[HKEY_LOCAL_MACHINE\\SOFTWARE\\Bareos] 679\"$k\"=- 680 681"; 682 close(FP); 683 system("regedit /s tmp.reg"); 684 system("regedit /e tmp2.reg HKEY_LOCAL_MACHINE\\SOFTWARE\\Bareos"); 685 686 open(FP, "<:encoding(UTF-16LE)", "tmp2.reg") 687 or return "ERR\nCan't open tmp2.reg $!\n"; 688 while (my $l = <FP>) { 689 if ($l =~ /"$k"=/) { 690 $ret = "ERR\nThe key $k is still present\n"; 691 } 692 } 693 close(FP); 694 unlink("tmp.reg"); 695 unlink("tmp2.reg"); 696 return $ret; 697} 698 699sub get_registry_key 700{ 701 my ($r) = shift; 702 if ($r->url !~ m!^/get_registry_key\?key=(\w+);val=(\w+)$!) { 703 return "ERR\nIncorrect url: " . $r->url . "\n"; 704 } 705 my ($k, $v) = ($1, $2); 706 my $ret = "ERR\nCan't get or verify registry key $k\n"; 707 708 unlink("tmp2.reg"); 709 system("regedit /e tmp2.reg HKEY_LOCAL_MACHINE\\SOFTWARE\\Bareos"); 710 open(FP, "<:encoding(UTF-16LE)", "tmp2.reg") 711 or return "ERR\nCan't open tmp2.reg $!\n"; 712 while (my $l = <FP>) { 713 if ($l =~ /"$k"="$v"/) { 714 $ret = "OK\n"; 715 } 716 } 717 close(FP); 718 unlink("tmp2.reg"); 719 720 return $ret; 721} 722 723my $mssql_user; 724my $mssql_pass; 725my $mssql_cred; 726my $mssql_bin; 727sub find_mssql 728{ 729 if ($_ =~ /sqlcmd.exe/i) { 730 $mssql_bin = $File::Find::name; 731 } 732} 733 734# Verify that we can use SQLCMD.exe 735sub check_mssql 736{ 737 my ($r) = shift; 738 my $ret = "ERR"; 739 if ($r->url !~ m!^/check_mssql\?user=(\w*);pass=(.*)$!) { 740 return "ERR\nIncorrect url: " . $r->url . "\n"; 741 } 742 ($mssql_user, $mssql_pass) = ($1, $2); 743 744 unless ($mssql_bin) { 745 find(\&find_mssql, 'c:/program files/microsoft sql server/'); 746 } 747 unless ($mssql_bin) { 748 find(\&find_mssql, 'c:/program files (x86)/microsoft sql server/'); 749 } 750 751 if (!$mssql_bin) { 752 return "ERR\nCan't find SQLCMD.exe in c:/program files\n"; 753 } 754 755 print $mssql_bin, "\n"; 756 $mssql_cred = ($mssql_user)?"-U $mssql_user -P $mssql_pass":""; 757 my $res = `"$mssql_bin" $mssql_cred -Q "SELECT 'OK';"`; 758 if ($res !~ /OK/) { 759 return "ERR\nCan't verify the SQLCMD result\n" . 760 "Please verify that MSSQL is accepting connection:\n" . 761 "$mssql_bin $mssql_cred -Q \"SELECT 1;\"\n"; 762 } 763 return "OK\n"; 764} 765 766# Create simple DB, a table and some information in 767sub setup_mssql_db 768{ 769 my ($r) = shift; 770 my $ret = "ERR"; 771 if ($r->url !~ m!^/setup_mssql_db\?db=([\w\d]+)$!) { 772 return "ERR\nIncorrect url: " . $r->url . "\n"; 773 } 774 my $db = $1; 775 776 unless ($mssql_bin) { 777 return "ERR\nCan't find mssql bin (run check_mssql first)\n"; 778 } 779 780 my $res = `"$mssql_bin" $mssql_cred -Q "CREATE DATABASE $db;"`; 781 $res = `"$mssql_bin" $mssql_cred -d $db -Q "CREATE TABLE table1 (a int, b int);"`; 782 $res = `"$mssql_bin" $mssql_cred -d $db -Q "INSERT INTO table1 (a, b) VALUES (1,1);"`; 783 $res = `"$mssql_bin" $mssql_cred -d $db -Q "SELECT 'OK' FROM table1;"`; 784 785 if ($res !~ /OK/) { 786 return "ERR\nCan't verify the SQLCMD result\n" . 787 "Please verify that MSSQL is accepting connection:\n" . 788 "$mssql_bin $mssql_cred -Q \"SELECT 1;\"\n"; 789 } 790 return "OK\n"; 791} 792 793# drop database 794sub cleanup_mssql_db 795{ 796 my ($r) = shift; 797 my $ret = "ERR"; 798 if ($r->url !~ m!^/cleanup_mssql_db\?db=([\w\d]+)$!) { 799 return "ERR\nIncorrect url: " . $r->url . "\n"; 800 } 801 my $db = $1; 802 803 unless ($mssql_bin) { 804 return "ERR\nCan't find mssql bin\n"; 805 } 806 807 my $res = `"$mssql_bin" $mssql_cred -Q "DROP DATABASE $db;"`; 808 809 return "OK\n"; 810} 811 812# truncate the table that is in database 813sub truncate_mssql_table 814{ 815 my ($r) = shift; 816 my $ret = "ERR"; 817 if ($r->url !~ m!^/truncate_mssql_table\?db=([\w\d]+)$!) { 818 return "ERR\nIncorrect url: " . $r->url . "\n"; 819 } 820 my $db = $1; 821 822 unless ($mssql_bin) { 823 return "ERR\nCan't find mssql bin\n"; 824 } 825 826 my $res = `"$mssql_bin" $mssql_cred -d $db -Q "TRUNCATE TABLE table1;"`; 827 $res = `"$mssql_bin" $mssql_cred -d $db -Q "SELECT 'OK' FROM table1;"`; 828 829 if ($res =~ /OK/) { 830 return "ERR\nCan't truncate $db.table1\n"; 831 } 832 return "OK\n"; 833} 834 835# test that table1 contains some rows 836sub test_mssql_content 837{ 838 my ($r) = shift; 839 my $ret = "ERR"; 840 if ($r->url !~ m!^/test_mssql_content\?db=([\w\d]+)$!) { 841 return "ERR\nIncorrect url: " . $r->url . "\n"; 842 } 843 my $db = $1; 844 845 unless ($mssql_bin) { 846 return "ERR\nCan't find mssql bin\n"; 847 } 848 849 my $res = `"$mssql_bin" $mssql_cred -d $db -Q "SELECT 'OK' FROM table1;"`; 850 851 if ($res !~ /OK/) { 852 return "ERR\nNo content from $mssql_bin\n$res\n"; 853 } 854 return "OK\n"; 855} 856 857my $mssql_mdf; 858my $mdf_to_find; 859sub find_mdf 860{ 861 if ($_ =~ /$mdf_to_find/i) { 862 $mssql_mdf = $File::Find::dir; 863 } 864} 865 866# put a mdf online 867sub online_mssql_db 868{ 869 my ($r) = shift; 870 if ($r->url !~ m!^/online_mssql_db\?mdf=([\w\d]+);db=([\w\d]+)$!) { 871 return "ERR\nIncorrect url: " . $r->url . "\n"; 872 } 873 my ($mdf, $db) = ($1, $2); 874 $mdf_to_find = "$mdf.mdf"; 875 876 find(\&find_mdf, 'c:/program files/microsoft sql server/'); 877 unless ($mssql_mdf) { 878 find(\&find_mssql, 'c:/program files (x86)/microsoft sql server/'); 879 } 880 unless ($mssql_mdf) { 881 return "ERR\nCan't find $mdf.mdf in c:/program files\n"; 882 } 883 $mssql_mdf =~ s:/:\\:g; 884 885 open(FP, ">c:/mssql.sql"); 886 print FP " 887USE [master] 888GO 889CREATE DATABASE [$db] ON 890( FILENAME = N'$mssql_mdf\\$mdf.mdf' ), 891( FILENAME = N'$mssql_mdf\\${mdf}_log.LDF' ) 892 FOR ATTACH 893GO 894USE [$db] 895GO 896SELECT 'OK' FROM table1 897GO 898"; 899 close(FP); 900 my $res = `"$mssql_bin" $mssql_cred -i c:\\mssql.sql`; 901 #unlink("c:/mssql.sql"); 902 if ($res !~ /OK/) { 903 return "ERR\nNo content from $mssql_bin\n"; 904 } 905 return "OK\n"; 906} 907 908# create a script c:/del.cmd to delete protected files with runscript 909sub remove_dir 910{ 911 my ($r) = shift; 912 if ($r->url !~ m!^/remove_dir\?file=([\w\d:\/\.\-+*]+);dest=([\w\d\.:\/]+)$!) { 913 return "ERR\nIncorrect url: " . $r->url . "\n"; 914 } 915 my ($file, $cmd) = ($1, $2); 916 $file =~ s:/:\\:g; 917 918 open(FP, ">$cmd") or return "ERR\nCan't open $file $!\n"; 919 print FP "DEL /F /S /Q $file\n"; 920 close(FP); 921 return "OK\n"; 922} 923 924sub get_traces 925{ 926 my ($file) = <"c:/program files/bareos/working/*.trace">; 927 if (!$file || ! -f $file) { 928 return "ERR\n$!\n"; 929 } 930 return $file; 931} 932 933sub truncate_traces 934{ 935 my $f = get_traces(); 936 unlink($f) or return "ERR\n$!\n"; 937 return "OK\n"; 938} 939 940# When adding an action, fill this hash with the right function 941my %action_list = ( 942 nop => sub { return "OK\n"; }, 943 stop => \&stop_fd, 944 start => \&start_fd, 945 install => \&install_fd, 946 compare => \&compare, 947 init_attrib_test => \&init_attrib_test, 948 init_weird_runscript_test => \&init_weird_runscript_test, 949 set_director_name => \&set_director_name, 950 cleandir => \&cleandir, 951 add_registry_key => \&add_registry_key, 952 del_registry_key => \&del_registry_key, 953 get_registry_key => \&get_registry_key, 954 quit => sub { exit 0; }, 955 reboot => \&reboot, 956 set_service => \&set_service, 957 get_service => \&get_service, 958 set_auto_logon => \&set_auto_logon, 959 remove_dir => \&remove_dir, 960 reload => \&reload, 961 create_schedtask => \&create_schedtask, 962 del_schedtask => \&del_schedtask, 963 check_schedtask => \&check_schedtask, 964 get_traces => \&get_traces, 965 truncate_traces => \&truncate_traces, 966 967 check_mssql => \&check_mssql, 968 setup_mssql_db => \&setup_mssql_db, 969 cleanup_mssql_db => \&cleanup_mssql_db, 970 truncate_mssql_table => \&truncate_mssql_table, 971 test_mssql_content => \&test_mssql_content, 972 online_mssql_db => \&online_mssql_db, 973 ); 974 975my $reload=0; 976sub reload 977{ 978 $reload=1; 979 return "OK\n"; 980} 981 982# handle client request 983sub handle_client 984{ 985 my ($c, $ip) = @_ ; 986 my $action; 987 my $r = $c->get_request ; 988 989 if (!$r) { 990 $c->send_error(RC_FORBIDDEN) ; 991 return; 992 } 993 if ($r->url->path !~ m!^/(\w+)!) { 994 $c->send_error(RC_NOT_FOUND) ; 995 return; 996 } 997 $action = $1; 998 999 if (($r->method eq 'GET') 1000 and $action_list{$action}) 1001 { 1002 print "Exec $action:\n"; 1003 1004 my $ret = $action_list{$action}($r); 1005 if ($action eq 'get_traces' && $ret !~ /ERR/) { 1006 print "Sending $ret\n"; 1007 $c->send_file_response($ret); 1008 1009 } else { 1010 my $h = HTTP::Headers->new('Content-Type' => 'text/plain') ; 1011 my $r = HTTP::Response->new(HTTP::Status::RC_OK, 1012 'OK', $h, $ret) ; 1013 print $ret; 1014 $c->send_response($r) ; 1015 } 1016 } else { 1017 print "$action not found, probably a version problem\n"; 1018 $c->send_error(RC_NOT_FOUND) ; 1019 } 1020 1021 $c->close; 1022} 1023 1024print "Starting regress-win32.pl daemon...\n"; 1025my $d = HTTP::Daemon->new ( LocalPort => 8091, 1026 ReuseAddr => 1) 1027 || die "Error: Can't bind $!" ; 1028 1029my $olddir = Cwd::cwd(); 1030while (1) { 1031 my $c = $d->accept ; 1032 my $ip = $c->peerhost; 1033 if (!$ip) { 1034 $c->send_error(RC_FORBIDDEN) ; 1035 } elsif ($src_ip && $ip ne $src_ip) { 1036 $c->send_error(RC_FORBIDDEN) ; 1037 } elsif ($c) { 1038 handle_client($c, $ip) ; 1039 } else { 1040 $c->send_error(RC_FORBIDDEN) ; 1041 } 1042 close($c) ; 1043 undef $c; 1044 chdir($olddir); 1045 1046 # When we have the reload command, just close the http daemon 1047 # and exec ourself 1048 if ($reload) { 1049 $d->close(); 1050 undef $d; 1051 1052 exec("$^X $0"); 1053 } 1054} 1055