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