home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #1 / NN_1993_1.iso / spool / comp / unix / ultrix / 9154 next >
Encoding:
Internet Message Format  |  1993-01-04  |  42.6 KB

  1. Path: sparky!uunet!olivea!decwrl!deccrl!news.crl.dec.com!rdg.dec.com!uvo.dec.com!uvo.dec.com!sac
  2. From: sac@uvo.dec.com (Stephen Carpenter)
  3. Newsgroups: comp.unix.ultrix
  4. Subject: Version 1.6 of pads
  5. Message-ID: <1993Jan3.130448.14246@decuk.uvo.dec.com>
  6. Date: 3 Jan 93 13:04:48 GMT
  7. Sender: sac@decuk.uvo.dec.com (Stephen Carpenter)
  8. Reply-To: sac@uvo.dec.com (Stephen Carpenter)
  9. Organization: Digital Equipment Co. Ltd
  10. Lines: 1672
  11.  
  12.  
  13. This is release 1.6 of pads, a utility for listing processes active in
  14. certain directories under ULTRIX.
  15.  
  16. The major changes in this version of pads are :-
  17.  
  18.         o Checks for files being executed.
  19.         o Works on VAX ULTRIX (at last!) using the standard C compiler.
  20.         o All search types are now done simultaneously.
  21.         o 100% faster than V1.5.
  22.         o Partition mode won't hang when accessing stale NFS file systems.
  23.  
  24.  
  25. Here's an example of pads at work :-
  26.  
  27.     % pads /etc
  28.     USER     PID   PPID  CMD         TERM    TYPE  MODE PATH
  29.     root     1     0     init        ?       exec       /etc/init
  30.     root     3810  1     elcsd       ?       exec       /etc/elcsd
  31.     root     8     0     idleproc    ?       exec       /etc/startcpu
  32.     root     139   1     ntpd        ?       file  R    /etc/ntp.conf
  33.     root     139   1     ntpd        ?       file  W    /etc/ntp.drift
  34.     root     156   1     mountd      ?       file  RW   /etc/rmtab
  35.     root     24984 325   nntpd       ?       exec       /etc/nntpd
  36.     guest    24117 127   nntpd       ?       exec       /etc/nntpd
  37.     sac      28123 28084 tcsh        ttype   cwd        /etc
  38.     root     3925  325   bootpd      ?       file  R    /etc/bootptab
  39.     root     25042 325   nntpd       ?       exec       /etc/nntpd
  40.     root     19902 1     named       ?       file  R    /etc/services
  41.     root     19902 1     named       ?       file  R    /etc/protocols
  42.                                                                        
  43.  
  44. The shar archive follows.
  45.  
  46.  
  47. Stephen.
  48.  
  49.    //---------------------------------------------------------------------\\
  50.   //  Stephen Carpenter               "One inode short of a file system"   \\
  51.  //                                                                         \\
  52.  \\  UNIX Support Specialist                   sac@uvo.dec.com              //
  53.   \\  Digital Equipment Corporation                                        //
  54.    \\_____________________________________________________________________// 
  55.            
  56.  
  57. ---------------------------------Cut Here-------------------------------------
  58. #! /bin/sh
  59. # This is a shell archive.  Remove anything before this line, then unpack
  60. # it by saving it into a file and typing "sh file".  To overwrite existing
  61. # files, type "sh file -c".  You can also feed this as standard input via
  62. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  63. # will see the following message at the end:
  64. #        "End of shell archive."
  65. # Contents:  README Makefile pads.1 pads.c
  66. # Wrapped by sac@decuk.uvo.dec.com on Sun Jan  3 12:40:57 1993
  67. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  68. if test -f 'README' -a "${1}" != "-c" ; then 
  69.   echo shar: Will not clobber existing file \"'README'\"
  70. else
  71. echo shar: Extracting \"'README'\" \(2675 characters\)
  72. sed "s/^X//" >'README' <<'END_OF_FILE'
  73. X   Copyright (c) 1991, 1992, 1993 by Digital Equipment Corporation
  74. X
  75. X   Permission to use, copy, modify, and distribute this software for any
  76. X   purpose and without fee is hereby granted, provided that the above
  77. X   copyright notice and this permission notice appear in all copies, and that
  78. X   the name of Digital Equipment Corporation not be used in advertising or
  79. X   publicity pertaining to distribution of the document or software without
  80. X   specific, written prior permission.
  81. X
  82. X   Digital Equipment Corporation makes no representations about the suitability
  83. X   of the software described herein for any purpose.  It is provided "as is"
  84. X   without express or implied warranty.
  85. X
  86. X
  87. X            ###########################
  88. X
  89. X
  90. This is release 1.6 of pads, a utility for listing processes active in
  91. certain directories under ULTRIX.
  92. X
  93. X
  94. The major changes in this version of pads are :-
  95. X
  96. X    o Checks for files being executed.
  97. X    o Works on VAX ULTRIX (at last!) using the standard C compiler.
  98. X    o All search types are now done simultaneously.
  99. X    o 100% faster than V1.5.
  100. X    o Partition mode won't hang when accessing stale NFS file systems.
  101. X
  102. X
  103. Here's an example of pads at work :-
  104. X
  105. X    % pads /etc
  106. X    USER     PID   PPID  CMD         TERM    TYPE  MODE PATH
  107. X    root     1     0     init        ?       exec       /etc/init
  108. X    root     3810  1     elcsd       ?       exec       /etc/elcsd
  109. X    root     8     0     idleproc    ?       exec       /etc/startcpu
  110. X    root     139   1     ntpd        ?       file  R    /etc/ntp.conf
  111. X    root     139   1     ntpd        ?       file  W    /etc/ntp.drift
  112. X    root     156   1     mountd      ?       file  RW   /etc/rmtab
  113. X    root     24984 325   nntpd       ?       exec       /etc/nntpd
  114. X    guest    24117 127   nntpd       ?       exec       /etc/nntpd
  115. X    sac      28123 28084 tcsh        ttype   cwd        /etc
  116. X    root     3925  325   bootpd      ?       file  R    /etc/bootptab
  117. X    root     25042 325   nntpd       ?       exec       /etc/nntpd
  118. X    root     19902 1     named       ?       file  R    /etc/services
  119. X    root     19902 1     named       ?       file  R    /etc/protocols
  120. X
  121. X
  122. History
  123. X~~~~~~~
  124. X
  125. I wrote pads after a colleague complained that he couldn't dismount a
  126. file system because someone had a process active in it and if he had
  127. a command like SHOW DEVICE /FILES from VMS he could track down the
  128. offending process.
  129. X
  130. Pads is completely original work. You may find that its functionality
  131. overlaps some programs like ofiles but I believe that it is unique
  132. in the way it can search whole directory structures or partitions.
  133. X
  134. X
  135. Author
  136. X~~~~~~
  137. X
  138. X     Stephen Carpenter, UK UNIX Support, Digital Equipment Corp.
  139. X
  140. X     E-mail: sac@uvo.dec.com
  141. END_OF_FILE
  142. if test 2675 -ne `wc -c <'README'`; then
  143.     echo shar: \"'README'\" unpacked with wrong size!
  144. fi
  145. # end of 'README'
  146. fi
  147. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  148.   echo shar: Will not clobber existing file \"'Makefile'\"
  149. else
  150. echo shar: Extracting \"'Makefile'\" \(1408 characters\)
  151. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  152. X###############################################################################
  153. X#
  154. X#  (c) Copyright 1991, 1992, 1993, Digital Equipment Corporation
  155. X#
  156. X#   Permission to use, copy, modify, and distribute this software for any
  157. X#   purpose and without fee is hereby granted, provided that the above
  158. X#   copyright notice and this permission notice appear in all copies, and that
  159. X#   the name of Digital Equipment Corporation not be used in advertising or
  160. X#   publicity pertaining to distribution of the document or software without
  161. X#   specific, written prior permission.
  162. X#
  163. X#   Digital Equipment Corporation makes no representations about the
  164. X#   suitability of the software described herein for any purpose.  It is
  165. X#   provided "as is" without express or implied warranty.
  166. X#
  167. X# DEC is a registered trademark of Digital Equipment Corporation
  168. X# DIGITAL is a registered trademark of Digital Equipment Corporation
  169. X#
  170. X###############################################################################
  171. X
  172. X
  173. X#
  174. X# Makefile for pads program
  175. X#
  176. X
  177. CC = cc
  178. CFLAGS = -O
  179. X
  180. X#
  181. X# The installation directories
  182. X#
  183. XEXE_DIR = /usr/local/bin
  184. MAN_DIR = /usr/man/man1
  185. X
  186. all: pads
  187. X
  188. pads: pads.c
  189. X    $(CC) $(CFLAGS) pads.c -o pads
  190. X
  191. X$(EXE_DIR)/pads: pads
  192. X    install -c -m 2755 -o root -g kmem -s pads $(EXE_DIR)
  193. X
  194. X$(MAN_DIR)/pads.1: pads.1
  195. X    install -c -m 0444 -o root -g system pads.1 $(MAN_DIR)
  196. X
  197. install: $(EXE_DIR)/pads $(MAN_DIR)/pads.1
  198. X
  199. clean:
  200. X    rm -f pads
  201. END_OF_FILE
  202. if test 1408 -ne `wc -c <'Makefile'`; then
  203.     echo shar: \"'Makefile'\" unpacked with wrong size!
  204. fi
  205. # end of 'Makefile'
  206. fi
  207. if test -f 'pads.1' -a "${1}" != "-c" ; then 
  208.   echo shar: Will not clobber existing file \"'pads.1'\"
  209. else
  210. echo shar: Extracting \"'pads.1'\" \(3976 characters\)
  211. sed "s/^X//" >'pads.1' <<'END_OF_FILE'
  212. X.\"
  213. X.\" ***************************************************************************
  214. X.\" *
  215. X.\" *  (c) Copyright 1991, 1992, 1993, Digital Equipment Corporation
  216. X.\" *
  217. X.\" *  Permission to use, copy, modify, and distribute this software for any
  218. X.\" *  purpose and without fee is hereby granted, provided that the above
  219. X.\" *  copyright notice and this permission notice appear in all copies, and
  220. X.\" *  that the name of Digital Equipment Corporation not be used in
  221. X.\" *  advertising or publicity pertaining to distribution of the document or
  222. X.\" *  software without specific, written prior permission.
  223. X.\" *
  224. X.\" *  Digital Equipment Corporation makes no representations about the
  225. X.\" *  suitability of the software described herein for any purpose.  It is
  226. X.\" *  provided "as is" without express or implied warranty.
  227. X.\" *
  228. X.\" * DEC is a registered trademark of Digital Equipment Corporation
  229. X.\" * DIGITAL is a registered trademark of Digital Equipment Corporation
  230. X.\" *
  231. X.\" ***************************************************************************
  232. X.\"
  233. X.TH pads 1
  234. X.SH Name
  235. pads \- process active directory search
  236. X.SH Syntax
  237. X.B pads
  238. X.B [\-r | \-p] [\-v]
  239. X.I directory...
  240. X.SH Description
  241. X
  242. The
  243. X.IR pads
  244. command searches for processes which have either current
  245. working directories matching, or open files in,
  246. the directories specified in the argument list.
  247. X
  248. XFor
  249. X.IR directory ,
  250. you can specify either a full or partial path.  You can specify
  251. multiple directories, separated by spaces.
  252. X
  253. X.SH Options
  254. X.IP \-r
  255. Recursively search any directories subordinate to
  256. X.PN directory .
  257. X
  258. X.IP \-p
  259. Partition mode. Search for matches based on the device numbers
  260. of the directories specified.
  261. X
  262. X.IP \-v
  263. Verbose mode. Display warning messages.
  264. X
  265. X.SH Output Fields
  266. X
  267. XFor each matched process the output fields are:
  268. X.IP USER 10
  269. Name of the owner of the process.
  270. X.IP PID 10
  271. The process identification (PID) number.
  272. X.IP PPID 10
  273. The process identification (PID) number of the parent process.
  274. X.IP CMD 10
  275. The command the process is executing.
  276. X.IP TERM 10
  277. The controlling terminal of the process.
  278. X.IP TYPE 10
  279. The file type of the process match:
  280. X.RS
  281. X.IP cwd 8
  282. The PATH field is the current working directory of the process.
  283. X.IP file 8
  284. The PATH field is a file the process currently has open.
  285. X.IP exec 8
  286. The PATH field is the executable being run in the process.
  287. X.RE
  288. X.IP MODE 10
  289. The open mode of the file encoded thus:
  290. X.RS
  291. X.IP R 4
  292. Open for reading
  293. X.IP W 4
  294. Open for writing
  295. X.IP A 4
  296. Open for appending
  297. X.IP S 4
  298. Shared lock
  299. X.IP X 4
  300. XExclusive use
  301. X.IP I 4
  302. Asychronous I/O notification
  303. X.IP B 4
  304. Block if inuse bit is set (shared line semaphore)
  305. X.RE
  306. X
  307. X.PP
  308. Additional fields in normal and recursive modes:
  309. X.IP PATH 10
  310. The path name of the process's current working directory or open file.
  311. X
  312. X.PP
  313. Additional fields in partition mode:
  314. X.IP DEVICE 10
  315. The major and minor device numbers of the partition
  316. the process is active in.
  317. X.IP GNODE 10
  318. The gnode number of the process's current working directory
  319. or open file.
  320. X.SH Example
  321. X
  322. Unable to unmount a filesystem:
  323. X.EX
  324. X% umount /mnt
  325. umount /dev/ra10h: Mount device busy
  326. X.EE
  327. One or more processes are therefore either active in
  328. or have open files within this filesystem.
  329. Using
  330. X.PN pads
  331. you can find the processes that are preventing the unmount:
  332. X.EX
  333. X% pads -p /mnt
  334. USER     PID   PPID  CMD         TERM    TYPE  MODE DEVICE     GNODE
  335. root     1079  421   csh         ttyp2   cwd        23/34      1852
  336. root     1281  1079  cat         ttyp2   file  R    23/34      1913
  337. X.EE
  338. It is now possible to kill the offending processes and unmount the
  339. filesystem:
  340. X.EX
  341. X% kill -9 1079 1281
  342. X% umount /mnt
  343. X.EE
  344. X
  345. X.SH Files
  346. X.TP 1.2i
  347. X.PN /vmunix
  348. System namelist.
  349. X.TP 1.2i
  350. X.PN /dev
  351. Searched to find terminal names.
  352. X.TP 1.2i
  353. X.PN /dev/kmem
  354. Kernel memory.
  355. X.TP 1.2i
  356. X.PN /dev/mem
  357. User process information.
  358. X.TP 1.2i
  359. X.PN /dev/drum
  360. Swap device.
  361. X
  362. X.SH Note
  363. This command is not part of ULTRIX and is NOT supported!
  364. X
  365. X.SH Author
  366. X
  367. Stephen Carpenter, UK UNIX Support, Digital Equipment Corp.
  368. X
  369. XE-mail: sac@uvo.dec.com
  370. X.EE
  371. END_OF_FILE
  372. if test 3976 -ne `wc -c <'pads.1'`; then
  373.     echo shar: \"'pads.1'\" unpacked with wrong size!
  374. fi
  375. # end of 'pads.1'
  376. fi
  377. if test -f 'pads.c' -a "${1}" != "-c" ; then 
  378.   echo shar: Will not clobber existing file \"'pads.c'\"
  379. else
  380. echo shar: Extracting \"'pads.c'\" \(29702 characters\)
  381. sed "s/^X//" >'pads.c' <<'END_OF_FILE'
  382. X/******************************************************************************
  383. X*******************************************************************************
  384. X*
  385. X*  (c) Copyright 1991, 1992, 1993, Digital Equipment Corporation
  386. X*  
  387. X*   Permission to use, copy, modify, and distribute this software for any
  388. X*   purpose and without fee is hereby granted, provided that the above
  389. X*   copyright notice and this permission notice appear in all copies, and that
  390. X*   the name of Digital Equipment Corporation not be used in advertising or
  391. X*   publicity pertaining to distribution of the document or software without
  392. X*   specific, written prior permission.
  393. X*
  394. X*   Digital Equipment Corporation makes no representations about the
  395. X*   suitability of the software described herein for any purpose.  It is
  396. X*   provided "as is" without express or implied warranty.
  397. X*  
  398. X* DEC is a registered trademark of Digital Equipment Corporation
  399. X* DIGITAL is a registered trademark of Digital Equipment Corporation
  400. X*
  401. X*******************************************************************************
  402. X******************************************************************************/
  403. X
  404. X
  405. X/*
  406. X * PROGRAM: pads (Process Active Directory Search)
  407. X *
  408. X *   Search for processes active in specified directories.
  409. X *
  410. X *
  411. X * NOTE:
  412. X *   This tool is NOT part of ULTRIX and is NOT a supported product.
  413. X *
  414. X * AUTHOR:
  415. X *   Stephen Carpenter, UK UNIX Support, Digital Equipment Co. Ltd.
  416. X *   E-Mail: sac@uvo.dec.com
  417. X */
  418. X
  419. X
  420. static char *version = "Version 1.6  -  3rd January 1993";
  421. X
  422. X
  423. X#include <stdlib.h>
  424. X#include <stdio.h>
  425. X#include <string.h>
  426. X#include <unistd.h>
  427. X#include <nlist.h>
  428. X#include <pwd.h>
  429. X
  430. X#include <sys/types.h>
  431. X#include <sys/dir.h>
  432. X#include <sys/gnode.h>
  433. X#include <sys/stat.h>
  434. X
  435. X#include <machine/pte.h>
  436. X#include <sys/param.h>
  437. X#include <sys/mount.h>
  438. X#include <sys/user.h>
  439. X#include <sys/proc.h>
  440. X#include <sys/text.h>
  441. X#include <sys/tty.h>
  442. X
  443. X#define KERNEL
  444. X#include <sys/file.h>
  445. X#undef KERNEL
  446. X
  447. X
  448. X/*
  449. X * Figure out if this a V4.2 or above system with the capability of
  450. X * extending the number of open files per process above 64 (to a max of 4096)
  451. X */
  452. X#ifdef NOFILE_IN_U
  453. X#  define OFILE_EXTEND
  454. X#else
  455. X#  define NOFILE_IN_U NOFILE
  456. X#endif
  457. X
  458. X/*
  459. X * Define a generic NULL pointer
  460. X */
  461. X#define NIL_PTR(type) (type *) 0x0
  462. X
  463. X/*
  464. X * Define a macro for the general error return of a syscall
  465. X */
  466. X#define ERROR -1
  467. X
  468. X/*
  469. X * Define a macro to make a copy of a string in new storage
  470. X */
  471. X#define strdup(x) strcpy((char *) malloc (1 + strlen (x)), (x))
  472. X
  473. X/*
  474. X * The maximum number of characters we're going to print on a line
  475. X */
  476. X#define MAX_LINE_WIDTH 132
  477. X
  478. X/*
  479. X * Define a boolean data type
  480. X */
  481. typedef enum Boolean {False, True} Boolean;
  482. X
  483. X/*
  484. X * Signify the type of match
  485. X */
  486. typedef enum Match {Cwd, File, Exec} Match;
  487. X
  488. X/*
  489. X * Define a record containing the gnode info we require
  490. X */
  491. struct entry
  492. X{
  493. X  dev_t device;
  494. X  gno_t number;
  495. X};
  496. X
  497. X/*
  498. X * Define a directory list record
  499. X */
  500. struct entries
  501. X{
  502. X  struct entry *dir_entry;
  503. X  char *entry_name;
  504. X  Boolean is_directory;
  505. X} *dir_entries;
  506. X
  507. int number_of_entries;
  508. X
  509. X/*
  510. X * Define the device list record
  511. X */
  512. struct devent
  513. X{
  514. X  dev_t device;
  515. X  char *dev_name;
  516. X} *dev_table;
  517. X
  518. int number_of_devents;
  519. X
  520. X/*
  521. X * File descriptors for the various type of system memory
  522. X */
  523. int kmem, mem, swap;
  524. X
  525. X/*
  526. X * Define the name lists were are interested in
  527. X */
  528. X#define N_PROC 0
  529. X#define N_NPROC 1
  530. struct nlist name_list[] = {
  531. X  { "_proc" },
  532. X  { "_nproc" },
  533. X  { 0 }
  534. X};
  535. X
  536. X/*
  537. X * Name by which the program was invoked
  538. X */
  539. char *program;
  540. X
  541. X/*
  542. X * Flags for the command line switches
  543. X */
  544. Boolean recursive_mode = False;
  545. Boolean partition_mode = False;
  546. Boolean verbose_mode = False;
  547. X
  548. X
  549. X/*
  550. X * FUNCTION: Lseek
  551. X *   Like lseek but with error handling
  552. X *
  553. X * ARGUMENTS:
  554. X *   file      - The file descriptor to seek
  555. X *   offset    - The offset from the beginning of the file to seek
  556. X *   file_name - The name of the file being seeked
  557. X *
  558. X * RETURN VALUE:
  559. X *   None.
  560. X */
  561. X
  562. void
  563. Lseek (file, offset, file_name)
  564. X  int file;
  565. X  long offset;
  566. X  char *file_name;
  567. X{
  568. X  if (lseek (file, (off_t) offset, 0) == ERROR)
  569. X  {
  570. X    fprintf (stderr, "%s: Failed to seek to offset %d in %s\n",
  571. X             program, offset, file_name);
  572. X    exit (1);
  573. X  }
  574. X}
  575. X
  576. X
  577. X/*
  578. X * FUNCTION: read_from
  579. X *   Combine seeking and reading into one operation.
  580. X *
  581. X * ARGUMENTS:
  582. X *   file      - The file descriptor to read from.
  583. X *   offset    - The offset from the beginning of the file to seek.
  584. X *   variable  - The variable to read information into.
  585. X *   size      - The number of bytes to read.
  586. X *   file_name - The name of the file being read.
  587. X *
  588. X * RETUTN VALUE:
  589. X *   None.
  590. X */
  591. X
  592. void
  593. read_from (file, offset, variable, size, file_name)
  594. X  int file;
  595. X  off_t offset;
  596. X  void *variable;
  597. X  size_t size;
  598. X  char *file_name;
  599. X{
  600. X  if (lseek (file, offset, 0) == ERROR)
  601. X  {
  602. X    fprintf (stderr, "%s: Failed to seek to offset %d in %s\n",
  603. X             program, offset, file_name);
  604. X    exit (1);
  605. X  }
  606. X
  607. X  if (read (file, (char *) variable, (int) size) != size)
  608. X  {
  609. X    fprintf (stderr, "%s: Failed to read %d bytes at 0x%x from %s\n",
  610. X             program, size, variable, file_name);
  611. X    exit (1);
  612. X  }
  613. X}
  614. X
  615. X
  616. X/*
  617. X * FUNCTION: full_name
  618. X *   Concatenate a file name to a directory name
  619. X *
  620. X * ARGUMENTS:
  621. X *   dir  - The name of the diretory where the file resides
  622. X *   file - The name of the file.
  623. X *
  624. X * RETURN VALUE:
  625. X *   A pointer to a string containing the path name of the file.
  626. X */
  627. X
  628. char *
  629. full_name (dir, file)
  630. X  char *dir;
  631. X  char *file;
  632. X{
  633. X  char *path = (char *) malloc (MAXPATHLEN * sizeof (char));
  634. X
  635. X  path = strcpy (path, dir);
  636. X  if (dir[strlen (dir) - 1] != '/')
  637. X    path = strcat (path, "/");
  638. X  path = strcat (path, file);
  639. X
  640. X  return (path);
  641. X}
  642. X
  643. X
  644. X/*
  645. X * FUNCTION: expand_name
  646. X *   Expand a file name to a full path name
  647. X *
  648. X * ARGUMENTS:
  649. X *   file - The name of the file.
  650. X *
  651. X * RETURN VALUE:
  652. X *   A string containing the full path name of the file.
  653. X */
  654. X
  655. char *
  656. expand_file (file)
  657. X  char *file;
  658. X{
  659. X  char *path = (char *) malloc (MAXPATHLEN * sizeof (char));
  660. X
  661. X  if (*file == '/')
  662. X    return (strcpy (path, file));
  663. X
  664. X  /*
  665. X   * Check if the file is the process cwd
  666. X   */
  667. X  if (!strcmp (file, "."))
  668. X  {
  669. X    path = (char *) getwd (path);
  670. X
  671. X    return (path);
  672. X  }
  673. X
  674. X  if (!strncmp (file, "./", 2))
  675. X    path = strcat ((char *) getwd (path), ++file);
  676. X  else {
  677. X    path = strcat ((char *) getwd (path), "/");
  678. X    path = strcat (path, file);
  679. X  }
  680. X
  681. X  return (path);
  682. X}
  683. X
  684. X
  685. X/*
  686. X * FUNCTION: get_tty_name
  687. X *   Match a tty structure against the device list
  688. X *
  689. X * ARGUMENTS:
  690. X *   ttyp - A pointer to the tty structure of the controlling terminal.
  691. X *
  692. X * RETURN VALUE:
  693. X *   A string containing the name of the tty device.
  694. X */
  695. X
  696. char *
  697. get_tty_name (tty_ptr)
  698. X  struct tty *tty_ptr;
  699. X{
  700. X  int index;
  701. X  struct tty control_tty;
  702. X
  703. X  if (tty_ptr != NIL_PTR (struct tty))
  704. X  {
  705. X    /*
  706. X     * Read the tty structure out of kernel memory
  707. X     */
  708. X    read_from (kmem, (off_t) tty_ptr, &control_tty,
  709. X               sizeof (struct tty), "/dev/kmem");
  710. X
  711. X    /*
  712. X     * Search the device list for this tty
  713. X     */
  714. X    for (index = 0; index < number_of_devents; index++)
  715. X      if ((dev_table + index)->device == control_tty.t_dev)
  716. X        return ((dev_table + index)->dev_name);
  717. X  }
  718. X
  719. X  /*
  720. X   * The process is not associated with a terminal
  721. X   */
  722. X  return ("?");
  723. X}
  724. X
  725. X
  726. X/*
  727. X * FUNCTION: create_device_table
  728. X *   Create a list of the character devices found in /dev
  729. X *
  730. X * ARGUMENTS:
  731. X *   None.
  732. X *
  733. X * RETURN VALUE:
  734. X *   None.
  735. X */
  736. X
  737. void
  738. create_device_table ()       
  739. X{
  740. X  struct direct *dir_entry;
  741. X  DIR *dir_ptr;
  742. X  struct stat stat_info;
  743. X
  744. X  dev_table = NIL_PTR (struct devent);
  745. X  number_of_devents = 0;
  746. X
  747. X  if ((dir_ptr = opendir ("/dev")) == NULL)
  748. X  {
  749. X    fprintf (stderr, "%s: ", program);
  750. X    perror ("Can't open directory /dev");
  751. X    return;
  752. X  }
  753. X
  754. X  /*
  755. X   * Check each device
  756. X   */
  757. X  while ((dir_entry = readdir(dir_ptr)) != NULL)
  758. X  {
  759. X    /*
  760. X     * Find out the type of device
  761. X     */
  762. X    if (lstat (full_name ("/dev", dir_entry->d_name), &stat_info) == ERROR)
  763. X    {
  764. X      fprintf (stderr, "%s: Can't stat ", program);
  765. X      perror (full_name ("/dev", dir_entry->d_name));
  766. X      continue;
  767. X    }
  768. X
  769. X    /*
  770. X     * Add any character devices to the list
  771. X     */
  772. X    if ((stat_info.st_mode & S_IFMT) == S_IFCHR)
  773. X    {
  774. X      number_of_devents++;
  775. X      dev_table =
  776. X         (struct devent *) realloc (dev_table,
  777. X                                    number_of_devents * sizeof (struct devent));
  778. X
  779. X      (dev_table + number_of_devents - 1)->dev_name = strdup (dir_entry->d_name);
  780. X      (dev_table + number_of_devents - 1)->device = stat_info.st_rdev;
  781. X    }
  782. X  }
  783. X  closedir(dir_ptr);
  784. X}
  785. X
  786. X
  787. X/*
  788. X * FUNCTION: add_dir_entry
  789. X *   Add an entry to the directory list
  790. X *
  791. X * ARGUMENTS:
  792. X *   entry_name - A string containing the name of the direcory to add
  793. X *
  794. X * RETURN VALUE:
  795. X *   None.
  796. X */
  797. X
  798. void
  799. add_dir_entry (entry_name, is_directory)
  800. X  char *entry_name;
  801. X  Boolean is_directory;
  802. X{
  803. X  struct entry *the_entry = (struct entry *) malloc (sizeof (struct entry));
  804. X  struct stat stat_info;
  805. X  struct fs_data mount_info;
  806. X
  807. X  if (partition_mode)
  808. X  {
  809. X    /*
  810. X     * In partition mode we use getmnt() rather than stat() to avoid
  811. X     * hangs due to NFS server problems
  812. X     */
  813. X    if (getmnt (0, &mount_info, 0, NOSTAT_ONE, entry_name) == ERROR)
  814. X    {
  815. X      fprintf (stderr, "%s: Can't get mount info for ", program);
  816. X      perror (entry_name);
  817. X      return;
  818. X    }
  819. X    the_entry->device = mount_info.fd_req.dev;
  820. X
  821. X  } else {
  822. X    /*
  823. X     * Get the gnode info
  824. X     */
  825. X    if (lstat (entry_name, &stat_info) == ERROR)
  826. X    {
  827. X      fprintf (stderr, "%s: Can't stat ", program);
  828. X      perror (entry_name);
  829. X      return;
  830. X    }
  831. X
  832. X    the_entry->device = stat_info.st_dev;
  833. X    the_entry->number = stat_info.st_ino;
  834. X  }
  835. X
  836. X  number_of_entries++;
  837. X  dir_entries = (struct entries *)
  838. X                    realloc (dir_entries,
  839. X                             number_of_entries * sizeof (struct entries));
  840. X
  841. X  /*
  842. X   * Store the gnode info
  843. X   */
  844. X  (dir_entries + number_of_entries - 1)->dir_entry = the_entry;
  845. X
  846. X  /*
  847. X   * Store the directory name
  848. X   */
  849. X  (dir_entries + number_of_entries - 1)->entry_name = strdup (entry_name);
  850. X
  851. X  (dir_entries + number_of_entries - 1)->is_directory = is_directory;
  852. X}
  853. X
  854. X
  855. X/*
  856. X * FUNCTION: recursive_dir_add
  857. X *   Recursively search the direcory structure for directory entries
  858. X *
  859. X * ARGUMENTS:
  860. X *   entry_name   - A string containing the name of the direcory search
  861. X *   do_recursion - A flag to determine if actual recursion is required
  862. X *
  863. X * RETURN VALUE:
  864. X *   None.
  865. X */
  866. X
  867. void
  868. recursive_dir_add (entry_name, do_recursion)
  869. X  char *entry_name;
  870. X  Boolean do_recursion;
  871. X{
  872. X  DIR *dir_ptr;
  873. X  struct direct *dir_entry;
  874. X  struct stat stat_info;
  875. X  char *file;
  876. X  char *error_string;
  877. X
  878. X  /*
  879. X   * Open the directory for reading
  880. X   */
  881. X  if ((dir_ptr = opendir (entry_name)) == NULL)
  882. X  {
  883. X    error_string = (char *) malloc (sizeof (char) * (strlen (entry_name) + 18));
  884. X    sprintf (error_string, "%s: Error opening %s", program, entry_name);
  885. X    perror (error_string);
  886. X    return;
  887. X  }
  888. X
  889. X  /*
  890. X   * Skip '.' & '..' directories
  891. X   */
  892. X  dir_entry = readdir (dir_ptr);
  893. X  dir_entry = readdir (dir_ptr);
  894. X
  895. X  for (dir_entry = readdir (dir_ptr); dir_entry != NULL;
  896. X       dir_entry = readdir (dir_ptr))
  897. X  {
  898. X    /*
  899. X     * Get the directory info
  900. X     */
  901. X    file = full_name (entry_name, dir_entry->d_name);
  902. X
  903. X    if (lstat (file, &stat_info) == ERROR)
  904. X    {
  905. X      fprintf (stderr, "%s: Can't stat ", program);
  906. X      perror (file);
  907. X      continue;
  908. X    }
  909. X
  910. X    if ((stat_info.st_mode & S_IFMT) == S_IFDIR)
  911. X    {
  912. X      /*
  913. X       * It's a directory so add the entry to the directory list
  914. X       * and search this directory for sub-directories.
  915. X       */
  916. X      add_dir_entry (file, True);
  917. X
  918. X      if (do_recursion)
  919. X        recursive_dir_add (file, True);
  920. X    } else
  921. X      add_dir_entry (file, False);
  922. X
  923. X    /*
  924. X     * Free up redundant space
  925. X     */
  926. X    free (file);
  927. X  }
  928. X  closedir (dir_ptr);
  929. X}
  930. X
  931. X
  932. X/*
  933. X * FUNCTION: create_dir_table
  934. X *   Initialise and start off the directory list
  935. X *
  936. X * ARGUMENTS:
  937. X *   argc    - Argument count
  938. X *   argv    - Argument vector
  939. X *
  940. X * RETURN VALUE:
  941. X *   None.
  942. X */
  943. X
  944. void
  945. create_dir_table (dir_argc, dir_argv)
  946. X  int dir_argc;
  947. X  char *dir_argv[];
  948. X{
  949. X  struct stat stat_info;
  950. X  int index;
  951. X  char *path;
  952. X
  953. X  /*
  954. X   * Initialise the directory list
  955. X   */
  956. X  number_of_entries = 0;
  957. X  dir_entries = NIL_PTR (struct entries);
  958. X
  959. X  /*
  960. X   * Add the directories in the arguments to the directory list
  961. X   */
  962. X  for (index = 0; index < dir_argc; index++)
  963. X  {
  964. X    path = expand_file (dir_argv[index]);
  965. X    if (partition_mode)
  966. X    {
  967. X        add_dir_entry (path, True);
  968. X    } else 
  969. X      if (recursive_mode)
  970. X      {
  971. X        add_dir_entry (path, True);
  972. X        recursive_dir_add (path, True);
  973. X      } else {
  974. X        if (lstat (path, &stat_info) == ERROR)
  975. X        {
  976. X          fprintf (stderr, "%s: Can't stat ", program);
  977. X          perror (path);
  978. X          exit (1);
  979. X        }
  980. X
  981. X        if ((stat_info.st_mode & S_IFMT) == S_IFDIR)
  982. X        {
  983. X          add_dir_entry (path, True);
  984. X          recursive_dir_add (path, False);
  985. X        } else
  986. X          add_dir_entry (path, False);
  987. X      }
  988. X    free (path);
  989. X  }
  990. X}
  991. X
  992. X
  993. X/*
  994. X * FUNCTION: get_user_area
  995. X *   Read the user area for a given process from memory or swap
  996. X *
  997. X * ARGUMENTS:
  998. X *   the_proc - The process to get the user area for
  999. X *
  1000. X * RETURN VALUE:
  1001. X *   A pointer to copy of the user area of the process
  1002. X */
  1003. X
  1004. struct user *
  1005. get_user_area (the_proc)
  1006. X  struct proc *the_proc;
  1007. X{
  1008. X  struct dmap stack_dmap;            /* Stack segment disk map                */
  1009. X  struct pte proc_pte[UPAGES];       /* Page table entries for process        */
  1010. X  char *user_area;                   /* The user area of the process          */
  1011. X  int user_block;                    /* File system block number of user area */
  1012. X  int clusters;                      /* Number of page clusters               */
  1013. X  int pagenum;                       /* Page number                           */
  1014. X  long pageaddr;                     /* Page address                          */
  1015. X
  1016. X  if ((the_proc->p_sched & SLOAD) == 0)
  1017. X  {
  1018. X    /*
  1019. X     * The process is currently swapped out
  1020. X     * We therefore need to pull the info out of the swap device
  1021. X     */
  1022. X
  1023. X    /*
  1024. X     * Read disk map for stack segment
  1025. X     */
  1026. X    read_from (kmem, (off_t) the_proc->p_smap,
  1027. X               &stack_dmap, sizeof (struct dmap), "/dev/kmem");
  1028. X
  1029. X    /*
  1030. X     * Read address of disk address of user page table
  1031. X     */
  1032. X    read_from (kmem, (off_t) stack_dmap.dm_ptdaddr,
  1033. X               &user_block, sizeof (int), "/dev/kmem");
  1034. X
  1035. X    /*
  1036. X     * Grab memory for the user area variable
  1037. X     */
  1038. X    user_area = (char *) malloc (sizeof (struct user));
  1039. X
  1040. X    /*
  1041. X     * Now read in the user area from swap
  1042. X     */
  1043. X    Lseek (swap, (long) dtob (user_block), "/dev/drum");
  1044. X    if (read (swap, user_area, sizeof (struct user)) != sizeof (struct user))
  1045. X    {
  1046. X      fprintf (stderr,
  1047. X               "%s: Can't read user area of process %d from /dev/drum\n",
  1048. X               program, the_proc->p_pid);
  1049. X
  1050. X      free (user_area);
  1051. X      return (NIL_PTR (struct user));
  1052. X    } else
  1053. X      return ((struct user *) user_area);
  1054. X
  1055. X  } else {
  1056. X
  1057. X    /*
  1058. X     * The process is in memory. Read the process pte from virtual memory.
  1059. X     */
  1060. X    Lseek (kmem, (long) the_proc->p_addr, "/dev/kmem");
  1061. X    if (read (kmem, (char *) &proc_pte[0], sizeof (proc_pte))
  1062. X        !=  sizeof (proc_pte))
  1063. X    {
  1064. X      fprintf (stderr,
  1065. X               "%s: Can't read pte for user page of process %d from /dev/kmem\n",
  1066. X               program, the_proc->p_pid);
  1067. X              
  1068. X      return (NIL_PTR (struct user));
  1069. X    }
  1070. X
  1071. X    /*
  1072. X     * Grab memory to hold the user pages
  1073. X     */
  1074. X    user_area = (char *) malloc (UPAGES * NBPG);
  1075. X
  1076. X    /*
  1077. X     * Read in the user area pages from memory
  1078. X     */
  1079. X    clusters = (sizeof (struct user) + NBPG*CLSIZE - 1) / (NBPG*CLSIZE);
  1080. X    while (--clusters >= 0)
  1081. X    {
  1082. X      pagenum = clusters * CLSIZE;
  1083. X      pageaddr = ctob (proc_pte[pagenum].pg_pfnum);
  1084. X      Lseek (mem, pageaddr, "/dev/mem");
  1085. X      if (read (mem, user_area + (NBPG * pagenum), CLSIZE*NBPG) != CLSIZE*NBPG)
  1086. X      {
  1087. X        fprintf (stderr,
  1088. X                 "%s: Can't read page 0x%x of process %d from /dev/mem\n",
  1089. X                 program, (int) pageaddr, the_proc->p_pid);
  1090. X
  1091. X        free (user_area);
  1092. X        return (NIL_PTR (struct user));
  1093. X      }
  1094. X    }
  1095. X    return ((struct user *) user_area);
  1096. X  }
  1097. X}
  1098. X
  1099. X
  1100. X/*
  1101. X * FUNCTION: file_open_mode
  1102. X *   Get the open mode of a file.
  1103. X *
  1104. X * ARGUMENTS:
  1105. X *   flags - The file mode flags.
  1106. X *
  1107. X * RETURN VALUE:
  1108. X *   A string containing the mode acronym.
  1109. X */
  1110. X
  1111. char *
  1112. file_open_mode (flags)
  1113. X  int flags;
  1114. X{
  1115. X  char *mode = (char *) malloc (7 * sizeof (char));
  1116. X  int pos = 0;
  1117. X
  1118. X  if (flags & FREAD)
  1119. X    mode[pos++] = 'R';
  1120. X
  1121. X  if (flags & FWRITE)
  1122. X    if (flags & FAPPEND)
  1123. X      mode[pos++] = 'A';
  1124. X    else
  1125. X      mode[pos++] = 'W';
  1126. X
  1127. X  if (flags & FSHLOCK)
  1128. X    mode[pos++] = 'S';
  1129. X
  1130. X  if (flags & FEXLOCK)
  1131. X    mode[pos++] = 'X';
  1132. X
  1133. X  if (flags & FASYNC)
  1134. X    mode[pos++] = 'I';
  1135. X
  1136. X  if (flags & FBLKINUSE)
  1137. X    mode[pos++] = 'B';
  1138. X
  1139. X  mode[pos] = '\0';
  1140. X
  1141. X  return (mode);
  1142. X}
  1143. X
  1144. X
  1145. X/*
  1146. X * FUNCTION: print_info
  1147. X *   Print a line of process information
  1148. X *
  1149. X * ARGUMENTS:
  1150. X *   user  - A string containing the user name of the process
  1151. X *   pid   - The process ID of the process
  1152. X *   cmd   - A string containing the command being executed by the process
  1153. X *   node  - The gnode of the CWD or open file
  1154. X *   type  - What sort of match is this?
  1155. X *   ttyp  - A pointer to the controlling terminal of the process
  1156. X *   flags - The flags the gnode was opened with
  1157. X *   file  - A string containing the name of the file or directory
  1158. X *
  1159. X * RETURN VALUE:
  1160. X *   None.
  1161. X */
  1162. X
  1163. void
  1164. print_info (user, pid, ppid, cmd, node, type, ttyp, flags, file)
  1165. X  char *user;
  1166. X  int pid;
  1167. X  int ppid;
  1168. X  char *cmd;
  1169. X  struct gnode node;
  1170. X  Match type;
  1171. X  struct tty *ttyp;
  1172. X  int flags;
  1173. X  char *file;
  1174. X{
  1175. X  char line[MAX_LINE_WIDTH];
  1176. X  char pid_string[10];
  1177. X  char *mode_string;
  1178. X  char *tty;
  1179. X
  1180. X  tty = get_tty_name (ttyp);
  1181. X
  1182. X  /*
  1183. X   * Build up the info line for each process
  1184. X   */
  1185. X  memset (line, ' ', sizeof (line));
  1186. X
  1187. X  strncpy (&line[0], user, strlen (user));
  1188. X  sprintf (&pid_string[0], "%d", pid);
  1189. X  strncpy (&line[9],  pid_string, strlen (pid_string));
  1190. X  sprintf (&pid_string[0], "%d", ppid);
  1191. X  strncpy (&line[15],  pid_string, strlen (pid_string));
  1192. X  strncpy (&line[21], cmd, strlen (cmd));
  1193. X  strncpy (&line[33], tty, strlen (tty));
  1194. X
  1195. X  switch (type)
  1196. X  {
  1197. X    case Cwd:
  1198. X      strncpy (&line[41], "cwd", 3);
  1199. X      break;
  1200. X    case File:
  1201. X      strncpy (&line[41], "file", 4);
  1202. X      break;
  1203. X    case Exec:
  1204. X      strncpy (&line[41], "exec", 4);
  1205. X  }
  1206. X
  1207. X  if (type == File)
  1208. X  {
  1209. X    mode_string = file_open_mode (flags);
  1210. X    if (partition_mode)
  1211. X    {
  1212. X      strncpy (&line[47], mode_string, strlen (mode_string));
  1213. X      sprintf (&line[52], "%d/%d  \t%d",
  1214. X               major(node.g_req.gr_dev), minor(node.g_req.gr_dev),
  1215. X               (int) node.g_req.gr_number);
  1216. X    } else {
  1217. X      strncpy (&line[47], mode_string, strlen (mode_string));
  1218. X      sprintf (&line[52], "%.*s", (MAX_LINE_WIDTH - 29), file);
  1219. X    }
  1220. X  } else
  1221. X    if (partition_mode)
  1222. X      sprintf (&line[52], "%d/%d\t%d",
  1223. X               major(node.g_req.gr_dev), minor(node.g_req.gr_dev),
  1224. X               (int) node.g_req.gr_number);
  1225. X    else
  1226. X      sprintf (&line[52], "%.*s", (MAX_LINE_WIDTH - 29), file);
  1227. X
  1228. X  /*
  1229. X   * Output the line info
  1230. X   */
  1231. X  puts (line);
  1232. X}
  1233. X
  1234. X
  1235. X/*
  1236. X * FUNCTION: gnode_check
  1237. X *   Check if the process CWD or open file gnode is in the
  1238. X *   direcory entries list.
  1239. X *
  1240. X * ARGUMENTS:
  1241. X *   user  - A string containing the user name of the process
  1242. X *   pid   - The process ID of the process
  1243. X *   cmd   - A string containing the command being executed by the process
  1244. X *   node  - The gnode of the CWD or open file
  1245. X *   flags - The flags the gnode was opened with
  1246. X *   ttyp  - A pointer to the controlling terminal of the process
  1247. X *   type  - What sort of match is this?
  1248. X *
  1249. X * RETURN VALUE:
  1250. X *   None.
  1251. X */
  1252. X
  1253. void
  1254. gnode_check (user, pid, ppid, cmd, node, flags, ttyp, type)
  1255. X  char *user;
  1256. X  int pid;
  1257. X  int ppid;
  1258. X  char *cmd;
  1259. X  struct gnode node;
  1260. X  int flags;
  1261. X  struct tty *ttyp;
  1262. X  Match type;
  1263. X{
  1264. X  int index;
  1265. X
  1266. X  /*
  1267. X   * Check if this gnode is in the directory list
  1268. X   */
  1269. X  for (index = 0; index < number_of_entries; index++)
  1270. X  {
  1271. X    /*
  1272. X     * Do we have the right device?
  1273. X     */
  1274. X    if (node.g_req.gr_dev == (dir_entries + index)->dir_entry->device)
  1275. X      if (partition_mode)
  1276. X        /*
  1277. X         * We're in partition mode and therefore we have a match
  1278. X         */
  1279. X        print_info (user, pid, ppid, cmd, node, type, ttyp, flags, "");
  1280. X      else
  1281. X        if (type == Cwd && !(dir_entries + index)->is_directory)
  1282. X          /*
  1283. X           * The cwd was actually a file! 
  1284. X           * Is this an OS bug??
  1285. X           */
  1286. X          continue;
  1287. X        else
  1288. X          /*
  1289. X           * Does the gnode check out?
  1290. X           */
  1291. X          if (node.g_req.gr_number == (dir_entries + index)->dir_entry->number)
  1292. X            print_info (user, pid, ppid, cmd, node, type, ttyp, flags,
  1293. X                        (dir_entries + index)->entry_name);
  1294. X  }
  1295. X}
  1296. X
  1297. X
  1298. X/*
  1299. X * FUNCTION: check_procs
  1300. X *   Search the process table for processes with current working directories
  1301. X *   matching the directory list entries
  1302. X *
  1303. X * ARGUMENTS:
  1304. X *   procbase - The address of the start of the process table
  1305. X *   nproc    - The size of the process table
  1306. X *
  1307. X * RETURN VALUE:
  1308. X *   None.
  1309. X */
  1310. X
  1311. void
  1312. check_procs (procbase, nproc)
  1313. X  long procbase;
  1314. X  int nproc;
  1315. X{
  1316. X  struct user *proc_uarea = NIL_PTR (struct user);
  1317. X  struct proc the_proc;
  1318. X  struct file **ofile_table_extension;
  1319. X  struct file open_file;
  1320. X  struct text text;
  1321. X  struct gnode node;
  1322. X  struct passwd *passwd_entry;
  1323. X  int index, index1;
  1324. X
  1325. X  /*
  1326. X   * Print title bar
  1327. X   */
  1328. X  if (partition_mode)
  1329. X    printf ("USER     PID   PPID  CMD         TERM    TYPE  MODE DEVICE\tGNODE\n");
  1330. X  else
  1331. X    printf ("USER     PID   PPID  CMD         TERM    TYPE  MODE PATH\n");
  1332. X
  1333. X#ifdef OFILE_EXTEND
  1334. X  /*
  1335. X   * Reserve space for the extended open file table of a process
  1336. X   */
  1337. X  ofile_table_extension =
  1338. X     (struct file **) malloc ((getdtablesize () - NOFILE_IN_U)
  1339. X                              * sizeof (struct file *));
  1340. X#endif
  1341. X
  1342. X  /*
  1343. X   * Walk the process table
  1344. X   */
  1345. X  for (index = 0; index < nproc; index++)
  1346. X  {
  1347. X    /*
  1348. X     * Read in the process structure
  1349. X     */
  1350. X    read_from (kmem, (off_t) (procbase + (long)(index * sizeof (struct proc))),
  1351. X               &the_proc, sizeof (struct proc), "/dev/kmem");
  1352. X
  1353. X    /*
  1354. X     * Skip over empty proc slots
  1355. X     */
  1356. X    if (the_proc.p_stat == 0 || the_proc.p_pid == 0)
  1357. X      continue;
  1358. X
  1359. X    /*
  1360. X     * Ignore zombies
  1361. X     */
  1362. X    if (the_proc.p_stat == SZOMB)
  1363. X    {
  1364. X      if (verbose_mode)
  1365. X        printf ("%s: Process %d is a zombie!\n", program, the_proc.p_pid);
  1366. X      continue;
  1367. X    }
  1368. X
  1369. X    /*
  1370. X     * Free up any malloced user area memory
  1371. X     */
  1372. X    if (proc_uarea != NIL_PTR (struct user))
  1373. X      free (proc_uarea);
  1374. X
  1375. X    /*
  1376. X     * Check for 'soft' errors in reading the user area
  1377. X     */
  1378. X    if ((proc_uarea = get_user_area (&the_proc)) == 0)
  1379. X      continue;
  1380. X
  1381. X    /*
  1382. X     * Get password info (we really want the user name)
  1383. X     */
  1384. X    passwd_entry = getpwuid (the_proc.p_uid);
  1385. X
  1386. X
  1387. X    /***
  1388. X     ** First check: Open Files
  1389. X     ***/
  1390. X
  1391. X#ifdef OFILE_EXTEND
  1392. X    /*
  1393. X     * If we have more than NOFILE_IN_U open files
  1394. X     * then read in the extended open file table.
  1395. X     */
  1396. X    if (proc_uarea->u_lastfile >= NOFILE_IN_U)
  1397. X    {
  1398. X      read_from (kmem, (off_t) proc_uarea->u_ofile_of, ofile_table_extension,
  1399. X                 proc_uarea->u_of_count * sizeof (struct file *), "/dev/kmem");
  1400. X    }
  1401. X#endif
  1402. X    for (index1 = 0; index1 <= proc_uarea->u_lastfile; index1++)
  1403. X    {
  1404. X      if (index1 < NOFILE_IN_U)
  1405. X      {
  1406. X        if (proc_uarea->u_ofile[index1] == NIL_PTR (struct file))
  1407. X          continue;
  1408. X
  1409. X        read_from (kmem, (off_t) proc_uarea->u_ofile[index1],
  1410. X                   &open_file, sizeof (open_file), "/dev/kmem");
  1411. X      } else {
  1412. X#ifdef OFILE_EXTEND
  1413. X        /*
  1414. X         * The open file is in the extended table
  1415. X         */
  1416. X        if (*(ofile_table_extension + index1 - NOFILE_IN_U)
  1417. X            == NIL_PTR (struct file))
  1418. X          continue;
  1419. X
  1420. X        read_from (kmem,
  1421. X                   (off_t) *(ofile_table_extension + index1 - NOFILE_IN_U),
  1422. X                   &open_file, sizeof (open_file), "/dev/kmem");
  1423. X#endif
  1424. X      }
  1425. X
  1426. X      /*
  1427. X       * The reference count should be at least one
  1428. X       */
  1429. X      if (open_file.f_count == 0)
  1430. X        continue;
  1431. X
  1432. X      /*
  1433. X       * Make sure that this file has a gnode
  1434. X       */
  1435. X      if (open_file.f_data == NIL_PTR (char))
  1436. X        continue;
  1437. X
  1438. X      /*
  1439. X       * Read in the gnode associated with this file
  1440. X       */
  1441. X      Lseek (kmem, (long) open_file.f_data, "/dev/kmem");
  1442. X      if (read (kmem, &node, sizeof (node)) !=  sizeof (node))
  1443. X      {
  1444. X        if (verbose_mode)
  1445. X          printf ("%s: Unable to read open file gnode 0x%x of process %d\n",
  1446. X                  program, open_file.f_data, the_proc.p_pid);
  1447. X      } else
  1448. X
  1449. X        /*
  1450. X         * Check if this gnode is in the directory list
  1451. X         */
  1452. X        gnode_check (passwd_entry->pw_name, the_proc.p_pid, the_proc.p_ppid,
  1453. X                     proc_uarea->u_comm, node, open_file.f_flag,
  1454. X                     the_proc.p_ttyp, File);
  1455. X    }
  1456. X
  1457. X
  1458. X    /***
  1459. X     ** Second check: Process Current Working Directory
  1460. X     ***/
  1461. X
  1462. X    /*
  1463. X     * Read in the current working directory gnode
  1464. X     */
  1465. X    Lseek (kmem, (long) proc_uarea->u_cdir, "/dev/kmem");
  1466. X    if (read (kmem, &node, sizeof (node)) !=  sizeof (node))
  1467. X    {
  1468. X      fprintf (stderr,
  1469. X               "%s: Error reading current directory gnode 0x%x of process %d\n",
  1470. X               program, proc_uarea->u_cdir, the_proc.p_pid);
  1471. X    } else
  1472. X
  1473. X      /*
  1474. X       * Check if this gnode is in the directory list
  1475. X       */
  1476. X      gnode_check (passwd_entry->pw_name, the_proc.p_pid, the_proc.p_ppid,
  1477. X                   proc_uarea->u_comm, node, 0, the_proc.p_ttyp, Cwd);
  1478. X
  1479. X
  1480. X    /***
  1481. X     ** Third check: Executables
  1482. X     ***/
  1483. X
  1484. X    /*
  1485. X     * Make sure there is a valid gnode (Wot no exec?)
  1486. X     */
  1487. X    if (the_proc.p_textp == NIL_PTR (struct text))
  1488. X      continue;
  1489. X
  1490. X    /*
  1491. X     * Read info about the text segment of this process
  1492. X     */
  1493. X    read_from (kmem, (off_t) the_proc.p_textp, &text,
  1494. X               sizeof (struct text), "/dev/kmem");
  1495. X
  1496. X    /*
  1497. X     * Read in the executable gnode
  1498. X     */
  1499. X    Lseek (kmem, (long) text.x_gptr, "/dev/kmem");
  1500. X    if (read (kmem, &node, sizeof (node)) !=  sizeof (node))
  1501. X    {
  1502. X      fprintf (stderr,
  1503. X               "%s: Error reading executable gnode 0x%x of process %d\n",
  1504. X               program, text.x_gptr, the_proc.p_pid);
  1505. X      continue;
  1506. X    }
  1507. X
  1508. X    /*
  1509. X     * Check if this gnode is in the directory list
  1510. X     */
  1511. X    gnode_check (passwd_entry->pw_name, the_proc.p_pid, the_proc.p_ppid,
  1512. X                 proc_uarea->u_comm, node, 0, the_proc.p_ttyp, Exec);
  1513. X  }
  1514. X}
  1515. X
  1516. X
  1517. X/*
  1518. X * FUNCTION: main
  1519. X *   Parse arguments and open device files
  1520. X *
  1521. X * ARGUMENTS:
  1522. X *   argc - The argument count
  1523. X *   argv - The argument vector
  1524. X *
  1525. X * RETURN VALUE:
  1526. X *   None.
  1527. X */
  1528. X
  1529. void
  1530. main (argc, argv)
  1531. X  int argc;
  1532. X  char *argv[];
  1533. X{
  1534. X  long procbase;        /* Start address of the process table          */
  1535. X  int nproc;            /* Number of processes in the process table    */
  1536. X
  1537. X  int option;
  1538. X  Boolean error_flag = False;
  1539. X
  1540. X  extern int optind, opterr;  /* Global variables used by getopt */
  1541. X  extern char *optarg;
  1542. X
  1543. X  /*
  1544. X   * Remember the program name
  1545. X   */
  1546. X  program = *argv;
  1547. X
  1548. X  /*
  1549. X   * Check the arguments
  1550. X   */
  1551. X  if (argc < 2)
  1552. X    error_flag = True;
  1553. X  else
  1554. X    while ((option = getopt (argc, argv, "qQrRpPvV")) != EOF)
  1555. X      switch (option)
  1556. X      {
  1557. X        case 'R':
  1558. X        case 'r':
  1559. X          if (partition_mode)
  1560. X            error_flag = True;
  1561. X          else
  1562. X            recursive_mode = True;
  1563. X          break;
  1564. X
  1565. X        case 'Q':
  1566. X        case 'q':
  1567. X        case 'P':
  1568. X        case 'p':
  1569. X          if (recursive_mode)
  1570. X            error_flag = True;
  1571. X          else
  1572. X            partition_mode = True;
  1573. X          break;
  1574. X
  1575. X        case 'V':
  1576. X        case 'v':
  1577. X          verbose_mode = True;
  1578. X          break;
  1579. X
  1580. X        case '?':
  1581. X          error_flag = True;
  1582. X      }
  1583. X
  1584. X  if (verbose_mode)
  1585. X    printf ("%s: %s\n", program, version);
  1586. X
  1587. X  if (optind == argc)
  1588. X    error_flag = True;
  1589. X
  1590. X  if (error_flag)
  1591. X  {
  1592. X    fprintf (stderr, "%s: incorrect syntax\n", program);
  1593. X    fprintf (stderr,
  1594. X             "%s: correct syntax: %s [-r | -p] [-v] directory...\n",
  1595. X             program, program);
  1596. X    exit (0);
  1597. X  }
  1598. X
  1599. X  /*
  1600. X   * Open the memory devices
  1601. X   */
  1602. X  if ((mem = open ("/dev/mem", 0)) < 0)
  1603. X  {
  1604. X    fprintf (stderr, "%s: ", program);
  1605. X    perror ("Can't open /dev/mem");
  1606. X    exit (1);
  1607. X  }
  1608. X
  1609. X  if ((kmem = open ("/dev/kmem", 0)) < 0)
  1610. X  {
  1611. X    fprintf (stderr, "%s: ", program);
  1612. X    perror ("Can't open /dev/kmem");
  1613. X    exit (1);
  1614. X  }
  1615. X
  1616. X  if ((swap = open ("/dev/drum", 0)) < 0)
  1617. X  {
  1618. X    fprintf (stderr, "%s: ", program);
  1619. X    perror ("Can't open /dev/drum");
  1620. X    exit (1);
  1621. X  }
  1622. X
  1623. X  /*
  1624. X   * Get the kernel name list
  1625. X   */
  1626. X  if (nlist ("/vmunix", name_list) == ERROR)
  1627. X  {
  1628. X    fprintf (stderr, "%s: Couldn't read name list from /vmunix\n", program);
  1629. X    exit (1);
  1630. X  }
  1631. X
  1632. X  if (name_list[N_PROC].n_type == 0)
  1633. X  {
  1634. X    fprintf (stderr,
  1635. X             "%s: Couldn't find symbol \"_proc\" in /vmunix\n", program);
  1636. X    exit (1);
  1637. X  }
  1638. X
  1639. X  if (name_list[N_NPROC].n_type == 0)
  1640. X  {
  1641. X    fprintf (stderr,
  1642. X             "%s: Couldn't find symbol \"_nproc\" in /vmunix\n", program);
  1643. X    exit (1);
  1644. X  }
  1645. X
  1646. X  /*
  1647. X   * Find the start of the process table
  1648. X   */
  1649. X  read_from (kmem, (off_t) name_list[N_PROC].n_value,
  1650. X             &procbase, sizeof (procbase), "/dev/kmem");
  1651. X
  1652. X  /*
  1653. X   * Find the size of the process table
  1654. X   */
  1655. X  read_from (kmem, (off_t) name_list[N_NPROC].n_value,
  1656. X             &nproc, sizeof (nproc), "/dev/kmem");
  1657. X  /*
  1658. X   * Create the terminal list
  1659. X   */
  1660. X  create_device_table ();
  1661. X
  1662. X  /*
  1663. X   * Create the list of directories
  1664. X   */
  1665. X  create_dir_table ((argc - optind), (argv + optind));
  1666. X
  1667. X  /*
  1668. X   * Check for processes active in those directories
  1669. X   */
  1670. X  if (number_of_entries > 0)
  1671. X    check_procs (procbase, nproc);
  1672. X
  1673. X  exit (0);
  1674. X}
  1675. END_OF_FILE
  1676. if test 29702 -ne `wc -c <'pads.c'`; then
  1677.     echo shar: \"'pads.c'\" unpacked with wrong size!
  1678. fi
  1679. # end of 'pads.c'
  1680. fi
  1681. echo shar: End of shell archive.
  1682. exit 0
  1683.