Spectrum-CLI

 view release on metacpan or  search on metacpan

CLI.pm  view on Meta::CPAN

            $self->{vnm} = shift
	 }
      }
   }
   if ('' eq $self->{dir}) {
      if ($ENV{SPEC_ROOT}) {
         $self->{dir} = "$ENV{SPEC_ROOT}/vnmsh"
      } elsif ($ENV{SPECROOT}) {
         $self->{dir} = "$ENV{SPECROOT}/vnmsh"
      }
   }

   if ('' eq $self->{dir}) {
      warn "must set SPEC_ROOT/SPECROOT environment variable or pass full path to vnmsh directory to \"new\" method!\n" if $self->{verbose};
      return undef
   }

   if ('' eq $ENV{VNMSHRCPATH} && -f "$self->{dir}/.vnmshrc") {
      $ENV{VNMSHRCPATH} = "$self->{dir}/.vnmshrc"
   }

   # discover which vnmsh commands are available:
   my $entry;
   my $dir = $self->{dir}; # kludge since perl doesn't like this in a glob
   foreach $entry (<$dir/*>) {
      my $cmd =  basename $entry; 
      $cmd    =~ s/.exe$//;
      if ($cmd =~ m;VnmShd$;) {
	 $daemon = $entry;
      }
      next if $cmd =~ m;(Vnm|stop)Shd$;; # skip these executables
      push(@{$self->{command}}, $cmd) if (-f $entry && -x _)

   }
   warn "valid vnmsh commands: @{$self->{command}}\n" if $self->{Verbose};

   # We don't want the vnmsh/connect command to launch VnmShd for us...
   # This is because (as of this writing - Spectrum 5.0r1) the vnmsh/connect
   # command not setting the close-on-exec flag before fork(2)ing/exec(2)ing
   # a VnmShd process.  This causes our perl read from pipe to hang (since
   # the other end of the pipe is still open for writing until VnmShd
   # terminates - ugh.)
   #
   # Unfortunately we now have a race condition here: If VnmShd shuts down
   # (e.g. is stopped intentionally) between when we start it and when we
   # run vnmsh/connect (which will restart VnmShd), we could hang
   # indefinitely in the read on the pipe from vnmsh/connect.
   # Then, when this new VnmShd terminates (e.g. is stopped intentionally)
   # read(2) will return with EOF, and we'll think we have a successful
   # connection - even though VnmShd is no longer running.
   # Ugh.
   #
   # All is not lost though - that would be an unlikely chain of events.
   # It should be able to be avoided by starting VnmShd "manually" before
   # any Spectrum::CLI scripts are run, and then shutting VnmShd down until
   # you know that no Spectrum::CLI scripts are running.
   #
   # This could all be fixed by fcntl(fd, F_GETFD, 0) followed by
   # fcntl(fd, F_SETFD, FD_CLOEXEC | flags) in vnmsh/connect.
   #
   # In hindsight it probably wasn't such a good idea for Spectrum to have
   # vnmsh/connect launch VnmShd when its not already running.  This runs
   # counter to the Unix permissions mechanism since any old Spectrum user
   # could be running VnmShd and doing SSAPI I/O on behalf of other users.
   # (IMHO, VnmShd should be run by the Spectrum install user.)

   # { Check to see if VnmShd is running (and start it if it's not):

   # determine which port VnmShd is to use (by parsing the config file):
   {
      my $fh = new IO::File "<$ENV{VNMSHRCPATH}";
      if (!ref($fh)) {
         warn "open \"$ENV{VNMSHRCPATH}\", \"r\": $!\n" if $self->{verbose}
      } else {
         while (<$fh>) {
            next if (m/^\s*#/); # skip comments
            if (m/\s*vsh_tcp_port\s*=\s*(0x([0-9a-f]+)|(\d+))/i) {
	       $self->{port} = $2? hex($2) : $3
            }
         }
      }
      undef $fh;
   }

   my $s = new IO::Socket::INET (Proto => 'tcp',
				 PeerAddr =>
				    ($self->{localhostname}?
				       $self->{localhostname} : hostname),
				 PeerPort =>
				    ($self->{port}? $self->{port}: 7777));
   if (!ref($s)) {
      warn "no VnmShd (yet)...\n" if $self->{Verbose};
      # start VnmShd
      if ('' eq $daemon) {
         warn("$self->{dir}/VnmShd not found!\n") if $self->{verbose};
         return undef
      }
      my @command = ($daemon);
      # FIXME stat(2)/access(2) VnmShd
      warn "fork, exec @command...\n" if $self->{Verbose};
      my $pid = fork();
      die "fork: $!\n" if (-1 == $pid);
      if (0 == $pid) { # child
	 # dissociate child from parent
	 setsid() or die "setsid: $!\n";
	 # Hmm... perhaps I should daemonize properly by chdir(2)ing,
	 # and association STDIN, STDOUT, and STDERR with "/dev/null".
	 # For the time being I'd like to see error messages (if any), so 
	 # we'll leave it alone.  Besides this is no sloppier than how
	 # vnmsh/connect leaves things (when it launches VnmShd).
	 exec @command;
	 die "exec \"@command\": $!\n"
      } else { # parent
         warn "waiting a bit...\n" if $self->{Verbose};
	 sleep($self->{timeout}? $self->{timeout} : 5)
      }
   }
   undef $s;

   # }



( run in 0.915 second using v1.01-cache-2.11-cpan-71847e10f99 )