1 | 1 | simandl | #!/usr/bin/env perl |
2 | | | use strict; |
3 | | | use warnings; |
4 | | | use diagnostics; |
5 | | | |
6 | | | # |
7 | | | # $Id: rrdtimer.pl,v 1.3 2003/10/16 10:25:36 bernisys Exp $ |
8 | | | # |
9 | | | # use Getopt::Long; |
10 | | | use FindBin; |
11 | | | use lib "./lib"; |
12 | | | use lib $FindBin::RealBin; |
13 | | | use HotSaNICparser; |
14 | | | use subs qw(main_loop call_modules call_module_read daemonize); |
15 | | | |
16 | | | # let all outputs be flushed directly |
17 | | | $|=1; |
18 | | | |
19 | | | # set commandline correctly |
20 | | | $0="rrdtimer"; |
21 | | | |
22 | | | (my $CALLDIR=$FindBin::RealBin) =~ s/\/rrdtimer//g; |
23 | | | (my $VERSION = '$Revision: 1.3 $') =~ s/.*(\d+\.\d+).*/$1/; |
24 | | | (my $IDENTIFIER = '$Id: rrdtimer.pl,v 1.3 2003/10/16 10:25:36 bernisys Exp $') =~ s/.*,v (.*) \$/$1/; |
25 | | | |
26 | | | print "reading & checking config ($CALLDIR/settings) ...\n"; |
27 | | | my %CONFIG=HotSaNICparser::get_config($CALLDIR); |
28 | | | $CONFIG{MODULEDIR}=$CONFIG{DAEMONDIR}."/modules"; |
29 | | | $CONFIG{SCHEDULED}=1; |
30 | | | |
31 | | | print "evaluating cmdline arguments...\n"; |
32 | | | my ($debuglevel,$runmode)=check_for_args(@ARGV); |
33 | | | if ($debuglevel>$CONFIG{"DEBUGLEVEL"}) { $CONFIG{"DEBUGLEVEL"}=$debuglevel; } |
34 | | | |
35 | | | |
36 | | | if ($CONFIG{DEBUGLEVEL} >0) { foreach my $k (keys %CONFIG) { print "$k=$CONFIG{$k}\n"; }} |
37 | | | if ($runmode < 128) { exit 0; } |
38 | | | |
39 | | | my $PID=HotSaNICparser::get_pid($CONFIG{DEBUGLEVEL},$CONFIG{PIDFILE},"rrdtimer"); |
40 | | | if ( $PID>0 ) { |
41 | | | print "\nAnother process is running on PID $PID - daemon stopped.\n\n"; |
42 | | | exit 1; |
43 | | | } |
44 | | | |
45 | | | my $debug=""; |
46 | | | if (($runmode&1)>0) { print "Debug mode enabled!\nIdentifier: $IDENTIFIER,\nLogdir: ",$CONFIG{LOGDIR},"\nPIDfile: ",$CONFIG{PIDFILE},"\n\n"; $debug="d"; } |
47 | | | |
48 | | | my @PIDs; |
49 | | | my %PIDs; |
50 | | | |
51 | | | daemonize(); |
52 | | | |
53 | | | $SIG{TERM} = \&signalhandler; |
54 | | | $SIG{HUP} = \&signalhandler; |
55 | | | $SIG{USR1} = \&signalhandler; |
56 | | | $SIG{USR2} = \&signalhandler; |
57 | | | |
58 | | | main_loop(); |
59 | | | |
60 | | | |
61 | | | ###################################################################### |
62 | | | # # |
63 | | | # SUBROUTINES BEGIN HERE # |
64 | | | # # |
65 | | | ###################################################################### |
66 | | | |
67 | | | |
68 | | | ###################################################################### |
69 | | | # |
70 | | | # signal-handler |
71 | | | # TERM -> terminate daemon and modules |
72 | | | # HUP -> re-configure |
73 | | | # USR1 -> kill daemon only |
74 | | | # USR2 -> kill modules only |
75 | | | # |
76 | | | sub signalhandler { |
77 | | | my ($sig)=@_; |
78 | | | |
79 | | | if (defined $sig) { |
80 | | | if (($sig eq "TERM") ||($sig eq "USR2")) { |
81 | | | print time,"Stopping all running modules.\n"; |
82 | | | if (@PIDs) { kill "TERM", @PIDs; @PIDs=(); } |
83 | | | } |
84 | | | |
85 | | | if (($sig eq "TERM") || ($sig eq "USR1")) { |
86 | | | print time,"Daemon exiting normally.\n"; |
87 | | | if (-e $CONFIG{PIDFILE}) { |
88 | | | unlink $CONFIG{PIDFILE}; |
89 | | | print "PID-file removed.\n"; |
90 | | | } |
91 | | | close STDIN; |
92 | | | close STDOUT; |
93 | | | close STDERR; |
94 | | | exit 0; |
95 | | | } |
96 | | | |
97 | | | if ($sig eq "HUP") { |
98 | | | print time," HUP signal received - signal not implemented yet...\n"; |
99 | | | foreach (keys %CONFIG) { print $_," -> ",$CONFIG{$_},"\n"; } |
100 | | | # TODO: |
101 | | | # |
102 | | | # - kill unused modules |
103 | | | # - start configured modules (if necessary) |
104 | | | # - re-configure all modules |
105 | | | # |
106 | | | } |
107 | | | } |
108 | | | } |
109 | | | |
110 | | | |
111 | | | ###################################################################### |
112 | | | # |
113 | | | # the main loop executes all timed scripts: |
114 | | | # |
115 | | | # modules/*/read-data every >=10 sec. (hardcoded) |
116 | | | # modules/*/diagrams every $DTIME |
117 | | | # convert() every $CTIME if $CONVERTMETHOD is other than "HTML" |
118 | | | # scan_for_modules() every $STIME |
119 | | | # |
120 | | | sub main_loop { |
121 | | | my ($now,$last,$sleeptime,$lastscan,$lastdiagram,$lastconvert,@modules); |
122 | | | |
123 | | | $now=time; |
124 | | | $last=$now-100; |
125 | | | $lastscan=$now; |
126 | | | $lastdiagram=int($now/$CONFIG{DTIME})*$CONFIG{DTIME}; |
127 | | | $lastconvert=int($now/$CONFIG{CTIME})*$CONFIG{CTIME}; |
128 | | | |
129 | | | @modules=HotSaNICparser::scan_for_modules($CONFIG{MODULEDIR},$CONFIG{DEBUGLEVEL},$CONFIG{RUN}); |
130 | | | if ($CONFIG{DEBUGLEVEL} > 0) { print time,": initializing modules...\n"; } |
131 | | | initialize_modules(@modules); |
132 | | | %PIDs=call_modules(@modules); |
133 | | | @PIDs=keys(%PIDs); |
134 | | | |
135 | | | |
136 | | | while () { |
137 | | | $now=time; |
138 | | | # if ($last+10 <= $now) { |
139 | | | if ($CONFIG{DEBUGLEVEL} > 0) { print "$now: main loop running\n"; } |
140 | | | |
141 | | | # scan for modules and (re-)start them if necessary |
142 | | | # |
143 | | | if ($lastscan+$CONFIG{STIME} <= $now) { |
144 | | | @modules=HotSaNICparser::scan_for_modules($CONFIG{MODULEDIR},$CONFIG{DEBUGLEVEL},$CONFIG{RUN}); |
145 | | | %PIDs=call_modules(@modules); |
146 | | | @PIDs=keys(%PIDs); |
147 | | | $lastscan=$now; |
148 | | | if ($CONFIG{DEBUGLEVEL} < 0) { logrotate(); } |
149 | | | } |
150 | | | |
151 | | | # for each module call the read-data script. |
152 | | | # |
153 | | | if ($CONFIG{DEBUGLEVEL} > 0) { print "$now: signaling ",join " ",@PIDs,"\n"; } |
154 | | | if (@PIDs) { |
155 | | | if ($CONFIG{SCHEDULED} == 0) { kill "SIGUSR1", @PIDs; } |
156 | | | else { |
157 | | | foreach (@PIDs) { |
158 | | | kill "SIGUSR1", $_; |
159 | | | my $wait=int($CONFIG{SCHEDULE_MIN}+rand($CONFIG{SCHEDULE_MAX}-$CONFIG{SCHEDULE_MIN}))/1000; |
160 | | | if ($CONFIG{DEBUGLEVEL} >3) { print "$wait($PIDs{$_}) "; } |
161 | | | select(undef,undef,undef,$wait); |
162 | | | } |
163 | | | if ($CONFIG{DEBUGLEVEL} >3) { print "\n"; } |
164 | | | } |
165 | | | } |
166 | | | $last=$now; |
167 | | | # } |
168 | | | |
169 | | | # check if diagrams have to be built. |
170 | | | # |
171 | | | if ($lastdiagram+$CONFIG{DTIME} <= $now) { |
172 | | | my $append; |
173 | | | if ($CONFIG{DIAGRAMLOG} eq "all") { $append=1; } |
174 | | | call_script($CONFIG{DAEMONDIR},"diagrams.pl",5,$CONFIG{LOGDIR}."/diagram.log",$append); |
175 | | | $lastdiagram+=$CONFIG{DTIME}; |
176 | | | |
177 | | | # check if mainpage-diagrams have to be generated. |
178 | | | # |
179 | | | if (($lastconvert+$CONFIG{CTIME} <= $now) && ($CONFIG{CONVERTMETHOD} ne "HTML")) { |
180 | | | call_script($CONFIG{DAEMONDIR},"convert.pl",0); |
181 | | | $lastconvert+=$CONFIG{CTIME}; |
182 | | | } |
183 | | | } |
184 | | | $sleeptime=10-(time % 10); |
185 | | | sleep $sleeptime; |
186 | | | } |
187 | | | } |
188 | | | |
189 | | | |
190 | | | ###################################################################### |
191 | | | # |
192 | | | # call init script in each module (if available) |
193 | | | # |
194 | | | sub initialize_modules { |
195 | | | my (@modules)=@_; |
196 | | | my ($name,$ouser,$osystem,$user,$system,$utime,$stime); |
197 | | | |
198 | | | print time," Initializing modules...\n"; |
199 | | | for $name (@modules) { |
200 | | | unlink $CONFIG{MODULEDIR}."/$name/*.dat"; |
201 | | | # unlink $CONFIG{MODULEDIR}."/$name/*.pid"; |
202 | | | unlink $CONFIG{MODULEDIR}."/$name/*.old"; |
203 | | | if ( -e $CONFIG{MODULEDIR}."/$name/init" ) { |
204 | | | print time," initializing ",$name,"\n"; |
205 | | | system "cd ".$CONFIG{MODULEDIR}."/$name; ./init"; |
206 | | | print time," initializing of ",$name," DONE!\n\n"; |
207 | | | } |
208 | | | } |
209 | | | print time," END Initializing modules...\n","-" x 50,"\n\n"; |
210 | | | } |
211 | | | |
212 | | | |
213 | | | ###################################################################### |
214 | | | # |
215 | | | # start read-data.pl script in each module |
216 | | | # |
217 | | | sub call_modules { |
218 | | | my (@modules)=@_; |
219 | | | my %PIDs; |
220 | | | my $nicelevel="0"; |
221 | | | |
222 | | | # iterate through all configured modules... |
223 | | | # |
224 | | | for my $module (@modules) { |
225 | | | chdir $CONFIG{MODULEDIR}."/$module"; |
226 | | | |
227 | | | my $PID=HotSaNICparser::get_pid($CONFIG{DEBUGLEVEL}); |
228 | | | |
229 | | | # if not running, start the module and wait for PIDfile to be generated |
230 | | | # |
231 | | | if ($PID == 0) { |
232 | | | my $count=-1; |
233 | | | print "\nstarting module: \"$module\"\n"; |
234 | | | if (-e "./running.pid") { |
235 | | | if ($CONFIG{DEBUGLEVEL}>1) { print "removing old PIDfile...\n"; } |
236 | | | unlink "./running.pid"; |
237 | | | } |
238 | | | if (-e "./read-data-wrapper.pl") { system("nice -$nicelevel ./read-data-wrapper.pl start $module"); } |
239 | | | else { system("nice -$nicelevel ./read-data.pl start $module"); } |
240 | | | $count=0; |
241 | | | while ( ($count<20) && (! -s "./running.pid") ) { |
242 | | | $count++; |
243 | | | print "."; |
244 | | | sleep 1; |
245 | | | } |
246 | | | $PID=HotSaNICparser::get_pid($CONFIG{DEBUGLEVEL}); |
247 | | | } |
248 | | | |
249 | | | if ($PID >0) { |
250 | | | print "$module running on PID $PID\n\n"; |
251 | | | $PIDs{$PID}=$module; |
252 | | | } |
253 | | | } |
254 | | | return %PIDs; |
255 | | | } |
256 | | | |
257 | | | |
258 | | | ###################################################################### |
259 | | | # |
260 | | | # call external script (incl. sanity checking etc) |
261 | | | # |
262 | | | sub call_script { |
263 | | | my ($path,$script,$nicelevel,$output,$append)=@_; |
264 | | | |
265 | | | if (! defined $append) { $append=0; } |
266 | | | if ( index("1 yes",lc $append) < 0) { rename $output,"$output.old"; } |
267 | | | if (! defined $output) { $output=""; } |
268 | | | if (! defined $nicelevel) { $nicelevel=0; } |
269 | | | |
270 | | | if ( (defined $path) && (defined $script) ) { |
271 | | | print time,": executing $path/$script with nice $nicelevel\n"; |
272 | | | if ( -e "$path/$script") { |
273 | | | if ($output ne "") { |
274 | | | if ($nicelevel ne 0) {system ("cd \"$path\"; nice -$nicelevel ./$script >$output &"); } |
275 | | | else {system ("cd \"$path\"; ./$script >$output &"); } |
276 | | | } |
277 | | | else { |
278 | | | if ($nicelevel ne 0) {system ("cd \"$path\"; nice -$nicelevel ./$script &"); } |
279 | | | else {system ("cd \"$path\"; ./$script &"); } |
280 | | | } |
281 | | | } |
282 | | | else { print time.": script not found! Check your installation.\n"; } |
283 | | | } |
284 | | | } |
285 | | | |
286 | | | |
287 | | | ###################################################################### |
288 | | | # |
289 | | | # fork into background |
290 | | | # |
291 | | | sub daemonize { |
292 | | | print "entering daemon mode...\n"; |
293 | | | if ($debug eq "") { |
294 | | | close STDIN; |
295 | | | close STDOUT; |
296 | | | close STDERR; |
297 | | | if (open(DEVTTY, "/dev/tty")) { ioctl(DEVTTY,0x20007471,0); close DEVTTY; } |
298 | | | open STDIN,"/dev/null"; |
299 | | | open STDOUT,">>".$CONFIG{LOGDIR}."/HotSaNIC.log"; |
300 | | | open STDERR,">&STDOUT"; |
301 | | | chdir "/"; |
302 | | | fork && exit 0; |
303 | | | print "\n\n----------------------------------------\n"; |
304 | | | print time,": archiver successfully forked into background and running on PID $$\n"; |
305 | | | } |
306 | | | else { print time,": archiver running in debug-mode on PID $$\n"; } |
307 | | | open FILE,">".$CONFIG{PIDFILE}; |
308 | | | print FILE $$; |
309 | | | close FILE; |
310 | | | } |
311 | | | |
312 | | | |
313 | | | ###################################################################### |
314 | | | # |
315 | | | # rotate logfiles |
316 | | | # |
317 | | | sub logrotate { |
318 | | | my ($size,$file); |
319 | | | |
320 | | | if ((defined $CONFIG{DEBUGLEVEL}) && ($CONFIG{DEBUGLEVEL} < 0)) { |
321 | | | |
322 | | | $file=$CONFIG{LOGDIR}."/HotSaNIC.log"; |
323 | | | (undef,undef,undef,undef,undef,undef,undef,$size,undef,undef,undef,undef,undef) = stat($file); |
324 | | | if (defined $size) { |
325 | | | if ($size > $CONFIG{LOGSIZE}) { |
326 | | | print time," $file exceeding ",$CONFIG{LOGSIZE}," bytes - rotating - keeping ",$CONFIG{LOGBACKUPS}," backups.\n"; |
327 | | | for (my $nn=$CONFIG{LOGBACKUPS};$nn>1;$nn--) { |
328 | | | if ( -e "$file.$nn" ) { unlink "$file.$nn"; } |
329 | | | if ( -e "$file.".($nn-1) ) { rename "$file.".($nn-1),"$file.".$nn; } |
330 | | | } |
331 | | | close STDOUT; |
332 | | | rename $file,"$file.1"; |
333 | | | open STDOUT,">>$file"; |
334 | | | close STDERR; |
335 | | | rename $file,"$file.1"; |
336 | | | open STDERR,">>$file"; |
337 | | | } |
338 | | | } |
339 | | | } |
340 | | | } |
341 | | | |
342 | | | |
343 | | | ###################################################################### |
344 | | | # |
345 | | | # evaluate commandline arguments |
346 | | | # |
347 | | | sub check_for_args { |
348 | | | my @args=@_; |
349 | | | |
350 | | | # set initial values |
351 | | | # |
352 | | | my $debuglevel=-1; |
353 | | | my $runmode=0; |
354 | | | |
355 | | | # Check if we were called with any options |
356 | | | # |
357 | | | foreach my $arg (@args) { |
358 | | | if (index($arg,"d") >= 0) { $runmode|=1; } |
359 | | | if (index($arg,"D") >= 0) { $runmode|=128; } |
360 | | | if (index($arg,"?") >= 0) { $runmode|=256; } |
361 | | | $arg=~ s/[a-zA-Z]//g; |
362 | | | if ($arg =~ /[0-9]/) { if ($arg > 0) { $debuglevel=$arg; } } |
363 | | | } |
364 | | | |
365 | | | if (($runmode == 0) || ($runmode > 255)) { |
366 | | | print "rrdtimer - CVS version $VERSION ($IDENTIFIER) - OS: $^O\n"; |
367 | | | print "usage:\nrrdtimer [options[debuglevel]]\n options:\n"; |
368 | | | print " D - enter daemon-mode (i.e. start the main loop)\n"; |
369 | | | print " d - enter debugging mode (don't fork into background)\n"; |
370 | | | print "\n"; |
371 | | | exit 0; |
372 | | | } |
373 | | | return ($debuglevel,$runmode); |
374 | | | } |
375 | | | |
376 | | | |