[comp.os.vms] Nanny Source V1.0 1/7

zar@JULIET.CALTECH.EDU.UUCP (06/18/87)

$!------------------------------Cut Here-------------------------
$ chk = "1884571211"
$ create nanny.tex
$ deck/dollars="ThEgReAtZaR"
\font\chapfont=cmbx10 scaled\magstep3
\font\subrubfont=cmbx10 scaled\magstephalf

\parskip=\bigskipamount
\parindent=0mm
\hsize=14truecm
\hoffset=1truecm
\vsize=23truecm
\voffset=.5truecm
\topskip=1truecm

\footline={\hfil}
\headline={\it\firstmark\hfil\folio}
\def\makeheadline{\vbox to 0pt{\vskip-.7truecm
    \ifnum\pageno=1 \else
        \ifnum\pageno<0 \line{\it\hfil\folio}\smallskip \hrule
        \else \line{\the\headline}\smallskip\hrule\fi\fi
        \vss}\nointerlineskip}

\newcount\chapcount \newcount\subcount \newcount\subsubcount
\chapcount=0 \subcount=0 \subsubcount=0

\def\chapter#1\par{\vskip 0pt plus.4\vsize \goodbreak
    \vskip 0pt plus-.4\vsize \bigskip \bigskip
    \advance \chapcount by 1 \subcount=0 \subsubcount=0
    \chapcontents{#1}\mark{\the\chapcount.\enspace#1}%
    {\chapfont \setbox0=\hbox{\the\chapcount.\enspace}\hangindent=\wd0
        \baselineskip=20truept \raggedright
        \noindent \box0 #1\bigskip \nobreak}}

\def\subrub#1\par{\vskip 0pt plus.3\vsize \goodbreak
    \vskip 0pt plus-.3\vsize \bigskip
    \advance \subcount by 1 \subsubcount=0
    \subcontents{#1}%
    {\subrubfont \setbox0=\hbox{\the\chapcount.\the\subcount\enspace}%
        \baselineskip=17truept \hangindent=\wd0
        \raggedright \noindent \box0 #1\medskip \nobreak}}

\def\subsubrub#1\par{\vskip 0pt plus.3\vsize \goodbreak
    \vskip 0pt plus-.3\vsize \bigskip
    \advance \subsubcount by 1
    \subsubcontents{#1}%
    {\bf\setbox0=\hbox{\the\chapcount.\the\subcount.\the\subsubcount\enspace}%
        \baselineskip=14truept \hangindent=\wd0
        \raggedright \noindent \box0 #1\medskip \nobreak}}

\newwrite\contents
\immediate\openout\contents=\jobname.contents

\def\chapcontents#1{\immediate\write\contents{\noexpand\chapline%
    {\the\pageno}{\the\chapcount}{#1}}}
\def\subcontents#1{\immediate\write\contents{\noexpand\subline%
    {\the\pageno}{\the\chapcount.\the\subcount}{#1}}}
\def\subsubcontents#1{\immediate\write\contents{\noexpand\subsubline%
    {\the\pageno}{\the\chapcount.\the\subcount.\the\subsubcount}{#1}}}

\long\def\bye{\immediate\closeout\contents\vfil\supereject\docontents\end}

\def\docontents{\pageno=-1\bf\parskip=0pt\parindent=0pt
    \def\punkter{\leaders\hbox to .75em{\hss.\hss}\hfill}
    \def\chapline##1##2##3{\smallskip\noindent##2\enspace##3\punkter##1}
    \def\subline##1##2##3{\smallskip\noindent\qquad##2\enspace##3\punkter##1}
    \def\subsubline##1##2##3{\smallskip\noindent
        \qquad\qquad##2\enspace##3\punkter##1}
    \vglue1cm
    \input \jobname.contents
    \vfil\supereject}

\newskip\ttglue{\tt \global\ttglue=.5em plus.25em minus.15em}
\chardef\other=12
\def\ttverbatim{\begingroup \catcode`\\=\other \catcode`\{=\other
    \catcode`\}=\other \catcode`\$=\other \catcode`\&=\other
    \catcode`\#=\other \catcode`\%=\other \catcode`\~=\other
    \catcode`\_=\other \catcode`\^=\other
    \obeyspaces \obeylines \tt}
{\obeyspaces\gdef {\ }}
\def\;{\char'73 }
\catcode`\;=\active
{\obeylines\gdef;{\ttverbatim\spaceskip=\ttglue\let^^M=\ \let;=\endgroup}}
\font\BIG=cmbx10 scaled\magstep5

\null\vfil
\centerline{\BIG N A N N Y}\bigskip\bigskip
\centerline{A Creation Of}
\centerline{Zar ltd.}
\vfil

The contents of this document and all matter described herein are
licensed solely by Zar ltd.\ and must not be duplicated or transferred
without written consent of Zar ltd. Questions and comments can be
directed to:

\bigskip\bigskip
\centerline{Daniel Zirin}
\centerline{Zar ltd.}
\centerline{P.O. Box 372}
\centerline{Pasadena, Cal 91102}
\bigskip\bigskip\eject

\pageno=1

\chapter Introduction

Nanny is a program to maintain an even balance of CPU for all
non-system processes, to allow individual users special commands to
manipulate processes with the same UIC, and to do various other
functions available to system users or standard users.

Nanny runs as a detached system process and reads all commands from a
system-wide permanent mailbox assigned to the logical name
NANNYS\$BOX. Included with this package are several programs which use
Nanny's commands. When you distribute these programs to your VAX
community, it is a good idea to protect the source and only allow
access to the executable. If you feel too threatened by allowing use
of one or many Nanny commands, a bit mask exists to disable one or all
of Nanny's commands.

Each time Nanny is started, she reads predefined values from a
parameter file to determine your system's site-specific requirements
and system dependent values that allow each system a means of
modifying Nanny in accord with the needs of your computer. For more
flexibility, a special command permits you to reread these values.

Each and every action Nanny takes, including any errors that may
occur, are written into a log file. This log file is closed nightly at
12:00, a new log file is opened, and the parameter file, described in
the previous paragraph, is reread. Many errors and/or status messages
from the Nanny will also appear on designated Nanny operator
terminals.

The next few sections will describe each command and function of
Nanny.

\chapter Priorities

Nanny is in an endless loop, checking for new processes, updating the
states of old processes, checking for processes removed from the
system, and performing other functions. Each loop is a cycle and at
the end of each cycle, Nanny will wait a specified time (usually
between 15 and 60 seconds) before starting another cycle. All
priorities are reestablished for each cycle of Nanny, regardless of
the demand on the system. The following algorithm determines what
priority the job will have after each cycle:
$$
\eqalign{newpri = &oldpri + 1 \hbox{\quad if}\cr
                  &cpuused < (cycletime * 1.1) / numusers\cr}
$$
or
$$
\eqalign{newpri = &oldpri - 1 \hbox{\quad if}\cr
                  &cpuused > ( cycletime / numusers ) * 1.1\cr}
$$
$Numusers$ are all processes with the same login priority AND the same
job mode (such as batch or interactive mode) AND does not increase
because of duplicate users. For example, if the users DXL, SHR, and
DMR were all batch jobs with a login priority of 3, $numusers$ for DXL
would be the value 3. But if DXL added another job to the same batch
queue (with the same login priority), $numusers$ would still be 3 only
allowing DXL one third of the CPU no matter how many jobs he added to
the same queue (this is optional and can be determined by bit flags in
the parameter file for each process type). $Cpuused$ is your
accumulated CPU usage since the last cycle. Priorities are not lowered
less than the process' login priority less one and are not raised
above the process' login priority. The $cycletime$ is determined from
the parameter file, described in detail later. It is also possible to
ask Nanny to use a running average in determining CPU use by changing
a parameter file variable.

\chapter Idle processes

All non-system interactive processes are checked during each cycle to
determine if the user has been idle. If the process has been idle for
more than the maximum allowable time (another parameter file
constant), the process is deleted. This action, though, is not taken
without warnings. A warning is sent to the process at $maxtime$
divided by 2 and again 30 seconds before logout. When the process is
logged out, an appropriate message is displayed at the process's
terminal. Idle time and $maxtime$ are constants in the parameter file.

It is possible to have a process not appear idle to Nanny when in fact,
it is (such as KERMIT is server mode). To handle this, Nanny has another
optional $maxelapsed$ parameter file variable that will force a user to
exit an image after the time specified by $maxelapsed$ (usually something
like 18-20 hours).

\chapter Commands

All commands sent to Nanny must take the form:

\nobreak{\tt\qquad command mbxch [arg1 [arg2 [\dots] ] ]}

The command must not be abbreviated and the entire message must be
followed by a space (ascii character 32). Each command sent must have
a mailbox device name following the command. Any arguments required by
the command (brackets indicate use if required) must be present and
each argument delimited by at least one space. The maximum length of a
command sent to Nanny can be 128 bytes long. When a command requires a
process I.D., the value must be represented in hexidecimal form. If
Nanny receives an unknown command or a command not properly assembled,
it will be ignored. If a command is unneeded or unwanted, you may
disable its use. A parameter file constant allows one command or all
commands to be disabled from system use. This constant is described
later.

After the message is sent to Nanny, the user may optionally read a
status byte from the mailbox specified with the command. The byte will
either be 1 for successful completion, or 32 to signify an error
occurred while attempting to complete the command.

\subrub ADDACC

The command ADDACC will add a user record to your system's accounting
data file via the system service \$SNDACC. ADDACC requires two
arguments: the process I.D.\ of the requester and the character string
to insert into the accounting data file.

\subrub DIE

The command DIE will request Nanny to return all processes to their
original priorities and terminate execution. This command requires no
arguments. If the requestor's group UIC number is greater than the
defined system group UIC number (explained later), the command will
not be performed.

\subrub ENTER

The command ENTER will ask the Nanny to start monitoring a process
removed with the FORGET command. This command requires two arguments:
The target process I.D. and the requestor's process I.D.. If the
requesting process group UIC number is greater than the defined system
group UIC number, no action will be taken.

\subrub FORGET

The command FORGET will ask to remove a process from Nanny's
observation. This command requires two arguments: the target process
I.D.\ and the requestor's process I.D.. If the requesting process
group UIC number is greater than the defined system group UIC number,
no action will be taken.

\subrub FREE

The FREE command will tell Nanny to deallocate a device allocated with
the GRAB command. This command requires one argument: the name of the
device to be deallocated. If the requesting process group UIC number
is greater than the defined system group UIC number, no action will be
taken.

\subrub GRAB

The GRAB command allocates a device to disallow system access to the
device. This command requires one argument: the name of the device to
be allocated. If the requesting process group UIC number is greater
than the defined system group UIC number, no action will be taken.

\subrub IGNORE

The IGNORE (opposite of LISTEN) command is not available at this time.

\subrub KILL

The command KILL will request Nanny to delete a process. The process
must have the same UIC as the request process or no action will be
taken. This command requires two arguments: the target process I.D.\
and the requestor's process I.D..

\subrub LISTEN

The LISTEN (opposite of IGNORE) command is not available at this time.

\subrub NEW

The command NEW will close the current log file, open a new one, and
reread the parameter file. This command has no arguments and can be
issued by all processes. If the requesting process group UIC number is
greater than the defined system group UIC number, no action will be
taken.

\subrub ODIS

The command ODIS will disable a previously enabled operator terminal
from receiving all operator messages. This comand has one argument:
the requestor's process I.D..

\subrub OEN

The command OEN will enable a terminal as an operator terminal to
receive all operator messages. This command has one argument: the
requestor's process I.D..

\subrub QSTART

The command QSTART will start or restart a specified queue. The
command requires two arguments: the name of the queue to start and the
process I.D.\ of the requestor.

\subrub QSTOP

The command QSTOP will stop or pause a specified batch or print queue.
This command requires two arguments: the name of the queue to stop and
the requestor's process I.D..

\subrub REQUEUE

The command REQUEUE will take the current job in a paused or stopped
print queue and requeue the job at the end of the print queue. This
command requires two arguments: the name of the print queue and the
requestor's process I.D..

\subrub RESUME

The command RESUME will remove a process from a suspended state via
the system service \$RESUME. This command requires two arguments: the
target process I.D.\ and the requestor's process I.D.. If the target
process and the requesting process do not have the same UIC, no action
will be taken.

\subrub STOP

The command STOP will cause a process executing an image to terminate
the image with the system service \$FORCEX. The requesting process and
target process must have the same UICs. This command requires two
arguments: the target process I.D.\ and the requestor's process I.D..

\subrub SUSPEND

The command SUSPEND will cause a process to enter a suspended state.
This command has two arguments: the target process I.D.\ and the
requestor's process I.D.. Both processes must have the same UIC or no
action will be taken.

\subrub WAKE

The WAKE command will queue a message to be sent to a user or terminal
at a specified date and time. This command is limitted to 25
outstanding messages throughout the system and is anonymous in nature.
The message has a maximum length of 40 bytes. The wake-up call
function accepts three arguments: a terminal name or username, an
absolute time (format: "dd-mmm-yyyy hh:mm:ss.ss"\; fields within the
absolute time may be omitted, but punctuation may not), and a message
preceded by a double quote. Only one space may delimit each argument.
An example would be:

\nobreak
{\tt\qquad WAKE ZAR: 12-MAY-1982 12:00:00.00 "Time to eat lunch.}

or

\nobreak
{\tt\qquad WAKE TTB2: -- ::. "This tests the wake-up call.}

If a username is specified for the first argument, a colon must follow
the name. If the wake-up call expires and the user is not logged on
the system, the message will not be sent. If the user specified is
logged on to more than one terminal, the user with the lowest process
I.D. will receive the wake-up call.

\subrub WCLR

The WCLR command will remove a wake-up call from Nanny's memory. It
requires one argument: the wake-up call identification number (between
10 and 35). Only users with system UICs can cancel a wake-up call
issued by another user.

\subrub WSHOW

The WSHOW command will return wake-up queue information to the
caller's return mailbox (before the actual return status sent). The
command takes no arguments and returns information in the following
format:

\nobreak
{\tt\qquad id own-uic destination date/time}

where `id' is the wake-up call identification number multiplied by
$-1$ (2 bytes), `own-uic' is the UIC of the issuing process (4 bytes),
`destination' is the name of a terminal or user to send the message
(12 bytes), and `date/time' is the system binary time when the call
will be sent (8 bytes). Nanny will send one packet of information (26
bytes) for each wake-up call in its memory after which a dumy packet
with an `id' equal to $-1$ will be sent signifying the end of the
queue. The next message sent will be the Nanny return status code.

\chapter Parameter File

The parameter file is a standard ASCII text file containing input
constants for Nanny. Nanny reads one constant per line from the
parameter file. These constants will set guildelines for Nanny to
follow when determining new priorities, logging off idle terminals,
and performing other functions. The parameter file is read once when
Nanny is started, and each night at midnight. The following
sub-paragraphs will define each constant of the parameter file in
detail. To format a constant for a FORTRAN list-directed I/O
statement, enter the value into the parameter file with no leading
blanks or zeros (leading blanks or zeros are optional when reading
variables with a list-directed I/O statement) and follow the constant
with at least one space (ASCII character 32).

\subrub Process name

This 15 byte character value is Nanny's process name. It should be
different from any other process name on the system.

\subrub System Group UIC Number

This value is the group number portion of the system's UIC (User
Identification Code). This value MUST be represented as an octal 3
digit number and may and may take a value between 1 and 255. While
Nanny is searching for processes to pick on, she will ignore processes
with a UIC group portion less than or equal to this value (for example
if SYSGRP (the value under discussion) is 3 and Nanny comes across a
process with a UIC of [2,1], the process will be ignored. If SYSGRP is
5 and the process's UIC was [7,1], the process will be entered into
Nanny's tables).

\subrub System Account

The system account is the account name (or number) all system
processes are charged to. To find out your system account, log-in as
the user SYSTEM and issue the command ";SHOW PROCESS/QUOTA;". In the
upper-left of the display will be ";Account name: xxxxxxxx;". Any
process that Nanny finds with this account name string will be
disregarded. The value is read from the parameter file with an (A8)
FORTRAN format statement (the first eight bytes are used to determine
the value).

\subrub Cycle Time

The cycle time is the time Nanny waits between process checks. The
value is represented in hundreths of seconds (i.e. 1000 is equal to
10.00 seconds). A good value should be between 30 and 60 seconds
(although values between 10 seconds and 2 minutes are allowed). This
value is read from the parameter file with a list-directed I/O
statement.

\subrub Maximum Idle Time And Maximum Elapsed Time

The maximum idle time is the total elapsed time before a interactive
user is removed from the system. Idle terminals are a waste of
resources and process slots. This value is expressed in Nanny cycle
time (specified by the previous line in the parameter file). The
maximum elapsed time is the maximum allowed elapsed time since login
that a process may exist. If a process exceeds this value, Nanny
forces the process to exit its image. This is good for programs like
KERMIT (in server mode) that trick Nanny into thinking the process
is never idle. This value is also expressed in Nanny cycle time.
These values are read with a list-directed I/O statement.

\subrub Non-idle Time And Non-idle I/O

Non-idle time is the amount of CPU needed to consider a interactive
process not idle. The value is expressed in hundreths of seconds
(i.e. 5 is 0.05 seconds of CPU). A good value would be between 2 and
20 (allowed values are between 0 and 299). Non-idle I/O is the amount
of combined buffered and direct I/O required to be non-idle. These
two values are read with a FORTRAN list-directed I/O statement.

\subrub Maximum memory usage

If the total physical memory usage of all processes monitored by Nanny
exceeds this value, Nanny will start suspending low priority batch
jobs (after which the SWAPPER will swap out the batch job rather than
interactive processes). Typically, this value should be 85% of your
system's total memory capacity. A value of 0 (zero) indicates you
don't want Nanny to suspend processes when memory usage peaks. Values
may be between 2048 pages and 65536 pages (1--32 megabytes). This
value is read from the parameter file with a list-directed I/O statement.

\subrub Low memory usage

If the total physical memory usage of all processes monitored by Nanny
is less than this value and the Nanny has previously suspended
processes, Nanny will resume the highest priority batch job suspended.
This value should be the `Maximum memory usage' minus the average
maximum working set extent of a typical batch job on your system. A
value of 0 (zero) is redundant with the previous parameter. Valid
values are 2048--65536 pages. This value is read from the parameter
file with a list-directed I/O statement.

\subrub Working set purge

This line should read ";YES;" if you want Nanny to purge her working
set after each cycle and ";NO;" if you want her to just purge it each
night at midnight. Purging Nanny's working set for every cycle may
save your system 100 to 150 pages of memory, but pagefaulting will be
high. Nanny will also start automatically purging memory if you have
a maximum memory usage specified (2 lines earlier in the parameter
file) and memory is considered low.

\subrub Free Disk Space

This line contains a single integer used in determining if disk space
is low in the disk check algorithm. A disk is full if the maximum
blocks divided by this number is greater than the free disk blocks.
A good number is 50. This value is read from the parameter file with
a list-directed I/O statement.

\subrub Disk checking

The next line are the device names of disks Nanny will check for low
space and errors. The disk names must be seperated by commas and the
list of names followed by a space (ascii character 32). A maximum of
16 disks can be specified. Nanny checks every 15 minutes if each disk
has less than 1/50 of the total available disk space left. A check for
an increase of 10 error counts on the disk since the last check is
also made. If either of the checks is true, messages are sent to Nanny
specified operator terminals.

\subrub Nanny operators

The next line are the device names of terminals to be designated as
Nanny operator terminals. Some Nanny errors and many Nanny status
messages are sent to these terminals. Included in this list of
terminals is ;OPA0:; (the console). The terminal names must be seperated
by commas and the list of names followed by a space (ascii character
32). A maximum of eight terminals may be specified.

\subrub Command Disable Mask

This value is a bit mask to disable one or more of Nanny's commands.
The value must be expressed in hexidecimal form and have exactly 8
digits. To disable a command, set the bit corresponding to the command
to be disabled. To enable a command, clear the bit. The following
define each bit of the mask and the command the bit represents:

{\obeylines\parindent=2em
Bit 1 -- This bit, if set, will disable the command ADDACC
Bit 2 -- This bit, if set, will disable the command DIE
Bit 3 -- This bit, if set, will disable the command ENTER
Bit 4 -- This bit, if set, will disable the command FORGET
Bit 5 -- This bit, if set, will disable the command FREE
Bit 6 -- This bit, if set, will disable the command GRAB
Bit 7 -- This bit, if set, will disable the command IGNORE
Bit 8 -- This bit, if set, will disable the command KILL
Bit 9 -- This bit, if set, will disable the command LISTEN
Bit 10 -- This bit, if set, will disable the command NEW
Bit 11 -- This bit, if set, will disable the command ODIS
Bit 12 -- This bit, if set, will disable the command OEN
Bit 13 -- This bit, if set, will disable the command QSTART
Bit 14 -- This bit, if set, will disable the command QSTOP
Bit 15 -- This bit, if set, will disable the command REQUEUE
Bit 16 -- This bit, if set, will disable the command RESUME
Bit 17 -- This bit, if set, will disable the command STOP
Bit 18 -- This bit, if set, will disable the command SUSPEND
Bit 19 -- This bit, if set, will disable the command WAKE
Bit 20 -- This bit, if set, will disable the command WCLR
Bit 21 -- This bit, if set, will disable the command WSHOW
Bits 22 through 32 -- unused.\par}

If the disable mask was equal to 00008009 (hex), the commands ADDACC,
FORGET, and RESUME would be disabled. The value FFFFFFFF disables all
commands and 00000000 enables all commands.

\subrub Function Enable Mask

This value is a bit mask to enable one or more of Nanny's functions.
The value must be expressed in hexidecimal form and have 8 digits. To
enable a function, set the bit corresponding to the function to be
enabled. To disable the function, clear the bit. The following defines
each bit of the mask and the function the bit represents:

{\parindent=4em

\item{Bit 1 --}This bit, if set, will allow Nanny to modify batch
process priorities if CPU usage is unfairly distributed.

\item{Bit 2 --}This bit, if set, will allow Nanny to modify detached
process priorities if CPU usage is unfairly distributed.

\item{Bit 3 --}This bit, if set, will allow Nanny to modify
interactive process priorities if CPU usage is unfairly distributed.

\item{Bit 4 --}This bit, if set, will allow Nanny to modify network
process priorities if CPU usage is unfairly distributed.

\item{Bit 5 --}This bit, if set, will allow Nanny to modify subprocess
priorities if CPU usage is unfairly distributed.

\item{Bit 6 --}This bit, if set, will cause duplicate users CPU totals
to be combined when determining CPU distribution. If disabled,
duplicate users will not exist.

\item{Bit 7 --}This bit, if set, will allow Nanny to suspend low
priority processes when memory usage peaks.

\item{Bit 8 --}This bit, if set, will allow Nanny to suspend batch
processes if memory is low.

\item{Bit 9 --}This bit, if set, will allow Nanny to suspend detach
processes if memory is low.

\item{Bit 10 --}This bit, if set, will allow Nanny to suspend interactive
processes if memory is low.

\item{Bit 11 --}This bit, if set, will allow Nanny to suspend network
processes if memory is low.

\item{Bit 12 --}This bit, if set, will allow Nanny to suspend subprocesses
if memory is low.

\item{Bit 13 --}This bit, if set, will allow Nanny to logoff idle
interactive system processes.

\item{Bit 14 --}This bit, if set, will send a logoff warning to idle
processes at 1/2 the total maximum idle time.

\item{Bit 15 --}This bit, if set, will send a logoff warning to idle
processes at approximately 60 seconds before logoff (depending on the
cycle time).

\item{Bit 16 --}This bit, if set, will send a warning to interactive
users with a CPU quota prior to exceeding the CPU quota.

\item{Bit 17 --}Reserved.

\item{Bit 18 --}27 -- Unused.

\item{Bit 28 --}Reserved.

\item{Bit 29 --}Update the system time at daylight savings time (every
six months). It is suggested you leave this off unless you check the
source code for your time zone corrections.

\item{Bit 30 --}Reserved.

\item{Bit 31 --}Causes debugging messages to be sent to the logfile
and NO functions are performed.

\item{Bit 32 --}Causes debugging messages to be sent to the logfile
and execute all desired functions.\par}

The value 3FFFFFFF enables all functions and 00000000 disables all
functions.

\subrub Ignoring users

The next line are the usernames of people the Nanny will entirly
ignore. The usernames must be seperated by commas and the list of
names followed by a space (ascii character 32). A maximum of 32 names
can be specified.

\subrub Ignoring terminals

The next line are the device names of terminals Nanny will ignore
(OPA0: for example). The device names must be specified as ";ddun:;"
or ";_ddun:;" (never use concealed devices!), seperated by commas, and
the list of names followed by a space (ascii character 32). A maximum
of 16 names can be specified.

\chapter Installation

To install Nanny, log-in as the user SYSTEM. Then, create a directory
to store Nanny's files. Ideally, this directory should be protected to
prohibit access to the world (non-system users). A sugested command
would be:

\nobreak
\qquad;$ CREATE/DIR/PROT=(S:RW,O:RW,G,W) SYS$SYSDEVICE:[SYSMGR.NANNY];

Edit the files STARTNAN.COM and NANNY.INP (parameter file). Use BUILD.COM
to create all executables. Add ";@STARTNAN;" to SYS\$MANAGER:SYSTARTUP.COM
and run the program NANNYACP to talk to Nanny while she's running (except
for wake-up calls). Use WAKEACP for sending, deleting, and showing wake-up
calls.

\bye
ThEgReAtZaR
$ checksum nanny.tex
$ if chk.nes.checksum$checksum then write sys$output -
  "NANNY.TEX didn't pass checksum. File may be corrupted."
$ if chk.nes.checksum$checksum then exit %x2c
$ exit