3 # This file is part of Stem.
4 # Copyright (C) 1999, 2000, 2001 Stem Systems, Inc.
6 # Stem is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # Stem is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with Stem; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 # For a license to use the Stem under conditions other than those
21 # described here, to purchase support for this software, or to purchase a
22 # commercial warranty contract, please contact Stem Systems at:
24 # Stem Systems, Inc. 781-643-7504
25 # 79 Everett St. info@stemsystems.com
40 This is the name under which this Cell was registered.
44 'name' => 'boot_file',
47 This is the file that describes the processes to bootstrap
53 Name of this boot entry
59 Path to command that will be booted
65 Default Name of logical log to send all status and process output
71 Default delay (in seconds) between spawning processes
77 Default user id to run the processes
82 'default' => '/bin/sh -c',
84 Default command wrapper for each process
90 Default dir to chdir to before running each process
98 Boot this program when this object is created
104 Restart this program when it exits
114 my( $class ) = shift ;
116 my $self = Stem::Class::parse_args( $attr_spec, @_ ) ;
117 return $self unless ref $self ;
119 my $boot_info = Stem::Util::load_file( $self->{'boot_file'} ) ;
120 return $boot_info unless ref $boot_info ;
122 foreach my $boot ( @{$boot_info} ) {
124 die "boot entry is not a hash\n" unless ref $boot eq 'HASH' ;
126 if ( my $skip = $boot->{'skip'} ) {
128 next if lc $skip eq 'yes' ;
131 my $boot_obj = Stem::Class::parse_args( $attr_spec,
136 die "boot entry error: $boot_obj\n" unless ref $boot_obj ;
138 my $cmd = $boot_obj->{'cmd'} ;
139 die "boot entry is missing 'cmd'\n" unless $cmd ;
141 my $name = $boot_obj->{'name'} ;
142 die "boot entry is missing 'name'\n" unless $name ;
144 $name2boot{ $name } = $boot_obj ;
146 if ( $boot_obj->{'boot_now'} ) {
148 $boot_obj->run_cmd() ;
164 if ( my $user = $self->{'user'} ) {
166 if ( getpwuid($<) ne $user ) {
168 $cmd .= "su - $user ; " ;
172 if ( my $wrap = $self->{'wrap'} ) {
174 $cmd .= qq{$wrap "} ;
175 $self->{'wrap_end'} ||= '"' ;
178 if ( my $chdir = $self->{'chdir'} ) {
180 $cmd .= "cd $chdir ; " ;
183 if ( my $stem_env = $self->{'stem_env'} ) {
185 my $cmd_env = join ' ', map(
186 "$_='$stem_env->{$_}'", keys %{$stem_env} ) ;
188 $cmd =~ s/run_stem/run_stem $cmd_env/ ;
191 $cmd .= $self->{'cmd'} ;
193 $cmd .= $self->{'wrap_end'} if $self->{'wrap_end'} ;
195 my $handle = gensym ;
199 if ( my $pid = open( $handle, '-|' ) ) {
201 #print "pid $pid\n" ;
202 $self->{'pid'} = $pid ;
203 $self->{'handle'} = $handle ;
205 elsif ( defined( $pid ) ) {
207 local( %ENV ) = ( %ENV, %{ $self->{'env'} || {} } ) ;
209 open( STDERR, '>&STDOUT' ) ;
212 die "Couldn't exec [$cmd]\n" ;
216 die "couldn't fork\n" ;
219 my $aio = Stem::AsyncIO->new(
222 'read_fh' => $handle,
223 'read_method' => 'boot_read',
224 'closed_method' => 'boot_closed',
227 $self->{'aio'} = $aio ;
229 if ( my $log = $self->{'log'} ) {
231 Stem::Log::Entry->new(
235 "Booting $self->{'name'} PID = $self->{'pid'}: $cmd\n",
244 my( $self, $data ) = @_ ;
246 #print "BOOT READ [$$data]\n" ;
248 if ( my $log = $self->{'log'} ) {
250 Stem::Log::Entry->new(
253 'text' => "Output for $self->{'name'}\n[${$data}]\n",
264 #print "BOOT closed\n" ;
266 $self->{'aio'}->shut_down() ;
267 delete $self->{'aio'} ;
269 my $boot_pid = $self->{'pid'} ;
270 my $pid = waitpid( $boot_pid, 0 ) ;
272 #print "WAIT [$pid]\n" ;
274 if ( my $log = $self->{'log'} ) {
276 Stem::Log::Entry->new(
279 'text' => "Boot $self->{'name'} exited PID = $pid",
283 # do restart if needed