DSTEVENS@VAXC.STEVENS-TECH.EDU (David L. Stevens) (09/11/87)
To whom it may concern,
I sent a message out a couple of days ago about getting the status
of a command from a subprocess that is still active. The subprocess would
have the following charicteristics:
1: Would have CLI loaded into it
2: Would be running at DCL level
3: SYS$INPUT , SYS$OUTPUT, & SYS$ERROR would be defined as mailboxes
4: Parent process would continue executing while the subprocess existed
5: Subprocess will not exit after executing a command
I now have a program that does all of the above. The program will create the
subprocess, allow a calling program to issue commands to it and, will return
the integer value of the $STATUS symbol to the calling routine. The
subprocess will stay there until you call the shutdown routine. The modules
are both written in VAX-C, they work at our site here, but then again since
this is a college, reallity may be warped beyond all recognition. So I can't
guarentee that it will run anywhere else. But for what its worth, here it is:
-------------------------Cut here -------------------------------------------
/*
**
** INCLUDE FILES
**
**/
#include stdio
#include descrip
#include "acct"
main()
{
#define COMMAND "What ever command you want"
#define NXT_COMMAND "Any other command you want"
unsigned int status;
unsigned int final_status;
static readonly
$DESCRIPTOR(show_command, "FINGER");
static readonly
$DESCRIPTOR(command_1, COMMAND);
static readonly
$DESCRIPTOR(command_2, NXT_COMMAND);
status = dcl_initialize();
if (TEST_STATUS)
{
status = dcl_execute_command(&show_command, &final_status);
if (! TEST_STATUS)
printf("\n DCL command failed with status = %x", status);
else
printf("\n The status of the show command was: %x",
final_status);
status = dcl_execute_command(&command_1, &final_status);
if (! TEST_STATUS)
printf("\n DCL command failed with status = %x", status);
else
printf("\n The status of the command was: %x",
final_status);
status = dcl_execute_command(&command_2, &final_status);
if (! TEST_STATUS)
printf("\n DCL command failed with status = %x", status);
else
printf("\n The status of the command was: %x",
final_status);
}
dcl_shutdown();
exit (status);
}
--------------------------------End of first module----------------------------
--------------------------------DCL command module-----------------------------
#module acct_dcl_command "1.0.001"
/*
**++
** FACILITY:
**
** Stevens accounting system
**
** ABSTRACT:
**
** This module implements an interface to the Digital Command Language
** (DCL). This is used to implement an interface to those items that are
** not callable.
**
** AUTHORS:
**
** Robert McQueen
** David L. Stevens
**
** CREATION DATE: 19-August-1987
**
** MODIFICATION HISTORY:
**--
**/
/*
**
** INCLUDE FILES
**
**/
#include stdio /* Standard I/O definitions */
#include dvidef /* GETDVI symbol definitions */
#include iodef /* IO symbol definitions */
#include prvdef /* Process privilege definitions */
#include ssdef /* System Service status definitions */
#include descrip /* Descriptor definitions */
#include "acct" /* Accounting definitions */
#define SUBPROCESS_LOG_FILE "Acct$subprocess_log_file.log"
/*
** The following are prototype function definitions
*/
unsigned int dcl_initialize(void);
unsigned int dcl_shutdown(void);
unsigned int dcl_execute_command(
struct dsc$descriptor *command,
unsigned int *final_status);
unsigned int dcl_final_status(
struct dcl_structure *process_info,
unsigned int *final_status);
unsigned int dcl_assign_mbx(
unsigned int *channel,
unsigned int *unit,
struct dsc$descriptor *name);
unsigned int dcl_write_command(
struct dcl_structure *process_info,
struct dsc$descriptor *command_line);
unsigned int dcl_wait_until_done(
struct dcl_structure *process_info);
unsigned int dcl_post_read_io(
char *buffer_address,
int buffer_length);
unsigned int post_termination_read(
struct dcl_structure *process_info);
unsigned int dcl_create_the_process(
unsigned int *privileges);
wake_ast();
term_ast();
read_ast();
/*
** Local structure definitions
*/
struct dcl_structure
{
unsigned long pid; /* PID */
unsigned short input_channel; /* Input channel */
unsigned short input_unit; /* Input unit number */
struct dsc$descriptor input_name; /* Input mailbox name */
struct io_status_block input_iosb; /* Input IOSB */
unsigned short output_channel; /* Output channel */
unsigned short output_unit; /* Output unit number */
struct dsc$descriptor output_name; /* Output mailbox name */
struct io_status_block output_iosb; /* Output IOSB */
unsigned short term_channel; /* Termination channel */
unsigned short term_unit; /* Termination unit number */
struct dsc$descriptor term_name; /* Termination mailbox name */
struct io_status_block term_iosb; /* Termination IOSB */
};
struct dcl_structure dcl;
unsigned int process_privileges[2] = {0, 0};
char term_buffer[255];
FILE *subproc_log_file;
/* DCL INITIALIZE
**++
** FUNCTIONAL DESCRIPTION:
**
** This function will initialize the DCL command processing. This routine
** should be called as part of the initialization of the accounting system.
**
** FORMAL PARAMETERS:
**
** none
**
** IMPLICIT INPUTS:
**
** none
**
** IMPLICIT OUTPUTS:
**
** Module initialized
**
** COMPLETION CODES:
**
** System service condition codes
**
** SIDE EFFECTS:
**
** none
**
**--
**/
unsigned int dcl_initialize(void)
{
/*
** Permanent strings
*/
static struct dsc$descriptor dyn_string = /* Prototype dynamic string */
$INIT_DESCRIPTOR; /* Initialize it */
/*
** Local variables
*/
unsigned int status; /* Condition code to return */
/*
** Main logic:
** - Initialize all dynamic strings
** - Create the input, output and termination mailboxes
*/
dcl.input_name = dyn_string; /* Initialize the dynamic strings */
dcl.output_name = dyn_string; /* Initialize the output string */
dcl.term_name = dyn_string; /* Initialize the termination string */
/*
** Assign an input mailbox for interprocess communications
*/
status = dcl_assign_mbx( /* Assign the mailbox */
&dcl.input_channel, /* Place to store the channel */
&dcl.input_unit, /* and the unit number */
&dcl.input_name); /* and the mailbox name */
if (! TEST_STATUS) /* Did this win? */
return status; /* No, return the failure status */
/*
** Assign an output mailbox for interprocess communications
*/
status = dcl_assign_mbx( /* Assign the mailbox */
&dcl.output_channel, /* Place to store the channel */
&dcl.output_unit, /* and the unit number */
&dcl.output_name); /* and the mailbox name */
if (! TEST_STATUS) /* Did this win? */
return status; /* No, return the failure status */
/*
** Assign a termination mailbox for interprocess communications
*/
status = dcl_assign_mbx( /* Assign the mailbox */
&dcl.term_channel, /* Place to store the channel */
&dcl.term_unit, /* and the unit number */
&dcl.term_name); /* and the mailbox name */
if (! TEST_STATUS) /* Did this win? */
return status; /* No, return the failure status */
/*
** Post ar read for when the process terminates
*/
post_termination_read(&dcl);
/*
** Set up the privileges that the subprocess will have
*/
process_privileges[0] = PRV$M_NETMBX | PRV$M_TMPMBX;
/*
** Now create the process and return to the caller
*/
return dcl_create_the_process(&process_privileges);
}
/* DCL SHUTDOWN
**++
** FUNCTIONAL DESCRIPTION:
**
** This function will shutdown the DCL command interface.
**
** FORMAL PARAMETERS:
**
** none
**
** IMPLICIT INPUTS:
**
** Local data structures
**
** IMPLICIT OUTPUTS:
**
** none
**
** COMPLETION CODES:
**
** System service condition code
**
** SIDE EFFECTS:
**
** none
**
**--
**/
unsigned int dcl_shutdown(void)
{
/*
** Local variables
*/
unsigned int status; /* Condition code to return */
/*
** Main logic:
** - Cancel all I/O
** - Deassign the channels
** - Kill the process
*/
/*
** Cancel IO on the Input channel,
** and then deassign the IO channel
*/
status = sys$cancel(dcl.input_channel); /* Cancel input I/O */
if (TEST_STATUS)
status = sys$dassgn(dcl.input_channel); /* Deassign the input channel */
if (! TEST_STATUS)
return status; /* Pass back failing status */
/*
** Cancel IO on the Output channel,
** and then deassign the IO channel
*/
status = sys$cancel(dcl.output_channel); /* Cancel the output I/O requests */
if (TEST_STATUS)
status = sys$dassgn(dcl.output_channel);/* Deassign the output channel */
if (! TEST_STATUS)
return status; /* Return the failing status */
/*
** Cancel IO on the Termination channel,
** and then deassign the IO channel
*/
status = sys$cancel(dcl.term_channel); /* Cancel the termination mailbox read */
if (TEST_STATUS)
status = sys$dassgn(dcl.term_channel); /* Deassign the channel */
if (! TEST_STATUS)
return status; /* Pass back any errors */
/*
** Now kill off the process, if it is still around
*/
status = sys$delprc(
&dcl.pid, /* Delete the process with this PID */
0); /* Don't use the process name */
if (status == SS$_NONEXPR) /* Already gone? */
status = SS$_NORMAL; /* Yes, convert this to a normal */
if (! TEST_STATUS)
return status; /* Return the failing status */
/*
** Return any dynamic strings that are in the block now.
*/
STR$FREE1_DX(&dcl.input_name); /* Return the input name */
STR$FREE1_DX(&dcl.output_name); /* Return the output name */
STR$FREE1_DX(&dcl.term_name); /* Free up the termination MBX name */
/*
** Close the Subprocess Log File
*/
fprintf(subproc_log_file, "\n\n End of Subprocess log file\n");
fclose(subproc_log_file);
/*
** At this point we are basically finished, so return the final status for the
** caller.
*/
return status; /* Return the final status */
}
/* DCL EXECUTE COMMAND
**++
** FUNCTIONAL DESCRIPTION:
**
** This function will execute a DCL command. It will wait until the
** command is complete and return the status of the executed command.
**
** FORMAL PARAMETERS:
**
** command - Pointer to a string descriptor which is the command to
** execute.
**
** IMPLICIT INPUTS:
**
** Local data structures
**
** IMPLICIT OUTPUTS:
**
** none
**
** COMPLETION CODES:
**
** System service condition code, program condition code
**
** SIDE EFFECTS:
**
** DCL command executed
**
**--
**/
unsigned int dcl_execute_command(
struct dsc$descriptor *command,
unsigned int *final_status)
{
/*
** Local variables
*/
unsigned int status;
/*
** Main logic:
** - Write the command to the subprocesses input device
** - Wait for the command to complete
** - Go get the final status of the command
*/
/*
** Now if the process got created correctly, we can go execute the command
*/
status = dcl_write_command( /* Go write the command to the */
&dcl, /* mailbox that */
command); /* we have opened */
/*
** If the previous call succeeded, wait until subprocess
** finishes the command
*/
if (TEST_STATUS)
status = dcl_wait_until_done( /* Now wait until the subprocess */
&dcl); /* has executed the command */
/*
** If everything is still fine then go and get the final status
*/
if (TEST_STATUS)
status = dcl_final_status( /* Go get the subprocess status */
&dcl, /* for the command that we */
final_status); /* just executed */
/*
** Return to the caller
*/
return status; /* Return the call status */
}
/* DCL FINAL STATUS
**++
** FUNCTIONAL DESCRIPTION:
**
** This function will determine the final status of the executed command.
** It will do this by translating the symbol $STATUS in the sub-process.
**
** FORMAL PARAMETERS:
**
** none
**
** IMPLICIT INPUTS:
**
** Local data structures
**
** IMPLICIT OUTPUTS:
**
** none
**
** COMPLETION CODES:
**
** Status of the command that was executed.
**
** SIDE EFFECTS:
**
** none
**
**--
**/
unsigned int dcl_final_status(
struct dcl_structure *process_info,
unsigned int *final_status)
{
/*
** Local permanent strings
*/
static readonly $DESCRIPTOR(command, "SHOW SYMBOL $STATUS");
static readonly $DESCRIPTOR(search_string, " $STATUS == \"%X");
/*
** Local variables
*/
unsigned int status; /* Condition code to return */
char read_buffer[255];
/*
** Main logic:
** - Issue a command to get the value of the symbol status
** - Read the responce off the subprocesses output channel
*/
status = dcl_write_command(process_info, &command);
if (TEST_STATUS)
{
/*
** Block variables
*/
struct dsc$descriptor final_status_string = $INIT_DESCRIPTOR;
unsigned short loop = TRUE;
unsigned int cmp_state;
unsigned int string_length;
/*
** Make sure that the buffer is cleared out, then
** Wait until the subprocess completes the SHOW SYMBOL $STATUS command
*/
while ( (TEST_STATUS) && (loop) )
{
/*
** Issue a QIO to read the result of the subprocesses DCL command
*/
memset(&read_buffer, '\0', 255);
status = dcl_post_read_io(&read_buffer, 255);
if (TEST_STATUS)
{
/*
** See if the Search_String is contained in the output buffer
*/
fprintf(subproc_log_file,"\n%s", read_buffer);
cmp_state = memcmp( /* See if the strings match */
&read_buffer, /* First string */
search_string.dsc$a_pointer, /* Second string */
search_string.dsc$w_length); /* Number of bytes to compare */
if (cmp_state == 0)
loop = FALSE;
} /* End IF ... */
} /* End While ... */
/*
** Now set up so we can move the string value to a descriptor, and
** then move it into the descriptor
*/
if (TEST_STATUS)
{
string_length = (process_info->output_iosb.count - 1) -
search_string.dsc$w_length;
STR$COPY_R(
&final_status_string,
&string_length,
&read_buffer[search_string.dsc$w_length]);
/*
** Convert the Hexidecimal Text into an Integer
*/
status = OTS$CVT_TZ_L(&final_status_string, final_status);
}
}
/*
** Return the final status
*/
return status;
}
/* DCL ASSIGN MAILBOX
**++
** FUNCTIONAL DESCRIPTION:
**
** This function will create a mailbox and return the unit number and the
** name of the mailbox.
**
** FORMAL PARAMETERS:
**
** channel - Place to store the channel number assigned to the mailbox.
** unit - Place to store the unit number of the mailbox that is assigned.
** name - Name of the mailbox that is assigned.
**
** IMPLICIT INPUTS:
**
** none
**
** IMPLICIT OUTPUTS:
**
** none
**
** COMPLETION CODES:
**
** System service condition code
**
** SIDE EFFECTS:
**
** Assigns a mailbox
**
**--
**/
unsigned int dcl_assign_mbx(
unsigned int *channel,
unsigned int *unit,
struct dsc$descriptor *name)
{
/*
** Local variables
*/
unsigned char name_string[128]; /* Name string */
short int name_length; /* Returned length of the name */
unsigned int status; /* Condition code to return */
unsigned int dummy; /* dummy variable */
struct item_list_3 getdvi_itemlist[] = /* Itemlist for GETDVIW call */
{sizeof name_string, DVI$_DEVNAM, &name_string, &name_length,
4, DVI$_UNIT, unit, &dummy,
0, 0, 0, 0};
/*
** Main logic:
** - Create the mailbox
** - Get the device name and the unit number via GETDVIW
*/
status = sys$crembx (
0, /* Perm flag */
channel, /* Where to store the channel */
1024, /* Maximum message size */
1024, /* Buffer quota */
0, /* Protection mask */
0, /* Access mode */
0); /* Logical name */
if (! TEST_STATUS) /* If that failed */
lib$signal(status); /* Note the fact */
/*
** Now get the mailbox device information
*/
status = sys$getdviw (
0, /* EFN */
*channel, /* Channel */
0, /* Device name */
&getdvi_itemlist, /* Item list */
0, /* I/O status block */
0, /* AST address */
0, /* AST parameters */
0); /* Null argument */
/*
** If the GETDVI worked then copy the answere into a Descriptor
*/
if (TEST_STATUS)
status = STR$COPY_R(
name, /* Place to store the name */
&name_length, /* Length of the name */
&name_string); /* Place were the name is */
/*
** If failure is indicated then Signal the error
*/
if (! TEST_STATUS)
lib$signal(status);
/*
** Return the final status to the caller
*/
return status;
}
/* DCL CREATE the PROCESS
**++
** FUNCTIONAL DESCRIPTION:
**
** This routine is called to create the subprocess. It will run the
** program LOGINOUT.EXE in order to create a CLI for the subprocess
** to use. Input and output devices will be based on Mailbox names
** defined in the DCL structure.
**
** FORMAL PARAMETERS:
**
** privileges -> Pointer to Quadword containing the privileges the
** subprocess is to be created with
**
** IMPLICIT INPUTS:
**
** none
**
** IMPLICIT OUTPUTS:
**
** none
**
** FUNCTION VALUE:
**
** System Service value
**
** SIDE EFFECTS:
**
** none
**
**--
**/
unsigned int dcl_create_the_process(
unsigned int *privileges)
{
/*
** Readonly strings
*/
static readonly
$DESCRIPTOR(process_name, "Lcl$sub_proc_");
static readonly
$DESCRIPTOR(image_name, "SYS$SYSTEM:LOGINOUT.EXE");
static readonly
$DESCRIPTOR(set_noon_command, "SET NOON");
/*
** Local variables
*/
struct dsc$descriptor final_process_name = $INIT_DESCRIPTOR;
struct dsc$descriptor char_descriptor = $STATIC_DESCRIPTOR;
char character;
char base_character;
unsigned int loop;
unsigned int status;
short int sequence_number;
/*
** Set up a static descriptor to point at a sequence character
*/
char_descriptor.dsc$a_pointer = &character;
char_descriptor.dsc$w_length = 1;
loop = TRUE;
sequence_number = 0;
base_character = '0';
/*
** Now Loop until either the process name is unique,
** or an error other than SS$_DUPLNAM occurs
*/
while (loop)
{
/*
** If the sequence number is = 10 and the base character is still an
** ASCII Zero, then reset the sequence number and change the base
** character to an ASCII Lower-case A
*/
if ( (base_character == '0') && (sequence_number == 10) )
{
base_character = 'a'; /* Now use Characters for uniqueness */
sequence_number = 0; /* Reset the sequence number */
}
/*
** Create a character form of the Sequence number
** and use it with the base name to get an Final Process Name
*/
character = base_character + sequence_number++;
STR$CONCAT( /* Concatenate the strings */
&final_process_name, /* Resultant string */
&process_name, /* First source string */
&char_descriptor); /* Last source string */
/*
** Now try to create the process with the specified privileges
*/
status = SYS$CREPRC( /* Call the Create Process function */
&dcl.pid, /* Process ID */
&image_name, /* Image to run */
&dcl.input_name, /* Definition for SYS$INPUT */
&dcl.output_name, /* Definition for SYS$OUTPUT */
&dcl.output_name, /* Definition for SYS$ERROR */
privileges, /* Privileges */
0, /* Quotas */
&final_process_name, /* Name of the process */
4, /* Base priority */
0, /* Use my UIC */
dcl.term_unit, /* Termination mailbox unit number */
0); /* Status flags */
/*
** Free up the dynamic string and see if we have to loop again
*/
STR$FREE1_DX(&final_process_name);
if (status == SS$_DUPLNAM)
loop = TRUE; /* Duplicate process name, try again */
else
loop = FALSE; /* Jump out of the loop */
} /* End WHILE ... */
/*
** If the process was created OK then issue a command to execute
** the required initial commands
*/
if (TEST_STATUS)
{
/*
** Open up a log file for a record of all the command outputs
*/
subproc_log_file = fopen(SUBPROCESS_LOG_FILE, "w");
if (subproc_log_file == NULL)
printf("\n WARNING, unable to open Subprocess Log File %s",SUBPROCESS_LOG_FILE);
else
fprintf(subproc_log_file,"\n Beginning of Log file for subprocess PID = %x (hex)\n", dcl.pid);
/*
** Issue a command to NOT logout the process on an error
*/
status = dcl_write_command(&dcl, &set_noon_command);
}
/*
** Return the final status to the caller
*/
return status;
}
/* DCL WRITE COMMAND
**++
** FUNCTIONAL DESCRIPTION:
**
** This procedure is used to write a DCL command to the Subprocesses
** input device. Thus forcing the subprocess to actually issue
** the DCL command.
**
** FORMAL PARAMETERS:
**
** process_info -> Internal data structure specifying characteristics
** of the subprocess
** command_line -> Pointer to a descriptor containing the DCL command
**
** IMPLICIT INPUTS:
**
** none
**
** IMPLICIT OUTPUTS:
**
** none
**
** FUNCTION VALUE:
**
** System service return
**
** SIDE EFFECTS:
**
** The DCL command is executed by the subprocess
**
**--
**/
unsigned int dcl_write_command(
struct dcl_structure *process_info,
struct dsc$descriptor *command_line)
{
/*
** Local variables
*/
unsigned int status;
/*
** Write the command out to the Subprocesses input channel
*/
status = SYS$QIOW( /* Issue a syncronous QIO */
0, /* No event flag */
process_info->input_channel, /* IO Channel */
IO$_WRITEVBLK | IO$M_NOW, /* IO operation - WRITE */
&process_info->input_iosb, /* IO status block */
0, /* No AST routine */
0, /* No AST arguement */
command_line->dsc$a_pointer, /* Address of output buffer */
command_line->dsc$w_length, /* Length of output buffer */
0, 0, 0, 0); /* No P3, P4, P5, P6 arguements */
/*
** If the QIO worked then get the status out of the IOSB
*/
if (TEST_STATUS)
status = process_info->input_iosb.status;
/*
** Return the final status
*/
return status;
}
/* DCL WAIT UNTIL DONE
**++
** FUNCTIONAL DESCRIPTION:
**
** This routine is called to suspend the current process until the
** subprocess has completed the command that it was issued. This
** is done by using a set mode I/O to call an AST routine when the
** subprocess writes something into the mailbox. After issueing the
** set mode I/O, the process then hibernates.
**
** FORMAL PARAMETERS:
**
** process_info -> Pointer to information block for the subprocess
**
** IMPLICIT INPUTS:
**
** none
**
** IMPLICIT OUTPUTS:
**
** none
**
** FUNCTION VALUE:
**
** System Service value
**
** SIDE EFFECTS:
**
** The process hibernates until the subprocess writes something
** to the output channel
**
**--
**/
unsigned int dcl_wait_until_done(
struct dcl_structure *process_info)
{
unsigned int status;
/*
** Issue the Set WRITE ATTENTION call for the Output mailbod
*/
status = SYS$QIOW( /* Issue the QIO */
0, /* No Event flag */
process_info->output_channel, /* IO Channel */
IO$_SETMODE | IO$M_WRTATTN, /* SETMODE IO */
&process_info->output_iosb, /* IO status block */
0, /* No AST address */
0, /* No AST arguement */
&wake_ast, /* Address of AST routine */
0, 0, 0, 0, 0); /* No other P? arguements */
/*
** Determine the result of the Set Mode QIO
*/
if (TEST_STATUS)
status = process_info->output_iosb.status;
/*
** If alls well, then goto sleep until the subprocess writes something to the
** mailbox
*/
if (TEST_STATUS)
SYS$HIBER();
/*
** Return the final status to the caller
*/
return status;
}
/* DCL POST READ I/O
**++
** FUNCTIONAL DESCRIPTION:
**
** This routine is called to read in the output that the subprocess
** got back from the command that it issued. The routine will
** keep reading until there is no more output to be read.
**
** FORMAL PARAMETERS:
**
** process_info -> Pointer to structure containing information on
** the subprocess
**
** IMPLICIT INPUTS:
**
** none
**
** IMPLICIT OUTPUTS:
**
** none
**
** FUNCTION VALUE:
**
** System service return
**
** SIDE EFFECTS:
**
** none
**
**--
**/
unsigned int dcl_post_read_io(
char *buffer_address,
int buffer_length)
{
unsigned int status = SS$_NORMAL;
/*
** Read in the output that the suprocess has written to the mailbox
*/
status = SYS$QIO( /* Issue the IO request */
0, /* No event flag */
dcl.output_channel, /* IO channel */
IO$_READVBLK, /* IO function - READ */
&dcl.output_iosb, /* IO status block */
&read_ast, /* AST address */
0, /* No AST arguement */
buffer_address, /* Buffer address */
buffer_length, /* Buffer length */
0, 0, 0, 0); /* No more arguements */
SYS$HIBER();
if (TEST_STATUS)
status = dcl.output_iosb.status;
return status;
}
/* POST TERMINATION READ
**++
** FUNCTIONAL DESCRIPTION:
**
** This routine is used to post an Asyncronous I/O to read information
** off the termination channel. When the subprocess is terminated
** a final message will be written to that channel.
**
** FORMAL PARAMETERS:
**
** process_info -> Pointer to block containing information about
** the subprocess
**
** IMPLICIT INPUTS:
**
** none
**
** IMPLICIT OUTPUTS:
**
** none
**
** FUNCTION VALUE:
**
** System Service routine
**
** SIDE EFFECTS:
**
** An Asyncronous I/O will be outstanding until subprocess terminates
**
**--
**/
unsigned int post_termination_read(
struct dcl_structure *process_info)
{
/*
** Post an async IO on the termination channel
*/
return SYS$QIO( /* Issue the IO request */
0, /* No event flag */
process_info->term_channel, /* IO channel */
IO$_READVBLK, /* IO function - READ */
&process_info->term_iosb, /* IO status block */
&term_ast, /* Address of AST routine */
0, /* No Ast arguements */
&term_buffer, /* Buffer address */
255, /* Buffer length */
0, 0, 0, 0); /* No more arguements */
}
/* WAKE-UP AST
**++
** FUNCTIONAL DESCRIPTION:
**
** This is the AST routine called when the subprocess writes something
** to the mailbox. The routine will wake up the current process
** and then exit.
**
** FORMAL PARAMETERS:
**
** none
**
** IMPLICIT INPUTS:
**
** none
**
** IMPLICIT OUTPUTS:
**
** none
**
** COMPLETION CODES:
**
** none
**
** SIDE EFFECTS:
**
** The process is woken back up
**
**--
**/
wake_ast()
{
/*
** Wake up the process
*/
SYS$WAKE( /* Wake up the process */
0, /* No PID, use our own */
0); /* No Process Name, use our own */
}
/* Subprocess TERMINATION AST
**++
** FUNCTIONAL DESCRIPTION:
**
** This is the AST routine called when the subprocess terminates.
**
** FORMAL PARAMETERS:
**
** none
**
** IMPLICIT INPUTS:
**
** none
**
** IMPLICIT OUTPUTS:
**
** none
**
** COMPLETION CODES:
**
** none
**
** SIDE EFFECTS:
**
** The process is woken back up
**
**--
**/
term_ast()
{
printf("\n *** ATTN*** The accounting subprocess has terminated\n");
}
/* READ I/O AST
**++
** FUNCTIONAL DESCRIPTION:
**
** This AST routine is called when the Asyncronous read of the mailbox
** completes. At that point we will wake up the current process.
**
** FORMAL PARAMETERS:
**
** none
**
** IMPLICIT INPUTS:
**
** none
**
** IMPLICIT OUTPUTS:
**
** none
**
** COMPLETION CODES:
**
** none
**
** SIDE EFFECTS:
**
** The current process is started up again
**
**--
**/
read_ast()
{
SYS$WAKE( /* Wake up the process */
0, /* No PID, use our own */
0); /* No Process Name, use our own */
}
----------------------------End of DCL command program-------------------------
----------------------------Required include file------------------------------
/*
**++
** FACILITY:
**
** Stevens Accounting System
**
** ABSTRACT:
**
** [@tbs@]
**
** AUTHORS:
**
** [@tbs@]
**
**
** CREATION DATE: 14-July-1987
**
** MODIFICATION HISTORY:
**--
**/
/*
** Define TEST_STATUS, to see if an error was returned or not
*/
#define TEST_STATUS (status & 1)
/*
** Parameters -- Standard VMS Specific parameters
*/
#define MAX_USERNAME 39 /* Maximum number of characters in a user name */
/*
* A macro, $DESCRIPTOR, is defined in the file included above, and can be
* used to declare descriptors for the usual C strings (NUL-terminated arrays
* of char). This macro is not adequate for all the cases requiring descriptors
* in this program, however, so we must define a few more macros:
*
* $DESCRIPTOR1 can be used for 1-character items, or for whole structures
* $DESCRIPTORM can be used for strings that are structure members, or for
* any other string not terminated by a NUL character
* $DESCRIPTORA generates an array descriptor, and is used to describe
* the workspaces and terminal control area
*
* LENGTH and POINTER are useful shorthands for accessing descriptor fields
*/
#define $DESCRIPTOR1(name,string) struct dsc$descriptor_s \
name = { sizeof(string), DSC$K_DTYPE_T, DSC$K_CLASS_S, &string }
#define $DESCRIPTORM(name,string) struct dsc$descriptor_s \
name = { sizeof(string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string }
#define $DESCRIPTORA(name,array,type) struct dsc$descriptor_a \
name = { sizeof (type), DSC$K_DTYPE_L, DSC$K_CLASS_A, array, 0, 0, { 0, 0, 0, 0, 0 }, 1, sizeof array }
#define LENGTH(descriptor) descriptor.dsc$w_length
#define POINTER(descriptor) descriptor.dsc$a_pointer
#define $INIT_DESCRIPTOR {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0}
#define $STATIC_DESCRIPTOR {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}
/*
** Structure definitions
**
** key_word_list - Structure to define what a keywork list is.
**
*/
struct key_word_list
{
struct dsc$descriptor *keyword; /* Pointer to keyword */
unsigned int keyword_information; /* keyword specific information */
};
/*
** Standard VAX/VMS item list definitions. This item lists are used for various
** system service calls. There are two flavors basic flavors, the three item
** item list and the two item item lits.
*/
struct item_list_2
{
unsigned short buffer_length; /* Length of the buffer */
unsigned short item_code; /* Item code */
unsigned int *buffer_address; /* Address of the buffer */
};
struct item_list_3
{
unsigned short buffer_length; /* Length of the buffer */
unsigned short item_code; /* Item code */
unsigned int *buffer_address; /* Address of the buffer */
unsigned int *return_length_address; /* Returned information */
};
struct item_list_acct
{
unsigned short buffer_length; /* Length of the buffer */
unsigned short item_code; /* Item code */
unsigned char buffer[]; /* Buffer */
};
/*
** Definitions for the item list descriptor
*/
#define DSC$ITEMLIST {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0}
/*
** Accounting information is passed in the program as an item list. That is it
** will conform to Digital's standard idea of what an item list is, except that
** the information that is contained in the item list will no be a pointer to
** any information, but the information itself.
**
** Information types:
** - String: - Stored as ASCIZ with a byte count.
** - Numbers: - Stored as a long word.
**
*/
/*
** All item codes are stored in ranges.
**
** 1 - 99 UAF associated data
** 100 - 199 Diskquota associated data
** 200 - 299 Project associated data
** 300 - 399 Quantum RS user associated data
** 400 - 499 Quantum RS group associated data
**
** New items are added on the end.
**
*/
#define ITM_END_OF_LIST 0 /* End of the item list */
/*
** General item codes
*/
#define ITM_UIC 1 /* General UIC */
/*
** UAF Item codes
*/
#define ITM_UAF_OWNER 10 /* Owner name */
#define ITM_UAF_ACCOUNT 11 /* Account */
#define ITM_UAF_DEVICE 12 /* Default device name */
#define ITM_UAF_DIRECTORY 13 /* Default directory name */
#define ITM_UAF_EXPIRATION 14 /* Expiration date/time */
#define ITM_UAF_UIC 15 /* UAF UIC */
/*
** Diskquota item codes
*/
#define ITM_DISK_PERM 30 /* Diskquota - Perm */
/*
** Quantum RS user item codes
*/
#define ITM_USN_INACTIVE 310 /* Inactive flag */
#define ITM_USN_BILLABLE 311 /* Billable flag */
#define ITM_USN_POST_DISK_USAGE 312 /* Post disk usage flag */
#define ITM_USN_POST_SESSION_USAGE 313 /* Post session resource usage */
/*
** Rate schedule associated with each user for each node.
*/
#define ITM_USN_VXA_RATES 320 /* Rate schedule used (SITVXA) */
#define ITM_USN_VXB_RATES 321 /* Rate schedule used (SITVXB) */
#define ITM_USN_VXC_RATES 322 /* Rate schedule used (SITVXC) */
/*
** Text descriptions of the users for each node.
*/
#define ITM_USN_VXA_DESCRIPTION 330 /* SITVXA user description (text) */
#define ITM_USN_VXB_DESCRIPTION 331 /* SITVXB user description (text) */
#define ITM_USN_VXC_DESCRIPTION 332 /* SITVXC user description (text) */
/*
** Quantum RS group item codes
*/
#define ITM_GRP_ACTIVE 410 /* Inactive flag */
#define ITM_GRP_BILLABLE 411 /* Billable flag */
#define ITM_GRP_AGGREGATE 412 /* Aggregate usage across group members*/
#define ITM_GRP_RATES 413 /* Group rate schedule */
#define ITM_GRP_CHG_COUNT 414 /* Group charge count */
#define ITM_GRP_INIT_DATE 415 /* Group initialization date */
#define ITM_GRP_MOD_COUNT 416 /* Modification count */
#define ITM_GRP_LAST_MOD_DATE 417 /* Last modification date */
#define ITM_GRP_DESCRIPTION 420 /* Group description (text) */
/*
** The following structure is used to map an item list item to a field in the
** current form that is being processed. This structure is used by all the
** modules to store the item list items into the form.
*/
struct item_field_mapping
{
unsigned short item_type; /* Item type to make from */
struct dsc$descriptor *field_name; /* Field name */
};
/*
** VAX/VMS I/O status block (IOSB) structure definition
*/
struct io_status_block
{
unsigned short int status; /* Final status */
unsigned short int count; /* Byte count for many devices */
unsigned long devdepend; /* Device dependent part */
};
/*
** The following definitions are required by the routines that handle the
** processing of the local databases. These databases include:
** Available UIC Database
** Group Definition Database
** Account Definition Database
*/
/* Define flags to specify which type of UIC Number to process */
#define FIND_UIC_MEMBER_NUMBER 1 /* Find a free UIC Member Number */
#define FIND_UIC_GROUP_NUMBER 2 /* Find a free UIC Group Number */
/*
** Define the UIC Number Catagories, which are actually indexes into
** an initial value array
*/
#define CGY$C_SYSTEM 0 /* Use valid System UIC's */
#define CGY$C_COMP_CENTER 1 /* Use valid Computer Center UIC's */
#define CGY$C_DEPARTMENT 2 /* Use valid Departmental UIC's */
#define CGY$C_RESEARCH 3 /* Use valid Research UIC's */
#define CGY$C_SPECIAL 4 /* Use valid Special project UIC's */
#define CGY$C_GRADUATE 5 /* Use valid Graduate UIC's */
#define CGY$C_UNDERGRADUATE 6 /* Use valid Undergraduate UIC's */
--------------------------End of include file----------------------------------
Good luck, and thanks for those who sent me help
David L. Stevens
Stevens Tech
CCnet: SITVXC::DSTEVENS
BITnet: DSTEVENS@SITVXA
INTERnet: DSTEVENS@VAXC.STEVENS-TECH.EDU
Disclaimer: It's not my fault
------------