Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 19 Mar 2000 22:12:41 -0500 (EST)
From:      Dan Papasian <bugg@bugg.strangled.net>
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   bin/17498: killall(1) is a slow perl script that's dependant on procfs 
Message-ID:  <200003200312.WAA01203@bugg.strangled.net>

next in thread | raw e-mail | index | archive | help

>Number:         17498
>Category:       bin
>Synopsis:       killall(1) is a slow perl script that's dependant on procfs
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Mar 19 19:20:00 PST 2000
>Closed-Date:
>Last-Modified:
>Originator:     Dan Papasian
>Release:        FreeBSD 4.0-CURRENT i386
>Organization:
none 
>Environment:
	I'm still running a late 4-CURRENT, but the patch (well, new files)
are intendend for HEAD, of course.

>Description:

	The problem is that killall(1) currently uses procfs for abstraction
of process information from the kernel, which while it sounds like an excellent
idea in concept, does not provide a significant advantage over using a
sysctl. 
	In cases where the system is to be secure, procfs usually is not
mounted.  This is because procfs has had more than one vulnerability found
in it over the years, and, well, "if they really don't need it, don't
let them have it" security logic.
	Most jails that are setup using jail() do not have access to a
mounted procfs.  If one were to use the command killall inside such
a jail, they'd just get an error about procfs not being mounted.
	The current implementation of killall crawls procfs looking for
a matching process.  It is effective, but not too speedy as the data is 
abstracted via a filesystem.  Following is proof of the current killall's
lack of speed:

With the stock killall:

curly% time killall top
        0.04 real         0.03 user         0.00 sys

With the sysctl based killall:

curly% time ./killall top
        0.00 real         0.00 user         0.00 sys

	Now, the difference in speed may not seem like a big issue, but the fact
is these tests were performed on an Intel Celeron 400 under hardly any
load.  On a slower computer, or under significant load, the increased efficency
is something that the end user will definetly feel.

>How-To-Repeat:

Use killall when you can't wait .04 seconds, or on a box without a mounted
procfs.
	

>Fix:
The following is an example C program that performs the same function
as the current implementation of killall(1), and is option-by-option 
compatible, bar two exceptions.  These exceptions are so-called
double verbosity (specifying the -v option twice to get a list of 
information obtained from procfs: this seems like a feature that
serves no practical purpose as ps(1) provides the same information)

The other feature which is not present in this version is the -m option.
This feature is dependant on its usage of perl, and may or may not be
worth reimplementing in C.

I've modified the existing manpage to reflect the changes made, and
in the event this program is accepted with out much changes to its
behavior, contact me and I will send you a copy of the manpage.

This program has only a dependency on being able to call sysctl(), not
procfs or /dev/kmem.

Please excuse in advance any whitespace, style, or coding errors in
this program.  I've tested it somewhat to make sure none exist,
but I'm sure some of you will be able to find things that could
be done better :)

