selftest: Add common fork_and_exec() function
authorTim Beale <timbeale@catalyst.net.nz>
Thu, 23 May 2019 04:35:07 +0000 (16:35 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 24 May 2019 03:19:17 +0000 (03:19 +0000)
Now the code has been refactored, we can move it into a common function.
This reduces code duplication and means we have a common place where we
start samba daemons from.

Note that some daemons behave slightly different, but the $daemon_ctx
allows us to customize their behaviour a bit.

Signed-off-by: Tim Beale <timbeale@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
selftest/target/Samba.pm
selftest/target/Samba3.pm
selftest/target/Samba4.pm

index 5a359fe6970d22593835009526d54096ef4ee6d0..6fd8d01da06358da70dea5f4049ad0daccc33a6a 100644 (file)
@@ -620,6 +620,66 @@ sub get_env_for_process
        return $proc_envs;
 }
 
+sub fork_and_exec
+{
+       my ($self, $env_vars, $daemon_ctx, $STDIN_READER) = @_;
+
+       unlink($daemon_ctx->{LOG_FILE});
+       print "STARTING $daemon_ctx->{NAME} for $ENV{ENVNAME}...";
+
+       my $pid = fork();
+
+       # exec the daemon in the child process
+       if ($pid == 0) {
+               # redirect the daemon's stdout/stderr to a log file
+               if (defined($daemon_ctx->{TEE_STDOUT})) {
+                       # in some cases, we want out from samba to go to the log file,
+                       # but also to the users terminal when running 'make test' on the
+                       # command line. This puts it on stderr on the terminal
+                       open STDOUT, "| tee $daemon_ctx->{LOG_FILE} 1>&2";
+               } else {
+                       open STDOUT, ">$daemon_ctx->{LOG_FILE}";
+               }
+               open STDERR, '>&STDOUT';
+
+               SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
+               if (defined($daemon_ctx->{PCAP_FILE})) {
+                       SocketWrapper::setup_pcap($daemon_ctx->{PCAP_FILE});
+               }
+
+               # setup ENV variables in the child process
+               set_env_for_process($daemon_ctx->{NAME}, $env_vars,
+                                   $daemon_ctx->{ENV_VARS});
+
+               # not all s3 daemons run in all testenvs (e.g. fileserver doesn't
+               # run winbindd). In which case, the child process just sleeps
+               if (defined($daemon_ctx->{SKIP_DAEMON})) {
+                       $SIG{USR1} = $SIG{ALRM} = $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub {
+                               my $signame = shift;
+                               print("Skip $daemon_ctx->{NAME} received signal $signame");
+                               exit 0;
+                       };
+                       sleep($self->{server_maxtime});
+                       exit 0;
+               }
+
+               $ENV{MAKE_TEST_BINARY} = $daemon_ctx->{BINARY_PATH};
+
+               # we close the child's write-end of the pipe and redirect the read-end
+               # to its stdin. That way the daemon will receive an EOF on stdin when
+               # parent selftest process closes its write-end.
+               close($env_vars->{STDIN_PIPE});
+               open STDIN, ">&", $STDIN_READER or die "can't dup STDIN_READER to STDIN: $!";
+
+               # the command args are stored as an array reference (because...Perl),
+               # so convert the reference back to an array
+               my @full_cmd = @{ $daemon_ctx->{FULL_CMD} };
+               exec(@full_cmd) or die("Unable to start $ENV{MAKE_TEST_BINARY}: $!");
+       }
+       print "DONE ($pid)\n";
+       return $pid;
+}
+
 my @exported_envvars = (
        # domain stuff
        "DOMAIN",
index d165588b325c7088cc664942dc483443250cfe6d..4abd5177cba21334cdb03727c090707b5db5d01f 100755 (executable)
@@ -1260,11 +1260,12 @@ sub make_bin_cmd
 
 sub check_or_start($$$$$) {
        my ($self, $env_vars, $nmbd, $winbindd, $smbd) = @_;
+       my $STDIN_READER;
 
        # use a pipe for stdin in the child processes. This allows
        # those processes to monitor the pipe for EOF to ensure they
        # exit when the test script exits
-       pipe(STDIN_READER, $env_vars->{STDIN_PIPE});
+       pipe($STDIN_READER, $env_vars->{STDIN_PIPE});
 
        my $binary = Samba::bindir_path($self, "nmbd");
        my @full_cmd = $self->make_bin_cmd($binary, $env_vars,
@@ -1273,6 +1274,8 @@ sub check_or_start($$$$$) {
        my $nmbd_envs = Samba::get_env_for_process("nmbd", $env_vars);
        delete $nmbd_envs->{RESOLV_WRAPPER_CONF};
        delete $nmbd_envs->{RESOLV_WRAPPER_HOSTS};
+
+       # fork and exec() nmbd in the child process
        my %daemon_ctx = (
                NAME => "nmbd",
                BINARY_PATH => $binary,
@@ -1283,39 +1286,10 @@ sub check_or_start($$$$$) {
        if ($nmbd ne "yes") {
                $daemon_ctx{SKIP_DAEMON} = 1;
        }
+       my $pid = Samba::fork_and_exec($self, $env_vars, \%daemon_ctx, $STDIN_READER);
 
-       unlink($daemon_ctx{LOG_FILE});
-       print "STARTING NMBD...";
-       my $pid = fork();
-       if ($pid == 0) {
-               open STDOUT, ">$daemon_ctx{LOG_FILE}";
-               open STDERR, '>&STDOUT';
-
-               SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
-
-               Samba::set_env_for_process($daemon_ctx{NAME}, $env_vars, $daemon_ctx{ENV_VARS});
-
-               if (defined($daemon_ctx{SKIP_DAEMON})) {
-                       $SIG{USR1} = $SIG{ALRM} = $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub {
-                               my $signame = shift;
-                               print("Skip $daemon_ctx{NAME} received signal $signame");
-                               exit 0;
-                       };
-                       sleep($self->{server_maxtime});
-                       exit 0;
-               }
-
-               $ENV{MAKE_TEST_BINARY} = $daemon_ctx{BINARY_PATH};
-
-               close($env_vars->{STDIN_PIPE});
-               open STDIN, ">&", \*STDIN_READER or die "can't dup STDIN_READER to STDIN: $!";
-
-               exec(@{ $daemon_ctx{FULL_CMD} })
-                       or die("Unable to start $ENV{MAKE_TEST_BINARY}: $!");
-       }
        $env_vars->{NMBD_TL_PID} = $pid;
        write_pid($env_vars, "nmbd", $pid);
-       print "DONE\n";
 
        $binary = Samba::bindir_path($self, "winbindd");
        @full_cmd = $self->make_bin_cmd($binary, $env_vars,
@@ -1324,6 +1298,8 @@ sub check_or_start($$$$$) {
        if (not defined($ENV{WINBINDD_DONT_LOG_STDOUT})) {
                push(@full_cmd, "--stdout");
        }
+
+       # fork and exec() winbindd in the child process
        %daemon_ctx = (
                NAME => "winbindd",
                BINARY_PATH => $binary,
@@ -1333,44 +1309,17 @@ sub check_or_start($$$$$) {
        if ($winbindd ne "yes") {
                $daemon_ctx{SKIP_DAEMON} = 1;
        }
+       my $pid = Samba::fork_and_exec($self, $env_vars, \%daemon_ctx, $STDIN_READER);
 
-       unlink($daemon_ctx{LOG_FILE});
-       print "STARTING WINBINDD...";
-       $pid = fork();
-       if ($pid == 0) {
-               open STDOUT, ">$daemon_ctx{LOG_FILE}";
-               open STDERR, '>&STDOUT';
-
-               SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
-
-               Samba::set_env_for_process($daemon_ctx{NAME}, $env_vars, $daemon_ctx{ENV_VARS});
-
-               if (defined($daemon_ctx{SKIP_DAEMON})) {
-                       $SIG{USR1} = $SIG{ALRM} = $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub {
-                               my $signame = shift;
-                               print("Skip $daemon_ctx{NAME} received signal $signame");
-                               exit 0;
-                       };
-                       sleep($self->{server_maxtime});
-                       exit 0;
-               }
-
-               $ENV{MAKE_TEST_BINARY} = $daemon_ctx{BINARY_PATH};
-
-               close($env_vars->{STDIN_PIPE});
-               open STDIN, ">&", \*STDIN_READER or die "can't dup STDIN_READER to STDIN: $!";
-
-               exec(@{ $daemon_ctx{FULL_CMD} })
-                       or die("Unable to start $ENV{MAKE_TEST_BINARY}: $!");
-       }
        $env_vars->{WINBINDD_TL_PID} = $pid;
        write_pid($env_vars, "winbindd", $pid);
-       print "DONE\n";
 
        $binary = Samba::bindir_path($self, "smbd");
        @full_cmd = $self->make_bin_cmd($binary, $env_vars,
                                         $ENV{SMBD_OPTIONS}, $ENV{SMBD_VALGRIND},
                                         $ENV{SMBD_DONT_LOG_STDOUT});
+
+       # fork and exec() smbd in the child process
        %daemon_ctx = (
                NAME => "smbd",
                BINARY_PATH => $binary,
@@ -1381,39 +1330,12 @@ sub check_or_start($$$$$) {
                $daemon_ctx{SKIP_DAEMON} = 1;
        }
 
-       unlink($daemon_ctx{LOG_FILE});
-       print "STARTING SMBD...";
-       $pid = fork();
-       if ($pid == 0) {
-               open STDOUT, ">$daemon_ctx{LOG_FILE}";
-               open STDERR, '>&STDOUT';
-
-               SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
+       my $pid = Samba::fork_and_exec($self, $env_vars, \%daemon_ctx, $STDIN_READER);
 
-               Samba::set_env_for_process($daemon_ctx{NAME}, $env_vars, $daemon_ctx{ENV_VARS});
-
-               if (defined($daemon_ctx{SKIP_DAEMON})) {
-                       $SIG{USR1} = $SIG{ALRM} = $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub {
-                               my $signame = shift;
-                               print("Skip $daemon_ctx{NAME} received signal $signame");
-                               exit 0;
-                       };
-                       sleep($self->{server_maxtime});
-                       exit 0;
-               }
-
-               $ENV{MAKE_TEST_BINARY} = $daemon_ctx{BINARY_PATH};
-
-               close($env_vars->{STDIN_PIPE});
-               open STDIN, ">&", \*STDIN_READER or die "can't dup STDIN_READER to STDIN: $!";
-
-               exec(@{ $daemon_ctx{FULL_CMD} })
-                       or die("Unable to start $ENV{MAKE_TEST_BINARY}: $!");
-       }
        $env_vars->{SMBD_TL_PID} = $pid;
        write_pid($env_vars, "smbd", $pid);
-       print "DONE\n";
 
+       # close the parent's read-end of the pipe
        close(STDIN_READER);
 
        return $self->wait_for_start($env_vars, $nmbd, $winbindd, $smbd);
index 883a8c8b585bb365e7eddf9033cf68d136ffeb01..0593a21c3538d18303f501f104719d0cb1716a86 100755 (executable)
@@ -141,6 +141,7 @@ sub check_or_start($$$)
                $samba_envs->{KRB5_KDC_PROFILE} = $env_vars->{MITKDC_CONFIG};
        }
 
+       # fork a child process and exec() samba
        my %daemon_ctx = (
                NAME => "samba",
                BINARY_PATH => $binary,
@@ -149,30 +150,11 @@ sub check_or_start($$$)
                TEE_STDOUT => 1,
                ENV_VARS => $samba_envs,
        );
+       my $pid = Samba::fork_and_exec($self, $env_vars, \%daemon_ctx, $STDIN_READER);
 
-       print "STARTING SAMBA...\n";
-       my $pid = fork();
-       if ($pid == 0) {
-               # we want out from samba to go to the log file, but also
-               # to the users terminal when running 'make test' on the command
-               # line. This puts it on stderr on the terminal
-               open STDOUT, "| tee $daemon_ctx{LOG_FILE} 1>&2";
-               open STDERR, '>&STDOUT';
-
-               SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
-
-               Samba::set_env_for_process($daemon_ctx{NAME}, $env_vars, $daemon_ctx{ENV_VARS});
-
-               $ENV{MAKE_TEST_BINARY} = $daemon_ctx{BINARY_PATH};
-
-               close($env_vars->{STDIN_PIPE});
-               open STDIN, ">&", $STDIN_READER or die "can't dup STDIN_READER to STDIN: $!";
-
-               exec(@{ $daemon_ctx{FULL_CMD} }) or die("Unable to start $daemon_ctx{BINARY_NAME}: $!");
-       }
        $env_vars->{SAMBA_PID} = $pid;
-       print "DONE ($pid)\n";
 
+       # close the parent's read-end of the pipe
        close($STDIN_READER);
 
        if ($self->wait_for_start($env_vars) != 0) {
@@ -415,6 +397,7 @@ sub setup_dns_hub_internal($$$)
        push (@args, "$env->{SERVER_IP}");
        push (@args, Samba::realm_to_ip_mappings());
        my @full_cmd = (@preargs, $binary, @args);
+
        my %daemon_ctx = (
                NAME => "dnshub",
                BINARY_PATH => $binary,
@@ -430,33 +413,14 @@ sub setup_dns_hub_internal($$$)
        # exit when the test script exits
        pipe($STDIN_READER, $env->{STDIN_PIPE});
 
-       print "STARTING rootdnsforwarder...\n";
-       my $pid = fork();
-       if ($pid == 0) {
-               # we want out from samba to go to the log file, but also
-               # to the users terminal when running 'make test' on the command
-               # line. This puts it on stderr on the terminal
-               open STDOUT, "| tee $daemon_ctx{LOG_FILE} 1>&2";
-               open STDERR, '>&STDOUT';
-
-               SocketWrapper::set_default_iface($env->{SOCKET_WRAPPER_DEFAULT_IFACE});
-               SocketWrapper::setup_pcap($daemon_ctx{PCAP_FILE});
-
-               Samba::set_env_for_process($daemon_ctx{NAME}, $env, $daemon_ctx{ENV_VARS});
+       my $pid = Samba::fork_and_exec($self, $env, \%daemon_ctx, $STDIN_READER);
 
-               $ENV{MAKE_TEST_BINARY} = $daemon_ctx{BINARY_PATH};
-
-               close($env->{STDIN_PIPE});
-               open STDIN, ">&", $STDIN_READER or die "can't dup STDIN_READER to STDIN: $!";
-
-               exec(@{ $daemon_ctx{FULL_CMD} })
-                       or die("Unable to start $daemon_ctx{NAME}: $!");
-       }
        $env->{SAMBA_PID} = $pid;
        $env->{KRB5_CONFIG} = "$prefix_abs/no_krb5.conf";
+
+       # close the parent's read-end of the pipe
        close($STDIN_READER);
 
-       print "DONE\n";
        return $env;
 }