2009-07-28 18:46:53 +04:00
/*
* Copyright ( C ) 2002 - 2003 , 2009 Red Hat , Inc .
*
2010-01-25 21:24:54 +03:00
* License : GPLv2 +
2009-07-28 18:46:53 +04:00
*
* Written by Lon Hohberger < lhh @ redhat . com >
*
2009-08-01 01:09:36 +04:00
* Serial client for fence_virt ( incomplete , but
* a good start )
*
* Based on :
2009-07-28 18:46:53 +04:00
* Ubersimpledumbterminal " ser " version 1.0 .3
*/
# include <stdio.h>
# include <termios.h>
# include <unistd.h>
# include <stdlib.h>
# include <sys/select.h>
# include <fcntl.h>
# include <errno.h>
# include <string.h>
# include <sys/ioctl.h>
# include <fdops.h>
# include <xvm.h>
# include <options.h>
# include <client.h>
2010-01-15 00:41:21 +03:00
# include <sys/time.h>
2010-01-14 07:34:35 +03:00
# include <arpa/inet.h>
# include <tcp.h>
2009-07-28 18:46:53 +04:00
static int
char_to_speed ( const char * speed )
{
if ( ! speed | | ! strlen ( speed ) )
return B9600 ;
if ( ! strcmp ( speed , " 2400 " ) )
return B2400 ;
if ( ! strcmp ( speed , " 9600 " ) )
return B9600 ;
if ( ! strcmp ( speed , " 19200 " ) )
return B19200 ;
if ( ! strcmp ( speed , " 38400 " ) )
return B38400 ;
if ( ! strcmp ( speed , " 57600 " ) )
return B57600 ;
if ( ! strcmp ( speed , " 115200 " ) )
return B115200 ;
return - 1 ;
}
static int
char_to_flags ( const char * param )
{
int db_f = CS8 , par_f = 0 , sb_f = 0 , x ;
if ( ! param | | ! strlen ( param ) )
return ( db_f | par_f | sb_f ) ;
if ( strlen ( param ) < 3 ) {
errno = EINVAL ;
return - 1 ;
}
for ( x = 0 ; x < 3 ; x + + ) {
2009-08-01 00:50:54 +04:00
switch ( param [ x ] ) {
2009-07-28 18:46:53 +04:00
case ' 5 ' :
db_f = CS5 ;
break ;
case ' 6 ' :
db_f = CS6 ;
break ;
case ' 7 ' :
db_f = CS7 ;
break ;
case ' 8 ' :
db_f = CS8 ;
break ;
case ' n ' :
case ' N ' :
par_f = 0 ;
break ;
case ' e ' :
case ' E ' :
par_f = PARENB ;
break ;
case ' o ' :
case ' O ' :
par_f = PARENB | PARODD ;
break ;
case ' 1 ' :
sb_f = 0 ;
break ;
case ' 2 ' :
sb_f = CSTOPB ;
break ;
default :
2009-08-01 00:50:54 +04:00
printf ( " Fail: %c \n " , param [ x ] ) ;
2009-07-28 18:46:53 +04:00
errno = EINVAL ;
return - 1 ;
}
}
return ( db_f | par_f | sb_f ) ;
}
static int
open_port ( char * file , char * cspeed , char * cparam )
{
struct termios ti ;
int fd , speed = B115200 , flags = 0 ;
struct flock lock ;
if ( ( speed = char_to_speed ( cspeed ) ) = = - 1 ) {
errno = EINVAL ;
return - 1 ;
}
if ( ( flags = char_to_flags ( cparam ) ) = = - 1 ) {
errno = EINVAL ;
return - 1 ;
}
if ( ( fd = open ( file , O_RDWR | O_EXCL ) ) = = - 1 ) {
perror ( " open " ) ;
return - 1 ;
}
memset ( & lock , 0 , sizeof ( lock ) ) ;
lock . l_type = F_WRLCK ;
if ( fcntl ( fd , F_SETLK , & lock ) = = - 1 ) {
perror ( " Failed to lock serial port " ) ;
close ( fd ) ;
return - 1 ;
}
memset ( & ti , 0 , sizeof ( ti ) ) ;
ti . c_cflag = ( speed | CLOCAL | CRTSCTS | CREAD | flags ) ;
if ( tcsetattr ( fd , TCSANOW , & ti ) < 0 ) {
perror ( " tcsetattr " ) ;
close ( fd ) ;
return - 1 ;
}
( void ) tcflush ( fd , TCIOFLUSH ) ;
return fd ;
}
static void
hangup ( int fd , int delay )
{
unsigned int bits ;
if ( ioctl ( fd , TIOCMGET , & bits ) ) {
perror ( " ioctl1 " ) ;
return ;
}
bits & = ~ ( TIOCM_DTR | TIOCM_CTS | TIOCM_RTS | TIOCM_DSR | TIOCM_CD ) ;
if ( ioctl ( fd , TIOCMSET , & bits ) ) {
perror ( " ioctl2 " ) ;
return ;
}
usleep ( delay ) ;
bits | = ( TIOCM_DTR | TIOCM_CTS | TIOCM_RTS | TIOCM_DSR | TIOCM_CD ) ;
if ( ioctl ( fd , TIOCMSET , & bits ) ) {
perror ( " ioctl3 " ) ;
return ;
}
}
2010-01-13 10:19:24 +03:00
void do_read_hostlist ( int fd , int timeout ) ;
2010-01-13 16:37:06 +03:00
int
wait_for ( int fd , const char * pattern , size_t size , struct timeval * tout )
{
2010-01-15 00:41:21 +03:00
char * pos = ( char * ) pattern ;
2010-01-13 16:37:06 +03:00
char c ;
int n ;
struct timeval tv ;
size_t remain = size ;
if ( tout ) {
memcpy ( & tv , tout , sizeof ( tv ) ) ;
tout = & tv ;
}
while ( remain ) {
n = _read_retry ( fd , & c , 1 , & tv ) ;
if ( n < 1 )
return - 1 ;
if ( c = = * pos ) {
+ + pos ;
- - remain ;
} else {
2010-01-15 00:41:21 +03:00
pos = ( char * ) pattern ;
2010-01-13 16:37:06 +03:00
remain = size ;
}
}
return 0 ;
}
2009-07-28 18:46:53 +04:00
int
serial_fence_virt ( fence_virt_args_t * args )
{
2010-01-14 07:34:35 +03:00
struct in_addr ina ;
struct in6_addr in6a ;
2009-07-28 18:46:53 +04:00
serial_req_t req ;
int fd , ret ;
2009-08-01 00:50:54 +04:00
char speed [ 32 ] , * flags = NULL ;
2009-07-28 18:46:53 +04:00
struct timeval tv ;
serial_resp_t resp ;
2010-01-14 07:34:35 +03:00
if ( args - > serial . device ) {
strncpy ( speed , args - > serial . speed , sizeof ( speed ) ) ;
2009-08-01 00:50:54 +04:00
2010-01-14 07:34:35 +03:00
//printf("Port: %s Speed: %s\n", args->serial.device, speed);
2009-07-28 18:46:53 +04:00
2010-01-14 07:34:35 +03:00
if ( ( flags = strchr ( speed , ' , ' ) ) ) {
* flags = 0 ;
flags + + ;
}
fd = open_port ( args - > serial . device , speed , flags ) ;
if ( fd = = - 1 ) {
perror ( " open_port " ) ;
return - 1 ;
}
2009-07-28 18:46:53 +04:00
2010-01-14 07:34:35 +03:00
hangup ( fd , 300000 ) ;
} else {
fd = - 1 ;
if ( inet_pton ( PF_INET , args - > serial . address , & ina ) ) {
fd = ipv4_connect ( & ina , args - > net . port , 3 ) ;
} else if ( inet_pton ( PF_INET6 , args - > serial . address , & in6a ) ) {
fd = ipv6_connect ( & in6a , args - > net . port , 3 ) ;
}
if ( fd < 0 ) {
perror ( " vmchannel connect " ) ;
printf ( " Failed to connect to %s:%d \n " , args - > serial . address ,
args - > net . port ) ;
2011-09-20 19:40:39 +04:00
return - 1 ;
2010-01-14 07:34:35 +03:00
}
2009-08-01 00:50:54 +04:00
}
2009-07-28 18:46:53 +04:00
memset ( & req , 0 , sizeof ( req ) ) ;
req . magic = SERIAL_MAGIC ;
req . request = ( uint8_t ) args - > op ;
2010-01-13 18:13:14 +03:00
gettimeofday ( & tv , NULL ) ;
req . seqno = ( int ) tv . tv_usec ;
2010-01-13 10:19:24 +03:00
if ( args - > domain )
strncpy ( ( char * ) req . domain , args - > domain , sizeof ( req . domain ) ) ;
2009-08-01 00:50:54 +04:00
2009-07-28 18:46:53 +04:00
tv . tv_sec = 3 ;
tv . tv_usec = 0 ;
2011-07-06 20:17:42 +04:00
swab_serial_req_t ( & req ) ;
2009-07-28 18:46:53 +04:00
ret = _write_retry ( fd , & req , sizeof ( req ) , & tv ) ;
if ( ret < sizeof ( req ) ) {
2012-06-01 23:22:02 +04:00
if ( ret < 0 ) {
close ( fd ) ;
2009-07-28 18:46:53 +04:00
return ret ;
2012-06-01 23:22:02 +04:00
}
2009-07-28 18:46:53 +04:00
printf ( " Failed to send request \n " ) ;
}
tv . tv_sec = args - > timeout ;
tv . tv_usec = 0 ;
2010-01-13 16:37:06 +03:00
resp . magic = SERIAL_MAGIC ;
2009-08-01 00:50:54 +04:00
do {
2010-01-13 16:37:06 +03:00
if ( wait_for ( fd , ( const char * ) & resp . magic ,
sizeof ( resp . magic ) , & tv ) = = 0 ) {
ret = _read_retry ( fd , & resp . response , sizeof ( resp . response ) , & tv ) ;
2012-05-16 17:15:42 +04:00
} else {
/* The other end died or closed the connection */
2012-06-01 23:22:02 +04:00
close ( fd ) ;
2012-05-16 17:15:42 +04:00
return - 1 ;
2010-01-13 16:37:06 +03:00
}
2011-07-06 20:17:42 +04:00
swab_serial_resp_t ( & resp ) ;
2009-08-01 00:50:54 +04:00
} while ( resp . magic ! = SERIAL_MAGIC & & ( tv . tv_sec | | tv . tv_usec ) ) ;
2009-07-28 18:46:53 +04:00
2012-06-01 23:22:02 +04:00
if ( resp . magic ! = SERIAL_MAGIC ) {
close ( fd ) ;
2009-07-28 18:46:53 +04:00
return - 1 ;
2012-06-01 23:22:02 +04:00
}
2010-01-13 10:19:24 +03:00
ret = resp . response ;
2010-01-13 17:26:32 +03:00
if ( resp . response = = RESP_HOSTLIST ) /* hostlist */ {
2010-01-13 10:19:24 +03:00
/* ok read hostlist */
do_read_hostlist ( fd , args - > timeout ) ;
ret = 0 ;
}
2009-08-01 00:50:54 +04:00
2009-07-28 18:46:53 +04:00
close ( fd ) ;
return ret ;
}