Regards,
	Dan Papasian.

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	killall.c
#
echo x - killall.c
sed 's/^X//' >killall.c << 'END-of-killall.c'
X/*-
X * Copyright (c) 2000 Dan Papasian.  All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. The name of the author may not be used to endorse or promote products
X *    derived from this software without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
X * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
X * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
X * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
X * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
X * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
X * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X */
X
X#include <sys/param.h>
X#include <sys/sysctl.h>
X#include <sys/user.h>
X
X#include <ctype.h>
X#include <err.h>
X#include <fcntl.h>
x#include <signal.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <sysexits.h>
X
X#define NOTSIG -1
X#define FALSE 0
X#define TRUE 1
X#define DENIED 2
X
X
Xshort           killall(char *, short);
Xvoid            usage(void);
Xshort           signame_to_signum(char *);
Xvoid            printsig(void);
Xshort           fake, verbose;
X
Xint
Xmain(int argc, char **argv)
X{
X	short           sig, rval, errors;
X
X	errors = verbose = fake = 0;
X	sig = SIGTERM;
X
X	if (argc < 2)
X		usage();
X	++argv;
X	while (--argc > 0 && **argv == '-') {
X
X		/* Remove dashes */
X		while (**argv == '-')
X			++* argv;
X
X		/* If the argument ends here, it isn't the signal */
X		/* If it is a digit, it is the signal.  Don't pass to switch */
X		if (argv[0][1] == '\0' && !isdigit(**argv)) {
X			switch (**argv) {
X			case 'd':
X			case 'v':
X				++verbose;
X				break;
X			case '?':
X			case 'h':
X				usage();
X				break;
X			case 's':
X				++fake;
X				break;
X			case 'l':
X				printsig();
X				exit(EX_OK);
X				break;
X			default:
X				warnx("Invalid argument %s", *argv);
X				usage();
X				break;
X			}
X		} else {
X			sig = signame_to_signum(*argv);
X			if (sig == NOTSIG)
X				errx(EX_USAGE, "Invalid signal %s", *argv);
X		}
X		argv++;
X	}
X	if (argc <= 0)
X		usage();
X
X	/* Find and execute each process */
X	while (argc > 0) {
X		rval = killall(*argv, sig);
X		if (rval != TRUE) {
X			errors = 1;
X			printf("No processes matching ``%s'' ", *argv);
X			if (rval == DENIED)
X				printf("belong to you.\n");
X			else
X				printf("\n");
X		}
X		--argc, ++argv;
X	}
X	exit(errors);
X	/* NOTREACHED */
X}
X
Xshort
Xkillall(char *request, short signal)
X{
X	unsigned int    i;
X	int             nentries;
X	short           found;
X	struct kinfo_proc *kp, *procall;
X	int             mib[3];
X	size_t          kplen;
X
X	mib[0] = CTL_KERN;
X	mib[1] = KERN_PROC;
X	mib[2] = KERN_PROC_ALL;
X
X	found = FALSE;
X
X	sysctl(mib, 3, NULL, &kplen, NULL, 0);
X	procall = kp = malloc(kplen);
X	sysctl(mib, 3, kp, &kplen, NULL, 0);
X
X	nentries = kplen / sizeof(*kp);
X
X	for (i = 0; i < nentries; i++, kp++) {
X		struct proc    *pr = &kp->kp_proc;
X		if (!pr->p_pid || pr->p_comm[0] == NULL)
X			break;
X		if (!strcmp(&pr->p_comm[0] + strlen(&pr->p_comm[0]) - strlen(request), request)) {
X			if (!fake) {
X				if (kill(pr->p_pid, signal)) {
X					if (errno == EPERM && found == FALSE)
X						found = DENIED;
X				} else
X					found = TRUE;
X			}
X			if (fake || verbose)
X				printf("pid %d with signal %d\n", pr->p_pid, signal);
X		}
X	}
X	free(procall);
X	return found;
X}
X
Xvoid
Xusage()
X{
X	errx(1, "usage [-help | -? | -h] [-s] [-v|-d] [-h|-s] [-l] SIGNAL procname");
X}
X
Xshort
Xsigname_to_signum(char *sig)
X{
X	short           n;
X
X	if (isdigit(*sig)) {
X		n = atoi(sig);
X		return n;
X	}
X	if (!strncasecmp(sig, "help", 4))
X		usage();
X
X	if (!strncasecmp(sig, "sig", 3))
X		sig += 3;
X
X	for (n = 1; n < NSIG; n++) {
X		if (!strcasecmp(sys_signame[n], sig))
X			return n;
X	}
X	return NOTSIG;		/* Not a signal */
X}
X
Xvoid
Xprintsig(void)
X{
X	short           n;
X
X	for (n = 1; n < NSIG; n++) {
X		printf("%s", sys_signame[n]);
X		if (n == (NSIG / 2) || n == (NSIG - 1))
X			printf("\n");
X		else
X			printf(" ");
X	}
X}
END-of-killall.c
exit


>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




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