Path: pa.dec.com!nntpd.lkg.dec.com!not-for-mail
From: Fred Kleinsorge <kleinsorge@star.enet.dec_nospam.com>
Newsgroups: comp.os.vms
Subject: Re: Is there also a F$SETENVIRONMENT lexical?
Date: Thu, 29 Oct 1998 13:35:54 -0400
Organization: OpenVMS Engineering
Lines: 296
Message-ID: <36386F3A.60AA5CAE@star.enet.dec_nospam.com>
References: <199810290629.HAA03456@gate.fim.fgan.de>
NNTP-Posting-Host: fgkaxp.zko.dec.com
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Mailer: Mozilla 3.03Gold (X11; I; OpenVMS V7.1     AlphaServer 2100A 5/250)

win@gate.fim.fgan.de wrote:
> 
> Hello,
> 
> I think it would be nice to have the F$SETENVIRONMENT lexical function.
> In case of this you could set a boot flag and reboot without manual
> console interaction. Also you can change the default boot device with-
> out shutdown and execute a reboot during the night (as batch), when all
> the workers (including yourself) sleeped well.
> 

/* 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 variabl    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;
}
