+++ /dev/null
-Changes from version 18 to 19 (25-OCT-1999)
-=============================
-
- - pstree: "static int" was only "static" (fix by Jeremy Buhler)
- - now uses cc -E instead of /lib/cpp (suggested by Kristofer Karas)
- - fuser: -s conflicted with -k (reported by David Hinds)
- - fuser: using -a with -s now yields an error
- - added a sanity check for signames.h (suggested by John Summerfield)
- - only "signals" < 100 are now added to signames.h, eliminating SIGSTKSZ
-
-
-Changes from version 17 to 18 (1-NOV-1998)
-=============================
-
- - fuser: usage summary listed -s (silent) as -q
- - fuser: fuser x/y yielded confusing error message if x/y doesn't exist
- (reported by Tigran Aivazian)
- - fuser: new option -i for interactive killing (like killall -i)
- - killall: tried to print a NULL pointer if full process name was unavailable
- and killing failed
- - killall: new option -g to kill process group instead of process
- - killall: cosmetic PROC_BASE changes (by Florian La Roche)
- - pidof: new option -g to show PGID instead of PID (by Florian La Roche)
- - pstree: new option -H to highlight process specified by PID
- - added -D_GNU_SOURCE to CFLAGS for glibc 2 compatibility
- - Makefile should now also work with bash-2
-
-
-Changes from version 16 to 17 (17-FEB-1998)
-=============================
-
- - fuser: now also handles /proc of recent 2.1 kernels (fix by Andreas Schwab;
- other fixed also proposed by Chris Wedgwood and Luca Berra)
- - pstree now properly handles init with PID = PPID = 1
- - fuser: no longer changes the name space for relative paths ending with the
- name of a name space (e.g. something/tcp)
- - fuser: now also reports mount points, swap files, and loop mounts
- - updated the fuser man page
- - killall: new option -w to wait for the killed processes to die
- - killall: didn't handle malloc failure
-
-
-Changes from version 15 to 16 (28-JUL-1997)
-=============================
-
- - killall: now gets the list of all PIDs before killing processes, thereby
- avoiding race between readdir and /proc (found by Boris Zentner)
- - make install no longer changes BINDIR and MANDIR if they already exist
- - changed psmisc.<version>.lsm to psmisc-<version>.lsm for consistency
-
-
-Changes from version 14 to 15 (16-JUN-1997)
-=============================
-
- - killall: killall -v didn't print the command name (fixed by Marty Leisner)
- - fuser: fuser -a <unix_domain_socket> could crash (reported by Helmut Geyer)
- - fuser: fuser -m didn't consider UNIX domain sockets (fix based on a patch by
- Andries Brouwer)
- - fuser: fuser -a /a /a /b no longer merges the first two entries
- - changed package name format from psmisc.<version> to psmisc-<version> to
- avoid annoyance messages from sunsite's archive scripts
-
-
-Changes from version 13 to 14 (19-APR-1997)
-=============================
-
- - killall: command-line parser didn't accept -signal (fixed by Chris Wedgwood)
- - pidof: minor man page correction
- - Makefile: pidof is now only installed when running make install-pidof
- - added a file with installation instructions (INSTALL)
-
-
-Changes from version 12 to 13 (16-APR-1997)
-=============================
-
- - fuser: didn't check for out of memory condition after malloc (oops !)
- - fuser: INET domain sockets can now be specified as
- [local_port][,[remote_host][,[remote_port]]]
- - fuser: now includes linux/kdev_t.h instead of linux/fs.h. This may break
- compilation with some ancient kernels.
- - killall: new option -q to suppress error message if no process was found
- - killall: man page didn't reset font properly
- - killall: now tries harder to handle very long names (> 15 characters)
- (proposed by Erik Thiele)
- - killall: new option -e to require exact name match
- - killall: now lists PIDs if invoked as "pidof" (proposed by Peter Daum)
- - minor Makefile change to eliminate need to patch for some versions of Linux
-
-
-Changes from version 11 to 12 (7-APR-1996)
-=============================
-
- - fuser is now able to look up INET and UNIX domain sockets
- - pstree: new option -n to sort its output by PID
- - pstree: new option -G to use VT100 line drawing characters
-
-
-Changes from version 10 to 11 (20-SEP-1995)
-=============================
-
- - added VERSION file
- - size of command name is now defined in comm.h - the old approach of
- obtaining values from linux/sched.h:struct task_struct doesn't work anymore)
- - signames.h is now generated from cpp output (linux/signals.h no longer
- defines them)
- - all commands now print the version number when invoked with the -V option
- - signames.h added to make clean
- - removed use of {,} expansion in mkdist
- - various minor documentation fixes
-
-
-Changes from version 9 to 10 (28-MAR-1995)
-============================
-
- - fuser: now prints header before first path (used to be on same line)
- - fuser: fixed line wrapping for long paths (used to wrap too early)
- - fuser: fixed a NULL pointer dereference in add_file
- - pstree: now outputs strings obtained from termcap with tputs
- - some cosmetic changes (to avoid certain warnings if using -Wconversion)
- - updated e-mail address in README
-
-Changes from version 8 to 9 (22-JAN-1995)
-===========================
-
- - fuser: now works with Plan 9 semantics (i.e. what recent kernels use;
- reported by Harald Koenig, Nick Simicich, and others)
- - fuser: now also scans /proc/*/maps
- - fuser: fixed NULL pointer dereferencing when processes are created while
- fuser is running (fix by Pauline Middelink)
- - fuser: now resets effective uid to real uid before killing, thereby making
- suid installation a smaller security risk
- - pstree: fixed process tree truncation (fix by Andreas Schwab)
- - pstree: added support for UTF-8 line drawing characters (adapted a patch by
- Johan Myreen)
- - killall.1 now warns about potential compatibility problems with killall
- on other systems (proposed by Christos Ricudis)
- - added a copyright notice
- - updated e-mail address
-
-Changes from version 7 to 8 (11-OCT-1994)
-===========================
-
- - pstree: added -a to display command line arguments
- - pstree, fuser and killall: display an error message if /proc has
- no process entries (i.e. if it is not mounted)
- - killall: more detailed usage output
- - killall: added killing by file
- - fuser and killall: fixed generation of signal list to include SIGUSR[12]
- - fuser: now also accepts signal numbers
- - "make install": now also installs man pages; executable permissions changed
- from 755 to 555; now installs fuser in /bin, killall and pstree in /usr/bin
- - "make spotless": fixed typo
- - man pages: minor corrections and improvements
-
-Changes from version 6 to 7
-===========================
-
- - pstree: -h didn't work because of incorrect termcap usage
- - pstree: changed branch drawing from --- to -+-
- \- `-
- - pstree: fixed indentation inside compacted subtrees
- - fuser and killall: don't kill themselves
- - fuser: suppresses m(map) if file is e(xecuted)
- - mkdist now includes itself
- - minor updates on all man pages
-
-Changes from version 5 to 6
-===========================
-
- - pstree: unknown display width expressed as zero width (TIOCGWINSZ) is
- now correctly handled.
- - fuser: added -s for silent operation.
- - fuser: added non-zero return code if no processes using any file are
- found.
- - pstree and fuser: non-printable characters in command names (fuser: also
- in file names) are now shown as \nnn (octal). \ is shown as \\.
- - added "install" target to Makefile to install binaries in /usr/local/bin
- - minor updates on all man pages.
-
-Changes from version 4 to 5
-===========================
-
- - killall: added interactive and verbose modes (options -i and -v)
- - fuser: added 0.99pl11 support (changed /proc/*/lib to /proc/*/mmap)
- - fuser: mmap'ed files and shared libraries are now marked with "m"
- (shlibs were marked with "s" and mmap'ed files weren't marked
- at all)
-
-Changes from version 3 to 4
-===========================
-
- - killall and fuser: now accept signal numbers too.
- - pstree: added listing of process trees by user name.
- - pstree: compaction sometimes generated wrong output.
- - fuser: did only recognize the first occurrence of a file when using
- the options -u or -v.
- - changed Makefile to create stripped impure executables.
+++ /dev/null
-psmisc (fuser, killall and pstree) program code, documentation and
-auxiliary programs are
-Copyright 1993-1999 Werner Almesberger.
-All rights reserved.
-
-Redistribution and use in source and binary forms of parts of or the
-whole original or derived work are permitted provided that the
-original work is properly attributed to the author. The name of the
-author may not be used to endorse or promote products derived from
-this software without specific prior written permission. This work
-is provided "as is" and without any express or implied warranties.
+++ /dev/null
-To build all programs in psmisc, simply execute
-
- make
-
-To install fuser, killall, pstree, and their man pages, run (as root)
-
- make install
-
-fuser is installed in /bin, killall and pstree are installed in /usr/bin
-
-pidof is not installed by make install because different versions of
-pidof exist and a different one may already be installed. If you want to
-install the pidof that comes with psmisc (and its man page), simply run
-(as root)
-
- make install-pidof
+++ /dev/null
-CC=cc
-CFLAGS=-O -DPSMISC_VERSION=\"`cat VERSION`\" \
- -D_GNU_SOURCE \
- -Wall -Wno-parentheses -Wwrite-strings -Wpointer-arith \
- # -Wcast-align -Wconversion -g
-LDFLAGS=#-s -N #-Xlinker -qmagic
-REAL_CPP=cc -E
-PROGS=killall pstree fuser
-EBINDIR=/bin # essential binaries
-BINDIR=/usr/bin # not so essential ones
-MANDIR=/usr/man/man1 # all man pages
-
-all: $(PROGS)
-
-signames.h: /usr/include/signal.h
- $(REAL_CPP) -dM - </usr/include/signal.h | \
- tr -s '\t ' ' ' | sort -n +2 | sed \
- 's:#define SIG\([A-Z]\+[0-9]*\) \([0-9]\+\) *\(\|/\*.*\)$$:{\
-\2,"\1" },:p;d' | \
- grep -v '[0-9][0-9][0-9]' >signames.h || \
- { rm -f signames.h; exit 1; }
- grep '^{ 1,"HUP" },$$' signames.h >/dev/null || \
- { rm -f signames.h; exit 1; }
-
-signals.o: signals.h signals.c signames.h Makefile
-
-fuser.o: fuser.c comm.h signals.h Makefile VERSION
-killall.o: killall.c comm.h signals.h Makefile VERSION
-
-fuser: fuser.o signals.o
-killall: killall.o signals.o
-
-pstree: pstree.c comm.h Makefile VERSION
- $(CC) $(CFLAGS) $(LDFLAGS) -o pstree pstree.c -ltermcap
-
-install: $(PROGS)
-# EBINDIR is expected to exist, so we don't try to create it
- install -o 0 -g 0 -m 555 fuser $(EBINDIR)
- [ -d $(BINDIR) ] || install -d -o 0 -g 0 -m 755 $(BINDIR)
- install -o 0 -g 0 -m 555 killall $(BINDIR)
- install -o 0 -g 0 -m 555 pstree $(BINDIR)
- [ -d $(MANDIR) ] || install -d -o 0 -g 0 -m 755 $(MANDIR)
- install -o 0 -g 0 -m 444 fuser.1 $(MANDIR)
- install -o 0 -g 0 -m 444 killall.1 $(MANDIR)
- install -o 0 -g 0 -m 444 pstree.1 $(MANDIR)
-
-install-pidof:
- @[ -x `echo $(BINDIR)`/killall ] || { \
- echo "Need `echo $(BINDIR)`/killall to install pidof"; \
- exit 1; }
- ln -sf killall `echo $(BINDIR)`/pidof
- install -o 0 -g 0 -m 444 pidof.1 $(MANDIR)
-
-clean:
- rm -f *.o signames.h
-
-spotless: clean
- rm -f $(PROGS)
+++ /dev/null
-psmisc, version 19
-==================
-
-This package contains four little utilities that use the proc FS:
-
- fuser identifies processes using files or sockets (similar to Sun's
- or SGI's fuser)
- killall kills processes by name, e.g. killall -HUP named
- pidof like killall, buts lists PIDs instead of killing processes
- pstree shows the currently running processes as a tree
-
-They should work with most recent kernels. Man pages are included.
-
-- Werner Almesberger <Werner.Almesberger@epfl.ch>
+++ /dev/null
-/* comm.h - command name length definition */
-
-/* Copyright 1995 Werner Almesberger. See file COPYING for details. */
-
-
-#ifndef COMM_H
-#define COMM_H
-
-#if 0 /* broken in 1.3.xx */
-#include <linux/sched.h>
-#define COMM_LEN sizeof(dummy.comm)
-extern struct task_struct dummy;
-#else
-#define COMM_LEN 16 /* synchronize with size of comm in struct task_struct in
- /usr/include/linux/sched.h */
-#endif
-
-#endif
+++ /dev/null
-.TH FUSER 1 "October 25, 1999" "Linux" "User Commands"
-.SH NAME
-fuser \- identify processes using files or sockets
-.SH SYNOPSIS
-.ad l
-.B fuser
-.RB [ \-a | \-s ]
-.RB [ \-n\ \fIspace ]
-.RB [ \-\fIsignal\fB ]
-.RB [ \-kimuv ]
-.I name ...
-.RB [ \- ]
-.RB [ \-n\ \fIspace ]
-.RB [ \-\fIsignal\fB ]
-.RB [ \-kimuv ]
-.I name ...
-.br
-.B fuser
-.RB \-l
-.br
-.B fuser
-.RB \-V
-.ad b
-.SH DESCRIPTION
-.B fuser
-displays the PIDs of processes using the specified files or file systems.
-In the default display mode, each file name is followed by a letter denoting
-the type of access:
-.RS
-.IP \fBc\fP
-current directory.
-.IP \fBe\fP
-executable being run.
-.IP \fBf\fP
-open file. \fBf\fP is omitted in default display mode.
-.IP \fBr\fP
-root directory.
-.IP \fBm\fP
-mmap'ed file or shared library.
-.RE
-.LP
-\fBfuser\fP returns a non-zero return code if none of the specified files
-is accessed or in case of a fatal error. If at least one access has been
-found, \fBfuser\fP returns zero.
-.PP
-In order to look up processes using TCP and UDP sockets, the corresponding
-name space has to be selected with the \fB-n\fP option. Then the socket(s) can
-be specified by the local and remote port, and the remote address. All fields
-are optional, but commas in front of missing fields must be present:
-
-.RB \fB[\fP\fIlcl_port\fP\fB][\fP,\fB[\fP\fIrmt_host\fP\fB][\fP,\fB[\fIrmt_port\fP\fB]]]
-
-Either symbolic or numeric values can be used for IP addresses and port
-numbers.
-.SH OPTIONS
-.IP \fB\-a\fP
-Show all files specified on the command line. By default, only files that are
-accessed by at least one process are shown.
-.IP \fB\-k\fP
-Kill processes accessing the file. Unless changed with \fB-\fP\fIsignal\fP,
-SIGKILL is sent. An \fBfuser\fP process never kills itself, but may kill
-other \fBfuser\fP processes. The effective user ID of the process executing
-\fBfuser\fP is set to its real user ID before attempting to kill.
-.IP \fB\-i\fP
-Ask the user for confirmation before killing a process. This option is
-silently ignored if \fB\-k\fP is not present too.
-.IP \fB\-l\fP
-List all known signal names.
-.IP \fB\-m\fP
-\fIname\fP specifies a file on a mounted file system or a block device that
-is mounted. All processes accessing files on that file system are listed.
-If a directory file is specified, it is automatically changed to
-\fIname\fP/. to use any file system that might be mounted on that
-directory.
-.IP \fB\-n\ \fIspace\fP
-Select a different name space. The name spaces \fBfile\fP (file names, the
-default), \fBudp\fP (local UDP ports), and \fBtcp\fP (local TCP ports) are
-supported. For ports, either the port number or the symbolic name can be
-specified. If there is no ambiguity, the shortcut notation
-\fIname\fB/\fIspace\fP (e.g. \fIname\fB/\fIproto\fP) can be used.
-.IP \fB\-s\fP
-Silent operation. \fB\-u\fP and \fB\-v\fP are ignored in this mode.
-\fB\-a\fP must not be used with \fB\-s\fP.
-.IP \fB\-\fIsignal\fP
-Use the specified signal instead of SIGKILL when killing processes. Signals
-can be specified either by name (e.g. \fB\-HUP\fP) or by number
-(e.g. \fB\-1\fP).
-.IP \fB\-u\fP
-Append the user name of the process owner to each PID.
-.IP \fB\-v\fP
-Verbose mode. Processes are shown in a \fBps\fP-like style. The fields PID,
-USER and COMMAND are similar to \fBps\fP. ACCESS shows how the process
-accesses the file. If the access is by the kernel (e.g. in the case of a
-mount point, a swap file, etc.), \fBkernel\fP is shown instead of the PID.
-.IP \fB\-V\fP
-Display version information.
-.IP \fB\-\fP
-Reset all options and set the signal back to SIGKILL.
-.SH FILES
-.nf
-/proc location of the proc file system
-.fi
-.SH EXAMPLES
-\fBfuser -km /home\fP kills all processes accessing the file system /home
-in any way.
-.LP
-\fBif fuser -s /dev/ttyS1; then :; else \fIsomething\fP; fi\fR invokes
-\fIsomething\fP if no other process is using /dev/ttyS1.
-.LP
-\fBfuser telnet/tcp\fP shows all processes at the (local) TELNET port.
-.SH RESTRICTIONS
-Processes accessing the same file or file system several times in the same way
-are only shown once.
-.PP
-If the same object is specified several times on the command line, some of
-those entries may be ignored.
-.PP
-\fBfuser\fP may only be able to gather partial information unless run with
-privileges. As a consequence, files opened by processes belonging to other
-users may not be listed and executables may be classified as mapped only.
-.PP
-Installing \fBfuser\fP SUID root will avoid problems associated with
-partial information, but may be undesirable for security and privacy
-reasons.
-.PP
-\fBudp\fP and \fBtcp\fP name spaces, and UNIX domain sockets can't be
-searched with kernels older than 1.3.78.
-.PP
-\fBudp\fP and \fBtcp\fP currently only work for IPv4.
-.PP
-Accesses by the kernel are only shown with the \fB-v\fP option.
-.PP
-The \fB-k\fP option only works on processes. If the user is the kernel,
-\fBfuser\fP will print an advice, but take no action beyond that.
-.SH AUTHOR
-Werner Almesberger <Werner.Almesberger@epfl.ch>
-.SH "SEE ALSO"
-kill(1), killall(1), ps(1), kill(2)
-.\"{{{}}}
+++ /dev/null
-/* fuser.c - identify processes using files */
-
-/* Copyright 1993-1999 Werner Almesberger. See file COPYING for details. */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <pwd.h>
-#include <signal.h>
-#include <limits.h>
-#include <netdb.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <linux/kdev_t.h> /* for MKDEV */
-#include <linux/major.h> /* for LOOP_MAJOR */
-
-#include "comm.h"
-#include "signals.h"
-
-
-#define PROC_BASE "/proc"
-#define UID_UNKNOWN -1
-#define NAME_FIELD 20 /* space reserved for file name */
-
-#define MAX_LINE 256 /* longest line we may ever find in /proc */
-
-
-#ifndef LOOP_MAJOR /* don't count on the headers too much ... */
-#define LOOP_MAJOR 7
-#endif
-
-
-#define REF_FILE 1 /* an open file */
-#define REF_ROOT 2 /* current root */
-#define REF_CWD 4 /* current directory */
-#define REF_EXE 8 /* executable */
-#define REF_MMAP 16 /* mmap'ed file or library */
-
-#define FLAG_KILL 1 /* kill process */
-#define FLAG_UID 2 /* show uid */
-#define FLAG_VERB 4 /* show verbose output */
-#define FLAG_DEV 8 /* show all processes using this device */
-#define FLAG_ASK 16 /* ask before killing a process */
-
-
-typedef struct _net_cache {
- int lcl_port;
- int rmt_port;
- unsigned long rmt_addr;
- ino_t ino;
- struct _net_cache *next;
-} NET_CACHE;
-
-typedef struct _unix_cache {
- dev_t fs_dev;
- ino_t fs_ino;
- ino_t net_ino;
- struct _unix_cache *next;
-} UNIX_CACHE;
-
-typedef struct {
- const char *name;
- NET_CACHE *cache;
- int once;
-} SPACE_DSC;
-
-typedef enum { it_proc,it_mount,it_loop,it_swap } ITEM_TYPE;
-
-typedef struct item_dsc {
- ITEM_TYPE type;
- union {
- struct {
- pid_t pid;
- int uid; /* must also accept UID_UNKNOWN */
- int ref_set;
- } proc;
- struct {
- const char *path;
- } misc;
- } u;
- struct item_dsc *next;
-} ITEM_DSC;
-
-typedef struct file_dsc {
- const char *name; /* NULL if previous entry has name */
- dev_t dev;
- ino_t ino;
- int flags,sig_num;
- SPACE_DSC *name_space; /* or NULL if no indication */
- ITEM_DSC *items;
- struct file_dsc *named,*next;
-} FILE_DSC;
-
-static SPACE_DSC name_spaces[] = {
- { "file", NULL, 0 }, /* must be first */
- { "tcp", NULL, 0 },
- { "udp", NULL, 0 },
- { NULL, NULL, 0 }
-};
-
-
-static FILE_DSC *files = NULL;
-static FILE_DSC *last_named = NULL;
-static UNIX_CACHE *unix_cache = NULL;
-static pid_t self;
-static int all = 0,found_item = 0;
-
-
-static void fill_net_cache(SPACE_DSC *dsc)
-{
- FILE *file;
- NET_CACHE *new,*last;
- char buffer[PATH_MAX+1],line[MAX_LINE+1];
-
- if (dsc->once) return;
- dsc->once = 1;
- sprintf(buffer,PROC_BASE "/net/%s",dsc->name);
- if (!(file = fopen(buffer,"r"))) {
- perror(buffer);
- exit(1);
- }
- last = NULL;
- (void) fgets(line,MAX_LINE,file);
- while (fgets(line,MAX_LINE,file)) {
- new = malloc(sizeof(NET_CACHE));
- if (!new) {
- perror("malloc");
- exit(1);
- }
- if (sscanf(line,"%*d: %*x:%x %lx:%x %*x %*x:%*x %*x:%*x %*x %*d %*d "
- "%ld",&new->lcl_port,&new->rmt_addr,&new->rmt_port,&new->ino) != 4) {
- free(new);
- continue;
- }
- if (!new->ino) {
- free(new);
- continue;
- }
- new->next = NULL;
- if (last) last->next = new;
- else dsc->cache = new;
- last = new;
- }
- (void) fclose(file);
-}
-
-
-static void fill_unix_cache(void)
-{
- static int once;
- FILE *file;
- UNIX_CACHE *new,*last;
- struct stat st;
- char path[PATH_MAX+1],line[MAX_LINE+1];
- int ino;
-
- if (once) return;
- once = 1;
- if (!(file = fopen(PROC_BASE "/net/unix","r"))) {
- perror(PROC_BASE "/net/unix");
- exit(1);
- }
- last = NULL;
- (void) fgets(line,MAX_LINE,file);
- while (fgets(line,MAX_LINE,file)) {
- if (sscanf(line,"%*x: %*x %*x %*x %*x %*x %d %s",&ino,path) != 2)
- continue;
- if (stat(path,&st) < 0) continue;
- new = malloc(sizeof(UNIX_CACHE));
- new->fs_dev = st.st_dev;
- new->fs_ino = st.st_ino;
- new->net_ino = ino;
- new->next = NULL;
- if (last) last->next = new;
- else unix_cache = new;
- last = new;
- }
- (void) fclose(file);
-
-}
-
-
-static unsigned long try_to_find_unix_dev(unsigned long inode)
-{
- UNIX_CACHE *walk;
-
- for (walk = unix_cache; walk; walk = walk->next)
- if (walk->net_ino == inode) return walk->fs_dev;
- return 0;
-}
-
-
-static void add_file(const char *path,unsigned long device,unsigned long inode,
- pid_t pid,int ref)
-{
- struct stat st;
- FILE_DSC *file,*next;
- ITEM_DSC **item,*this;
- unsigned long mount_dev;
-
- if (device) mount_dev = device;
- else mount_dev = try_to_find_unix_dev(inode);
- for (file = files; file; file = next) {
- next = file->next;
- if (file->flags & FLAG_DEV ? mount_dev && mount_dev == file->dev :
- device == file->dev && inode == file->ino) {
- if (!file->name) file = file->named;
- for (item = &file->items; *item; item = &(*item)->next)
- if ((*item)->type == it_proc && (*item)->u.proc.pid >= pid)
- break;
- if (*item && (*item)->u.proc.pid == pid) this = *item;
- else {
- if (!(this = malloc(sizeof(ITEM_DSC)))) {
- perror("malloc");
- exit(1);
- }
- this->type = it_proc;
- this->u.proc.pid = pid;
- this->u.proc.uid = UID_UNKNOWN;
- this->u.proc.ref_set = 0;
- this->next = *item;
- *item = this;
- found_item = 1;
- }
- this->u.proc.ref_set |= ref;
- if ((file->flags & (FLAG_UID | FLAG_VERB)) && this->u.proc.uid ==
- UID_UNKNOWN && lstat(path,&st) >= 0) this->u.proc.uid = st.st_uid;
- }
- }
-}
-
-
-static void add_other(ITEM_TYPE type,unsigned long mount_dev,
- unsigned long device,unsigned long inode,const char *path)
-{
- FILE_DSC *file,*next;
- ITEM_DSC **item,*this;
-
- for (file = files; file; file = next) {
- next = file->next;
- if (file->flags & FLAG_DEV ? mount_dev == file->dev :
- device == file->dev && inode == file->ino) {
- if (!file->name) file = file->named;
- for (item = &file->items; *item; item = &(*item)->next);
- /* there's no easy way to suppress duplicates, so we don't */
- if (!(this = malloc(sizeof(ITEM_DSC)))) {
- perror("malloc");
- exit(1);
- }
- this->type = type;
- if (!(this->u.misc.path = strdup(path))) {
- perror("strdup");
- exit(1);
- }
- this->next = *item;
- *item = this;
- found_item = 1;
- }
- }
-}
-
-
-static void check_link(const char *path,pid_t pid,int type)
-{
- struct stat st;
-
- if (stat(path,&st) >= 0)
- add_file(path,st.st_dev,st.st_ino,pid,type);
-}
-
-
-static void check_map(const char *rel,pid_t pid,int type)
-{
- FILE *file;
- char line[MAX_LINE+1];
- int major,minor;
- unsigned long inode;
-
- if (!(file = fopen(rel,"r"))) return;
- while (fgets(line,MAX_LINE,file)) {
- if (sscanf(line,"%*s %*s %*s %x:%x %ld",&major,&minor,&inode) != 3)
- continue;
- if (major || minor || inode)
- add_file(rel,MKDEV(major,minor),inode,pid,type);
- }
- fclose(file);
-}
-
-
-static void check_dir(const char *rel,pid_t pid,int type)
-{
- DIR *dir;
- struct dirent *de;
- char path[PATH_MAX+1];
-
- if (!(dir = opendir(rel))) return;
- while (de = readdir(dir))
- if (strcmp(de->d_name,".") && strcmp(de->d_name,"..")) {
- sprintf(path,"%s/%s",rel,de->d_name);
- check_link(path,pid,type);
- }
- (void) closedir(dir);
-}
-
-
-static void scan_fd(void)
-{
- DIR *dir;
- struct dirent *de;
- char path[PATH_MAX+1];
- pid_t pid;
- int empty;
-
- if (!(dir = opendir(PROC_BASE))) {
- perror(PROC_BASE);
- exit(1);
- }
- empty = 1;
- while (de = readdir(dir))
- if (pid = atoi(de->d_name)) {
- empty = 0;
- sprintf(path,"%s/%d",PROC_BASE,pid);
- if (chdir(path) >= 0) {
- check_link("root",pid,REF_ROOT);
- check_link("cwd",pid,REF_CWD);
- check_link("exe",pid,REF_EXE);
- check_dir("lib",pid,REF_MMAP);
- check_dir("mmap",pid,REF_MMAP);
- check_map("maps",pid,REF_MMAP);
- check_dir("fd",pid,REF_FILE);
- }
- }
- (void) closedir(dir);
- if (empty) {
- fprintf(stderr,PROC_BASE " is empty (not mounted ?)\n");
- exit(1);
- }
-}
-
-
-static void scan_mounts(void)
-{
- FILE *file;
- struct stat st_dev,st_parent,st_mounted;
- char line[MAX_LINE+1],path[PATH_MAX+1],mounted[PATH_MAX+3];
- char tmp[MAX_LINE+1];
- char *end;
-
- if (!(file = fopen(PROC_BASE "/mounts","r"))) return; /* old kernel */
- while (fgets(line,MAX_LINE,file)) {
- if (sscanf(line,"%s %s",path,mounted) != 2) continue;
- /* new kernel :-) */
- if (stat(path,&st_dev) < 0) continue; /* might be NFS or such */
- if (S_ISBLK(st_dev.st_mode) && MAJOR(st_dev.st_rdev) == LOOP_MAJOR) {
- FILE *pipe;
-
- sprintf(tmp,"losetup %s",path);
- if (!(pipe = popen(tmp,"r")))
- fprintf(stderr,"popen(%s) failed\n",tmp);
- else {
- int dev,ino;
-
- if (fscanf(pipe,"%*s [%x]:%d",&dev,&ino) == 2)
- add_other(it_loop,dev,dev,ino,path);
- (void) fclose(pipe);
- }
- }
- if (stat(mounted,&st_mounted) < 0) {
- perror(mounted);
- continue;
- }
- end = strchr(mounted,0);
- strcpy(end,"/..");
- if (stat(mounted,&st_parent) >= 0) {
- *end = 0;
- add_other(it_mount,st_parent.st_dev,st_mounted.st_dev,
- st_mounted.st_ino,mounted);
- }
- }
- (void) fclose(file);
-}
-
-
-static void scan_swaps(void)
-{
- FILE *file;
- struct stat st;
- char line[MAX_LINE+1],path[PATH_MAX+1],type[MAX_LINE+1];
-
- if (!(file = fopen(PROC_BASE "/swaps","r"))) return; /* old kernel */
- (void) fgets(line,MAX_LINE,file);
- while (fgets(line,MAX_LINE,file)) {
- if (sscanf(line,"%s %s",path,type) != 2) continue; /* new kernel :-) */
- if (strcmp(type,"file")) continue;
- if (stat(path,&st) >= 0)
- add_other(it_swap,st.st_dev,st.st_dev,st.st_ino,path);
- }
- (void) fclose(file);
-}
-
-
-static int ask(pid_t pid)
-{
- int ch,c;
-
- fflush(stdout);
- do {
- fprintf(stderr,"Kill process %d ? (y/n) ",pid);
- fflush(stderr);
- do if ((ch = getchar()) == EOF) exit(0);
- while (ch == '\n' || ch == '\t' || ch == ' ');
- do if ((c = getchar()) == EOF) exit(0);
- while (c != '\n');
- }
- while (ch != 'y' && ch != 'n' && ch != 'Y' && ch != 'N');
- return ch == 'y' || ch == 'Y';
-}
-
-
-static void kill_item(const FILE_DSC *file,const ITEM_DSC *item)
-{
- char tmp[10];
-
- switch (item->type) {
- case it_proc:
- if (item->u.proc.pid == self) return;
- if ((file->flags & FLAG_ASK) && !ask(item->u.proc.pid)) return;
- if (kill(item->u.proc.pid,file->sig_num) >= 0) break;
- sprintf(tmp,"kill %d",item->u.proc.pid);
- perror(tmp);
- break;
- case it_mount:
- fprintf(stderr,"No automatic removal. Please use umount %s\n",
- item->u.misc.path);
- break;
- case it_loop:
- fprintf(stderr,"No automatic removal. Please use umount %s\n",
- item->u.misc.path);
- break;
- case it_swap:
- fprintf(stderr,"No automatic removal. Please use swapoff %s\n",
- file->name);
- break;
- }
-}
-
-
-static void show_files_or_kill(void)
-{
- const FILE_DSC *file;
- const ITEM_DSC *item;
- FILE *f;
- const struct passwd *pw;
- const char *user,*scan;
- char tmp[10],path[PATH_MAX+1],comm[COMM_LEN+1];
- int length,header,first,dummy;
- header = 1;
- for (file = files; file; file = file->next)
- if (file->name && (file->items || all)) {
- if (header && (file->flags & FLAG_VERB)) {
- printf("\n%*s USER PID ACCESS COMMAND\n",NAME_FIELD,"");
- header = 0;
- }
- length = 0;
- for (scan = file->name; *scan; scan++)
- if (*scan == '\\') length += printf("\\\\");
- else if (*scan > ' ' && *scan <= '~') {
- putchar(*scan);
- length++;
- }
- else length += printf("\\%03o",*scan);
- if (file->name_space)
- length += printf("/%s",file->name_space->name);
- if (!(file->flags & FLAG_VERB)) {
- putchar(':');
- length++;
- }
- while (length < NAME_FIELD) {
- putchar(' ');
- length++;
- }
- first = 1;
- for (item = file->items; item; item = item->next) {
- if (!(file->flags & FLAG_VERB)) {
- if (item->type != it_proc) continue;
- if (item->u.proc.ref_set & REF_FILE)
- printf("%6d",item->u.proc.pid);
- if (item->u.proc.ref_set & REF_ROOT)
- printf("%6dr",item->u.proc.pid);
- if (item->u.proc.ref_set & REF_CWD)
- printf("%6dc",item->u.proc.pid);
- if (item->u.proc.ref_set & REF_EXE)
- printf("%6de",item->u.proc.pid);
- else if (item->u.proc.ref_set & REF_MMAP)
- printf("%6dm",item->u.proc.pid);
- if ((file->flags & FLAG_UID) && item->u.proc.uid !=
- UID_UNKNOWN)
- if (pw = getpwuid(item->u.proc.uid))
- printf("(%s)",pw->pw_name);
- else printf("(%d)",item->u.proc.uid);
- first = 0;
- }
- else {
- const char *name;
- int uid;
-
- switch (item->type) {
- case it_proc:
- sprintf(path,PROC_BASE "/%d/stat",item->u.proc.pid);
- strcpy(comm,"???");
- if (f = fopen(path,"r")) {
- (void) fscanf(f,"%d (%[^)]",&dummy,comm);
- (void) fclose(f);
- }
- name = comm;
- uid = item->u.proc.uid;
- break;
- case it_mount:
- case it_loop:
- case it_swap:
- name = item->u.misc.path;
- uid = 0;
- break;
- default:
- fprintf(stderr,"Internal error (type %d)\n",
- item->type);
- exit(1);
- }
- if (uid == UID_UNKNOWN) user = "???";
- else if (pw = getpwuid(uid)) user = pw->pw_name;
- else {
- sprintf(tmp,"%d",uid);
- user = tmp;
- }
- if (!first) printf("%*s",NAME_FIELD,"");
- else if (length > NAME_FIELD)
- printf("\n%*s",NAME_FIELD,"");
- printf(" %-8s ",user);
- switch (item->type) {
- case it_proc:
- printf("%6d %c%c%c%c%c ",item->u.proc.pid,
- item->u.proc.ref_set & REF_FILE ? 'f' : '.',
- item->u.proc.ref_set & REF_ROOT ? 'r' : '.',
- item->u.proc.ref_set & REF_CWD ? 'c' : '.',
- item->u.proc.ref_set & REF_EXE ? 'e' : '.',
- (item->u.proc.ref_set & REF_MMAP) &&
- !(item->u.proc.ref_set & REF_EXE) ? 'm' : '.');
- break;
- case it_mount:
- printf("kernel mount ");
- break;
- case it_loop:
- printf("kernel loop ");
- break;
- case it_swap:
- printf("kernel swap ");
- break;
- }
- if (name)
- for (scan = name; *scan; scan++)
- if (*scan == '\\') printf("\\\\");
- else if (*scan > ' ' && *scan <= '~')
- putchar(*scan);
- else printf("\\%03o",(unsigned char) *scan);
- putchar('\n');
- }
- first = 0;
- }
- if (!(file->flags & FLAG_VERB) || first) putchar('\n');
- if (first)
- fprintf(stderr,"No process references; use -v for the complete"
- " list\n");
- if (file->flags & FLAG_KILL)
- for (item = file->items; item; item = item->next)
- kill_item(file,item);
- }
-}
-
-
-static void kill_files(void)
-{
- const FILE_DSC *file;
- const ITEM_DSC *item;
-
- for (file = files; file; file = file->next)
- if (file->flags & FLAG_KILL)
- for (item = file->items; item; item = item->next)
- kill_item(file,item);
-}
-
-
-static void enter_item(const char *name,int flags,int sig_number,dev_t dev,
- ino_t ino,SPACE_DSC *name_space)
-{
- static FILE_DSC *last = NULL;
- FILE_DSC *new;
-
- if (!(new = malloc(sizeof(FILE_DSC)))) {
- perror("malloc");
- exit(1);
- }
- if (last_named && !strcmp(last_named->name,name) &&
- last_named->name_space == name_space) new->name = NULL;
- else if (!(new->name = strdup(name))) {
- perror("strdup");
- exit(1);
- }
- new->flags = flags;
- new->sig_num = sig_number;
- new->items = NULL;
- new->next = NULL;
- new->dev = dev;
- new->ino = ino;
- new->name_space = name_space;
- if (last) last->next = new;
- else files = new;
- last = new;
- new->named = last_named;
- if (new->name) last_named = new;
-}
-
-
-static int parse_inet(const char *spec,const char *name_space,int *lcl_port,
- unsigned long *rmt_addr,int *rmt_port)
-{
- char *s,*here,*next,*end;
- int port,field;
-
- if (!(s = strdup(spec))) {
- perror("strdup");
- exit(1);
- }
- *lcl_port = *rmt_port = -1;
- *rmt_addr = 0;
- field = 0;
- for (here = s; here; here = next ? next+1 : NULL) {
- next = strchr(here,',');
- if (next) *next = 0;
- switch (field) {
- case 0:
- /* fall through */
- case 2:
- if (!*here) break;
- port = strtoul(here,&end,0);
- if (*end) {
- struct servent *se;
-
- if (!(se = getservbyname(here,name_space)))
- return 0;
- port = ntohs(se->s_port);
- }
- if (field) *rmt_port = port;
- else *lcl_port = port;
- break;
- case 1:
- if (!*here) break;
- if ((long) (*rmt_addr = inet_addr(here)) == -1) {
- struct hostent *hostent;
-
- if (!(hostent = gethostbyname(here))) return 0;
- if (hostent->h_addrtype != AF_INET) return 0;
- memcpy(rmt_addr,hostent->h_addr,hostent->h_length);
- }
- break;
- default:
- return 0;
- }
- field++;
- }
- return 1;
-}
-
-
-static void usage(void)
-{
- fprintf(stderr,"usage: fuser [ -a | -s ] [ -n space ] [ -signal ] "
- "[ -kimuv ] name ...\n%13s[ - ] [ -n space ] [ -signal ] [ -kimuv ] "
- "name ...\n","");
- fprintf(stderr," fuser -l\n");
- fprintf(stderr," fuser -V\n\n");
- fprintf(stderr," -a display unused files too\n");
- fprintf(stderr," -k kill processes accessing that file\n");
- fprintf(stderr," -i ask before killing (ignored without -k)\n");
- fprintf(stderr," -l list signal names\n");
- fprintf(stderr," -m mounted FS\n");
- fprintf(stderr," -n space search in the specified name space (file, "
- "udp, or tcp)\n");
- fprintf(stderr," -s silent operation\n");
- fprintf(stderr," -signal send signal instead of SIGKILL\n");
- fprintf(stderr," -u display user ids\n");
- fprintf(stderr," -v verbose output\n");
- fprintf(stderr," -V display version information\n");
- fprintf(stderr," - reset options\n\n");
- fprintf(stderr," udp/tcp names: [local_port][,[rmt_host][,[rmt_port]]]"
- "\n\n");
- exit(1);
-}
-
-
-int main(int argc,char **argv)
-{
- SPACE_DSC *name_space;
- char path[PATH_MAX+1];
- int flags,silent,do_kill,sig_number,no_files;
-
- flags = silent = do_kill = 0;
- sig_number = SIGKILL;
- name_space = name_spaces;
- no_files = 1;
- if (argc < 2) usage();
- if (argc == 2 && !strcmp(argv[1],"-l")) {
- list_signals();
- return 0;
- }
- while (--argc) {
- argv++;
- if (**argv == '-')
- if (!argv[0][1]) {
- flags = 0;
- sig_number = SIGKILL;
- }
- else while (*++*argv) {
- int end;
-
- end = 0;
- switch (**argv) {
- case 'a':
- all = 1;
- break;
- case 'k':
- flags |= FLAG_KILL;
- do_kill = 1;
- break;
- case 'i':
- flags |= FLAG_ASK;
- break;
- case 'm':
- flags |= FLAG_DEV;
- break;
- case 'n':
- if (!--argc) usage();
- argv++;
- for (name_space = name_spaces; name_space->name;
- name_space++)
- if (!strcmp(*argv,name_space->name)) break;
- if (!name_space->name) usage();
- end = 1;
- break;
- case 's':
- silent = 1;
- break;
- case 'u':
- flags |= FLAG_UID;
- break;
- case 'v':
- flags |= FLAG_VERB;
- break;
- case 'V':
- fprintf(stderr,"fuser from psmisc version "
- PSMISC_VERSION "\n");
- return 0;
- default:
- if (isupper(**argv) || isdigit(**argv)) {
- sig_number = get_signal(*argv,"fuser");
- argv[0][1] = 0;
- break;
- }
- usage();
- }
- if (end) break;
- }
- else {
- SPACE_DSC *this_name_space;
- struct stat st;
- char *here;
-
- no_files = 0;
- last_named = NULL;
- this_name_space = name_space;
- if (name_space != name_spaces || stat(*argv,&st) < 0) {
- here = strchr(*argv,'/');
- if (here && here != *argv) {
- for (this_name_space = name_spaces; this_name_space->name;
- this_name_space++)
- if (!strcmp(here+1,this_name_space->name)) {
- *here = 0;
- break;
- }
- if (!this_name_space->name) this_name_space = name_spaces;
- }
- }
- if (this_name_space == name_spaces) {
- if (stat(*argv,&st) < 0) {
- perror(*argv);
- continue;
- }
- if (flags & FLAG_DEV)
- if (S_ISBLK(st.st_mode)) st.st_dev = st.st_rdev;
- else if (S_ISDIR(st.st_mode)) {
- sprintf(path,"%s/.",*argv);
- if (stat(*argv,&st) < 0) {
- perror(*argv);
- continue;
- }
- }
- if (S_ISSOCK(st.st_mode) || (flags & FLAG_DEV))
- fill_unix_cache();
- if (!S_ISSOCK(st.st_mode) || (flags & FLAG_DEV))
- enter_item(*argv,flags,sig_number,st.st_dev,st.st_ino,NULL);
- else {
- UNIX_CACHE *walk;
-
- for (walk = unix_cache; walk; walk = walk->next)
- if (walk->fs_dev == st.st_dev && walk->fs_ino ==
- st.st_ino)
- enter_item(*argv,flags,sig_number,0,walk->net_ino,
- NULL);
- }
- }
- else {
- NET_CACHE *walk;
- unsigned long rmt_addr;
- int lcl_port,rmt_port;
-
- if (flags & FLAG_DEV) {
- fprintf(stderr,"ignoring -m in name space \"%s\"\n",
- this_name_space->name);
- flags &= ~FLAG_DEV;
- }
- fill_net_cache(this_name_space);
- if (!parse_inet(*argv,this_name_space->name,&lcl_port,
- &rmt_addr,&rmt_port)) {
- fprintf(stderr,"%s/%s: invalid specificiation\n",*argv,
- this_name_space->name);
- continue;
- }
- for (walk = this_name_space->cache; walk; walk = walk->next)
- if ((lcl_port == -1 || walk->lcl_port == lcl_port) &&
- (!rmt_addr || walk->rmt_addr == rmt_addr) &&
- (rmt_port == -1 || walk->rmt_port == rmt_port))
- enter_item(*argv,flags,sig_number,0,walk->ino,
- this_name_space);
- }
- }
- }
- if (no_files || (all && silent)) usage();
- scan_fd();
- scan_mounts();
- scan_swaps();
- if (do_kill && seteuid(getuid()) < 0) {
- perror("seteuid");
- return 1;
- }
- self = getpid();
- if (silent) kill_files();
- else show_files_or_kill();
- return found_item ? 0 : 1;
-}
+++ /dev/null
-.TH KILLALL 1 "Sep 7, 1999" "Linux" "User Commands"
-.SH NAME
-killall \- kill processes by name
-.SH SYNOPSIS
-.ad l
-.B killall
-.RB [ \-egiqvw ]
-.RB [ \-\fIsignal\fB ]
-.I name ...
-.br
-.B killall
-.RB \-l
-.br
-.B killall
-.RB \-V
-.ad b
-.SH DESCRIPTION
-.B killall
-sends a signal to all processes running any of the specified commands. If no
-signal name is specified, SIGTERM is sent.
-.PP
-Signals can be specified either by name (e.g. \fB\-HUP\fP) or by number
-(e.g. \fB\-1\fP). Signal 0 (check if a process exists) can only be specified
-by number.
-.PP
-If the command name contains a slash (\fB/\fP), processes executing that
-particular file will be selected for killing, independent of their name.
-.PP
-\fBkillall\fP returns a non-zero return code if no process has been killed
-for any of the listed commands. If at least one process has been killed for
-each command, \fBkillall\fP returns zero.
-.PP
-A \fBkillall\fP process never kills itself (but may kill other \fBkillall\fP
-processes).
-.SH OPTIONS
-.IP \fB\-e\fP
-Require an exact match for very long names. If a command name is longer
-than 15 characters, the full name may be unavailable (i.e. it is swapped
-out). In this case, \fBkillall\fP will kill everything that matches within
-the first 15 characters. With \fB\-e\fP, such entries are skipped.
-\fBkillall\fP prints a message for each skipped entry
-if \fB\-v\fP is specified in addition to \fB\-e\fP,
-.IP \fB\-g\fP
-Kill the process group to which the process belongs. The kill signal is only
-sent once per group, even if multiple processes belonging to the same process
-group were found.
-.IP \fB\-i\fP
-Interactively ask for confirmation before killing.
-.IP \fB\-l\fP
-List all known signal names.
-.IP \fB\-q\fP
-Do not complain if no processes were killed.
-.IP \fB\-v\fP
-Report if the signal was successfully sent.
-.IP \fB\-V\fP
-Display version information.
-.IP \fB\-w\fP
-Wait for all killed processes to die. \fBkillall\fP checks once per second if
-any of the killed processes still exist and only returns if none are left.
-Note that \fBkillall\fP may wait forever if the signal was ignored, had no
-effect, or if the process stays in zombie state.
-.SH FILES
-.nf
-/proc location of the proc file system
-.fi
-.SH "KNOWN BUGS"
-Killing by file only works for executables that are kept open during
-execution, i.e. impure executables can't be killed this way.
-.PP
-Be warned that typing \fBkillall\fP \fIname\fP may not have the desired
-effect on non-Linux systems, especially when done by a privileged
-user.
-.PP
-\fBkillall \-w\fP doesn't detect if a process disappears and is replaced by
-a new process with the same PID between scans.
-.SH AUTHOR
-Werner Almesberger <Werner.Almesberger@epfl.ch>
-.SH "SEE ALSO"
-kill(1), fuser(1), pidof(1), ps(1), kill(2)
-.\"{{{}}}
+++ /dev/null
-/* killall.c - kill processes by name or list PIDs */
-
-/* Copyright 1993-1998 Werner Almesberger. See file COPYING for details. */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <signal.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "comm.h"
-#include "signals.h"
-
-
-#define PROC_BASE "/proc"
-#define MAX_NAMES (sizeof(unsigned long)*8)
-
-
-static int verbose = 0,exact = 0,interactive = 0,quiet = 0,wait_until_dead = 0,
- process_group = 0,pidof;
-
-
-static int ask(char *name,pid_t pid)
-{
- int ch,c;
-
- do {
- printf("Kill %s(%s%d) ? (y/n) ",name,process_group ? "pgid " : "",pid);
- fflush(stdout);
- do if ((ch = getchar()) == EOF) exit(0);
- while (ch == '\n' || ch == '\t' || ch == ' ');
- do if ((c = getchar()) == EOF) exit(0);
- while (c != '\n');
- }
- while (ch != 'y' && ch != 'n' && ch != 'Y' && ch != 'N');
- return ch == 'y' || ch == 'Y';
-}
-
-
-static int kill_all(int signal,int names,char **namelist)
-{
- DIR *dir;
- struct dirent *de;
- FILE *file;
- struct stat st,sts[MAX_NAMES];
- int *name_len;
- char path[PATH_MAX+1],comm[COMM_LEN];
- char command_buf[PATH_MAX+1];
- char *command;
- pid_t *pid_table,pid,self,*pid_killed;
- pid_t *pgids;
- int empty,i,j,okay,length,got_long,error;
- int pids,max_pids,pids_killed;
- unsigned long found;
-
- if (!(name_len = malloc(sizeof(int)*names))) {
- perror("malloc");
- exit(1);
- }
- for (i = 0; i < names; i++)
- if (!strchr(namelist[i],'/')) {
- sts[i].st_dev = 0;
- name_len[i] = strlen(namelist[i]);
- }
- else if (stat(namelist[i],&sts[i]) < 0) {
- perror(namelist[i]);
- exit(1);
- }
- self = getpid();
- found = 0;
- if (!(dir = opendir(PROC_BASE))) {
- perror(PROC_BASE);
- exit(1);
- }
- max_pids = 256;
- pid_table = malloc(max_pids*sizeof(pid_t));
- if (!pid_table) {
- perror("malloc");
- exit(1);
- }
- pids = 0;
- while (de = readdir(dir)) {
- if (!(pid = atoi(de->d_name)) || pid == self) continue;
- if (pids == max_pids) {
- if (!(pid_table = realloc(pid_table,2*pids*sizeof(pid_t)))) {
- perror("realloc");
- exit(1);
- }
- max_pids *= 2;
- }
- pid_table[pids++] = pid;
- }
- (void) closedir(dir);
- empty = 1;
- pids_killed = 0;
- pid_killed = malloc(max_pids*sizeof(pid_t));
- if (!pid_killed) {
- perror("malloc");
- exit(1);
- }
- if (!process_group) pgids = NULL; /* silence gcc */
- else {
- pgids = malloc(pids*sizeof(pid_t));
- if (!pgids) {
- perror("malloc");
- exit(1);
- }
- }
- for (i = 0; i < pids; i++) {
- sprintf(path,PROC_BASE "/%d/stat",pid_table[i]);
- if (!(file = fopen(path,"r"))) continue;
- empty = 0;
- okay = fscanf(file,"%*d (%[^)]",comm) == 1;
- (void) fclose(file);
- if (!okay) continue;
- got_long = 0;
- command = NULL; /* make gcc happy */
- length = strlen(comm);
- if (length == COMM_LEN-1) {
- sprintf(path,PROC_BASE "/%d/cmdline",pid_table[i]);
- if (!(file = fopen(path,"r"))) continue;
- okay = fscanf(file,"%s",command_buf) == 1;
- (void) fclose(file);
- if (exact && !okay) {
- if (verbose)
- fprintf(stderr,"skipping partial match %s(%d)\n",comm,
- pid_table[i]);
- continue;
- }
- got_long = okay;
- if (okay) {
- command = strrchr(command_buf,'/');
- if (command) command++;
- else command = command_buf;
- }
- }
- for (j = 0; j < names; j++) {
- pid_t id;
-
- if (!sts[j].st_dev) {
- if (length != COMM_LEN-1 || name_len[j] < COMM_LEN-1) {
- if (strcmp(namelist[j],comm)) continue;
- }
- else if (got_long ? strcmp(namelist[j],command) :
- strncmp(namelist[j],comm,COMM_LEN-1)) continue;
- }
- else {
- sprintf(path,PROC_BASE "/%d/exe",pid_table[i]);
- if (stat(path,&st) < 0) continue;
- if (sts[j].st_dev != st.st_dev || sts[j].st_ino != st.st_ino)
- continue;
- }
- if (!process_group) id = pid_table[i];
- else {
- int j;
-
- id = getpgid(pid_table[i]);
- pgids[i] = id;
- if (id < 0) {
- fprintf(stderr,"getpgid(%d): %s\n",pid_table[i],
- strerror(errno));
- }
- for (j = 0; j < i; j++)
- if (pgids[j] == id) break;
- if (j < i) continue;
- }
- if (interactive && !ask(comm,id)) continue;
- if (pidof) {
- if (found) putchar(' ');
- printf("%d",id);
- found |= 1 << j;
- }
- else if (kill(process_group ? -id : id,signal) >= 0) {
- if (verbose)
- fprintf(stderr,"Killed %s(%s%d)\n",got_long ? command :
- comm,process_group ? "pgid " : "",id);
- found |= 1 << j;
- pid_killed[pids_killed++] = id;
- }
- else if (errno != ESRCH || interactive)
- fprintf(stderr,"%s(%d): %s\n",got_long ? command :
- comm,id,strerror(errno));
- }
- }
- if (empty) {
- fprintf(stderr,PROC_BASE " is empty (not mounted ?)\n");
- exit(1);
- }
- if (!quiet && !pidof)
- for (i = 0; i < names; i++)
- if (!(found & (1 << i)))
- fprintf(stderr,"%s: no process killed\n",namelist[i]);
- if (pidof) putchar('\n');
- error = found == ((1 << (names-1)) | ((1 << (names-1))-1)) ? 0 : 1;
- /*
- * We scan all (supposedly) killed processes every second to detect dead
- * processes as soon as possible in order to limit problems of race with
- * PID re-use.
- */
- while (pids_killed && wait_until_dead) {
- for (i = 0; i < pids_killed;) {
- if (kill(process_group ? -pid_killed[i] : pid_killed[i],0) < 0 &&
- errno == ESRCH) {
- pid_killed[i] = pid_killed[--pids_killed];
- continue;
- }
- i++;
- }
- sleep(1); /* wait a bit longer */
- }
- return error;
-}
-
-
-static void usage_pidof(void)
-{
- fprintf(stderr,"usage: pidof [ -eg ] name ...\n");
- fprintf(stderr," pidof -V\n\n");
- fprintf(stderr," -e require exact match for very long names;\n");
- fprintf(stderr," skip if the command line is unavailable\n");
- fprintf(stderr," -g show process group ID instead of process ID\n");
- fprintf(stderr," -V display version information\n\n");
-}
-
-
-static void usage_killall(void)
-{
- fprintf(stderr,"usage: killall [ -egiqvw ] [ -signal ] name ...\n");
- fprintf(stderr," killall -l\n");
- fprintf(stderr," killall -V\n\n");
- fprintf(stderr," -e require exact match for very long names;\n");
- fprintf(stderr," skip if the command line is unavailable\n");
- fprintf(stderr," -g kill process group instead of process\n");
- fprintf(stderr," -i ask for confirmation before killing\n");
- fprintf(stderr," -l list all known signal names\n");
- fprintf(stderr," -q quiet; don't print complaints\n");
- fprintf(stderr," -signal send signal instead of SIGTERM\n");
- fprintf(stderr," -v report if the signal was successfully sent\n");
- fprintf(stderr," -V display version information\n");
- fprintf(stderr," -w wait for processes to die\n\n");
-}
-
-
-static void usage(void)
-{
- if (pidof) usage_pidof();
- else usage_killall();
- exit(1);
-}
-
-
-int main(int argc,char **argv)
-{
- char *name,*walk;
- int sig_num;
-
- name = strrchr(*argv,'/');
- if (name) name++;
- else name = *argv;
- pidof = strcmp(name,"killall");
- if (argc == 2 && !strcmp(argv[1],"-l")) {
- if (pidof) usage();
- list_signals();
- return 0;
- }
- if (argc == 2 && !strcmp(argv[1],"-V")) {
- fprintf(stderr,"%s from psmisc version " PSMISC_VERSION "\n",
- pidof ? "pidof" : "killall");
- return 0;
- }
- sig_num = SIGTERM;
- while (argc > 1 && *argv[1] == '-') {
- argc--;
- argv++;
- if (**argv == '-') {
- for (walk = *argv+1; *walk && strchr("eigqvw",*walk); walk++) {
- switch (*walk) {
- case 'e':
- exact = 1;
- break;
- case 'i':
- if (pidof) usage();
- interactive = 1;
- break;
- case 'g':
- process_group = 1;
- break;
- case 'q':
- if (pidof) usage();
- quiet = 1;
- break;
- case 'v':
- if (pidof) usage();
- verbose = 1;
- break;
- case 'w':
- if (pidof) usage();
- wait_until_dead = 1;
- break;
- }
- }
- if (*walk)
- if (walk != *argv+1 || pidof) usage();
- else sig_num = get_signal(*argv+1,"killall");
- }
- }
- if (argc < 2) usage();
- if (argc > MAX_NAMES+1) {
- fprintf(stderr,"Maximum number of names is %d\n",MAX_NAMES);
- exit(1);
- }
- return kill_all(sig_num,argc-1,argv+1);
-}
+++ /dev/null
-#!/bin/sh
-VERSION=`cat ./VERSION`
-cd ..
-tar cvf - psmisc/VERSION psmisc/README psmisc/INSTALL psmisc/CHANGES \
- psmisc/COPYING psmisc/psmisc-$VERSION.lsm \
- psmisc/Makefile psmisc/comm.h psmisc/signals.h \
- psmisc/*.[c1] psmisc/mkdist | gzip -9 >psmisc-$VERSION.tar.gz
+++ /dev/null
-.TH PIDOF 1 "May 6, 1998" "Linux" "User Commands"
-.SH NAME
-pidof \- finds processes by name and lists their PIDs
-.SH SYNOPSIS
-.ad l
-.B pidif
-.RB [ \-eg ]
-.I name ...
-.br
-.B pidof
-.RB \-V
-.ad b
-.SH DESCRIPTION
-.B pidof
-lists the PIDs of all processes running any of the specified commands.
-.PP
-If the command name contains a slash (\fB/\fP), processes executing that
-particular file will be selected, independent of their name.
-.PP
-\fBpidof\fP returns a non-zero return code if no process has been found
-for any of the listed commands. If at least one process has been found for
-each command, \fBpidof\fP returns zero.
-.SH OPTIONS
-.IP \fB\-e\fP
-Require an exact match for very long names. If a command name is longer
-than 15 characters, the full name may be unavailable (i.e. it is swapped
-out). In this case, \fBpidof\fP will list everything that matches within
-the first 15 characters. With \fB\-e\fP, such entries are silently skipped.
-.IP \fB\-g\fP
-Show process group IDs instead of process IDs. If multiple processes with
-the same process group ID were found, only the first process is shown.
-.IP \fB\-V\fP
-Display version information.
-.SH FILES
-.nf
-/proc location of the proc file system
-.fi
-.SH "KNOWN BUGS"
-Selection by file only works for executables that are kept open during
-execution, i.e. impure executables can't be selected this way.
-.SH AUTHOR
-Werner Almesberger <Werner.Almesberger@epfl.ch>
-.SH "SEE ALSO"
-killall(1), fuser(1), ps(1)
-.\"{{{}}}
+++ /dev/null
-Begin3
-Title: psmisc
-Version: 19
-Entered-date: 25OCT99
-Description: miscellaneous proc FS tools: fuser, killall, pidof, and pstree
-Keywords: psmisc, fuser, killall, pidof, pstree
-Author: Werner Almesberger <Werner.Almesberger@epfl.ch>
-Maintained-by: Werner Almesberger <Werner.Almesberger@epfl.ch>
-Primary-site: lrcftp.epfl.ch /pub/linux/local/psmisc
- 21 kB psmisc-19.tar.gz
-Alternate-site: sunsite.unc.edu /pub/Linux/system/status/ps
-Platforms: Should work with most kernels. Requires /proc
-Copying-policy: BSD-like
-End
+++ /dev/null
-.TH PSTREE 1 "May 6, 1998" "Linux" "User Commands"
-.SH NAME
-pstree \- display a tree of processes
-.SH SYNOPSIS
-.ad l
-.B pstree
-.RB [ \-a ]
-.RB [ \-c ]
-.RB [ \-h | \-H \fIpid\fB ]
-.RB [ \-l ]
-.RB [ \-n ]
-.RB [ \-p ]
-.RB [ \-u ]
-.RB [ \-G | \-U ]
-.RB [ \fIpid\fB | \fIuser\fB]
-.br
-.B pstree
-.RB \-V
-.ad b
-.SH DESCRIPTION
-.B pstree
-shows running processes as a tree. The tree is rooted at either
-\fIpid\fP or \fBinit\fP if \fIpid\fP is omitted. If a user name is specified,
-all process trees rooted at processes owned by that user are shown.
-.PP
-\fBpstree\fP visually merges identical branches by putting them in square
-brackets and prefixing them with the repetition count, e.g.
-.nf
-.sp
- init\-+\-getty
- |\-getty
- |\-getty
- `-getty
-.sp
-.fi
-becomes
-.nf
-.sp
- init\-\-\-4*[getty]
-.sp
-.fi
-.SH OPTIONS
-.IP \fB\-a\fP
-Show command line arguments. If the command line of a process is swapped out,
-that process is shown in parentheses. \fB\-a\fP implicitly disables compaction.
-.IP \fB\-c\fP
-Disable compaction of identical subtrees. By default, subtrees are compacted
-whenever possible.
-.IP \fB\-G\fP
-Use VT100 line drawing characters.
-.IP \fB\-h\fP
-Highlight the current process and its ancestors. This is a no-op if the
-terminal doesn't support highlighting or if neither the current process
-nor any of its ancestors are in the subtree being shown.
-.IP \fB\-H\fP
-Like \fB\-h\fP, but highlight the specified process instead. Unlike with
-\fB\-h\fP, \fBpstree\fP fails when using \fB\-H\fP if highlighting is not
-available.
-.IP \fB\-l\fP
-Display long lines. By default, lines are truncated to the display width or
-132 if output is sent to a non-tty or if the display width is unknown.
-.IP \fB\-n\fP
-Sort processes with the same ancestor by PID instead of by name. (Numeric
-sort.)
-.IP \fB\-p\fP
-Show PIDs. PIDs are shown as decimal numbers in parentheses after each
-process name. \fB\-p\fP implicitly disables compaction.
-.IP \fB\-u\fP
-Show uid transitions. Whenever the uid of a process differs from the uid of
-its parent, the new uid is shown in parentheses after the process name.
-.IP \fB\-U\fP
-Use UTF-8 (Unicode) line drawing characters. Under Linux 1.1-54 and above,
-UTF-8 mode is entered on the console with \fBecho -e '\\033%8'\fP and left
-with \fBecho -e '\\033%@'\fP
-.IP \fB\-V\fP
-Display version information.
-.SH FILES
-.nf
-/proc location of the proc file system
-.fi
-.SH AUTHOR
-Werner Almesberger <Werner.Almesberger@epfl.ch>
-.SH "SEE ALSO"
-ps(1), top(1)
-.\"{{{}}}
+++ /dev/null
-/* pstree.c - display process tree */
-
-/* Copyright 1993-1999 Werner Almesberger. See file COPYING for details. */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <pwd.h>
-#include <dirent.h>
-#include <termios.h>
-#include <termcap.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#include "comm.h"
-
-
-#ifndef MAX_DEPTH
-#define MAX_DEPTH 100
-#endif
-#define PROC_BASE "/proc"
-
-/* UTF-8 defines by Johan Myreen */
-#define UTF_V "\342\224\202\277" /* Vertical line drawing char */
-#define UTF_VR "\342\224\234\277" /* Vertical and right */
-#define UTF_H "\342\224\200\277" /* Horizontal */
-#define UTF_UR "\342\224\224\277" /* Up and right */
-#define UTF_HD "\342\224\254\277" /* Horizontal and down */
-
-#define VT_BEG "\033(0\017" /* use graphic chars */
-#define VT_END "\033(B" /* back to normal char set */
-#define VT_V "x" /* see UTF definitions above */
-#define VT_VR "t"
-#define VT_H "q"
-#define VT_UR "m"
-#define VT_HD "w"
-
-typedef struct _proc {
- char comm[COMM_LEN+1];
- char **argv; /* only used : argv[0] is 1st arg; undef if argc < 1 */
- int argc; /* with -a : number of arguments, -1 if swapped */
- pid_t pid;
- uid_t uid;
- int highlight;
- struct _child *children;
- struct _proc *parent;
- struct _proc *next;
-} PROC;
-
-typedef struct _child {
- PROC *child;
- struct _child *next;
-} CHILD;
-
-static struct {
- const char *empty_2; /* */
- const char *branch_2; /* |- */
- const char *vert_2; /* | */
- const char *last_2; /* `- */
- const char *single_3; /* --- */
- const char *first_3; /* -+- */
-} sym_ascii = { " ",
- "|-",
- "| ",
- "`-",
- "---",
- "-+-" },
- sym_utf = { " ",
- UTF_VR UTF_H,
- UTF_V " ",
- UTF_UR UTF_H,
- UTF_H UTF_H UTF_H,
- UTF_H UTF_HD UTF_H },
- sym_vt100 = { " ",
- VT_BEG VT_VR VT_H VT_END,
- VT_BEG VT_V VT_END " ",
- VT_BEG VT_UR VT_H VT_END,
- VT_BEG VT_H VT_H VT_H VT_END,
- VT_BEG VT_H VT_HD VT_H VT_END },
- *sym = &sym_ascii;
-
-static PROC *list = NULL;
-static int width[MAX_DEPTH],more[MAX_DEPTH];
-static int print_args = 0,compact = 1,user_change = 0,pids = 0,by_pid = 0,
- trunc = 1;
-static int output_width = 132;
-static int cur_x = 1;
-static char last_char = 0;
-static int dumped = 0; /* used by dump_by_user */
-
-
-static void out_char(char c)
-{
- cur_x += (c & 0xc0) != 0x80; /* only count first UTF-8 char */
- if (cur_x <= output_width || !trunc) putchar(c);
- if (cur_x == output_width+1 && trunc)
- if (last_char || (c & 0x80)) putchar('+');
- else {
- last_char = c;
- cur_x--;
- return;
- }
-}
-
-
-static void out_string(const char *str)
-{
- while (*str) out_char(*str++);
-}
-
-
-static int out_int(int x) /* non-negative integers only */
-{
- int digits,div;
-
- digits = 0;
- for (div = 1; x/div; div *= 10) digits++;
- if (!digits) digits = 1;
- for (div /= 10; div; div /= 10) out_char('0'+(x/div) % 10);
- return digits;
-}
-
-
-static void out_newline(void)
-{
- if (last_char && cur_x == output_width) putchar(last_char);
- last_char = 0;
- putchar('\n');
- cur_x = 1;
-}
-
-
-static PROC *find_proc(pid_t pid)
-{
- PROC *walk;
-
- for (walk = list; walk; walk = walk->next)
- if (walk->pid == pid) break;
- return walk;
-}
-
-
-static PROC *new_proc(const char *comm,pid_t pid,uid_t uid)
-{
- PROC *new;
-
- if (!(new = malloc(sizeof(PROC)))) {
- perror("malloc");
- exit(1);
- }
- strcpy(new->comm,comm);
- new->pid = pid;
- new->uid = uid;
- new->highlight = 0;
- new->children = NULL;
- new->parent = NULL;
- new->next = list;
- return list = new;
-}
-
-
-static void add_child(PROC *parent,PROC *child)
-{
- CHILD *new,**walk;
- int cmp;
-
- if (!(new = malloc(sizeof(CHILD)))) {
- perror("malloc");
- exit(1);
- }
- new->child = child;
- for (walk = &parent->children; *walk; walk = &(*walk)->next)
- if (by_pid) {
- if ((*walk)->child->pid > child->pid) break;
- }
- else if ((cmp = strcmp((*walk)->child->comm,child->comm)) > 0) break;
- else if (!cmp && (*walk)->child->uid > child->uid) break;
- new->next = *walk;
- *walk = new;
-}
-
-
-static void set_args(PROC *this,const char *args,int size)
-{
- char *start;
- int i;
-
- if (!size) {
- this->argc = -1;
- return;
- }
- this->argc = 0;
- for (i = 0; i < size-1; i++)
- if (!args[i]) this->argc++;
- if (!this->argc) return;
- if (!(this->argv = malloc(sizeof(char *)*this->argc))) {
- perror("malloc");
- exit(1);
- }
- start = strchr(args,0)+1;
- size -= start-args;
- if (!(this->argv[0] = malloc((size_t) size))) {
- perror("malloc");
- exit(1);
- }
- start = memcpy(this->argv[0],start,(size_t) size);
- for (i = 1; i < this->argc; i++) this->argv[i] = start = strchr(start,0)+1;
-}
-
-
-static void add_proc(const char *comm,pid_t pid,pid_t ppid,uid_t uid,
- const char *args,int size)
-{
- PROC *this,*parent;
-
- if (!(this = find_proc(pid))) this = new_proc(comm,pid,uid);
- else {
- strcpy(this->comm,comm);
- this->uid = uid;
- }
- if (args) set_args(this,args,size);
- if (pid == ppid) ppid = 0;
- if (!(parent = find_proc(ppid))) parent = new_proc("?",ppid,0);
- add_child(parent,this);
- this->parent = parent;
-}
-
-
-static int tree_equal(const PROC *a,const PROC *b)
-{
- const CHILD *walk_a,*walk_b;
-
- if (strcmp(a->comm,b->comm)) return 0;
- if (user_change && a->uid != b->uid) return 0;
- for (walk_a = a->children, walk_b = b->children; walk_a && walk_b;
- walk_a = walk_a->next, walk_b = walk_b->next)
- if (!tree_equal(walk_a->child,walk_b->child)) return 0;
- return !(walk_a || walk_b);
-}
-
-
-static void dump_tree(PROC *current,int level,int rep,int leaf,int last,
- uid_t prev_uid,int closing)
-{
- CHILD *walk,*next,**scan;
- const struct passwd *pw;
- int lvl,i,add,offset,len,swapped,info,count,comm_len,first;
- const char *tmp,*here;
- char comm_tmp[5];
-
- if (!current) return;
- if (level >= MAX_DEPTH-1) {
- fprintf(stderr,"MAX_DEPTH not big enough.\n");
- exit(1);
- }
- if (!leaf)
- for (lvl = 0; lvl < level; lvl++) {
- for (i = width[lvl]+1; i; i--) out_char(' ');
- out_string(lvl == level-1 ? last ? sym->last_2 : sym->branch_2 :
- more[lvl+1] ? sym->vert_2 : sym->empty_2);
- }
- if (rep < 2) add = 0;
- else {
- add = out_int(rep)+2;
- out_string("*[");
- }
- if (current->highlight && (tmp = tgetstr("md",NULL))) tputs(tmp,1,putchar);
- if (swapped = print_args && current->argc < 0) out_char('(');
- comm_len = 0;
- for (here = current->comm; *here; here++)
- if (*here == '\\') {
- out_string("\\\\");
- comm_len += 2;
- }
- else if (*here > ' ' && *here <= '~') {
- out_char(*here);
- comm_len++;
- }
- else {
- sprintf(comm_tmp,"\\%03o",(unsigned char) *here);
- out_string(comm_tmp);
- comm_len += 4;
- }
- offset = cur_x;
- info = pids || (user_change && prev_uid != current->uid);
- if (info) out_char(swapped ? ',' : '(');
- if (pids) (void) out_int(current->pid);
- if (user_change && prev_uid != current->uid) {
- if (pids) out_char(',');
- if ((pw = getpwuid(current->uid))) out_string(pw->pw_name);
- else (void) out_int(current->uid);
- }
- if (info || swapped) out_char(')');
- if (current->highlight && (tmp = tgetstr("me",NULL))) tputs(tmp,1,putchar);
- if (print_args) {
- for (i = 0; i < current->argc; i++) {
- out_char(' ');
- len = 0;
- for (here = current->argv[i]; *here; here++)
- len += *here > ' ' && *here <= '~' ? 1 : 4;
- if (cur_x+len <= output_width-(i == current->argc-1 ? 0 : 4))
- for (here = current->argv[i]; *here; here++)
- if (*here > ' ' && *here <= '~') out_char(*here);
- else {
- sprintf(comm_tmp,"\\%03o",(unsigned char) *here);
- out_string(comm_tmp);
- }
- else {
- out_string("...");
- break;
- }
- }
- }
- if (print_args || !current->children) {
- while (closing--) out_char(']');
- out_newline();
- if (print_args) {
- more[level] = !last;
- width[level] = swapped+(comm_len > 1 ? 0 : -1);
- for (walk = current->children; walk; walk = walk->next)
- dump_tree(walk->child,level+1,1,0,!walk->next,current->uid,0);
- }
- }
- else {
- more[level] = !last;
- width[level] = comm_len+cur_x-offset+add;
- if (cur_x >= output_width && trunc) {
- out_string(sym->first_3);
- out_string("+");
- out_newline();
- }
- else {
- first = 1;
- for (walk = current->children; walk; walk = next) {
- count = 0;
- next = walk->next;
- if (compact) {
- scan = &walk->next;
- while (*scan)
- if (!tree_equal(walk->child,(*scan)->child))
- scan = &(*scan)->next;
- else {
- if (next == *scan) next = (*scan)->next;
- count++;
- *scan = (*scan)->next;
- }
- }
- if (first) {
- out_string(next ? sym->first_3 : sym->single_3);
- first = 0;
- }
- dump_tree(walk->child,level+1,count+1,walk == current->children,
- !next,current->uid,closing+(count ? 1 : 0));
- }
- }
- }
-}
-
-
-static void dump_by_user(PROC *current,uid_t uid)
-{
- const CHILD *walk;
-
- if (current->uid == uid) {
- if (dumped) putchar('\n');
- dump_tree(current,0,1,1,1,uid,0);
- dumped = 1;
- return;
- }
- for (walk = current->children; walk; walk = walk->next)
- dump_by_user(walk->child,uid);
-}
-
-
-static void read_proc(void)
-{
- DIR *dir;
- struct dirent *de;
- FILE *file;
- struct stat st;
- char path[PATH_MAX+1],comm[COMM_LEN+1];
- char *buffer;
- pid_t pid,ppid;
- int fd,size;
- int empty,dummy;
-
- if (!print_args) buffer = NULL;
- else if (!(buffer = malloc((size_t) (output_width+1)))) {
- perror("malloc");
- exit(1);
- }
- if (!(dir = opendir(PROC_BASE))) {
- perror(PROC_BASE);
- exit(1);
- }
- empty = 1;
- while (de = readdir(dir))
- if (pid = atoi(de->d_name)) {
- sprintf(path,"%s/%d/stat",PROC_BASE,pid);
- if (file = fopen(path,"r")) {
- empty = 0;
- if (fstat(fileno(file),&st) < 0) {
- perror(path);
- exit(1);
- }
- if (fscanf(file,"%d (%[^)]) %c %d",&dummy,comm,(char *) &dummy,
- &ppid) == 4) {
- if (!print_args) add_proc(comm,pid,ppid,st.st_uid,NULL,0);
- else {
- sprintf(path,"%s/%d/cmdline",PROC_BASE,pid);
- if ((fd = open(path,O_RDONLY)) < 0) {
- perror(path);
- exit(1);
- }
- if ((size = read(fd,buffer,(size_t) output_width)) < 0)
- {
- perror(path);
- exit(1);
- }
- (void) close(fd);
- if (size) buffer[size++] = 0;
- add_proc(comm,pid,ppid,st.st_uid,buffer,size);
- }
- }
- (void) fclose(file);
- }
- }
- (void) closedir(dir);
- if (print_args) free(buffer);
- if (empty) {
- fprintf(stderr,PROC_BASE " is empty (not mounted ?)\n");
- exit(1);
- }
-}
-
-
-#if 0
-
-/* Could use output of ps achlx | awk '{ print $3,$4,$2,$13 }' */
-
-static void read_stdin(void)
-{
- char comm[PATH_MAX+1];
- char *cmd;
- int pid,ppid,uid;
-
- while (scanf("%d %d %d %s\n",&pid,&ppid,&uid,comm) == 4) {
- if (cmd = strrchr(comm,'/')) cmd++;
- else cmd = comm;
- if (*cmd == '-') cmd++;
- add_proc(cmd,pid,ppid,uid,NULL,0);
- }
-}
-
-#endif
-
-
-static void usage(void)
-{
- fprintf(stderr,"usage: pstree [ -a ] [ -c ] [ -h | -H pid ] [ -l ] [ -n ] "
- "[ -p ] [ -u ]\n%14s[ -G | -U ] [ pid | user]\n","");
- fprintf(stderr," pstree -V\n\n");
- fprintf(stderr," -a show command line arguments\n");
- fprintf(stderr," -c don't compact identical subtrees\n");
- fprintf(stderr," -h highlight current process and its ancestors\n");
- fprintf(stderr," -H pid highlight process \"pid\" and its ancestors\n");
- fprintf(stderr," -G use VT100 line drawing characters\n");
- fprintf(stderr," -l don't truncate long lines\n");
- fprintf(stderr," -n sort output by PID\n");
- fprintf(stderr," -p show PIDs; implies -c\n");
- fprintf(stderr," -u show uid transitions\n");
- fprintf(stderr," -U use UTF-8 (Unicode) line drawing characters\n");
- fprintf(stderr," -V display version information\n");
- fprintf(stderr," pid start at pid, default 1 (init)\n");
- fprintf(stderr," user show only trees rooted at processes of that "
- "user\n\n");
- exit(1);
-}
-
-
-int main(int argc,char **argv)
-{
- PROC *current;
- struct winsize winsz;
- const struct passwd *pw;
- pid_t pid,highlight;
- char termcap_area[1024];
- int c;
-
- if (ioctl(1,TIOCGWINSZ,&winsz) >= 0)
- if (winsz.ws_col) output_width = winsz.ws_col;
- pid = 1;
- highlight = 0;
- pw = NULL;
- while ((c = getopt(argc,argv,"acGhH:npluUV")) != EOF)
- switch (c) {
- case 'a':
- print_args = 1;
- break;
- case 'c':
- compact = 0;
- break;
- case 'G':
- if (sym != &sym_ascii) usage();
- sym = &sym_vt100;
- break;
- case 'h':
- if (highlight) usage();
- if (getenv("TERM") && tgetent(termcap_area,getenv("TERM")) > 0)
- highlight = getpid();
- break;
- case 'H':
- if (highlight) usage();
- if (!getenv("TERM")) {
- fprintf(stderr,"TERM is not set\n");
- return 1;
- }
- if (tgetent(termcap_area,getenv("TERM")) <= 0) {
- fprintf(stderr,"can't get terminal capabilities\n");
- return 1;
- }
- if (!(highlight = atoi(optarg))) usage();
- break;
- case 'l':
- trunc = 0;
- break;
- case 'n':
- by_pid = 1;
- break;
- case 'p':
- pids = 1;
- compact = 0;
- break;
- case 'u':
- user_change = 1;
- break;
- case 'U':
- if (sym != &sym_ascii) usage();
- sym = &sym_utf;
- break;
- case 'V':
- fprintf(stderr,"pstree from psmisc version " PSMISC_VERSION
- "\n");
- return 0;
- default:
- usage();
- }
- if (optind == argc-1)
- if (isdigit(*argv[optind])) {
- if (!(pid = atoi(argv[optind++]))) usage();
- }
- else if (!(pw = getpwnam(argv[optind++]))) {
- fprintf(stderr,"No such user name: %s\n",argv[optind-1]);
- return 1;
- }
- if (optind != argc) usage();
- read_proc();
- for (current = find_proc(highlight); current; current = current->parent)
- current->highlight = 1;
- if (!pw)
- dump_tree(find_proc(pid),0,1,1,1,0,0);
- else {
- dump_by_user(find_proc(1),pw->pw_uid);
- if (!dumped) {
- fprintf(stderr,"No processes found.\n");
- return 1;
- }
- }
- return 0;
-}
+++ /dev/null
-/* signals.c - signal name handling */
-
-/* Copyright 1993-1995 Werner Almesberger. See file COPYING for details. */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include "signals.h"
-
-
-typedef struct {
- int number;
- const char *name;
-} SIGNAME;
-
-
-static SIGNAME signals[] = {
-#include "signames.h"
- { 0,NULL }};
-
-
-void list_signals(void)
-{
- SIGNAME *walk;
- int col;
-
- col = 0;
- for (walk = signals; walk->name; walk++) {
- if (col+strlen(walk->name)+1 > 80) {
- putchar('\n');
- col = 0;
- }
- printf("%s%s",col ? " " : "",walk->name);
- col += strlen(walk->name)+1;
- }
- putchar('\n');
-}
-
-
-int get_signal(char *name,const char *cmd)
-{
- SIGNAME *walk;
-
- if (isdigit(*name))
- return atoi(name);
- for (walk = signals; walk->name; walk++)
- if (!strcmp(walk->name,name)) break;
- if (walk->name) return walk->number;
- fprintf(stderr,"%s: unknown signal; %s -l lists signals.\n",name,cmd);
- exit(1);
-}
+++ /dev/null
-/* signals.h - signal name handling */
-
-/* Copyright 1993-1995 Werner Almesberger. See file COPYING for details. */
-
-
-#ifndef SIGNALS_H
-#define SIGNALS_H
-
-void list_signals(void);
-
-/* Lists all known signal names on standard output. */
-
-int get_signal(char *name,const char *cmd);
-
-/* Returns the signal number of NAME. If no such signal exists, an error
- message is displayed and the program is terminated. CMD is the name of the
- application. */
-
-#endif