1package ProFTPD::Tests::Commands::STAT; 2 3use lib qw(t/lib); 4use base qw(ProFTPD::TestSuite::Child); 5use strict; 6 7use Cwd; 8use File::Path qw(mkpath); 9use File::Spec; 10use IO::Handle; 11 12use ProFTPD::TestSuite::FTP; 13use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite); 14 15$| = 1; 16 17my $order = 0; 18 19my $TESTS = { 20 stat_file => { 21 order => ++$order, 22 test_class => [qw(forking)], 23 }, 24 25 stat_dir => { 26 order => ++$order, 27 test_class => [qw(forking)], 28 }, 29 30 stat_dir_with_files_bug3990 => { 31 order => ++$order, 32 test_class => [qw(bug forking)], 33 }, 34 35 stat_symlink_showsymlinks_off => { 36 order => ++$order, 37 test_class => [qw(forking)], 38 }, 39 40 stat_symlink_showsymlinks_on => { 41 order => ++$order, 42 test_class => [qw(forking)], 43 }, 44 45 stat_symlink_showsymlinks_off_chrooted_bug4219 => { 46 order => ++$order, 47 test_class => [qw(forking rootprivs)], 48 }, 49 50 stat_symlink_showsymlinks_on_chrooted_bug4219 => { 51 order => ++$order, 52 test_class => [qw(forking rootprivs)], 53 }, 54 55 stat_system => { 56 order => ++$order, 57 test_class => [qw(forking)], 58 }, 59 60 stat_enoent => { 61 order => ++$order, 62 test_class => [qw(forking)], 63 }, 64 65 stat_listoptions_bug3295 => { 66 order => ++$order, 67 test_class => [qw(bug forking)], 68 }, 69 70}; 71 72sub new { 73 return shift()->SUPER::new(@_); 74} 75 76sub list_tests { 77 return testsuite_get_runnable_tests($TESTS); 78} 79 80sub stat_file { 81 my $self = shift; 82 my $tmpdir = $self->{tmpdir}; 83 my $setup = test_setup($tmpdir, 'cmds'); 84 85 my $test_file = File::Spec->rel2abs($setup->{config_file}); 86 87 my $config = { 88 PidFile => $setup->{pid_file}, 89 ScoreboardFile => $setup->{scoreboard_file}, 90 SystemLog => $setup->{log_file}, 91 92 AuthUserFile => $setup->{auth_user_file}, 93 AuthGroupFile => $setup->{auth_group_file}, 94 95 IfModules => { 96 'mod_delay.c' => { 97 DelayEngine => 'off', 98 }, 99 }, 100 }; 101 102 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 103 $config); 104 105 # Open pipes, for use between the parent and child processes. Specifically, 106 # the child will indicate when it's done with its test by writing a message 107 # to the parent. 108 my ($rfh, $wfh); 109 unless (pipe($rfh, $wfh)) { 110 die("Can't open pipe: $!"); 111 } 112 113 my $ex; 114 115 # Fork child 116 $self->handle_sigchld(); 117 defined(my $pid = fork()) or die("Can't fork: $!"); 118 if ($pid) { 119 eval { 120 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 121 $client->login($setup->{user}, $setup->{passwd}); 122 $client->stat('cmds.conf'); 123 124 my $resp_code = $client->response_code(); 125 my $resp_msgs = $client->response_msgs(); 126 my $resp_msg = $resp_msgs->[1]; 127 $client->quit(); 128 129 my $expected = 213; 130 $self->assert($expected == $resp_code, 131 test_msg("Expected response code $expected, got $resp_code")); 132 133 $expected = '^(\s+)?\S+\s+\d+\s+\S+\s+\S+\s+.*?\s+(\S+)$'; 134 $self->assert(qr/$expected/, $resp_msg, 135 test_msg("Expected response message '$expected', got '$resp_msg'")); 136 }; 137 if ($@) { 138 $ex = $@; 139 } 140 141 $wfh->print("done\n"); 142 $wfh->flush(); 143 144 } else { 145 eval { server_wait($setup->{config_file}, $rfh) }; 146 if ($@) { 147 warn($@); 148 exit 1; 149 } 150 151 exit 0; 152 } 153 154 # Stop server 155 server_stop($setup->{pid_file}); 156 $self->assert_child_ok($pid); 157 158 test_cleanup($setup->{log_file}, $ex); 159} 160 161sub stat_dir { 162 my $self = shift; 163 my $tmpdir = $self->{tmpdir}; 164 my $setup = test_setup($tmpdir, 'cmds'); 165 166 my $test_dir = File::Spec->rel2abs("$tmpdir/test.d"); 167 mkpath($test_dir); 168 169 if ($< == 0) { 170 unless (chmod(0755, $test_dir)) { 171 die("Can't set perms on $test_dir to 0755: $!"); 172 } 173 174 unless (chown($setup->{uid}, $setup->{gid}, $test_dir)) { 175 die("Can't set owner of $test_dir to $setup->{uid}/$setup->{gid}: $!"); 176 } 177 } 178 179 my $config = { 180 PidFile => $setup->{pid_file}, 181 ScoreboardFile => $setup->{scoreboard_file}, 182 SystemLog => $setup->{log_file}, 183 184 AuthUserFile => $setup->{auth_user_file}, 185 AuthGroupFile => $setup->{auth_group_file}, 186 187 IfModules => { 188 'mod_delay.c' => { 189 DelayEngine => 'off', 190 }, 191 }, 192 }; 193 194 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 195 $config); 196 197 # Open pipes, for use between the parent and child processes. Specifically, 198 # the child will indicate when it's done with its test by writing a message 199 # to the parent. 200 my ($rfh, $wfh); 201 unless (pipe($rfh, $wfh)) { 202 die("Can't open pipe: $!"); 203 } 204 205 my $ex; 206 207 # Fork child 208 $self->handle_sigchld(); 209 defined(my $pid = fork()) or die("Can't fork: $!"); 210 if ($pid) { 211 eval { 212 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 213 $client->login($setup->{user}, $setup->{passwd}); 214 $client->stat('test.d'); 215 216 my $resp_code = $client->response_code(); 217 my $resp_msgs = $client->response_msgs(); 218 my $resp_msg = $resp_msgs->[1]; 219 $client->quit(); 220 221 my $expected = 212; 222 $self->assert($expected == $resp_code, 223 test_msg("Expected response code $expected, got $resp_code")); 224 225 $expected = '^(\s+)?\S+\s+\d+\s+\S+\s+\S+\s+.*?\s+(\S+)$'; 226 $self->assert(qr/$expected/, $resp_msg, 227 test_msg("Expected response message '$expected', got '$resp_msg'")); 228 }; 229 if ($@) { 230 $ex = $@; 231 } 232 233 $wfh->print("done\n"); 234 $wfh->flush(); 235 236 } else { 237 eval { server_wait($setup->{config_file}, $rfh) }; 238 if ($@) { 239 warn($@); 240 exit 1; 241 } 242 243 exit 0; 244 } 245 246 # Stop server 247 server_stop($setup->{pid_file}); 248 $self->assert_child_ok($pid); 249 250 test_cleanup($setup->{log_file}, $ex); 251} 252 253sub stat_dir_with_files_bug3990 { 254 my $self = shift; 255 my $tmpdir = $self->{tmpdir}; 256 my $setup = test_setup($tmpdir, 'cmds'); 257 258 my $test_dir = File::Spec->rel2abs("$tmpdir/test.d"); 259 mkpath($test_dir); 260 261 for (my $i = 0; $i < 5; $i++) { 262 my $test_file = File::Spec->rel2abs("$test_dir/file$i.dat"); 263 if (open(my $fh, "> $test_file")) { 264 close($fh); 265 266 } else { 267 die("Can't open $test_file: $!"); 268 } 269 } 270 271 for (my $i = 0; $i < 5; $i++) { 272 my $test_file = File::Spec->rel2abs("$test_dir/.hidden$i.dat"); 273 if (open(my $fh, "> $test_file")) { 274 close($fh); 275 276 } else { 277 die("Can't open $test_file: $!"); 278 } 279 } 280 281 # Make sure that, if we're running as root, that the home directory has 282 # permissions/privs set for the account we create 283 if ($< == 0) { 284 unless (chmod(0755, $test_dir)) { 285 die("Can't set perms on $test_dir to 0755: $!"); 286 } 287 288 unless (chown($setup->{uid}, $setup->{gid}, $test_dir)) { 289 die("Can't set owner of $test_dir to $setup->{uid}/$setup->{gid}: $!"); 290 } 291 } 292 293 my $config = { 294 PidFile => $setup->{pid_file}, 295 ScoreboardFile => $setup->{scoreboard_file}, 296 SystemLog => $setup->{log_file}, 297 298 AuthUserFile => $setup->{auth_user_file}, 299 AuthGroupFile => $setup->{auth_group_file}, 300 301 IfModules => { 302 'mod_delay.c' => { 303 DelayEngine => 'off', 304 }, 305 }, 306 }; 307 308 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 309 $config); 310 311 # Open pipes, for use between the parent and child processes. Specifically, 312 # the child will indicate when it's done with its test by writing a message 313 # to the parent. 314 my ($rfh, $wfh); 315 unless (pipe($rfh, $wfh)) { 316 die("Can't open pipe: $!"); 317 } 318 319 my $ex; 320 321 # Fork child 322 $self->handle_sigchld(); 323 defined(my $pid = fork()) or die("Can't fork: $!"); 324 if ($pid) { 325 eval { 326 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 327 $client->login($setup->{user}, $setup->{passwd}); 328 $client->stat('test.d'); 329 330 my $resp_code = $client->response_code(); 331 my $resp_msgs = $client->response_msgs(); 332 my $resp_nmsgs = scalar(@$resp_msgs); 333 my $resp_msg = $resp_msgs->[1]; 334 $client->quit(); 335 336 my $expected = 212; 337 $self->assert($expected == $resp_code, 338 test_msg("Expected response code $expected, got $resp_code")); 339 340 $expected = '^(\s+)?\S+\s+\d+\s+\S+\s+\S+\s+.*?\s+(\S+)$'; 341 $self->assert(qr/$expected/, $resp_msg, 342 test_msg("Expected response message '$expected', got '$resp_msg'")); 343 344 $expected = 14; 345 $self->assert($expected == $resp_nmsgs, 346 test_msg("Expected $expected response lines, got $resp_nmsgs")); 347 }; 348 if ($@) { 349 $ex = $@; 350 } 351 352 $wfh->print("done\n"); 353 $wfh->flush(); 354 355 } else { 356 eval { server_wait($setup->{config_file}, $rfh) }; 357 if ($@) { 358 warn($@); 359 exit 1; 360 } 361 362 exit 0; 363 } 364 365 # Stop server 366 server_stop($setup->{pid_file}); 367 $self->assert_child_ok($pid); 368 369 test_cleanup($setup->{log_file}, $ex); 370} 371 372sub stat_symlink_showsymlinks_off { 373 my $self = shift; 374 my $tmpdir = $self->{tmpdir}; 375 my $setup = test_setup($tmpdir, 'cmds'); 376 377 my $test_dir = File::Spec->rel2abs("$tmpdir/test.d"); 378 mkpath($test_dir); 379 380 my $test_file = File::Spec->rel2abs("$test_dir/test.txt"); 381 if (open(my $fh, "> $test_file")) { 382 unless (close($fh)) { 383 die("Can't write $test_file: $!"); 384 } 385 386 } else { 387 die("Can't open $test_file: $!"); 388 } 389 390 # Change to the test directory in order to create a relative path in the 391 # symlink we need 392 393 my $cwd = getcwd(); 394 unless (chdir($test_dir)) { 395 die("Can't chdir to $test_dir: $!"); 396 } 397 398 unless (symlink('./test.txt', './test.lnk')) { 399 die("Can't symlink 'test.lnk' to './test.txt': $!"); 400 } 401 402 unless (chdir($cwd)) { 403 die("Can't chdir to $cwd: $!"); 404 } 405 406 if ($< == 0) { 407 unless (chmod(0755, $test_dir)) { 408 die("Can't set perms on $test_dir to 0755: $!"); 409 } 410 411 unless (chown($setup->{uid}, $setup->{gid}, $test_dir)) { 412 die("Can't set owner of $test_dir to $setup->{uid}/$setup->{gid}: $!"); 413 } 414 } 415 416 my $config = { 417 PidFile => $setup->{pid_file}, 418 ScoreboardFile => $setup->{scoreboard_file}, 419 SystemLog => $setup->{log_file}, 420 421 AuthUserFile => $setup->{auth_user_file}, 422 AuthGroupFile => $setup->{auth_group_file}, 423 424 ShowSymlinks => 'off', 425 426 IfModules => { 427 'mod_delay.c' => { 428 DelayEngine => 'off', 429 }, 430 }, 431 }; 432 433 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 434 $config); 435 436 # Open pipes, for use between the parent and child processes. Specifically, 437 # the child will indicate when it's done with its test by writing a message 438 # to the parent. 439 my ($rfh, $wfh); 440 unless (pipe($rfh, $wfh)) { 441 die("Can't open pipe: $!"); 442 } 443 444 my $ex; 445 446 # Fork child 447 $self->handle_sigchld(); 448 defined(my $pid = fork()) or die("Can't fork: $!"); 449 if ($pid) { 450 eval { 451 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 452 $client->login($setup->{user}, $setup->{passwd}); 453 $client->stat('test.d/test.lnk'); 454 455 my $resp_code = $client->response_code(); 456 my $resp_msgs = $client->response_msgs(); 457 my $resp_msg = $resp_msgs->[1]; 458 $client->quit(); 459 460 if ($ENV{TEST_VERBOSE}) { 461 use Data::Dumper; 462 print STDERR "# Response:\n", Dumper($resp_msgs), "\n"; 463 } 464 465 my $expected = 213; 466 $self->assert($expected == $resp_code, 467 test_msg("Expected response code $expected, got $resp_code")); 468 469 $expected = '^(\s+)?\-\S+\s+\d+\s+\S+\s+\S+\s+.*?\s+(\S+)$'; 470 $self->assert(qr/$expected/, $resp_msg, 471 test_msg("Expected response message '$expected', got '$resp_msg'")); 472 }; 473 if ($@) { 474 $ex = $@; 475 } 476 477 $wfh->print("done\n"); 478 $wfh->flush(); 479 480 } else { 481 eval { server_wait($setup->{config_file}, $rfh) }; 482 if ($@) { 483 warn($@); 484 exit 1; 485 } 486 487 exit 0; 488 } 489 490 # Stop server 491 server_stop($setup->{pid_file}); 492 $self->assert_child_ok($pid); 493 494 test_cleanup($setup->{log_file}, $ex); 495} 496 497sub stat_symlink_showsymlinks_on { 498 my $self = shift; 499 my $tmpdir = $self->{tmpdir}; 500 my $setup = test_setup($tmpdir, 'cmds'); 501 502 my $test_dir = File::Spec->rel2abs("$tmpdir/test.d"); 503 mkpath($test_dir); 504 505 my $test_file = File::Spec->rel2abs("$test_dir/test.txt"); 506 if (open(my $fh, "> $test_file")) { 507 unless (close($fh)) { 508 die("Can't write $test_file: $!"); 509 } 510 511 } else { 512 die("Can't open $test_file: $!"); 513 } 514 515 # Change to the test directory in order to create a relative path in the 516 # symlink we need 517 518 my $cwd = getcwd(); 519 unless (chdir($test_dir)) { 520 die("Can't chdir to $test_dir: $!"); 521 } 522 523 unless (symlink('./test.txt', './test.lnk')) { 524 die("Can't symlink 'test.lnk' to './test.txt': $!"); 525 } 526 527 unless (chdir($cwd)) { 528 die("Can't chdir to $cwd: $!"); 529 } 530 531 if ($< == 0) { 532 unless (chmod(0755, $test_dir)) { 533 die("Can't set perms on $test_dir to 0755: $!"); 534 } 535 536 unless (chown($setup->{uid}, $setup->{gid}, $test_dir)) { 537 die("Can't set owner of $test_dir to $setup->{uid}/$setup->{gid}: $!"); 538 } 539 } 540 541 my $config = { 542 PidFile => $setup->{pid_file}, 543 ScoreboardFile => $setup->{scoreboard_file}, 544 SystemLog => $setup->{log_file}, 545 546 AuthUserFile => $setup->{auth_user_file}, 547 AuthGroupFile => $setup->{auth_group_file}, 548 549 ShowSymlinks => 'on', 550 551 IfModules => { 552 'mod_delay.c' => { 553 DelayEngine => 'off', 554 }, 555 }, 556 }; 557 558 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 559 $config); 560 561 # Open pipes, for use between the parent and child processes. Specifically, 562 # the child will indicate when it's done with its test by writing a message 563 # to the parent. 564 my ($rfh, $wfh); 565 unless (pipe($rfh, $wfh)) { 566 die("Can't open pipe: $!"); 567 } 568 569 my $ex; 570 571 # Fork child 572 $self->handle_sigchld(); 573 defined(my $pid = fork()) or die("Can't fork: $!"); 574 if ($pid) { 575 eval { 576 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 577 $client->login($setup->{user}, $setup->{passwd}); 578 $client->stat('test.d/test.lnk'); 579 580 my $resp_code = $client->response_code(); 581 my $resp_msgs = $client->response_msgs(); 582 my $resp_msg = $resp_msgs->[1]; 583 $client->quit(); 584 585 if ($ENV{TEST_VERBOSE}) { 586 use Data::Dumper; 587 print STDERR "# Response:\n", Dumper($resp_msgs), "\n"; 588 } 589 590 my $expected = 213; 591 $self->assert($expected == $resp_code, 592 test_msg("Expected response code $expected, got $resp_code")); 593 594 $expected = '^(\s+)?l\S+\s+\d+\s+\S+\s+\S+\s+.*?\s+(\S+)$'; 595 $self->assert(qr/$expected/, $resp_msg, 596 test_msg("Expected response message '$expected', got '$resp_msg'")); 597 598 $expected = '.*?test\.d\/test\.lnk \-> test\.d\/test\.txt$'; 599 $self->assert(qr/$expected/, $resp_msg, 600 test_msg("Expected response message '$expected', got '$resp_msg'")); 601 }; 602 if ($@) { 603 $ex = $@; 604 } 605 606 $wfh->print("done\n"); 607 $wfh->flush(); 608 609 } else { 610 eval { server_wait($setup->{config_file}, $rfh) }; 611 if ($@) { 612 warn($@); 613 exit 1; 614 } 615 616 exit 0; 617 } 618 619 # Stop server 620 server_stop($setup->{pid_file}); 621 $self->assert_child_ok($pid); 622 623 test_cleanup($setup->{log_file}, $ex); 624} 625 626sub stat_symlink_showsymlinks_off_chrooted_bug4219 { 627 my $self = shift; 628 my $tmpdir = $self->{tmpdir}; 629 my $setup = test_setup($tmpdir, 'cmds'); 630 631 my $test_dir = File::Spec->rel2abs("$tmpdir/test.d"); 632 mkpath($test_dir); 633 634 my $test_file = File::Spec->rel2abs("$test_dir/test.txt"); 635 if (open(my $fh, "> $test_file")) { 636 unless (close($fh)) { 637 die("Can't write $test_file: $!"); 638 } 639 640 } else { 641 die("Can't open $test_file: $!"); 642 } 643 644 # Change to the test directory in order to create a relative path in the 645 # symlink we need 646 647 my $cwd = getcwd(); 648 unless (chdir($test_dir)) { 649 die("Can't chdir to $test_dir: $!"); 650 } 651 652 unless (symlink('./test.txt', './test.lnk')) { 653 die("Can't symlink 'test.lnk' to './test.txt': $!"); 654 } 655 656 unless (chdir($cwd)) { 657 die("Can't chdir to $cwd: $!"); 658 } 659 660 if ($< == 0) { 661 unless (chmod(0755, $test_dir)) { 662 die("Can't set perms on $test_dir to 0755: $!"); 663 } 664 665 unless (chown($setup->{uid}, $setup->{gid}, $test_dir)) { 666 die("Can't set owner of $test_dir to $setup->{uid}/$setup->{gid}: $!"); 667 } 668 } 669 670 my $config = { 671 PidFile => $setup->{pid_file}, 672 ScoreboardFile => $setup->{scoreboard_file}, 673 SystemLog => $setup->{log_file}, 674 675 AuthUserFile => $setup->{auth_user_file}, 676 AuthGroupFile => $setup->{auth_group_file}, 677 678 DefaultRoot => '~', 679 ShowSymlinks => 'off', 680 681 IfModules => { 682 'mod_delay.c' => { 683 DelayEngine => 'off', 684 }, 685 }, 686 }; 687 688 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 689 $config); 690 691 # Open pipes, for use between the parent and child processes. Specifically, 692 # the child will indicate when it's done with its test by writing a message 693 # to the parent. 694 my ($rfh, $wfh); 695 unless (pipe($rfh, $wfh)) { 696 die("Can't open pipe: $!"); 697 } 698 699 my $ex; 700 701 # Fork child 702 $self->handle_sigchld(); 703 defined(my $pid = fork()) or die("Can't fork: $!"); 704 if ($pid) { 705 eval { 706 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 707 $client->login($setup->{user}, $setup->{passwd}); 708 $client->stat('test.d/test.lnk'); 709 710 my $resp_code = $client->response_code(); 711 my $resp_msgs = $client->response_msgs(); 712 my $resp_msg = $resp_msgs->[1]; 713 $client->quit(); 714 715 if ($ENV{TEST_VERBOSE}) { 716 use Data::Dumper; 717 print STDERR "# Response:\n", Dumper($resp_msgs), "\n"; 718 } 719 720 my $expected = 213; 721 $self->assert($expected == $resp_code, 722 test_msg("Expected response code $expected, got $resp_code")); 723 724 $expected = '^(\s+)?\-\S+\s+\d+\s+\S+\s+\S+\s+.*?\s+(\S+)$'; 725 $self->assert(qr/$expected/, $resp_msg, 726 test_msg("Expected response message '$expected', got '$resp_msg'")); 727 }; 728 if ($@) { 729 $ex = $@; 730 } 731 732 $wfh->print("done\n"); 733 $wfh->flush(); 734 735 } else { 736 eval { server_wait($setup->{config_file}, $rfh) }; 737 if ($@) { 738 warn($@); 739 exit 1; 740 } 741 742 exit 0; 743 } 744 745 # Stop server 746 server_stop($setup->{pid_file}); 747 $self->assert_child_ok($pid); 748 749 test_cleanup($setup->{log_file}, $ex); 750} 751 752sub stat_symlink_showsymlinks_on_chrooted_bug4219 { 753 my $self = shift; 754 my $tmpdir = $self->{tmpdir}; 755 my $setup = test_setup($tmpdir, 'cmds'); 756 757 my $test_dir = File::Spec->rel2abs("$tmpdir/test.d"); 758 mkpath($test_dir); 759 760 my $test_file = File::Spec->rel2abs("$test_dir/test.txt"); 761 if (open(my $fh, "> $test_file")) { 762 unless (close($fh)) { 763 die("Can't write $test_file: $!"); 764 } 765 766 } else { 767 die("Can't open $test_file: $!"); 768 } 769 770 # Change to the test directory in order to create a relative path in the 771 # symlink we need 772 773 my $cwd = getcwd(); 774 unless (chdir($test_dir)) { 775 die("Can't chdir to $test_dir: $!"); 776 } 777 778 unless (symlink('./test.txt', './test.lnk')) { 779 die("Can't symlink 'test.lnk' to './test.txt': $!"); 780 } 781 782 unless (chdir($cwd)) { 783 die("Can't chdir to $cwd: $!"); 784 } 785 786 if ($< == 0) { 787 unless (chmod(0755, $test_dir)) { 788 die("Can't set perms on $test_dir to 0755: $!"); 789 } 790 791 unless (chown($setup->{uid}, $setup->{gid}, $test_dir)) { 792 die("Can't set owner of $test_dir to $setup->{uid}/$setup->{gid}: $!"); 793 } 794 } 795 796 my $config = { 797 PidFile => $setup->{pid_file}, 798 ScoreboardFile => $setup->{scoreboard_file}, 799 SystemLog => $setup->{log_file}, 800 801 AuthUserFile => $setup->{auth_user_file}, 802 AuthGroupFile => $setup->{auth_group_file}, 803 804 DefaultRoot => '~', 805 ShowSymlinks => 'on', 806 807 IfModules => { 808 'mod_delay.c' => { 809 DelayEngine => 'off', 810 }, 811 }, 812 }; 813 814 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 815 $config); 816 817 # Open pipes, for use between the parent and child processes. Specifically, 818 # the child will indicate when it's done with its test by writing a message 819 # to the parent. 820 my ($rfh, $wfh); 821 unless (pipe($rfh, $wfh)) { 822 die("Can't open pipe: $!"); 823 } 824 825 my $ex; 826 827 # Fork child 828 $self->handle_sigchld(); 829 defined(my $pid = fork()) or die("Can't fork: $!"); 830 if ($pid) { 831 eval { 832 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 833 $client->login($setup->{user}, $setup->{passwd}); 834 $client->stat('test.d/test.lnk'); 835 836 my $resp_code = $client->response_code(); 837 my $resp_msgs = $client->response_msgs(); 838 my $resp_msg = $resp_msgs->[1]; 839 $client->quit(); 840 841 if ($ENV{TEST_VERBOSE}) { 842 use Data::Dumper; 843 print STDERR "# Response:\n", Dumper($resp_msgs), "\n"; 844 } 845 846 my $expected = 213; 847 $self->assert($expected == $resp_code, 848 test_msg("Expected response code $expected, got $resp_code")); 849 850 $expected = '^(\s+)?l\S+\s+\d+\s+\S+\s+\S+\s+.*?\s+(\S+)$'; 851 $self->assert(qr/$expected/, $resp_msg, 852 test_msg("Expected response message '$expected', got '$resp_msg'")); 853 854 $expected = '.*?test\.d\/test\.lnk \-> \/test\.d\/test\.txt$'; 855 $self->assert(qr/$expected/, $resp_msg, 856 test_msg("Expected response message '$expected', got '$resp_msg'")); 857 }; 858 if ($@) { 859 $ex = $@; 860 } 861 862 $wfh->print("done\n"); 863 $wfh->flush(); 864 865 } else { 866 eval { server_wait($setup->{config_file}, $rfh) }; 867 if ($@) { 868 warn($@); 869 exit 1; 870 } 871 872 exit 0; 873 } 874 875 # Stop server 876 server_stop($setup->{pid_file}); 877 $self->assert_child_ok($pid); 878 879 test_cleanup($setup->{log_file}, $ex); 880} 881 882sub stat_system { 883 my $self = shift; 884 my $tmpdir = $self->{tmpdir}; 885 my $setup = test_setup($tmpdir, 'cmds'); 886 887 my $config = { 888 PidFile => $setup->{pid_file}, 889 ScoreboardFile => $setup->{scoreboard_file}, 890 SystemLog => $setup->{log_file}, 891 892 AuthUserFile => $setup->{auth_user_file}, 893 AuthGroupFile => $setup->{auth_group_file}, 894 895 IfModules => { 896 'mod_delay.c' => { 897 DelayEngine => 'off', 898 }, 899 }, 900 }; 901 902 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 903 $config); 904 905 # Open pipes, for use between the parent and child processes. Specifically, 906 # the child will indicate when it's done with its test by writing a message 907 # to the parent. 908 my ($rfh, $wfh); 909 unless (pipe($rfh, $wfh)) { 910 die("Can't open pipe: $!"); 911 } 912 913 my $ex; 914 915 # Fork child 916 $self->handle_sigchld(); 917 defined(my $pid = fork()) or die("Can't fork: $!"); 918 if ($pid) { 919 eval { 920 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 921 $client->login($setup->{user}, $setup->{passwd}); 922 $client->stat(); 923 924 my $resp_code = $client->response_code(); 925 my $resp_msgs = $client->response_msgs(); 926 $client->quit(); 927 928 my $expected = 211; 929 $self->assert($expected == $resp_code, 930 test_msg("Expected response code $expected, got $resp_code")); 931 }; 932 if ($@) { 933 $ex = $@; 934 } 935 936 $wfh->print("done\n"); 937 $wfh->flush(); 938 939 } else { 940 eval { server_wait($setup->{config_file}, $rfh) }; 941 if ($@) { 942 warn($@); 943 exit 1; 944 } 945 946 exit 0; 947 } 948 949 # Stop server 950 server_stop($setup->{pid_file}); 951 $self->assert_child_ok($pid); 952 953 test_cleanup($setup->{log_file}, $ex); 954} 955 956sub stat_enoent { 957 my $self = shift; 958 my $tmpdir = $self->{tmpdir}; 959 my $setup = test_setup($tmpdir, 'cmds'); 960 961 my $config = { 962 PidFile => $setup->{pid_file}, 963 ScoreboardFile => $setup->{scoreboard_file}, 964 SystemLog => $setup->{log_file}, 965 966 AuthUserFile => $setup->{auth_user_file}, 967 AuthGroupFile => $setup->{auth_group_file}, 968 969 IfModules => { 970 'mod_delay.c' => { 971 DelayEngine => 'off', 972 }, 973 }, 974 }; 975 976 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 977 $config); 978 979 # Open pipes, for use between the parent and child processes. Specifically, 980 # the child will indicate when it's done with its test by writing a message 981 # to the parent. 982 my ($rfh, $wfh); 983 unless (pipe($rfh, $wfh)) { 984 die("Can't open pipe: $!"); 985 } 986 987 my $ex; 988 989 # Fork child 990 $self->handle_sigchld(); 991 defined(my $pid = fork()) or die("Can't fork: $!"); 992 if ($pid) { 993 eval { 994 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 995 $client->login($setup->{user}, $setup->{passwd}); 996 997 my $enoent_file = 'foo.bar.baz.d'; 998 999 eval { $client->stat($enoent_file) }; 1000 unless ($@) { 1001 die("STAT succeeded unexpectedly"); 1002 } 1003 1004 my $resp_code = $client->response_code(); 1005 my $resp_msg = $client->response_msg(); 1006 $client->quit(); 1007 1008 my $expected = 450; 1009 $self->assert($expected == $resp_code, 1010 test_msg("Expected response code $expected, got $resp_code")); 1011 1012 $expected = "$enoent_file: No such file or directory"; 1013 $self->assert($expected eq $resp_msg, 1014 test_msg("Expected response message '$expected', got '$resp_msg'")); 1015 }; 1016 if ($@) { 1017 $ex = $@; 1018 } 1019 1020 $wfh->print("done\n"); 1021 $wfh->flush(); 1022 1023 } else { 1024 eval { server_wait($setup->{config_file}, $rfh) }; 1025 if ($@) { 1026 warn($@); 1027 exit 1; 1028 } 1029 1030 exit 0; 1031 } 1032 1033 # Stop server 1034 server_stop($setup->{pid_file}); 1035 $self->assert_child_ok($pid); 1036 1037 test_cleanup($setup->{log_file}, $ex); 1038} 1039 1040sub stat_listoptions_bug3295 { 1041 my $self = shift; 1042 my $tmpdir = $self->{tmpdir}; 1043 my $setup = test_setup($tmpdir, 'cmds'); 1044 1045 my $config = { 1046 PidFile => $setup->{pid_file}, 1047 ScoreboardFile => $setup->{scoreboard_file}, 1048 SystemLog => $setup->{log_file}, 1049 1050 AuthUserFile => $setup->{auth_user_file}, 1051 AuthGroupFile => $setup->{auth_group_file}, 1052 1053 ListOptions => '-1', 1054 1055 IfModules => { 1056 'mod_delay.c' => { 1057 DelayEngine => 'off', 1058 }, 1059 }, 1060 }; 1061 1062 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 1063 $config); 1064 1065 # Open pipes, for use between the parent and child processes. Specifically, 1066 # the child will indicate when it's done with its test by writing a message 1067 # to the parent. 1068 my ($rfh, $wfh); 1069 unless (pipe($rfh, $wfh)) { 1070 die("Can't open pipe: $!"); 1071 } 1072 1073 my $ex; 1074 1075 # Fork child 1076 $self->handle_sigchld(); 1077 defined(my $pid = fork()) or die("Can't fork: $!"); 1078 if ($pid) { 1079 eval { 1080 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 1081 $client->login($setup->{user}, $setup->{passwd}); 1082 1083 my ($resp_code, $resp_msg) = $client->stat('cmds.conf'); 1084 $client->quit(); 1085 1086 my $expected = 213; 1087 $self->assert($expected == $resp_code, 1088 test_msg("Expected response code $expected, got $resp_code")); 1089 1090 $expected = '^(\s+)?\S+\s+\d+\s+\S+\s+\S+\s+.*?\s+(\S+)$'; 1091 $self->assert(qr/$expected/, $resp_msg, 1092 test_msg("Expected response message '$expected', got '$resp_msg'")); 1093 }; 1094 if ($@) { 1095 $ex = $@; 1096 } 1097 1098 $wfh->print("done\n"); 1099 $wfh->flush(); 1100 1101 } else { 1102 eval { server_wait($setup->{config_file}, $rfh) }; 1103 if ($@) { 1104 warn($@); 1105 exit 1; 1106 } 1107 1108 exit 0; 1109 } 1110 1111 # Stop server 1112 server_stop($setup->{pid_file}); 1113 $self->assert_child_ok($pid); 1114 1115 test_cleanup($setup->{log_file}, $ex); 1116} 1117 11181; 1119