#!/usr/pkg/bin/perl

=begin metadata

Name: kill
Description: send signals to a process
Author: Theo Van Dinter, felicity@kluge.net
License:

=end metadata

=cut


#
# An implementation of the 'kill' utility in Perl.  Written for the Perl
# Power Tools (PPT) project by Theo Van Dinter (felicity@kluge.net).

use strict;
use Config;

usage() unless @ARGV;
my @signals = getsigs();
my %hsignals = map { $_ => 1 } @signals;
my $signal = 'TERM';

if ($ARGV[0] eq '-l') { # list signals
	siglist();
	exit 0;
}
elsif ( $ARGV[0] =~ m/\A\-([0-9]+)\Z/ ) { # -signalnumber
	$signal = $1;
	shift @ARGV;
	if ($signal > $#signals) {
		print "$0: $signal: Unknown signal; valid signals...\n";
		siglist();
		exit 1;
	}
}
elsif ( $ARGV[0] =~ /\A\-(.+)\Z/ ) { # -NAME or -s NAME
	$signal = $1;
	shift @ARGV;
	$signal = shift @ARGV if ( lc $signal eq "s" ); # -s has signalname param.
	$signal = uc $signal;
	$signal =~ s/^SIG//; # remove the "SIG" from SIGNAME
	unless ($hsignals{$signal}) {
		print "$0: $signal: Unknown signal; valid signals...\n";
		siglist();
		exit 1;
	}
}

die "$0: No PIDs specified.\n" unless ( @ARGV );

my($ret) = 0;
foreach ( @ARGV ) { # do the kills...
	unless (m/\A\-?[0-9]+\Z/) {
		warn "$0: failed to parse argument '$_'\n";
		exit 1;
	}
	unless (kill $signal, $_) {
		warn "$0: $_: $!\n";
		$ret = 1;
	}
}

exit $ret;

sub usage {
	print "usage:  $0 [-s signalname] PID...
	$0 [-signalname] PID...
	$0 [-signalnumber] PID...
	$0 PID...
	$0 [-l]
";
	exit 1;
}

sub siglist {
	foreach my $i (1 .. $#signals) {
		printf "%2d:%-6s%s",$i,$signals[$i],
			( ($i % 8 == 0) || ($i == $#signals) )?"\n":" ";
	}
}

sub getsigs {
	die 'no signal names detected' unless defined $Config{'sig_name'};
	my @names = split/\s+/, $Config{'sig_name'};
	die 'empty signal list' unless @names;
	return @names;
}

=head1 NAME

kill - send signals to a process

=head1 SYNOPSIS

B<kill>
[ B<-s> I<signalname> C<PID...> ]
[ B<-signalname> C<PID...> ]
[ B<-signalnumber> C<PID...> ]
[ C<PID...> ]
[ B<-l> ]

=head1 DESCRIPTION

B<kill> sends a signal to all PIDS specified on the command line.  This is
typically done to cause a process to terminate and/or to reload configuration
files, etc.  Signal handlers are specified per program, so the effects of a
received signal may vary.

=head1 OPTIONS AND ARGUMENTS

=over 4

=item I<-s>	This parameter takes a single argument of a signal name (see -l)
to be sent to the specified PIDs.

=item I<-signalname>	A short form of the C<-s signalname> parameter.

=item I<-signalnumber>	This parameter specifies that the given signal number
should be sent to the specified PID listing.

=item I<-l>	Display a listing of all available signals on the current system.

=back

=head1 NOTES

If no signal is specified on the command line, SIGTERM is sent to the
specified PIDs.

kill returns 0 on success or >0 if an error occurred.

kill is built-in to csh(1);  See csh(1) for details.

Only the super-user may send signals to other users' processes.

This version of kill does not support I<-l [signal]> since there didn't seem
to be any use to the parameter (it didn't work on any platform I tried
either.)

Signal names may have the I<SIG> prefix.  i.e.: C<kill -HUP> and C<kill
-SIGHUP> are equivalent.

The signal list C<kill -l> displays in an "extended" form which lists both
the signal name and the signal number for easy reference.

=head1 HISTORY

Perl version rewritten for the Perl Power Tools project from the
description of the kill program in OpenBSD.

=head1 AUTHOR

Theo Van Dinter (felicity@kluge.net)

=head1 SEE ALSO

csh(1), ps(1), kill(2)

