home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / sna / arexec / arexec.c next >
Text File  |  1997-04-09  |  16KB  |  428 lines

  1. /*****************************************************************************
  2.  *
  3.  *  MODULE NAME : AREXEC.C
  4.  *
  5.  *  COPYRIGHTS:
  6.  *             This module contains code made available by IBM
  7.  *             Corporation on an AS IS basis.  Any one receiving the
  8.  *             module is considered to be licensed under IBM copyrights
  9.  *             to use the IBM-provided source code in any way he or she
  10.  *             deems fit, including copying it, compiling it, modifying
  11.  *             it, and redistributing it, with or without
  12.  *             modifications.  No license under any IBM patents or
  13.  *             patent applications is to be implied from this copyright
  14.  *             license.
  15.  *
  16.  *             A user of the module should understand that IBM cannot
  17.  *             provide technical support for the module and will not be
  18.  *             responsible for any consequences of use of the program.
  19.  *
  20.  *             Any notices, including this one, are not to be removed
  21.  *             from the module without the prior written consent of
  22.  *             IBM.
  23.  *
  24.  *  AUTHOR:    Peter J. Schwaller
  25.  *             VNET:     PJS at RALVM6           Tie Line: 444-4376
  26.  *             Internet: pjs@ralvm6.vnet.ibm.com     (919) 254-4376
  27.  *
  28.  *  FUNCTION:  Execute a command on a remote workstation and display the
  29.  *             output from the command (both stdout and stderr) on the
  30.  *             requesting workstation.
  31.  *
  32.  *  Usage:
  33.  *      AREXEC destination command
  34.  *
  35.  *    Destination may be either a partner LU alias (up to eight
  36.  *    characters) or a fully qualified LU name (3-17 characters separated
  37.  *    by a period)
  38.  *
  39.  *  AVAILABILITY:
  40.  *             These sample programs and source are also available on
  41.  *             CompuServe through the APPC Information Exchange.  To get
  42.  *             to the APPC forum just type 'GO APPC' from any CompuServe
  43.  *             prompt.  The samples are available in the Sample Programs
  44.  *             library section.  Just search on the keyword CPICPGMS to
  45.  *             find all the samples in this series.
  46.  *
  47.  *             Updates for the sample programs and support for many more
  48.  *             CPI-C platforms will also be made available on CompuServe.
  49.  *
  50.  *  RELATED FILES:
  51.  *             See AREXEC.DOC for usage instructions.
  52.  *
  53.  *  CHANGE HISTORY:
  54.  *  Date       Description
  55.  *  06/15/92   NS/DOS accepts version 2.02 into system test.
  56.  *  08/05/92   Version 2.31 released to CompuServe
  57.  *             This version was also distributed at the APPC/APPN Platform
  58.  *             Developer's Conference held in Raleigh, NC.
  59.  *  08/13/92   Changed all printf and fprintf calls to use a write_*() call.
  60.  *  08/17/92   Made security handling code conditionally compiled.
  61.  *  08/23/92   Removed call to cpicinit_default_destination().
  62.  *  08/24/92   Version 2.32 released to CompuServe.
  63.  *  09/22/92   Version 2.33 released to CompuServe.
  64.  *  11/17/92   Added support for printing remote operating system name.
  65.  *             Version 2.34 released to CompuServe
  66.  *  01/07/93   Version 2.35
  67.  *             Fixed a number of problems when compiling with IBM C Set/2
  68.  *                password input was displayed
  69.  *                timer resolution was 1 second
  70.  *
  71.  *****************************************************************************/
  72.  
  73. /*****************************************************************************
  74.  * OVERVIEW of AREXEC CPI-C Flows
  75.  *
  76.  *   Client (AREXEC)                     Server (AREXECD)
  77.  *   --------------                      ---------------
  78.  * Set up conversation
  79.  *   Allocate       -------------------> Accept Conversation
  80.  * Exchange Version Numbers
  81.  *   Send Data      -------------------> Receive
  82.  *   Receive        <------------------- Send Data
  83.  * Send the Command
  84.  *   Send Data      -------------------> Receive
  85.  * Receive the Output
  86.  * -->                                           <--
  87.  * | Receive        <------------------- Send Data |     LOOP
  88.  * ---                                           ---
  89.  * Command is finished
  90.  * Receive          <------------------- Deallocate(FLUSH)
  91.  *****************************************************************************/
  92.  
  93. #if defined(WINDOWS)||defined(WIN32)
  94. #include <windows.h>
  95. #endif
  96. #include "wincpic.h"
  97.  
  98. /* standard C include files */
  99. #include <stdio.h>
  100. #include <string.h>
  101. #include <stdlib.h>
  102.  
  103. /* Set up constant declarations */
  104. #include "cpicdefs.h"
  105.  
  106. /* Collection of routines with special ported version for each platform */
  107. #include "cpicport.h"
  108.  
  109. /* CPI-C error handling routines */
  110. /* This file is supplied with AREXEC */
  111. #include "cpicerrs.h"
  112.  
  113. /* Argument processing procedure */
  114. /* This file is supplied with AREXEC */
  115. #include "getopt.h"
  116.  
  117. /* CPI-C initialization routines */
  118. /* This file is supplied with AREXEC */
  119. #include "cpicinit.h"
  120.  
  121. #define  MAX_COMMAND_LENGTH   500
  122.  
  123. /* CPI-C error handling info */
  124. CPICERR * cpicerr;
  125.  
  126. /* These are the defaults to be used if the user does not provide arguments  */
  127. /* to override these values.                                                 */
  128. #define  DEFAULT_TP_NAME   "AREXECD"
  129. #define  DEFAULT_MODE_NAME "#INTER"
  130. #define  DEFAULT_SYM_DEST  "AREXECD"
  131.  
  132. /* Define these here so we can make changes throughout the code. */
  133. /*
  134.  * The PROGRAM_INFO string should be kept in sync with the
  135.  * MAJOR_VERSION and MINOR_VERSION constants.  Although the
  136.  * cpicerr_exchange_version() call will support values up to 255,
  137.  * values for MINOR_VERSION should be from 00-99 to maintain the
  138.  * two character format in the version string.
  139.  */
  140. #define  PROGRAM_NAME      "AREXEC"
  141. #define  PROGRAM_INFO      "version 2.35"
  142. #define  MAJOR_VERSION     (2)
  143. #define  MINOR_VERSION     (35)
  144. #define  LOG_FILE_NAME     "arexec.err"
  145. #define  LOG_FILE_PATH     "$LOGPATH"
  146.  
  147. /* local structure definition */
  148. typedef struct command_info {
  149.     char        buffer[MAX_COMMAND_LENGTH];
  150.     CM_INT32    buffer_length;
  151. } COMMAND_INFO;
  152.  
  153. /* local function prototypes */
  154. void process_arguments(int argc,
  155.                        char *argv[],
  156.                        CPICINIT * cpicinit,
  157.                        COMMAND_INFO * command_info);
  158.  
  159. /*
  160.  * Message displayed with show_info() when APING is started.
  161.  */
  162. char * intro[] = {
  163.     PROGRAM_NAME " " PROGRAM_INFO " - Execute a remote command.",
  164.     "  by Peter J. Schwaller (pjs@ralvm6.vnet.ibm.com)",
  165.     NULL
  166.     };
  167.  
  168. /*
  169.  * Message displayed with show_info() when AREXEC is started.
  170.  */
  171. char * usage[] = {
  172.     "",
  173.     "Usage:",
  174.     "AREXEC [flags] destination command",
  175.     "Flags:",
  176.     "  destination",
  177.     "\tmay be either a symbolic destination name or a partner LU name",
  178.     "  command",
  179.     "\tcommand string to be executed on the remote machine",
  180.     "  -m mode_name",
  181.     "\tMode name (default: " DEFAULT_MODE_NAME ")",
  182.     "  -t tp_name",
  183. #if defined(SUPPORTS_SETTING_SECURITY)
  184.     "\tthe TP to use on the allocate (default: " DEFAULT_TP_NAME ")",
  185.     "  -u userid",
  186.     "  -p password",
  187.     "\tSecurity parameters.  If a userid is specified without a password,",
  188.     "\tyou will be prompted for the password.",
  189.     "  -n",
  190.     "\tDo not use any security (SECURITY=NONE).",
  191. #endif
  192.     NULL
  193.     };
  194.  
  195.  
  196. void _cdecl
  197. main( int argc, char *argv[])
  198. {
  199.     /* Variables used for CPI-C calls */
  200.     unsigned char cm_conv_id[8];            /* CPI-C conversation ID         */
  201.     CM_INT32     cm_rc;                     /* CPI-C return code             */
  202.     CM_INT32     rts_received;              /* request to send received      */
  203.     CM_INT32     max_receive_len;           /* Max receive length on CMRCV   */
  204.     CM_INT32     what_received;             /* What received parm from CMRCV */
  205.     CM_INT32     received_len;              /* Amount of data rcvd on CMRCV  */
  206.     CM_INT32     status_received;           /* Status from CMRCV             */
  207.  
  208.     /* Destination information */
  209.     CPICINIT *   cpicinit;
  210.  
  211.     char         partner_major_version;
  212.     char         partner_minor_version;
  213.     char         opsys_string[64];
  214.  
  215. #if defined(WINDOWS) || defined(WIN32)
  216.     unsigned short WinCPICVersion = 0x0001;
  217.     WCPICDATA CPICData;
  218. #endif
  219.  
  220.     COMMAND_INFO command_info;
  221.  
  222.     /*
  223.      * Make sure all output is seen as soon as possible.
  224.      */
  225.     setbuf(stdout, NULL);
  226.  
  227.     show_info(intro);                       /* Show program information      */
  228.  
  229. #if (defined(WIN32) || defined(WINDOWS))                              /*WIN32*/
  230.        /****************************************************************WIN32*/
  231.        /* Initialisation for WinCPIC                                   *WIN32*/
  232.        /****************************************************************WIN32*/
  233.     if (WinCPICStartup(WinCPICVersion,&CPICData))                     /*WIN32*/
  234.     {                                                                 /*WIN32*/
  235.        return;                                                        /*WIN32*/
  236.     }                                                                 /*WIN32*/
  237. #endif                                                                /*WIN32*/
  238.  
  239.     /*
  240.      * Create a new CPICINIT structure and initialize values.
  241.      * The procedures are in CPICINIT.C
  242.      */
  243.     cpicinit = cpicinit_new();
  244.     cpicinit_default_tp_name(cpicinit, DEFAULT_TP_NAME);
  245.     cpicinit_default_mode_name(cpicinit, DEFAULT_MODE_NAME);
  246.     cpicinit_default_sym_dest_name(cpicinit, DEFAULT_SYM_DEST);
  247.  
  248.  
  249.     /*
  250.      * Process all of the command line arguments.  All of the conversation
  251.      * setup arguments are stored in the cpicinit object.  The command
  252.      * to be sent is returned in the buffer variable within command_info.
  253.      */
  254.     process_arguments(argc, argv, cpicinit, &command_info);
  255.  
  256.     if (cpicinit_query_password_needed(cpicinit)) {
  257.         /* get a password from the user */
  258.         cpicinit_get_password(cpicinit);
  259.     }
  260.  
  261.     /*
  262.      * Initialize the CPICERR structure.  This is done before the CMINIT
  263.      * call so that we can use CPICERR for help with errors on CMINIT.
  264.      * The procedure is in CPICERR.C
  265.      */
  266.     cpicerr = cpicerr_new();
  267.     cpicerr_set_program_name(cpicerr, PROGRAM_NAME);
  268.     cpicerr_set_program_info(cpicerr, PROGRAM_INFO);
  269.     cpicerr_set_major_version(cpicerr, MAJOR_VERSION);
  270.     cpicerr_set_minor_version(cpicerr, MINOR_VERSION);
  271.     cpicerr_set_log_file_name(cpicerr, LOG_FILE_NAME);
  272.     cpicerr_set_log_file_path(cpicerr, LOG_FILE_PATH);
  273.  
  274.     cpicinit_setup_conversation(cpicinit, cm_conv_id, cpicerr);
  275.  
  276.     {
  277.     CM_SYNC_LEVEL sync_level = CM_CONFIRM;
  278.     cmssl(cm_conv_id,                        /* Set sync level               */
  279.           &sync_level,
  280.           &cm_rc);
  281.     }
  282.  
  283.     cmallc(cm_conv_id,                       /* Allocate the conversation    */
  284.            &cm_rc);
  285.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMALLC, cm_rc);
  286.  
  287.     cpicerr_exchange_version_plus(cpicerr,
  288.                                   cm_conv_id,
  289.                                   CM_SEND_STATE,
  290.                                   &partner_major_version,
  291.                                   &partner_minor_version,
  292.                                   opsys_string,
  293.                                   sizeof(opsys_string));
  294.     /*
  295.      * Display the operating system string returned in the exchange.
  296.      * The string length will be 0 if the operating system string
  297.      * wasn't available.
  298.      */
  299.  
  300.     if (strlen(opsys_string) != 0) {
  301.         write_output("\nConnected to a partner running on: %s\n",
  302.                      opsys_string);
  303.     }
  304.  
  305.     convert_to_ascii(command_info.buffer, command_info.buffer_length);
  306.     cmsend(cm_conv_id,                     /* Send Data                      */
  307.            (unsigned char *)command_info.buffer, /* data pointer             */
  308.            &command_info.buffer_length,    /* length of data sent            */
  309.            &rts_received,                  /* request to send indicator      */
  310.            &cm_rc);
  311.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
  312.  
  313.     max_receive_len = sizeof(command_info.buffer);
  314.     do {
  315.         cmrcv(cm_conv_id,                   /* Receive Data                  */
  316.               (unsigned char *)command_info.buffer, /* Data Pointer          */
  317.               &max_receive_len,             /* Size of Data Buffer           */
  318.               &what_received,               /* returned - what received      */
  319.               &received_len,                /* returned - length of data     */
  320.               &status_received,             /* returned - status received    */
  321.               &rts_received,                /* returned - request to send    */
  322.               &cm_rc);
  323.  
  324.        if (what_received != CM_NO_DATA_RECEIVED &&
  325.             (cm_rc == CM_OK || cm_rc == CM_DEALLOCATED_NORMAL)) {
  326.                                             /* Write the received data       */
  327.             convert_from_ascii(command_info.buffer, received_len);
  328.             fwrite(command_info.buffer, 1, (unsigned int)received_len, stdout);
  329.        }
  330.  
  331.     } while ( !cm_rc );
  332.  
  333.     if (cm_rc != CM_DEALLOCATED_NORMAL) {
  334.         cpicerr_handle_rc(cpicerr, MSG_CMRCV, cm_rc);
  335.     }
  336.  
  337.     /* destroy the object we created with cpicinit_new() */
  338.     cpicinit_destroy(cpicinit);
  339.  
  340.     /* destroy the object we created with cpicerr_new() */
  341.     cpicerr_destroy(cpicerr);
  342.  
  343.     exit(EXIT_SUCCESS);
  344. }
  345.  
  346.  
  347. void
  348. process_arguments(int argc,
  349.                   char *argv[],
  350.                   CPICINIT * cpicinit,
  351.                   COMMAND_INFO * command_info)
  352. {
  353.     int         set_destination = 0;
  354.     int         c;                          /* flag specifed, used w/getopt  */
  355.  
  356.     command_info -> buffer_length = 0;
  357.     command_info -> buffer[0] = '\0';
  358.  
  359.     while (optind != argc) {
  360.         c = getopt(argc, argv, "?t:m:u:p:T:M:U:P:Nn");
  361.         switch (c) {
  362.         case EOF:
  363.             if (set_destination == 0) {
  364.                 set_destination = 1;
  365.                 optarg = argv[optind];
  366.                 if (optarg[0] == '?') {
  367.                    show_info(usage);
  368.                    exit(EXIT_FAILURE);
  369.                 }
  370.                 optind++;
  371.                 cpicinit_set_destination(cpicinit, optarg);
  372.             } else {
  373.                 command_info -> buffer[0] = '\0';
  374.                 for ( ; optind<argc ; optind++ ) {
  375.                     command_info -> buffer_length += strlen(argv[optind])+1;
  376.                     if (command_info->buffer_length < MAX_COMMAND_LENGTH) {
  377.                         strcat(command_info->buffer, argv[optind]);
  378.                         strcat(command_info->buffer, " ");
  379.                     } else {
  380.                         write_error(
  381.                                 "Command length exceeds max allowed (%d).\n",
  382.                                 MAX_COMMAND_LENGTH-1);
  383.                         write_error(
  384.                                 "No command will be sent.\n");
  385.                         exit(EXIT_FAILURE);
  386.                     }
  387.                 }
  388.             }
  389.             break;
  390.         case 'M':
  391.         case 'm':
  392.             cpicinit_set_mode_name(cpicinit, optarg);
  393.             break;
  394.         case 'T':
  395.         case 't':
  396.             cpicinit_set_tp_name(cpicinit,optarg);
  397.             break;
  398. #if defined(SUPPORTS_SETTING_SECURITY)
  399.         case 'U':
  400.         case 'u':
  401.             cpicinit_set_userid(cpicinit, optarg);
  402.             break;
  403.         case 'P':
  404.         case 'p':
  405.             cpicinit_set_password(cpicinit, optarg);
  406.             break;
  407.         case 'N':
  408.         case 'n':
  409.             cpicinit_set_security_type(cpicinit, CM_SECURITY_NONE);
  410.             break;
  411. #endif
  412.         case '?':
  413.             show_info(usage);
  414.             exit(EXIT_FAILURE);
  415.             break;
  416.         default:
  417.             write_output("Invalid flag.  Use AREXEC -? for usage\n");
  418.             exit(EXIT_FAILURE);
  419.         }
  420.     }
  421.     if (!(set_destination && command_info->buffer_length)) {
  422.         write_error(
  423.                 "You must specify at least a destination and a command.\n");
  424.         show_info(usage);
  425.         exit(EXIT_FAILURE);
  426.     }
  427. }
  428.