home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!olivea!decwrl!deccrl!news.crl.dec.com!rdg.dec.com!uvo.dec.com!uvo.dec.com!sac
- From: sac@uvo.dec.com (Stephen Carpenter)
- Newsgroups: comp.unix.ultrix
- Subject: Version 1.6 of pads
- Message-ID: <1993Jan3.130448.14246@decuk.uvo.dec.com>
- Date: 3 Jan 93 13:04:48 GMT
- Sender: sac@decuk.uvo.dec.com (Stephen Carpenter)
- Reply-To: sac@uvo.dec.com (Stephen Carpenter)
- Organization: Digital Equipment Co. Ltd
- Lines: 1672
-
-
- This is release 1.6 of pads, a utility for listing processes active in
- certain directories under ULTRIX.
-
- The major changes in this version of pads are :-
-
- o Checks for files being executed.
- o Works on VAX ULTRIX (at last!) using the standard C compiler.
- o All search types are now done simultaneously.
- o 100% faster than V1.5.
- o Partition mode won't hang when accessing stale NFS file systems.
-
-
- Here's an example of pads at work :-
-
- % pads /etc
- USER PID PPID CMD TERM TYPE MODE PATH
- root 1 0 init ? exec /etc/init
- root 3810 1 elcsd ? exec /etc/elcsd
- root 8 0 idleproc ? exec /etc/startcpu
- root 139 1 ntpd ? file R /etc/ntp.conf
- root 139 1 ntpd ? file W /etc/ntp.drift
- root 156 1 mountd ? file RW /etc/rmtab
- root 24984 325 nntpd ? exec /etc/nntpd
- guest 24117 127 nntpd ? exec /etc/nntpd
- sac 28123 28084 tcsh ttype cwd /etc
- root 3925 325 bootpd ? file R /etc/bootptab
- root 25042 325 nntpd ? exec /etc/nntpd
- root 19902 1 named ? file R /etc/services
- root 19902 1 named ? file R /etc/protocols
-
-
- The shar archive follows.
-
-
- Stephen.
-
- //---------------------------------------------------------------------\\
- // Stephen Carpenter "One inode short of a file system" \\
- // \\
- \\ UNIX Support Specialist sac@uvo.dec.com //
- \\ Digital Equipment Corporation //
- \\_____________________________________________________________________//
-
-
- ---------------------------------Cut Here-------------------------------------
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: README Makefile pads.1 pads.c
- # Wrapped by sac@decuk.uvo.dec.com on Sun Jan 3 12:40:57 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(2675 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- X Copyright (c) 1991, 1992, 1993 by Digital Equipment Corporation
- X
- X Permission to use, copy, modify, and distribute this software for any
- X purpose and without fee is hereby granted, provided that the above
- X copyright notice and this permission notice appear in all copies, and that
- X the name of Digital Equipment Corporation not be used in advertising or
- X publicity pertaining to distribution of the document or software without
- X specific, written prior permission.
- X
- X Digital Equipment Corporation makes no representations about the suitability
- X of the software described herein for any purpose. It is provided "as is"
- X without express or implied warranty.
- X
- X
- X ###########################
- X
- X
- This is release 1.6 of pads, a utility for listing processes active in
- certain directories under ULTRIX.
- X
- X
- The major changes in this version of pads are :-
- X
- X o Checks for files being executed.
- X o Works on VAX ULTRIX (at last!) using the standard C compiler.
- X o All search types are now done simultaneously.
- X o 100% faster than V1.5.
- X o Partition mode won't hang when accessing stale NFS file systems.
- X
- X
- Here's an example of pads at work :-
- X
- X % pads /etc
- X USER PID PPID CMD TERM TYPE MODE PATH
- X root 1 0 init ? exec /etc/init
- X root 3810 1 elcsd ? exec /etc/elcsd
- X root 8 0 idleproc ? exec /etc/startcpu
- X root 139 1 ntpd ? file R /etc/ntp.conf
- X root 139 1 ntpd ? file W /etc/ntp.drift
- X root 156 1 mountd ? file RW /etc/rmtab
- X root 24984 325 nntpd ? exec /etc/nntpd
- X guest 24117 127 nntpd ? exec /etc/nntpd
- X sac 28123 28084 tcsh ttype cwd /etc
- X root 3925 325 bootpd ? file R /etc/bootptab
- X root 25042 325 nntpd ? exec /etc/nntpd
- X root 19902 1 named ? file R /etc/services
- X root 19902 1 named ? file R /etc/protocols
- X
- X
- History
- X~~~~~~~
- X
- I wrote pads after a colleague complained that he couldn't dismount a
- file system because someone had a process active in it and if he had
- a command like SHOW DEVICE /FILES from VMS he could track down the
- offending process.
- X
- Pads is completely original work. You may find that its functionality
- overlaps some programs like ofiles but I believe that it is unique
- in the way it can search whole directory structures or partitions.
- X
- X
- Author
- X~~~~~~
- X
- X Stephen Carpenter, UK UNIX Support, Digital Equipment Corp.
- X
- X E-mail: sac@uvo.dec.com
- END_OF_FILE
- if test 2675 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(1408 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X###############################################################################
- X#
- X# (c) Copyright 1991, 1992, 1993, Digital Equipment Corporation
- X#
- X# Permission to use, copy, modify, and distribute this software for any
- X# purpose and without fee is hereby granted, provided that the above
- X# copyright notice and this permission notice appear in all copies, and that
- X# the name of Digital Equipment Corporation not be used in advertising or
- X# publicity pertaining to distribution of the document or software without
- X# specific, written prior permission.
- X#
- X# Digital Equipment Corporation makes no representations about the
- X# suitability of the software described herein for any purpose. It is
- X# provided "as is" without express or implied warranty.
- X#
- X# DEC is a registered trademark of Digital Equipment Corporation
- X# DIGITAL is a registered trademark of Digital Equipment Corporation
- X#
- X###############################################################################
- X
- X
- X#
- X# Makefile for pads program
- X#
- X
- CC = cc
- CFLAGS = -O
- X
- X#
- X# The installation directories
- X#
- XEXE_DIR = /usr/local/bin
- MAN_DIR = /usr/man/man1
- X
- all: pads
- X
- pads: pads.c
- X $(CC) $(CFLAGS) pads.c -o pads
- X
- X$(EXE_DIR)/pads: pads
- X install -c -m 2755 -o root -g kmem -s pads $(EXE_DIR)
- X
- X$(MAN_DIR)/pads.1: pads.1
- X install -c -m 0444 -o root -g system pads.1 $(MAN_DIR)
- X
- install: $(EXE_DIR)/pads $(MAN_DIR)/pads.1
- X
- clean:
- X rm -f pads
- END_OF_FILE
- if test 1408 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'pads.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'pads.1'\"
- else
- echo shar: Extracting \"'pads.1'\" \(3976 characters\)
- sed "s/^X//" >'pads.1' <<'END_OF_FILE'
- X.\"
- X.\" ***************************************************************************
- X.\" *
- X.\" * (c) Copyright 1991, 1992, 1993, Digital Equipment Corporation
- X.\" *
- X.\" * Permission to use, copy, modify, and distribute this software for any
- X.\" * purpose and without fee is hereby granted, provided that the above
- X.\" * copyright notice and this permission notice appear in all copies, and
- X.\" * that the name of Digital Equipment Corporation not be used in
- X.\" * advertising or publicity pertaining to distribution of the document or
- X.\" * software without specific, written prior permission.
- X.\" *
- X.\" * Digital Equipment Corporation makes no representations about the
- X.\" * suitability of the software described herein for any purpose. It is
- X.\" * provided "as is" without express or implied warranty.
- X.\" *
- X.\" * DEC is a registered trademark of Digital Equipment Corporation
- X.\" * DIGITAL is a registered trademark of Digital Equipment Corporation
- X.\" *
- X.\" ***************************************************************************
- X.\"
- X.TH pads 1
- X.SH Name
- pads \- process active directory search
- X.SH Syntax
- X.B pads
- X.B [\-r | \-p] [\-v]
- X.I directory...
- X.SH Description
- X
- The
- X.IR pads
- command searches for processes which have either current
- working directories matching, or open files in,
- the directories specified in the argument list.
- X
- XFor
- X.IR directory ,
- you can specify either a full or partial path. You can specify
- multiple directories, separated by spaces.
- X
- X.SH Options
- X.IP \-r
- Recursively search any directories subordinate to
- X.PN directory .
- X
- X.IP \-p
- Partition mode. Search for matches based on the device numbers
- of the directories specified.
- X
- X.IP \-v
- Verbose mode. Display warning messages.
- X
- X.SH Output Fields
- X
- XFor each matched process the output fields are:
- X.IP USER 10
- Name of the owner of the process.
- X.IP PID 10
- The process identification (PID) number.
- X.IP PPID 10
- The process identification (PID) number of the parent process.
- X.IP CMD 10
- The command the process is executing.
- X.IP TERM 10
- The controlling terminal of the process.
- X.IP TYPE 10
- The file type of the process match:
- X.RS
- X.IP cwd 8
- The PATH field is the current working directory of the process.
- X.IP file 8
- The PATH field is a file the process currently has open.
- X.IP exec 8
- The PATH field is the executable being run in the process.
- X.RE
- X.IP MODE 10
- The open mode of the file encoded thus:
- X.RS
- X.IP R 4
- Open for reading
- X.IP W 4
- Open for writing
- X.IP A 4
- Open for appending
- X.IP S 4
- Shared lock
- X.IP X 4
- XExclusive use
- X.IP I 4
- Asychronous I/O notification
- X.IP B 4
- Block if inuse bit is set (shared line semaphore)
- X.RE
- X
- X.PP
- Additional fields in normal and recursive modes:
- X.IP PATH 10
- The path name of the process's current working directory or open file.
- X
- X.PP
- Additional fields in partition mode:
- X.IP DEVICE 10
- The major and minor device numbers of the partition
- the process is active in.
- X.IP GNODE 10
- The gnode number of the process's current working directory
- or open file.
- X.SH Example
- X
- Unable to unmount a filesystem:
- X.EX
- X% umount /mnt
- umount /dev/ra10h: Mount device busy
- X.EE
- One or more processes are therefore either active in
- or have open files within this filesystem.
- Using
- X.PN pads
- you can find the processes that are preventing the unmount:
- X.EX
- X% pads -p /mnt
- USER PID PPID CMD TERM TYPE MODE DEVICE GNODE
- root 1079 421 csh ttyp2 cwd 23/34 1852
- root 1281 1079 cat ttyp2 file R 23/34 1913
- X.EE
- It is now possible to kill the offending processes and unmount the
- filesystem:
- X.EX
- X% kill -9 1079 1281
- X% umount /mnt
- X.EE
- X
- X.SH Files
- X.TP 1.2i
- X.PN /vmunix
- System namelist.
- X.TP 1.2i
- X.PN /dev
- Searched to find terminal names.
- X.TP 1.2i
- X.PN /dev/kmem
- Kernel memory.
- X.TP 1.2i
- X.PN /dev/mem
- User process information.
- X.TP 1.2i
- X.PN /dev/drum
- Swap device.
- X
- X.SH Note
- This command is not part of ULTRIX and is NOT supported!
- X
- X.SH Author
- X
- Stephen Carpenter, UK UNIX Support, Digital Equipment Corp.
- X
- XE-mail: sac@uvo.dec.com
- X.EE
- END_OF_FILE
- if test 3976 -ne `wc -c <'pads.1'`; then
- echo shar: \"'pads.1'\" unpacked with wrong size!
- fi
- # end of 'pads.1'
- fi
- if test -f 'pads.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'pads.c'\"
- else
- echo shar: Extracting \"'pads.c'\" \(29702 characters\)
- sed "s/^X//" >'pads.c' <<'END_OF_FILE'
- X/******************************************************************************
- X*******************************************************************************
- X*
- X* (c) Copyright 1991, 1992, 1993, Digital Equipment Corporation
- X*
- X* Permission to use, copy, modify, and distribute this software for any
- X* purpose and without fee is hereby granted, provided that the above
- X* copyright notice and this permission notice appear in all copies, and that
- X* the name of Digital Equipment Corporation not be used in advertising or
- X* publicity pertaining to distribution of the document or software without
- X* specific, written prior permission.
- X*
- X* Digital Equipment Corporation makes no representations about the
- X* suitability of the software described herein for any purpose. It is
- X* provided "as is" without express or implied warranty.
- X*
- X* DEC is a registered trademark of Digital Equipment Corporation
- X* DIGITAL is a registered trademark of Digital Equipment Corporation
- X*
- X*******************************************************************************
- X******************************************************************************/
- X
- X
- X/*
- X * PROGRAM: pads (Process Active Directory Search)
- X *
- X * Search for processes active in specified directories.
- X *
- X *
- X * NOTE:
- X * This tool is NOT part of ULTRIX and is NOT a supported product.
- X *
- X * AUTHOR:
- X * Stephen Carpenter, UK UNIX Support, Digital Equipment Co. Ltd.
- X * E-Mail: sac@uvo.dec.com
- X */
- X
- X
- static char *version = "Version 1.6 - 3rd January 1993";
- X
- X
- X#include <stdlib.h>
- X#include <stdio.h>
- X#include <string.h>
- X#include <unistd.h>
- X#include <nlist.h>
- X#include <pwd.h>
- X
- X#include <sys/types.h>
- X#include <sys/dir.h>
- X#include <sys/gnode.h>
- X#include <sys/stat.h>
- X
- X#include <machine/pte.h>
- X#include <sys/param.h>
- X#include <sys/mount.h>
- X#include <sys/user.h>
- X#include <sys/proc.h>
- X#include <sys/text.h>
- X#include <sys/tty.h>
- X
- X#define KERNEL
- X#include <sys/file.h>
- X#undef KERNEL
- X
- X
- X/*
- X * Figure out if this a V4.2 or above system with the capability of
- X * extending the number of open files per process above 64 (to a max of 4096)
- X */
- X#ifdef NOFILE_IN_U
- X# define OFILE_EXTEND
- X#else
- X# define NOFILE_IN_U NOFILE
- X#endif
- X
- X/*
- X * Define a generic NULL pointer
- X */
- X#define NIL_PTR(type) (type *) 0x0
- X
- X/*
- X * Define a macro for the general error return of a syscall
- X */
- X#define ERROR -1
- X
- X/*
- X * Define a macro to make a copy of a string in new storage
- X */
- X#define strdup(x) strcpy((char *) malloc (1 + strlen (x)), (x))
- X
- X/*
- X * The maximum number of characters we're going to print on a line
- X */
- X#define MAX_LINE_WIDTH 132
- X
- X/*
- X * Define a boolean data type
- X */
- typedef enum Boolean {False, True} Boolean;
- X
- X/*
- X * Signify the type of match
- X */
- typedef enum Match {Cwd, File, Exec} Match;
- X
- X/*
- X * Define a record containing the gnode info we require
- X */
- struct entry
- X{
- X dev_t device;
- X gno_t number;
- X};
- X
- X/*
- X * Define a directory list record
- X */
- struct entries
- X{
- X struct entry *dir_entry;
- X char *entry_name;
- X Boolean is_directory;
- X} *dir_entries;
- X
- int number_of_entries;
- X
- X/*
- X * Define the device list record
- X */
- struct devent
- X{
- X dev_t device;
- X char *dev_name;
- X} *dev_table;
- X
- int number_of_devents;
- X
- X/*
- X * File descriptors for the various type of system memory
- X */
- int kmem, mem, swap;
- X
- X/*
- X * Define the name lists were are interested in
- X */
- X#define N_PROC 0
- X#define N_NPROC 1
- struct nlist name_list[] = {
- X { "_proc" },
- X { "_nproc" },
- X { 0 }
- X};
- X
- X/*
- X * Name by which the program was invoked
- X */
- char *program;
- X
- X/*
- X * Flags for the command line switches
- X */
- Boolean recursive_mode = False;
- Boolean partition_mode = False;
- Boolean verbose_mode = False;
- X
- X
- X/*
- X * FUNCTION: Lseek
- X * Like lseek but with error handling
- X *
- X * ARGUMENTS:
- X * file - The file descriptor to seek
- X * offset - The offset from the beginning of the file to seek
- X * file_name - The name of the file being seeked
- X *
- X * RETURN VALUE:
- X * None.
- X */
- X
- void
- Lseek (file, offset, file_name)
- X int file;
- X long offset;
- X char *file_name;
- X{
- X if (lseek (file, (off_t) offset, 0) == ERROR)
- X {
- X fprintf (stderr, "%s: Failed to seek to offset %d in %s\n",
- X program, offset, file_name);
- X exit (1);
- X }
- X}
- X
- X
- X/*
- X * FUNCTION: read_from
- X * Combine seeking and reading into one operation.
- X *
- X * ARGUMENTS:
- X * file - The file descriptor to read from.
- X * offset - The offset from the beginning of the file to seek.
- X * variable - The variable to read information into.
- X * size - The number of bytes to read.
- X * file_name - The name of the file being read.
- X *
- X * RETUTN VALUE:
- X * None.
- X */
- X
- void
- read_from (file, offset, variable, size, file_name)
- X int file;
- X off_t offset;
- X void *variable;
- X size_t size;
- X char *file_name;
- X{
- X if (lseek (file, offset, 0) == ERROR)
- X {
- X fprintf (stderr, "%s: Failed to seek to offset %d in %s\n",
- X program, offset, file_name);
- X exit (1);
- X }
- X
- X if (read (file, (char *) variable, (int) size) != size)
- X {
- X fprintf (stderr, "%s: Failed to read %d bytes at 0x%x from %s\n",
- X program, size, variable, file_name);
- X exit (1);
- X }
- X}
- X
- X
- X/*
- X * FUNCTION: full_name
- X * Concatenate a file name to a directory name
- X *
- X * ARGUMENTS:
- X * dir - The name of the diretory where the file resides
- X * file - The name of the file.
- X *
- X * RETURN VALUE:
- X * A pointer to a string containing the path name of the file.
- X */
- X
- char *
- full_name (dir, file)
- X char *dir;
- X char *file;
- X{
- X char *path = (char *) malloc (MAXPATHLEN * sizeof (char));
- X
- X path = strcpy (path, dir);
- X if (dir[strlen (dir) - 1] != '/')
- X path = strcat (path, "/");
- X path = strcat (path, file);
- X
- X return (path);
- X}
- X
- X
- X/*
- X * FUNCTION: expand_name
- X * Expand a file name to a full path name
- X *
- X * ARGUMENTS:
- X * file - The name of the file.
- X *
- X * RETURN VALUE:
- X * A string containing the full path name of the file.
- X */
- X
- char *
- expand_file (file)
- X char *file;
- X{
- X char *path = (char *) malloc (MAXPATHLEN * sizeof (char));
- X
- X if (*file == '/')
- X return (strcpy (path, file));
- X
- X /*
- X * Check if the file is the process cwd
- X */
- X if (!strcmp (file, "."))
- X {
- X path = (char *) getwd (path);
- X
- X return (path);
- X }
- X
- X if (!strncmp (file, "./", 2))
- X path = strcat ((char *) getwd (path), ++file);
- X else {
- X path = strcat ((char *) getwd (path), "/");
- X path = strcat (path, file);
- X }
- X
- X return (path);
- X}
- X
- X
- X/*
- X * FUNCTION: get_tty_name
- X * Match a tty structure against the device list
- X *
- X * ARGUMENTS:
- X * ttyp - A pointer to the tty structure of the controlling terminal.
- X *
- X * RETURN VALUE:
- X * A string containing the name of the tty device.
- X */
- X
- char *
- get_tty_name (tty_ptr)
- X struct tty *tty_ptr;
- X{
- X int index;
- X struct tty control_tty;
- X
- X if (tty_ptr != NIL_PTR (struct tty))
- X {
- X /*
- X * Read the tty structure out of kernel memory
- X */
- X read_from (kmem, (off_t) tty_ptr, &control_tty,
- X sizeof (struct tty), "/dev/kmem");
- X
- X /*
- X * Search the device list for this tty
- X */
- X for (index = 0; index < number_of_devents; index++)
- X if ((dev_table + index)->device == control_tty.t_dev)
- X return ((dev_table + index)->dev_name);
- X }
- X
- X /*
- X * The process is not associated with a terminal
- X */
- X return ("?");
- X}
- X
- X
- X/*
- X * FUNCTION: create_device_table
- X * Create a list of the character devices found in /dev
- X *
- X * ARGUMENTS:
- X * None.
- X *
- X * RETURN VALUE:
- X * None.
- X */
- X
- void
- create_device_table ()
- X{
- X struct direct *dir_entry;
- X DIR *dir_ptr;
- X struct stat stat_info;
- X
- X dev_table = NIL_PTR (struct devent);
- X number_of_devents = 0;
- X
- X if ((dir_ptr = opendir ("/dev")) == NULL)
- X {
- X fprintf (stderr, "%s: ", program);
- X perror ("Can't open directory /dev");
- X return;
- X }
- X
- X /*
- X * Check each device
- X */
- X while ((dir_entry = readdir(dir_ptr)) != NULL)
- X {
- X /*
- X * Find out the type of device
- X */
- X if (lstat (full_name ("/dev", dir_entry->d_name), &stat_info) == ERROR)
- X {
- X fprintf (stderr, "%s: Can't stat ", program);
- X perror (full_name ("/dev", dir_entry->d_name));
- X continue;
- X }
- X
- X /*
- X * Add any character devices to the list
- X */
- X if ((stat_info.st_mode & S_IFMT) == S_IFCHR)
- X {
- X number_of_devents++;
- X dev_table =
- X (struct devent *) realloc (dev_table,
- X number_of_devents * sizeof (struct devent));
- X
- X (dev_table + number_of_devents - 1)->dev_name = strdup (dir_entry->d_name);
- X (dev_table + number_of_devents - 1)->device = stat_info.st_rdev;
- X }
- X }
- X closedir(dir_ptr);
- X}
- X
- X
- X/*
- X * FUNCTION: add_dir_entry
- X * Add an entry to the directory list
- X *
- X * ARGUMENTS:
- X * entry_name - A string containing the name of the direcory to add
- X *
- X * RETURN VALUE:
- X * None.
- X */
- X
- void
- add_dir_entry (entry_name, is_directory)
- X char *entry_name;
- X Boolean is_directory;
- X{
- X struct entry *the_entry = (struct entry *) malloc (sizeof (struct entry));
- X struct stat stat_info;
- X struct fs_data mount_info;
- X
- X if (partition_mode)
- X {
- X /*
- X * In partition mode we use getmnt() rather than stat() to avoid
- X * hangs due to NFS server problems
- X */
- X if (getmnt (0, &mount_info, 0, NOSTAT_ONE, entry_name) == ERROR)
- X {
- X fprintf (stderr, "%s: Can't get mount info for ", program);
- X perror (entry_name);
- X return;
- X }
- X the_entry->device = mount_info.fd_req.dev;
- X
- X } else {
- X /*
- X * Get the gnode info
- X */
- X if (lstat (entry_name, &stat_info) == ERROR)
- X {
- X fprintf (stderr, "%s: Can't stat ", program);
- X perror (entry_name);
- X return;
- X }
- X
- X the_entry->device = stat_info.st_dev;
- X the_entry->number = stat_info.st_ino;
- X }
- X
- X number_of_entries++;
- X dir_entries = (struct entries *)
- X realloc (dir_entries,
- X number_of_entries * sizeof (struct entries));
- X
- X /*
- X * Store the gnode info
- X */
- X (dir_entries + number_of_entries - 1)->dir_entry = the_entry;
- X
- X /*
- X * Store the directory name
- X */
- X (dir_entries + number_of_entries - 1)->entry_name = strdup (entry_name);
- X
- X (dir_entries + number_of_entries - 1)->is_directory = is_directory;
- X}
- X
- X
- X/*
- X * FUNCTION: recursive_dir_add
- X * Recursively search the direcory structure for directory entries
- X *
- X * ARGUMENTS:
- X * entry_name - A string containing the name of the direcory search
- X * do_recursion - A flag to determine if actual recursion is required
- X *
- X * RETURN VALUE:
- X * None.
- X */
- X
- void
- recursive_dir_add (entry_name, do_recursion)
- X char *entry_name;
- X Boolean do_recursion;
- X{
- X DIR *dir_ptr;
- X struct direct *dir_entry;
- X struct stat stat_info;
- X char *file;
- X char *error_string;
- X
- X /*
- X * Open the directory for reading
- X */
- X if ((dir_ptr = opendir (entry_name)) == NULL)
- X {
- X error_string = (char *) malloc (sizeof (char) * (strlen (entry_name) + 18));
- X sprintf (error_string, "%s: Error opening %s", program, entry_name);
- X perror (error_string);
- X return;
- X }
- X
- X /*
- X * Skip '.' & '..' directories
- X */
- X dir_entry = readdir (dir_ptr);
- X dir_entry = readdir (dir_ptr);
- X
- X for (dir_entry = readdir (dir_ptr); dir_entry != NULL;
- X dir_entry = readdir (dir_ptr))
- X {
- X /*
- X * Get the directory info
- X */
- X file = full_name (entry_name, dir_entry->d_name);
- X
- X if (lstat (file, &stat_info) == ERROR)
- X {
- X fprintf (stderr, "%s: Can't stat ", program);
- X perror (file);
- X continue;
- X }
- X
- X if ((stat_info.st_mode & S_IFMT) == S_IFDIR)
- X {
- X /*
- X * It's a directory so add the entry to the directory list
- X * and search this directory for sub-directories.
- X */
- X add_dir_entry (file, True);
- X
- X if (do_recursion)
- X recursive_dir_add (file, True);
- X } else
- X add_dir_entry (file, False);
- X
- X /*
- X * Free up redundant space
- X */
- X free (file);
- X }
- X closedir (dir_ptr);
- X}
- X
- X
- X/*
- X * FUNCTION: create_dir_table
- X * Initialise and start off the directory list
- X *
- X * ARGUMENTS:
- X * argc - Argument count
- X * argv - Argument vector
- X *
- X * RETURN VALUE:
- X * None.
- X */
- X
- void
- create_dir_table (dir_argc, dir_argv)
- X int dir_argc;
- X char *dir_argv[];
- X{
- X struct stat stat_info;
- X int index;
- X char *path;
- X
- X /*
- X * Initialise the directory list
- X */
- X number_of_entries = 0;
- X dir_entries = NIL_PTR (struct entries);
- X
- X /*
- X * Add the directories in the arguments to the directory list
- X */
- X for (index = 0; index < dir_argc; index++)
- X {
- X path = expand_file (dir_argv[index]);
- X if (partition_mode)
- X {
- X add_dir_entry (path, True);
- X } else
- X if (recursive_mode)
- X {
- X add_dir_entry (path, True);
- X recursive_dir_add (path, True);
- X } else {
- X if (lstat (path, &stat_info) == ERROR)
- X {
- X fprintf (stderr, "%s: Can't stat ", program);
- X perror (path);
- X exit (1);
- X }
- X
- X if ((stat_info.st_mode & S_IFMT) == S_IFDIR)
- X {
- X add_dir_entry (path, True);
- X recursive_dir_add (path, False);
- X } else
- X add_dir_entry (path, False);
- X }
- X free (path);
- X }
- X}
- X
- X
- X/*
- X * FUNCTION: get_user_area
- X * Read the user area for a given process from memory or swap
- X *
- X * ARGUMENTS:
- X * the_proc - The process to get the user area for
- X *
- X * RETURN VALUE:
- X * A pointer to copy of the user area of the process
- X */
- X
- struct user *
- get_user_area (the_proc)
- X struct proc *the_proc;
- X{
- X struct dmap stack_dmap; /* Stack segment disk map */
- X struct pte proc_pte[UPAGES]; /* Page table entries for process */
- X char *user_area; /* The user area of the process */
- X int user_block; /* File system block number of user area */
- X int clusters; /* Number of page clusters */
- X int pagenum; /* Page number */
- X long pageaddr; /* Page address */
- X
- X if ((the_proc->p_sched & SLOAD) == 0)
- X {
- X /*
- X * The process is currently swapped out
- X * We therefore need to pull the info out of the swap device
- X */
- X
- X /*
- X * Read disk map for stack segment
- X */
- X read_from (kmem, (off_t) the_proc->p_smap,
- X &stack_dmap, sizeof (struct dmap), "/dev/kmem");
- X
- X /*
- X * Read address of disk address of user page table
- X */
- X read_from (kmem, (off_t) stack_dmap.dm_ptdaddr,
- X &user_block, sizeof (int), "/dev/kmem");
- X
- X /*
- X * Grab memory for the user area variable
- X */
- X user_area = (char *) malloc (sizeof (struct user));
- X
- X /*
- X * Now read in the user area from swap
- X */
- X Lseek (swap, (long) dtob (user_block), "/dev/drum");
- X if (read (swap, user_area, sizeof (struct user)) != sizeof (struct user))
- X {
- X fprintf (stderr,
- X "%s: Can't read user area of process %d from /dev/drum\n",
- X program, the_proc->p_pid);
- X
- X free (user_area);
- X return (NIL_PTR (struct user));
- X } else
- X return ((struct user *) user_area);
- X
- X } else {
- X
- X /*
- X * The process is in memory. Read the process pte from virtual memory.
- X */
- X Lseek (kmem, (long) the_proc->p_addr, "/dev/kmem");
- X if (read (kmem, (char *) &proc_pte[0], sizeof (proc_pte))
- X != sizeof (proc_pte))
- X {
- X fprintf (stderr,
- X "%s: Can't read pte for user page of process %d from /dev/kmem\n",
- X program, the_proc->p_pid);
- X
- X return (NIL_PTR (struct user));
- X }
- X
- X /*
- X * Grab memory to hold the user pages
- X */
- X user_area = (char *) malloc (UPAGES * NBPG);
- X
- X /*
- X * Read in the user area pages from memory
- X */
- X clusters = (sizeof (struct user) + NBPG*CLSIZE - 1) / (NBPG*CLSIZE);
- X while (--clusters >= 0)
- X {
- X pagenum = clusters * CLSIZE;
- X pageaddr = ctob (proc_pte[pagenum].pg_pfnum);
- X Lseek (mem, pageaddr, "/dev/mem");
- X if (read (mem, user_area + (NBPG * pagenum), CLSIZE*NBPG) != CLSIZE*NBPG)
- X {
- X fprintf (stderr,
- X "%s: Can't read page 0x%x of process %d from /dev/mem\n",
- X program, (int) pageaddr, the_proc->p_pid);
- X
- X free (user_area);
- X return (NIL_PTR (struct user));
- X }
- X }
- X return ((struct user *) user_area);
- X }
- X}
- X
- X
- X/*
- X * FUNCTION: file_open_mode
- X * Get the open mode of a file.
- X *
- X * ARGUMENTS:
- X * flags - The file mode flags.
- X *
- X * RETURN VALUE:
- X * A string containing the mode acronym.
- X */
- X
- char *
- file_open_mode (flags)
- X int flags;
- X{
- X char *mode = (char *) malloc (7 * sizeof (char));
- X int pos = 0;
- X
- X if (flags & FREAD)
- X mode[pos++] = 'R';
- X
- X if (flags & FWRITE)
- X if (flags & FAPPEND)
- X mode[pos++] = 'A';
- X else
- X mode[pos++] = 'W';
- X
- X if (flags & FSHLOCK)
- X mode[pos++] = 'S';
- X
- X if (flags & FEXLOCK)
- X mode[pos++] = 'X';
- X
- X if (flags & FASYNC)
- X mode[pos++] = 'I';
- X
- X if (flags & FBLKINUSE)
- X mode[pos++] = 'B';
- X
- X mode[pos] = '\0';
- X
- X return (mode);
- X}
- X
- X
- X/*
- X * FUNCTION: print_info
- X * Print a line of process information
- X *
- X * ARGUMENTS:
- X * user - A string containing the user name of the process
- X * pid - The process ID of the process
- X * cmd - A string containing the command being executed by the process
- X * node - The gnode of the CWD or open file
- X * type - What sort of match is this?
- X * ttyp - A pointer to the controlling terminal of the process
- X * flags - The flags the gnode was opened with
- X * file - A string containing the name of the file or directory
- X *
- X * RETURN VALUE:
- X * None.
- X */
- X
- void
- print_info (user, pid, ppid, cmd, node, type, ttyp, flags, file)
- X char *user;
- X int pid;
- X int ppid;
- X char *cmd;
- X struct gnode node;
- X Match type;
- X struct tty *ttyp;
- X int flags;
- X char *file;
- X{
- X char line[MAX_LINE_WIDTH];
- X char pid_string[10];
- X char *mode_string;
- X char *tty;
- X
- X tty = get_tty_name (ttyp);
- X
- X /*
- X * Build up the info line for each process
- X */
- X memset (line, ' ', sizeof (line));
- X
- X strncpy (&line[0], user, strlen (user));
- X sprintf (&pid_string[0], "%d", pid);
- X strncpy (&line[9], pid_string, strlen (pid_string));
- X sprintf (&pid_string[0], "%d", ppid);
- X strncpy (&line[15], pid_string, strlen (pid_string));
- X strncpy (&line[21], cmd, strlen (cmd));
- X strncpy (&line[33], tty, strlen (tty));
- X
- X switch (type)
- X {
- X case Cwd:
- X strncpy (&line[41], "cwd", 3);
- X break;
- X case File:
- X strncpy (&line[41], "file", 4);
- X break;
- X case Exec:
- X strncpy (&line[41], "exec", 4);
- X }
- X
- X if (type == File)
- X {
- X mode_string = file_open_mode (flags);
- X if (partition_mode)
- X {
- X strncpy (&line[47], mode_string, strlen (mode_string));
- X sprintf (&line[52], "%d/%d \t%d",
- X major(node.g_req.gr_dev), minor(node.g_req.gr_dev),
- X (int) node.g_req.gr_number);
- X } else {
- X strncpy (&line[47], mode_string, strlen (mode_string));
- X sprintf (&line[52], "%.*s", (MAX_LINE_WIDTH - 29), file);
- X }
- X } else
- X if (partition_mode)
- X sprintf (&line[52], "%d/%d\t%d",
- X major(node.g_req.gr_dev), minor(node.g_req.gr_dev),
- X (int) node.g_req.gr_number);
- X else
- X sprintf (&line[52], "%.*s", (MAX_LINE_WIDTH - 29), file);
- X
- X /*
- X * Output the line info
- X */
- X puts (line);
- X}
- X
- X
- X/*
- X * FUNCTION: gnode_check
- X * Check if the process CWD or open file gnode is in the
- X * direcory entries list.
- X *
- X * ARGUMENTS:
- X * user - A string containing the user name of the process
- X * pid - The process ID of the process
- X * cmd - A string containing the command being executed by the process
- X * node - The gnode of the CWD or open file
- X * flags - The flags the gnode was opened with
- X * ttyp - A pointer to the controlling terminal of the process
- X * type - What sort of match is this?
- X *
- X * RETURN VALUE:
- X * None.
- X */
- X
- void
- gnode_check (user, pid, ppid, cmd, node, flags, ttyp, type)
- X char *user;
- X int pid;
- X int ppid;
- X char *cmd;
- X struct gnode node;
- X int flags;
- X struct tty *ttyp;
- X Match type;
- X{
- X int index;
- X
- X /*
- X * Check if this gnode is in the directory list
- X */
- X for (index = 0; index < number_of_entries; index++)
- X {
- X /*
- X * Do we have the right device?
- X */
- X if (node.g_req.gr_dev == (dir_entries + index)->dir_entry->device)
- X if (partition_mode)
- X /*
- X * We're in partition mode and therefore we have a match
- X */
- X print_info (user, pid, ppid, cmd, node, type, ttyp, flags, "");
- X else
- X if (type == Cwd && !(dir_entries + index)->is_directory)
- X /*
- X * The cwd was actually a file!
- X * Is this an OS bug??
- X */
- X continue;
- X else
- X /*
- X * Does the gnode check out?
- X */
- X if (node.g_req.gr_number == (dir_entries + index)->dir_entry->number)
- X print_info (user, pid, ppid, cmd, node, type, ttyp, flags,
- X (dir_entries + index)->entry_name);
- X }
- X}
- X
- X
- X/*
- X * FUNCTION: check_procs
- X * Search the process table for processes with current working directories
- X * matching the directory list entries
- X *
- X * ARGUMENTS:
- X * procbase - The address of the start of the process table
- X * nproc - The size of the process table
- X *
- X * RETURN VALUE:
- X * None.
- X */
- X
- void
- check_procs (procbase, nproc)
- X long procbase;
- X int nproc;
- X{
- X struct user *proc_uarea = NIL_PTR (struct user);
- X struct proc the_proc;
- X struct file **ofile_table_extension;
- X struct file open_file;
- X struct text text;
- X struct gnode node;
- X struct passwd *passwd_entry;
- X int index, index1;
- X
- X /*
- X * Print title bar
- X */
- X if (partition_mode)
- X printf ("USER PID PPID CMD TERM TYPE MODE DEVICE\tGNODE\n");
- X else
- X printf ("USER PID PPID CMD TERM TYPE MODE PATH\n");
- X
- X#ifdef OFILE_EXTEND
- X /*
- X * Reserve space for the extended open file table of a process
- X */
- X ofile_table_extension =
- X (struct file **) malloc ((getdtablesize () - NOFILE_IN_U)
- X * sizeof (struct file *));
- X#endif
- X
- X /*
- X * Walk the process table
- X */
- X for (index = 0; index < nproc; index++)
- X {
- X /*
- X * Read in the process structure
- X */
- X read_from (kmem, (off_t) (procbase + (long)(index * sizeof (struct proc))),
- X &the_proc, sizeof (struct proc), "/dev/kmem");
- X
- X /*
- X * Skip over empty proc slots
- X */
- X if (the_proc.p_stat == 0 || the_proc.p_pid == 0)
- X continue;
- X
- X /*
- X * Ignore zombies
- X */
- X if (the_proc.p_stat == SZOMB)
- X {
- X if (verbose_mode)
- X printf ("%s: Process %d is a zombie!\n", program, the_proc.p_pid);
- X continue;
- X }
- X
- X /*
- X * Free up any malloced user area memory
- X */
- X if (proc_uarea != NIL_PTR (struct user))
- X free (proc_uarea);
- X
- X /*
- X * Check for 'soft' errors in reading the user area
- X */
- X if ((proc_uarea = get_user_area (&the_proc)) == 0)
- X continue;
- X
- X /*
- X * Get password info (we really want the user name)
- X */
- X passwd_entry = getpwuid (the_proc.p_uid);
- X
- X
- X /***
- X ** First check: Open Files
- X ***/
- X
- X#ifdef OFILE_EXTEND
- X /*
- X * If we have more than NOFILE_IN_U open files
- X * then read in the extended open file table.
- X */
- X if (proc_uarea->u_lastfile >= NOFILE_IN_U)
- X {
- X read_from (kmem, (off_t) proc_uarea->u_ofile_of, ofile_table_extension,
- X proc_uarea->u_of_count * sizeof (struct file *), "/dev/kmem");
- X }
- X#endif
- X for (index1 = 0; index1 <= proc_uarea->u_lastfile; index1++)
- X {
- X if (index1 < NOFILE_IN_U)
- X {
- X if (proc_uarea->u_ofile[index1] == NIL_PTR (struct file))
- X continue;
- X
- X read_from (kmem, (off_t) proc_uarea->u_ofile[index1],
- X &open_file, sizeof (open_file), "/dev/kmem");
- X } else {
- X#ifdef OFILE_EXTEND
- X /*
- X * The open file is in the extended table
- X */
- X if (*(ofile_table_extension + index1 - NOFILE_IN_U)
- X == NIL_PTR (struct file))
- X continue;
- X
- X read_from (kmem,
- X (off_t) *(ofile_table_extension + index1 - NOFILE_IN_U),
- X &open_file, sizeof (open_file), "/dev/kmem");
- X#endif
- X }
- X
- X /*
- X * The reference count should be at least one
- X */
- X if (open_file.f_count == 0)
- X continue;
- X
- X /*
- X * Make sure that this file has a gnode
- X */
- X if (open_file.f_data == NIL_PTR (char))
- X continue;
- X
- X /*
- X * Read in the gnode associated with this file
- X */
- X Lseek (kmem, (long) open_file.f_data, "/dev/kmem");
- X if (read (kmem, &node, sizeof (node)) != sizeof (node))
- X {
- X if (verbose_mode)
- X printf ("%s: Unable to read open file gnode 0x%x of process %d\n",
- X program, open_file.f_data, the_proc.p_pid);
- X } else
- X
- X /*
- X * Check if this gnode is in the directory list
- X */
- X gnode_check (passwd_entry->pw_name, the_proc.p_pid, the_proc.p_ppid,
- X proc_uarea->u_comm, node, open_file.f_flag,
- X the_proc.p_ttyp, File);
- X }
- X
- X
- X /***
- X ** Second check: Process Current Working Directory
- X ***/
- X
- X /*
- X * Read in the current working directory gnode
- X */
- X Lseek (kmem, (long) proc_uarea->u_cdir, "/dev/kmem");
- X if (read (kmem, &node, sizeof (node)) != sizeof (node))
- X {
- X fprintf (stderr,
- X "%s: Error reading current directory gnode 0x%x of process %d\n",
- X program, proc_uarea->u_cdir, the_proc.p_pid);
- X } else
- X
- X /*
- X * Check if this gnode is in the directory list
- X */
- X gnode_check (passwd_entry->pw_name, the_proc.p_pid, the_proc.p_ppid,
- X proc_uarea->u_comm, node, 0, the_proc.p_ttyp, Cwd);
- X
- X
- X /***
- X ** Third check: Executables
- X ***/
- X
- X /*
- X * Make sure there is a valid gnode (Wot no exec?)
- X */
- X if (the_proc.p_textp == NIL_PTR (struct text))
- X continue;
- X
- X /*
- X * Read info about the text segment of this process
- X */
- X read_from (kmem, (off_t) the_proc.p_textp, &text,
- X sizeof (struct text), "/dev/kmem");
- X
- X /*
- X * Read in the executable gnode
- X */
- X Lseek (kmem, (long) text.x_gptr, "/dev/kmem");
- X if (read (kmem, &node, sizeof (node)) != sizeof (node))
- X {
- X fprintf (stderr,
- X "%s: Error reading executable gnode 0x%x of process %d\n",
- X program, text.x_gptr, the_proc.p_pid);
- X continue;
- X }
- X
- X /*
- X * Check if this gnode is in the directory list
- X */
- X gnode_check (passwd_entry->pw_name, the_proc.p_pid, the_proc.p_ppid,
- X proc_uarea->u_comm, node, 0, the_proc.p_ttyp, Exec);
- X }
- X}
- X
- X
- X/*
- X * FUNCTION: main
- X * Parse arguments and open device files
- X *
- X * ARGUMENTS:
- X * argc - The argument count
- X * argv - The argument vector
- X *
- X * RETURN VALUE:
- X * None.
- X */
- X
- void
- main (argc, argv)
- X int argc;
- X char *argv[];
- X{
- X long procbase; /* Start address of the process table */
- X int nproc; /* Number of processes in the process table */
- X
- X int option;
- X Boolean error_flag = False;
- X
- X extern int optind, opterr; /* Global variables used by getopt */
- X extern char *optarg;
- X
- X /*
- X * Remember the program name
- X */
- X program = *argv;
- X
- X /*
- X * Check the arguments
- X */
- X if (argc < 2)
- X error_flag = True;
- X else
- X while ((option = getopt (argc, argv, "qQrRpPvV")) != EOF)
- X switch (option)
- X {
- X case 'R':
- X case 'r':
- X if (partition_mode)
- X error_flag = True;
- X else
- X recursive_mode = True;
- X break;
- X
- X case 'Q':
- X case 'q':
- X case 'P':
- X case 'p':
- X if (recursive_mode)
- X error_flag = True;
- X else
- X partition_mode = True;
- X break;
- X
- X case 'V':
- X case 'v':
- X verbose_mode = True;
- X break;
- X
- X case '?':
- X error_flag = True;
- X }
- X
- X if (verbose_mode)
- X printf ("%s: %s\n", program, version);
- X
- X if (optind == argc)
- X error_flag = True;
- X
- X if (error_flag)
- X {
- X fprintf (stderr, "%s: incorrect syntax\n", program);
- X fprintf (stderr,
- X "%s: correct syntax: %s [-r | -p] [-v] directory...\n",
- X program, program);
- X exit (0);
- X }
- X
- X /*
- X * Open the memory devices
- X */
- X if ((mem = open ("/dev/mem", 0)) < 0)
- X {
- X fprintf (stderr, "%s: ", program);
- X perror ("Can't open /dev/mem");
- X exit (1);
- X }
- X
- X if ((kmem = open ("/dev/kmem", 0)) < 0)
- X {
- X fprintf (stderr, "%s: ", program);
- X perror ("Can't open /dev/kmem");
- X exit (1);
- X }
- X
- X if ((swap = open ("/dev/drum", 0)) < 0)
- X {
- X fprintf (stderr, "%s: ", program);
- X perror ("Can't open /dev/drum");
- X exit (1);
- X }
- X
- X /*
- X * Get the kernel name list
- X */
- X if (nlist ("/vmunix", name_list) == ERROR)
- X {
- X fprintf (stderr, "%s: Couldn't read name list from /vmunix\n", program);
- X exit (1);
- X }
- X
- X if (name_list[N_PROC].n_type == 0)
- X {
- X fprintf (stderr,
- X "%s: Couldn't find symbol \"_proc\" in /vmunix\n", program);
- X exit (1);
- X }
- X
- X if (name_list[N_NPROC].n_type == 0)
- X {
- X fprintf (stderr,
- X "%s: Couldn't find symbol \"_nproc\" in /vmunix\n", program);
- X exit (1);
- X }
- X
- X /*
- X * Find the start of the process table
- X */
- X read_from (kmem, (off_t) name_list[N_PROC].n_value,
- X &procbase, sizeof (procbase), "/dev/kmem");
- X
- X /*
- X * Find the size of the process table
- X */
- X read_from (kmem, (off_t) name_list[N_NPROC].n_value,
- X &nproc, sizeof (nproc), "/dev/kmem");
- X
- X /*
- X * Create the terminal list
- X */
- X create_device_table ();
- X
- X /*
- X * Create the list of directories
- X */
- X create_dir_table ((argc - optind), (argv + optind));
- X
- X /*
- X * Check for processes active in those directories
- X */
- X if (number_of_entries > 0)
- X check_procs (procbase, nproc);
- X
- X exit (0);
- X}
- END_OF_FILE
- if test 29702 -ne `wc -c <'pads.c'`; then
- echo shar: \"'pads.c'\" unpacked with wrong size!
- fi
- # end of 'pads.c'
- fi
- echo shar: End of shell archive.
- exit 0
-