Cleaned up demos, various build fixes
[urisagit/Stem.git] / lib / Stem / Boot.pm
CommitLineData
4536f655 1# File: Stem/Boot.pm
2
3# This file is part of Stem.
4# Copyright (C) 1999, 2000, 2001 Stem Systems, Inc.
5
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.
10
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.
15
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
19
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:
23
24# Stem Systems, Inc. 781-643-7504
25# 79 Everett St. info@stemsystems.com
26# Arlington, MA 02474
27# USA
28
29package Stem::Boot ;
30
31use strict ;
32use Carp ;
33use Symbol ;
34
35my $attr_spec = [
36
37 {
38 'name' => 'reg_name',
39 'help' => <<HELP,
40This is the name under which this Cell was registered.
41HELP
42 },
43 {
44 'name' => 'boot_file',
45 'required' => 1,
46 'help' => <<HELP,
47This is the file that describes the processes to bootstrap
48HELP
49 },
50 {
51 'name' => 'name',
52 'help' => <<HELP,
53Name of this boot entry
54HELP
55 },
56 {
57 'name' => 'cmd',
58 'help' => <<HELP,
59Path to command that will be booted
60HELP
61 },
62 {
63 'name' => 'log',
64 'help' => <<HELP,
65Default Name of logical log to send all status and process output
66HELP
67 },
68 {
69 'name' => 'delay',
70 'help' => <<HELP,
71Default delay (in seconds) between spawning processes
72HELP
73 },
74 {
75 'name' => 'user',
76 'help' => <<HELP,
77Default user id to run the processes
78HELP
79 },
80 {
81 'name' => 'wrap',
82 'default' => '/bin/sh -c',
83 'help' => <<HELP,
84Default command wrapper for each process
85HELP
86 },
87 {
88 'name' => 'chdir',
89 'help' => <<HELP,
90Default dir to chdir to before running each process
91HELP
92 },
93 {
94 'name' => 'boot_now',
95 'type' => 'boolean',
96 'default' => 1,
97 'help' => <<HELP,
98Boot this program when this object is created
99HELP
100 },
101 {
102 'name' => 'restart',
103 'help' => <<HELP,
104Restart this program when it exits
105HELP
106 },
107] ;
108
109my %name2boot ;
110
111
112sub new {
113
114 my( $class ) = shift ;
115
116 my $self = Stem::Class::parse_args( $attr_spec, @_ ) ;
117 return $self unless ref $self ;
118
119 my $boot_info = Stem::Util::load_file( $self->{'boot_file'} ) ;
120 return $boot_info unless ref $boot_info ;
121
122 foreach my $boot ( @{$boot_info} ) {
123
124 die "boot entry is not a hash\n" unless ref $boot eq 'HASH' ;
125
126 if ( my $skip = $boot->{'skip'} ) {
127
128 next if lc $skip eq 'yes' ;
129 }
130
131 my $boot_obj = Stem::Class::parse_args( $attr_spec,
132 %{$self},
133 %{$boot}
134 ) ;
135
136 die "boot entry error: $boot_obj\n" unless ref $boot_obj ;
137
138 my $cmd = $boot_obj->{'cmd'} ;
139 die "boot entry is missing 'cmd'\n" unless $cmd ;
140
141 my $name = $boot_obj->{'name'} ;
142 die "boot entry is missing 'name'\n" unless $name ;
143
144 $name2boot{ $name } = $boot_obj ;
145
146 if ( $boot_obj->{'boot_now'} ) {
147
148 $boot_obj->run_cmd() ;
149 }
150 }
151
152 return ;
153}
154
155
156sub run_cmd {
157
158 my( $self ) = @_ ;
159
160#print Store $self ;
161
162 my $cmd ;
163
164 if ( my $user = $self->{'user'} ) {
165
166 if ( getpwuid($<) ne $user ) {
167
168 $cmd .= "su - $user ; " ;
169 }
170 }
171
172 if ( my $wrap = $self->{'wrap'} ) {
173
174 $cmd .= qq{$wrap "} ;
175 $self->{'wrap_end'} ||= '"' ;
176 }
177
178 if ( my $chdir = $self->{'chdir'} ) {
179
180 $cmd .= "cd $chdir ; " ;
181 }
182
183 if ( my $stem_env = $self->{'stem_env'} ) {
184
185 my $cmd_env = join ' ', map(
186 "$_='$stem_env->{$_}'", keys %{$stem_env} ) ;
187
188 $cmd =~ s/run_stem/run_stem $cmd_env/ ;
189 }
190
191 $cmd .= $self->{'cmd'} ;
192
193 $cmd .= $self->{'wrap_end'} if $self->{'wrap_end'} ;
194
195 my $handle = gensym ;
196
197#print "$cmd\n" ;
198
199 if ( my $pid = open( $handle, '-|' ) ) {
200
201#print "pid $pid\n" ;
202 $self->{'pid'} = $pid ;
203 $self->{'handle'} = $handle ;
204 }
205 elsif ( defined( $pid ) ) {
206
207 local( %ENV ) = ( %ENV, %{ $self->{'env'} || {} } ) ;
208
209 open( STDERR, '>&STDOUT' ) ;
210
211 exec $cmd ;
212 die "Couldn't exec [$cmd]\n" ;
213 }
214 else {
215
216 die "couldn't fork\n" ;
217 }
218
219 my $aio = Stem::AsyncIO->new(
220
221 'object' => $self,
222 'read_fh' => $handle,
223 'read_method' => 'boot_read',
224 'closed_method' => 'boot_closed',
225 ) ;
226
227 $self->{'aio'} = $aio ;
228
229 if ( my $log = $self->{'log'} ) {
230
231 Stem::Log::Entry->new(
232 'logs' => $log,
233 'label' => 'boot',
234 'text' =>
235 "Booting $self->{'name'} PID = $self->{'pid'}: $cmd\n",
236 ) ;
237 }
238
239 return ;
240}
241
242sub boot_read {
243
244 my( $self, $data ) = @_ ;
245
246#print "BOOT READ [$$data]\n" ;
247
248 if ( my $log = $self->{'log'} ) {
249
250 Stem::Log::Entry->new(
251 'logs' => $log,
252 'label' => 'boot',
253 'text' => "Output for $self->{'name'}\n[${$data}]\n",
254 ) ;
255 }
256
257 return ;
258}
259
260sub boot_closed {
261
262 my( $self ) = @_ ;
263
264#print "BOOT closed\n" ;
265
266 $self->{'aio'}->shut_down() ;
267 delete $self->{'aio'} ;
268
269 my $boot_pid = $self->{'pid'} ;
270 my $pid = waitpid( $boot_pid, 0 ) ;
271
272#print "WAIT [$pid]\n" ;
273
274 if ( my $log = $self->{'log'} ) {
275
276 Stem::Log::Entry->new(
277 'logs' => $log,
278 'label' => 'boot',
279 'text' => "Boot $self->{'name'} exited PID = $pid",
280 ) ;
281 }
282
283# do restart if needed
284
285
286
287
288 return ;
289}
290
2911 ;