Skip site navigation (1)Skip section navigation (2)
Date:      31 Aug 2000 21:54:46 +0200
From:      Juergen Nickelsen <jnickelsen@acm.org>
To:        freebsd-hackers@freebsd.org
Subject:   New script to run a number of jobs (also in the background)
Message-ID:  <x7u2c1fbp5.fsf@goting.jn.berlin.snafu.de>

next in thread | raw e-mail | index | archive | help
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 <jnickelsen@acm.org>
# 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 majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?x7u2c1fbp5.fsf>