From owner-freebsd-bugs Sun Mar 19 19:20:12 2000 Delivered-To: freebsd-bugs@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (Postfix) with ESMTP id 8BCCB37B887 for ; Sun, 19 Mar 2000 19:20:06 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.9.3/8.9.2) id TAA98385; Sun, 19 Mar 2000 19:20:06 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: from bugg.strangled.net (c705742-a.htfdw1.ct.home.com [24.2.137.94]) by hub.freebsd.org (Postfix) with ESMTP id 3886A37B868 for ; Sun, 19 Mar 2000 19:11:47 -0800 (PST) (envelope-from bugg@bugg.strangled.net) Received: (from bugg@localhost) by bugg.strangled.net (8.9.3/8.9.3) id WAA01203; Sun, 19 Mar 2000 22:12:41 -0500 (EST) (envelope-from bugg) Message-Id: <200003200312.WAA01203@bugg.strangled.net> Date: Sun, 19 Mar 2000 22:12:41 -0500 (EST) From: Dan Papasian Reply-To: bugg@bugg.strangled.net To: FreeBSD-gnats-submit@freebsd.org X-Send-Pr-Version: 3.2 Subject: bin/17498: killall(1) is a slow perl script that's dependant on procfs Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >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 X#include X#include X X#include X#include X#include x#include X#include X#include X#include X#include 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