Blob Blame History Raw
/*
||=======================================================================
|| smiucv - Helper utility that provides an IUCV interface to the z/VM
||          System Management API (SMAPI).
||
|| This utility reads requests from stdin, sends them to the SMAPI server
|| via IUCV and writes the response to stdout.  It's intended for use by
|| the smaclient shell command.
||
|| Usage:
||
||   smiucv [user] [name] <request >response
||
||   User and name are optional and will default to VSMREQIU and DMSRSRQU.
||
|| Written by Leland Lucius
||=======================================================================
*/

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netiucv/iucv.h>
#include <sys/socket.h>

/*
|| Default remote IUCV user and name
*/
#define IUCV_USER "VSMREQIU"
#define IUCV_NAME "DMSRSRQU"

/*
|| Read data from the SMAPI server and write it to stdout
*/
int
readwrite( int fd, void *ptr, int len )
{
    unsigned char *buffer = (unsigned char *) ptr;
    struct timeval timeout;
    fd_set readfds;
    int i;
    int rc;

    /*
    || Initialize timeout
    */
    timeout.tv_sec = 30;
    timeout.tv_usec = 0;

    /*
    || Large responses will arrive in chunks
    */
    for( i = 0; i < len; i += rc )
    {
        /*
        || Wait for timeout or data
        */
        FD_ZERO( &readfds);
        FD_SET( fd, &readfds );
        if( ( rc = select( fd + 1, &readfds, NULL, NULL, &timeout ) ) < 0 )
        {
            fprintf( stderr, "select() failed: %d - %s\n", errno, strerror( errno ) );
            return 1;
        }
        else if( rc == 0 )
        {
            fprintf( stderr, "Timeout waiting for response from remote\n" );
            return 1;
        }

        /*
        || Read it
        */
        if( ( rc = recv( fd, &buffer[i], len - i, 0 ) ) < 0 )
        {
            fprintf( stderr, "Error reading from socket: %d - %s\n", errno, strerror( errno ) );
            return 1;
        }
        else if( rc == 0 )
        {
            fprintf( stderr, "Connection closed by remote\n" );
            return 1;
        }
    }

    /*
    || Write to stdout
    */
    if( write( fileno( stdout ), buffer, len ) != len )
    {
        fprintf( stderr, "Error writing to stdout: %d - %s\n", errno, strerror( errno ) );
        return 1;
    }

    return 0;
}

int
main( int argc, char *argv[] )
{
    struct sockaddr_iucv siu;
    unsigned char *buffer = NULL;
    char *user;
    char *name;
    int used = 0;
    int bufsize = 0;
    int fd = -1;
    int rc = 0;
    int len;
    int reqid;

    /*
    || Initialize sockaddr
    */
    memset( &siu, 0, sizeof( siu ) );
    siu.siucv_family = AF_IUCV;
    memset( &siu.siucv_nodeid, ' ', 8 );
    memset( &siu.siucv_user_id, ' ', 8 );
    memset( &siu.siucv_name, ' ', 8 );

    /*
    || Set userid...default or first command line argument
    */
    user = IUCV_USER;
    if( argc > 1 && argv[ 1 ] )
    {
        user = argv[ 1 ];
    }
    len = strlen( user );
    memcpy( &siu.siucv_user_id, user, ( len > 8 ? 8 : len ) );

    /*
    || Set name...default or second command line argument
    */
    name = IUCV_NAME;
    if( argc > 2 && argv[ 2 ] )
    {
        name = argv[ 2 ];
    }
    len = strlen( name );
    memcpy( &siu.siucv_name, name, ( len > 8 ? 8 : len ) );

    /*
    || Allocate an IUCV socket
    */
    fd = socket( AF_IUCV, SOCK_STREAM, IPPROTO_IP );
    if( fd == -1 )
    {
        fprintf( stderr, "Unable to create socket: %d - %s", errno, strerror( errno ) );
        rc = 1;
        goto die;
    }

    /*
    || Bind it
    */
    rc = bind( fd, (struct sockaddr *) &siu, sizeof( siu ) );
    if( rc < 0 )
    {
        fprintf( stderr, "Unable to bind: %d - %s", errno, strerror( errno ) );
        rc = 1;
        goto die;
    }
                                                     
    /*
    || Connect to partner
    */
    rc = connect( fd, (struct sockaddr *) &siu, sizeof( siu ) );
    if( rc == -1 )
    {
        fprintf( stderr, "Unable to connect: %d - %s", errno, strerror( errno ) );
        rc = 1;
        goto die;
    }

    /*
    || Read request into buffer
    */
    do
    {
        if( used == bufsize )
        {
            bufsize += 8192;
            buffer = realloc( buffer, bufsize );
            if( buffer == NULL )
            {
                fprintf( stderr, "Unable to alloc buffer: %d - %s\n", errno, strerror( errno ) );
                rc = 1;
                goto die;
            }
        }
    } while( read( fileno( stdin ), &buffer[ used++ ], 1 ) == 1 );

    /*
    || Send it to the server
    */
    if( write( fd, buffer, --used ) != used )
    {
        fprintf( stderr, "Error writing to socket: %d - %s\n", errno, strerror( errno ) );
        rc = 1;
        goto die;
    }

    /*
    || Get the first request ID
    */
    if( ( rc = readwrite( fd, &reqid, sizeof( reqid ) ) ) != 0 )
    {
        goto die;
    }

    /*
    || Get the response length
    */
    if( ( rc = readwrite( fd, &len, sizeof( len ) ) ) != 0 )
    {
        goto die;
    }

    /*
    || Free original buffer and allocate a new one
    */
    free( buffer );
    buffer = malloc( len );
    if( buffer == NULL )
    {
        fprintf( stderr, "Unable to alloc buffer: %d - %s\n", errno, strerror( errno ) );
        rc = 1;
        goto die;
    }

    /*
    || Get the response
    */
    if( ( rc = readwrite( fd, buffer, len ) ) != 0 )
    {
        goto die;
    }

die:

    /*
    || Free the buffer
    */
    if( buffer )
    {
        free( buffer );
    }

    /*
    || Kill the socket
    */
    if( fd != -1 )
    {
        shutdown( fd, SHUT_RDWR );
        close( fd );    
    }

    return rc;
}