From: hoffman@xdelta.zko.dec.nospam
Sent: Monday, August 02, 1999 6:15 PM
To: Info-VAX@Mvb.Saic.Com
Subject: Re: Setting SRM console variables from within OpenVMS ?


In article <f+s39HAbAEp3EwtY@csking.demon.co.uk>, Chris King <chris@csking.demon.co.uk> writes:
:Does anyone know if there is a VMS equivalent of the Tru64 "consvar"
:command to set SRM console variables ?

  Ayup.

  You can use the (now documented) sys$getenv call to read the console
  environment variables.  This call has been around for years, but is
  now documented with OpenVMS Alpha V7.2.

  To set the console environment variables you could:

    o poke around and look for an (undocumented) sys$setenv call that might 
      just happen to exist. :-)

      If you should find this routine, the API might be structured and might
      work just like the sys$getenv() call, and it might even explain the 
      "ST" prefix on all those sys$getenv() symbol definitions. :-)

      I'd expect that any sys$setenv call found would probably require the
      caller to have CMKRNL privilege. :-)

    o you could use something akin to attached get_env() and set_env() 
      routines in the example program attached below.

      The attached example C code does not use documented or supported
      interfaces, and -- like any other kernel code -- it might just crash 
      your OpenVMS system, and it might require a rebuild after an ECO or 
      upgrade.

      CMKRNL privilege is required.


 --------------------------- pure personal opinion ---------------------------
   Hoff (Stephen) Hoffman   OpenVMS Engineering   hoffman#xdelta.zko.dec.com


/*
 * DEFAULT_BOOT -- reads environment variable bootdef_dev and
 * writes its value to environment variable boot_dev
 *
 * This program is designed to emulate VAX style shutdown/reboot
 * behaviour on Alpha machines.  On VAX, on a shutdown/reboot invoked
 * from VMS, the reboot occurs from the default boot device.  On Alpha,
 * the reboot occurs from the device from which you last successfully
 * booted.   This program copies environment variable BOOTDEF_DEV
 * (default boot device list) to BOOT_DEV (device list used by the last
 * bootstrap attempt), which effectively causes the reboot to occur from
 * the device(s) specified in BOOTDEF_DEV.
 *
 * This program is useful, for example, if you occasionally boot an
 * alternate system disk and you want the reboot to occur from your
 * usual system disk.  In this case you may do something like:
 *
 *       $ run default_boot
 *       $ reboot
 *
 * The default_boot program will copy BOOTDEF_DEV to BOOT_DEV, and
 * the reboot will occur using the device list in BOOTDEF_DEV.
 *
 * You must have CMKRNL priviledge to run this program.  It is
 * recommended that only one copy of this program runs at any one time.
 *
 */
#pragma module default_boot

#include <ints.h>
#include <hwrpbdef.h>
#include <ssdef.h>
#include <dcdef.h>
#include <stdio>
#include <vms_macros.h>

/* Local definitions */
#define BUF$K_LENGTH 132

/* External global variables */

extern HWRPB    *exe$gpq_hwrpb;

/* External routines */

extern int      sys$cmkrnl ();
extern void     exit ();
extern int      strlen ();

/* Routines defined in this module */

uint64  get_env ();
uint64  set_env ();

/*
 * Global array to associate environment variable numbers with
 * strings.  Though it does not say so in the SRM, some of the
 * environment variables can be returned in different forms.  For
 * example, if you say ...get_env ("bootdef_dev") you get the
 * name of the boot device in the form dka0.0.2.6.0.  But if
 * you say ...get_env (3) you get the full path of the boot
 * device SCSI 0 0 2 6 0 -- very different.  So, here I am
 * making a table which can be indexed by environment variable
 * number.  The entries point to strings corresponding to the
 * environment variable number.  See page 2-27 in the console
 * chapter of the SRM.
 */
static char *env_strings [] = {
    "reserved",
    "auto_action",
    "boot_dev",
    "bootdef_dev",
    "booted_dev",
    "boot_file",
    "booted_file",
    "boot_osflags",
    "booted_osflags",
    "boot_reset",
    "dump_dev",
    "enable_audit",
    "license",
    "char_set",
    "language",
    "tty_dev"
};

main (argc, argv)

int     argc;
char    *argv [];

