From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 19-SEP-1990 05:18:27.51
To:	MRGATE::"ARISIA::EVERHART"
CC:	
Subj:	Re: VMS equiv. to RSTS/E SHOW USERS [Includes IMAGES.C]

Received:  by crdgw1.ge.com (5.57/GE 1.73)
	 id AA05143; Wed, 19 Sep 90 05:05:20 EDT
Received: From UCBVAX.BERKELEY.EDU by CRVAX.SRI.COM with TCP; Tue, 18 SEP 90 15:50:37 PDT
Received: by ucbvax.Berkeley.EDU (5.63/1.42)
	id AA08866; Tue, 18 Sep 90 15:35:39 -0700
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 18 Sep 90 22:32:48 GMT
From: agate!agate!jym@ucbvax.Berkeley.EDU  (Jym Dyer)
Organization: Berserkeley
Subject: Re: VMS equiv. to RSTS/E SHOW USERS [Includes IMAGES.C]
Message-Id: <JYM.90Sep18153248@remarque.berkeley.edu>
References: <1990Sep18.173216.20974@ecst.csuchico.edu>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com

.-.
|W|ell, it's just a matter of calling $getjpi and getting the name
`-' of the program.  You can even do this from DCL, but it's better
    to write a program so's you can install it with WORLD privs.
.-.
|I| have an example program below.  I wrote it a few years ago, so
`-' it only shows the last four digits of the PID (these days you
    usually need to see all eight).  A few things to consider:

	o The fparse() function works like DCL's f$parse()
	  lexical.  The getredirection() function just enables
	  the Unix-like ">" and ">>" redirection.  Both are
	  part of DECUS C.

	o If you're wondering what all the CLI stuff is, the
	  idea is that the CLI (usually DCL; sometimes SHELL)
	  shows up in parentheses.

    <_Jym_>

--------------8<-------------cut-here-------------8<--------------
#module IMAGES "Jym V1.1-002"

/* IMAGES.C
**=============================================================================
** Facility:	None
**-----------------------------------------------------------------------------
** Prefix:	None
**-----------------------------------------------------------------------------
** Abstract
** ~~~~~~~~
**  VMS has a number of ways to look at processes running on a system (SHOW and
** MONITOR), but none of them list the images (programs) running.  This program
** provides that information.
**-----------------------------------------------------------------------------
** Usage
** ~~~~~
**	$ images [-abdin] [-gow] [-v]
**
**	$ images -a	Show processes in all modes:  batch, detached,
**			interactive, and network.
**	$ images -b	Show batch mode processes.
**	$ images -d	Show detached mode processes
**	$ images -g	Show only processes in your group (needs GROUP privs).
**	$ images -i	Show interactive mode processes.
**	$ images -n	Show network mode processes.
**	$ images -o	Show only your own processes.
**	$ images -v	Show images verbosely - with their entire filespecs.
**	$ images -w	Show all processes in the "world" (needs WORLD privs).
**	$ images >file	Redirect output to "file".
**	$ images >>file	Append output to "file".
**
** If none of the "mode" options (a, b, d, i, and n) are selected, only the
** interactive processes are shown.  If none of the "privilege" options (g, o,
** and w) are selected, the privilege of the process running this program . . .
** or if this program has been installed with privileges, those privileges are
** used.  Options can be combined.  One can, for example, show batch mode and
** detached mode processes by typing "images -bd".  One can look at one's own
** network processes by typing "images -no" . . . "images -ao" is useful to
** see what processes one might have running.  If several "privilege" options
** are specified, the last one on the command line is used.  For example, if
** you type "images -gwo", only the owner's processes will be shown.
**-----------------------------------------------------------------------------
** Function
** ~~~~~~~~
**  main()
**-----------------------------------------------------------------------------
** Environment
** ~~~~~~~~~~~
**  Must be linked with the VAX C RTL.  Uses DECUS C and STRLIB functions, thus
** we require that this be linked with DECUS C VAXLIB.OLB and STRLIB.OLB.
**  At run time, if being run under the DCL CLI, it is useful to have an
** "images" command symbol defined:
**
**	$ im*ages == "$tools$library:images"
**
**  This program is most useful if it is installed with WORLD privileges.
**-----------------------------------------------------------------------------
** Author:	Jym Dyer - 8-Mar-1988
**-----------------------------------------------------------------------------
** Modifications
** ~~~~~~~~~~~~~
** 1.0-001 - Original version.  Jym 8-Mar-1988
** 1.1-002 - Added -v option.  Jym 1-Apr-1988
**=============================================================================
*/

