Hello all,
a while ago I wrote yet another script to run a number of programs
on a certain occasion which is similar to periodic(8). My main goal
was to run jobs (fetching mail and news) in parallel when I go
online with my dial-up account. These should be finished, though,
before the time is set with ntpdate. (ntpdate should have a minimum
round-trip time.)
The script reads a directory (the only argument is the path name) of
arbitrary programs and executes them in ASCII order. It executes
programs with names *.bg in the background and waits for their
termination either before it terminates or when it encounters a
program with a name *.wait (which is then also executed).
Usage: run-jobs [-v [-v]] [-p argv0] jobs-directory-path
I'd like to see someone like this in the standard OS. If anyone
thinks it is worth including, please do; I would then take
suggestions for improvement and write a manpage. The program is
deliberately not plug-compatible with periodic(8) -- I think it is
more flexible to just take a pathname as an argument. The pathname
may, of course, have a descriptive name like /etc/periodic/daily.
Well, also if no one thinks this should be in FreeBSD, I'll gladly
take suggestions, of course. I just might not feel compelled to
write a manpage. :-)
Greetings, Juergen.
#!/usr/bin/perl -w
# -*- perl -*-
#
# Run a number of job scripts (actually arbitrary programs) in the
# specified directory. Source a file env.pl, if it exists. Run
# programs with names matching *.bg in the background. On program
# names matching *.wait, wait until all background processes are
# finished before continuing with the *.wait program.
#
#-
# Copyright (c) 2000 Juergen Nickelsen <[EMAIL PROTECTED]>
# All rights reserved.
#
# Redistribution and use in source form, with or without modification, are
# permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $Id: run-jobs.pl,v 1.3 2000/06/27 07:04:33 ni Exp $
#
use strict ;
my $verbose = 0 ; # verbosity flag may be 0, 1, 2, ...
my $progname = "run-jobs" ; # name of program (argv[0] doesn't work)
my $ls = "/bin/ls" ; # need them sorted
my $envfile = "env.pl" ; # read and evaluated at startup
my $verbarg = "" ; # argument for jobs if $verbose
my $nprocs = 0 ; # Number of background jobs running
$| = 1 ; # due to fork()
my %procs = () ; # processes indexed by pid
my $jobsdir ; # directory containing job scripts
# return local time in iso format
sub isodate {
my ($sec, $min, $hour, $mday, $mon, $year, undef, undef, undef) =
localtime(time);
return sprintf("%04d-%02d-%02d %02d:%02d:%02d",
$year + 1900, $mon + 1, $mday, $hour, $min, $sec) ;
}
# print something if $verbose
sub vprint {
print "$progname: @_\n" if $verbose ;
}
# print something if $verbose >= 2
sub vvprint {
print "$progname: @_\n" if $verbose >= 2 ;
}
# run job in background
sub run_bg {
my ($cmd) = @_ ;
my $pid = 0 ;
if ($pid = fork()) {
vprint "started process $pid with $cmd @ARGV" ;
$procs{$pid} = $cmd ;
$nprocs++ ;
} else {
if (!defined($pid)) {
warn "fork failed ($!)" ;
} else {
exec "./$cmd @ARGV" ;
}
}
}
# wait for all background jobs
sub wait_for_children {
my $pid ;
my $status ;
if ($nprocs > 0) {
vprint sprintf("waiting for $nprocs child process%s",
$nprocs != 1 ? "es" : "") ;
while (($pid = wait) != -1) {
$nprocs-- ;
$status = $? >> 8 ;
vprint sprintf "child process $pid exits with $status" .
" ($procs{$pid}), $nprocs left" ;
}
}
}
MAIN: do {
# check commandline for verbose flag and program name argument
FLAGS: while ($ARGV[0]) {
if ($ARGV[0] =~ /^-/) {
if ($ARGV[0] eq "-v") {
$verbose++ ;
$verbarg = "-v" ;
shift ;
} elsif ($ARGV[0] eq "-p") {
shift ;
$progname = shift ;
}
} else {
last FLAGS ;
}
}
$jobsdir = shift ; # directory containing job scripts
if (!defined($jobsdir)) {
die "usage: $progname [-v] [-p progname] directory [args...]\n" ;
}
# change to directory with jobs
chdir $jobsdir || die "$progname: can't chdir to $jobsdir ($!)\n" ;
# read file with enviroment variables etc. if present
if (open (ENVF, $envfile)) {
my $savenl ;
my $env ;
vprint "eval $envfile" ;
$savenl = $/ ;
$/ = undef ; # Slurp whole file
$env = <ENVF> ;
$/ = $savenl ;
eval $env ;
warn $@ if $@ ;
}
# read job file names
my @jobs = `$ls` ;
vprint "start jobs at " . isodate() ;
# run jobs
LOOP: for (@jobs) {
chomp ;
vvprint "check $_" ;
if (-x $_ && ! -d $_) {
if (/~$/) { # Skip Emacs backup files
next LOOP ;
} elsif (/\.bg$/) { # run *.bg in background
run_bg $_ ;
} else {
if (/\.wait$/) { # wait for children on all *.wait`
vprint "waiting on $_" ;
wait_for_children() ;
}
vprint "run $_ @ARGV" ;
system "./$_ @ARGV" ;
}
}
}
wait_for_children() ;
vprint "finished at " . isodate() ;
}
# EOF
To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-hackers" in the body of the message