{
    int         status;
    int         i;
    int         num_bytes;
    int         arglist [6];
    char        bootdef_dev [BUF$K_LENGTH];
    char        boot_dev [BUF$K_LENGTH];
    uint64      callback_status;

    /* Initialize character buffers with zeros */
    for (i=0; i++; i < BUF$K_LENGTH) {
        bootdef_dev [i] = (char) 0;
        boot_dev [i] = (char) 0;
    }

    /* Call kernel routine to read environment variable */
    for (i=0; i++; i < BUF$K_LENGTH) {
        bootdef_dev [i] = (char) 0;
        boot_dev [i] = (char) 0;
    }

    /* Call kernel routine to read environment variable bootdef_dev */
    arglist [0] = 3;
    arglist [1] = HWRPB_CRB$K_BOOTCMD_DEV,
    arglist [2] = (int) bootdef_dev;
    arglist [3] = (int) &callback_status;
    status = sys$cmkrnl (get_env, arglist);
    if (!(status & 1)) exit (status);

    /*
     * Console callbacks return status in bits 63:61.  For get_env,
     * if the status is success, the number of bytes returned is
     * in the lower longword of the status quadword.  So, break the
     * status into two longwords and look it over.
     */
    status = callback_status >> 61;
    num_bytes = callback_status;

    /*
     * The callback status is as follows (now in bits 2:0)
     *   000 = success
     *   001 = success, byte stream truncated
     *   110 = environment variable not recognized
     */
    switch (status) {
        case 0:
            /* Success */
            break;
        case 1: {
            /* Success, but byte stream truncated.  Display
             * what we got and exit.
             */
            printf ("BOOTDEF_DEV partially read.  %d bytes read\n", num_bytes);
            printf ("BOOTDEF_DEV : %s\n", bootdef_dev);
            printf ("BOOT_DEV not updated.  Exiting...\n");
            exit (0);
        }
        case 6: {
            printf ("Environment variable not recognized. Exiting...\n");
            exit (0);
        }
        default: {
            printf ("Unknown status returned by get_env: %d\n", status);
            printf ("Exiting...\n");
            exit (0);
        }
    }   /* end switch (status) */

    /*
     * We now have BOOTDEF_DEV.  Use set_env to write BOOTDEF_DEV to
     * BOOT_DEV.
     */
    arglist [0] = 3;
    arglist [1] = HWRPB_CRB$K_BOOT_DEV; /* EV to be written */
    arglist [2] = (int) bootdef_dev;    /* String to be written to EV */
    arglist [3] = (int) &callback_status;
    status = sys$cmkrnl (set_env, arglist);
    if (!(status & 1)) exit (status);

    /*
     * Console callbacks return status in bits 63:61.  For set_env,
     * if the status is success, everything is written.
     * Break the status into two longwords and look it over.
     */
    status = callback_status >> 61;
    num_bytes = callback_status;

    /*
     * The set_env callback status is as follows (in bits 2:0)
     *   000 = success
     *   100 = fail, variable is read only
     *   110 = environment variable not recognized
     *   111 = fail, byte stream exceeds value length
     */
    if (status != 0) {
        printf ("SET_ENV (boot_dev) failed.  Callback status : %d\n", status);
        printf ("Exiting...\n");
        exit (0);
    }

    exit (SS$_NORMAL);
}











uint64  get_env (int    env_number,
                 char   *buffer,
                 uint64 *callback_status)
/*
 *      Routine get_env -- performs get_env console callback to read
 *                          specified environment variable
 *
 *      INPUTS
 *              env_number      Number of environment variable.
 *                              See SRM or HWRPBDEF.H
 *              buffer          pointer to an array of characters.
 *                              On success, the requested env.
 *                              variable is written to this array.
 *              callback_status Pointer to a quadword.  The status
 *                              of the get_env console callback
 *                              is returned in this quadword.
 *
 *      OUTPUTS
 *              SS$_NORMAL      The callback executed, the actual
 *                              status of the callback returned
 *                              in callback_status.
 */
{
    uint64      status;
    HWRPB_CRB   *crb;
    uint64      (* dispatch)();

    crb = (HWRPB_CRB *) ((int)exe$gpq_hwrpb +
      exe$gpq_hwrpb->hwrpb$iq_crb_offset);
    dispatch = (uint64 (*)()) crb->hwrpb_crb$il_va_dispatch_pd_l;

    /* Execute get_env console callback to read bootdef_dev */

/*
 *  status = (uint64) dispatch (HWRPB_CRB$K_GET_ENV,
 *                              env_number,
 *                              buffer,
 *                              BUF$K_LENGTH);
 */
    status = (uint64) dispatch (HWRPB_CRB$K_GET_ENV,
                                env_strings [env_number],
                                buffer,
                                BUF$K_LENGTH);

    *callback_status = status;
    return SS$_NORMAL;
}

uint64  set_env (int    env_number,
                 char   *buffer,
                 uint64 *callback_status)
/*
 *      Routine set_env -- performs set_env console callback
 *                     to write specified environment variable
 *
 *      INPUTS
 *              env_number      environment variable to be written
 *              buffer          pointer to an array of characters.
 *                              On success, this string is written
 *                              to the specified EV.
 *              callback_status Pointer to a quadword.  The status
 *                              of the get_env console callback
 *                              is returned in this quadword.
 *
 *      OUTPUTS
 *              SS$_NORMAL      The callback executed, the actual
 *                              status of the callback returned
 *                              in callback_status.
 */
{
    uint64      status;
    HWRPB_CRB   *crb;
    uint64      (* dispatch)();

    crb = (HWRPB_CRB *) ((int)exe$gpq_hwrpb + 
       exe$gpq_hwrpb->hwrpb$iq_crb_offset);
    dispatch = (uint64 (*)()) crb->hwrpb_crb$il_va_dispatch_pd_l;

    status = (uint64) dispatch (HWRPB_CRB$K_SET_ENV,
                                env_strings [env_number],
                                buffer,
                                strlen (buffer));

    *callback_status = status;
    return SS$_NORMAL;
}