/* -=- FILE INCLUSIONS -=- */

#include stdio
#include stdlib
#include string

#include descrip
#include jpidef
#include nam
#include prvdef
#include ssdef
#include stsdef

/* -=- STRUCTURE DEFINITION -=- */

/* This is the structure of an item used by sys$getjpi() and sys$getjpiw().
** Those functions take an item list comprised of an array of these items
** followed by a longword with a value of zero.
*/
typedef struct
{
  unsigned short int  buffer_size;
  unsigned short int  item_code;
  void  *buffer_p;
  unsigned short int  *buffer_length_p;
}  GETJPI_ITEM_T;

/* -=- FUNCTION -=- */

/* main()
**-----------------------------------------------------------------------------
*/
main(argc,argv)
 int argc;
 char *argv[];
{
  /* --- EXTERNALS AND GLOBALS --- */

  extern char  tolower();

  extern char  *fparse();		/* DECUS C library function. */
  extern int  getopt();			/* String library function. */
  extern int  getredirection();		/* DECUS C library function. */
  extern long int  shell$is_shell();

  extern int  lib$signal();
  extern void  sys$exit();
  extern int  sys$getjpiw();
  extern int  sys$setprv();

  /* --- LOCAL VARIABLES --- */

  /* --- Values Gotten From sys$getjpiw() --- */

  char  cli_name[39 + 1];		/* Buffer to store CLI name.
					*/
  short int  cli_name_length;		/* Length of `cli_name'.
					*/
  char  image_filespec[NAM$C_MAXRSS + 1];
					/* Buffer to store image filespec.
					*/
  short int  image_filespec_length;	/* Length of `image_filespec'.
					*/
  long int  master_pid;			/* Master PID (used to see if an inter-
					** active process is a subprocess).
					*/
  long int  mode;			/* Mode (batch, detached, interactive,
					** or network).
					*/
  long int  pid;			/* PID.
					*/
  char  process_name[15 + 1];		/* Buffer to store process name.
					*/
  short int  process_name_length;	/* Length of `process_name'.
					*/
  char  username[12 + 1];		/* Buffer to store username.
					*/
  short int  username_length;		/* Length of `username'.
					*/

  /* --- Values Sent to sys$getjpiw() --- */

  long int  root_pid = -1;		/* This value, passed as the "root PID"
					** argument to sys$getjpiw(), causes
					** that function to return information
					** for every function it is privileged
					** to access.
					*/
  struct
  {
    GETJPI_ITEM_T  item[7];
    long int  terminating_zero;
  }  item_list =
  {
    {
      {sizeof cli_name - 1,JPI$_CLINAME,&cli_name,&cli_name_length},
      {NAM$C_MAXRSS,JPI$_IMAGNAME,&image_filespec,&image_filespec_length},
      {sizeof master_pid,JPI$_MASTER_PID,&master_pid,0},
      {sizeof mode,JPI$_MODE,&mode,0},
      {sizeof pid,JPI$_PID,&pid,0},
      {sizeof process_name - 1,JPI$_PRCNAM,&process_name,&process_name_length},
      {sizeof username - 1,JPI$_USERNAME,&username,&username_length}
    },
    0
  };					/* This is a sys$getjpiw() item list,
					** telling sys$getjpiw() to get seven
					** different types of information and
					** where to put them.
					*/

  /* --- Privilege Quadword Masks --- */

  int  priv_both[2] = {PRV$M_GROUP | PRV$M_WORLD,0};
  int  priv_group[2] = {PRV$M_GROUP,0};
  int  priv_world[2] = {PRV$M_WORLD,0};

  /* --- Miscellany --- */

  char  *character_p;			/* General-purpose character pointer,
					** used to convert the image name to
					** lowercase.
					*/
  char  *image_name;			/* Pointer to the image name text,
					** which is malloc()ed and free()d.
					*/
  char  is_verbose = FALSE;		/* Flag telling us to show images
					** verbosely - that is, with its
					** full file specification.
					*/
  char  mode_table[] =
  {
    'd',				/* JPI$K_DETACHED */
    'n',				/* JPI$K_NETWORK */
    'b',				/* JPI$K_BATCH */
    ' ',				/* JPI$K_INTERACTIVE */
    's'					/* Indicates subprocess. */
  };					/* A table of characters to indicate
					** the modes of the processes.  These
					** characters are displayed next to
					** the PID.  Note that the first four
					** correspond with JPI$K_ constants for
					** the modes.  The 's'indicates an
					** interactive subprocess.
					*/
  int  option;				/* Value returned from getopt()
					** when command line options are
					** being parsed.
					*/
  char  relevant_modes = 0;		/* When the command options are parsed,
					** and "mode" options (a, b, d, i, and
					** n) are detected, this variable is
					** updated to indicate which nodes will
					** be shown.
					*/
  register int  status;			/* Status of call to sys$getjpiw().
					*/

  /* --- PARSE COMMAND OPTIONS --- */

  if (!shell$is_shell())
  {
    argc = getredirection(argc,argv);
    argv[0] = "images";
  }
  while ((option = getopt(argc,argv,"abdginovw")) != EOF)
   switch (option)
  {
    case 'a':
      relevant_modes |= ((1 << JPI$K_BATCH) | (1 << JPI$K_DETACHED)
       | (1 << JPI$K_INTERACTIVE) | (1 << JPI$K_NETWORK));
      break;

    case 'b':
      relevant_modes |= (1 << JPI$K_BATCH);
      break;

    case 'd':
      relevant_modes |= (1 << JPI$K_DETACHED);
      break;

    case 'g':
      sys$setprv(1,&priv_group,0,0);
      sys$setprv(0,&priv_world,0,0);
      break;

    case 'i':
      relevant_modes |= (1 << JPI$K_INTERACTIVE);
      break;

    case 'n':
      relevant_modes |= (1 << JPI$K_NETWORK);
      break;

    case 'o':
      sys$setprv(0,&priv_both,0,0);
      break;

    case 'v':
      is_verbose = TRUE;
      break;

    case 'w':
      sys$setprv(1,&priv_both,0,0);
      break;

    default:
      fprintf(
	stderr,"%s: Usage: %s [-abdin -gow -v]\n",argv[0],argv[0]
      );
      sys$exit(SS$_NORMAL);
  }

  /* If the user hasn't specified any particular modes as a command option,
  ** our default is to show the interactive processes.
  */
  if (relevant_modes == 0)
   relevant_modes = (1 << JPI$K_INTERACTIVE);

  /* --- GET AND SHOW PROCESS INFORMATION --- */

  printf(
    " PID__ Username____ Process_Name___ Image_Name_________________________\n"
  );
  for (;;)
  {
    if ((status = sys$getjpiw(0,&root_pid,0,&item_list,0,0,0)) == SS$_NOPRIV)
     continue;
    else if (status == SS$_NOMOREPROC)
     break;
    else if (status != SS$_NORMAL)
     lib$signal((status & ~STS$M_SEVERITY) | STS$K_WARNING);

    if (!(relevant_modes & (1 << mode)))
     continue;

    if ((mode == JPI$K_INTERACTIVE) && (pid != master_pid))
     mode++;				/* To indicate subprocess. */

    if (image_filespec_length)
    {
      image_filespec[image_filespec_length] = '\0';
      if (is_verbose)
       image_name = strcpy(malloc(image_filespec_length + 1),image_filespec);
      else
       image_name = fparse(image_filespec,0,0,"name","synchk");
    }
    else
    {
      sprintf(image_filespec,"(%.*s)",cli_name_length,cli_name);
      image_name =
       strcpy(malloc(cli_name_length + sizeof "()"),image_filespec);
    }
    for (character_p = image_name; *character_p; ++character_p)
     *character_p = tolower(*character_p);

    printf(
      " %04.4X%c %-12.12s %-15.15s %s\n",
      (pid & 0xffff),
      mode_table[mode],
      username,
      process_name,
      image_name
    );

    free(image_name);
  }

  if (status != SS$_NOMOREPROC)
   sys$exit(status);
}

