Spectrum-CLI
view release on metacpan or search on metacpan
$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 )