Initial revision
This commit is contained in:
284
src/libCom/cmdSubr.c
Normal file
284
src/libCom/cmdSubr.c
Normal file
@@ -0,0 +1,284 @@
|
||||
/* $Id$
|
||||
* Author: Roger A. Cole
|
||||
* Date: 10-24-90
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 10-24-90 rac initial version
|
||||
* .01 06-18-91 rac installed in SCCS
|
||||
*
|
||||
* make options
|
||||
* -DvxWorks makes a version for VxWorks
|
||||
* -DNDEBUG don't compile assert() checking
|
||||
* -DDEBUG compile various debug code, including checks on
|
||||
* malloc'd memory
|
||||
*/
|
||||
/*+/mod***********************************************************************
|
||||
* TITLE cmdSubr - routines for implementing keyboard command processing
|
||||
*
|
||||
* DESCRIPTION
|
||||
* intended for use with either UNIX lwp library or with VxWorks
|
||||
*
|
||||
* void cmdCloseContext( ppCxCmd )
|
||||
* long cmdBgCheck( pCxCmd )
|
||||
* void cmdRead( ppCxCmd, pStopFlag )
|
||||
* void cmdSource( ppCxCmd )
|
||||
*
|
||||
* BUGS
|
||||
* o if changes in the command context (e.g., re-directing output) are
|
||||
* made at other than root context level, such changes aren't preserved
|
||||
* when closing out the level and moving to the previous level.
|
||||
*
|
||||
*-***************************************************************************/
|
||||
#include <genDefs.h>
|
||||
#include <genTasks.h>
|
||||
#include <cmdDefs.h>
|
||||
#include <cadef.h>
|
||||
|
||||
#ifdef vxWorks
|
||||
/*----------------------------------------------------------------------------
|
||||
* includes and defines for VxWorks compile
|
||||
*---------------------------------------------------------------------------*/
|
||||
# include <vxWorks.h>
|
||||
# include <stdioLib.h>
|
||||
# include <ctype.h>
|
||||
#else
|
||||
/*----------------------------------------------------------------------------
|
||||
* includes and defines for Sun compile
|
||||
*---------------------------------------------------------------------------*/
|
||||
# include <stdio.h>
|
||||
# include <ctype.h>
|
||||
# include <sys/types.h> /* for 'select' operations */
|
||||
# include <sys/time.h> /* for 'select' operations */
|
||||
#endif
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME cmdBgCheck - validate a ``bg'' command
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Check to see if a bg command can be honored. This depends on
|
||||
* whether the command was in a source'd file (can't have bg there),
|
||||
* and on whether running under VxWorks (bg is OK) or UNIX (not OK).
|
||||
*
|
||||
* If the command shouldn't be honored, this routine prints a message.
|
||||
*
|
||||
* RETURNS
|
||||
* OK, or
|
||||
* ERROR if the bg command should not be honored
|
||||
*
|
||||
*-*/
|
||||
long
|
||||
cmdBgCheck(pCxCmd)
|
||||
CX_CMD *pCxCmd; /* IO pointer to command context */
|
||||
{
|
||||
HELP_TOPIC *pBgTopic;
|
||||
|
||||
if (pCxCmd != pCxCmd->pCxCmdRoot) {
|
||||
(void)printf("can't use bg command in source file\n");
|
||||
return ERROR;
|
||||
}
|
||||
#ifdef vxWorks
|
||||
return OK;
|
||||
#else
|
||||
pBgTopic = helpTopicFind(&pCxCmd->helpList, "bg");
|
||||
if (pBgTopic != NULL)
|
||||
helpTopicPrint(stdout, pBgTopic);
|
||||
return ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME cmdRead - read the next input line
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Prints a prompt, waits for input to be available, and then reads
|
||||
* the input line into the buffer in the command context.
|
||||
*
|
||||
* If input is from a source'd file, no prompt is printed, and the
|
||||
* input line is printed. At EOF on the file, the "source level"
|
||||
* in the command context is closed, changing to the previous
|
||||
* source level; the line buffer will contain a zero length line.
|
||||
*
|
||||
* RETURNS
|
||||
* void
|
||||
*
|
||||
* BUGS
|
||||
* o under VxWorks, with stdout redirected to a socket, a prompt which
|
||||
* doesn't end with '\n' doesn't get sent
|
||||
*
|
||||
* SEE ALSO
|
||||
* cmdSource()
|
||||
*
|
||||
*-*/
|
||||
void
|
||||
cmdRead(ppCxCmd, pStopFlag)
|
||||
CX_CMD **ppCxCmd; /* IO ptr to pointer to command context */
|
||||
int *pStopFlag; /* I pointer to flag; 1 says to "stop" */
|
||||
{
|
||||
#ifndef vxWorks
|
||||
fd_set fdSet; /* set of fd's to watch with select */
|
||||
int fdSetWidth; /* width of select bit mask */
|
||||
struct timeval fdSetTimeout;/* timeout interval for select */
|
||||
#endif
|
||||
CX_CMD *pCxCmd; /* pointer to present command context */
|
||||
|
||||
pCxCmd = *ppCxCmd;
|
||||
/*-----------------------------------------------------------------------------
|
||||
* handle keyboard input as a special case. Only for keyboard input is a
|
||||
* prompt printed. Only for keyboard input is there protection against blocking
|
||||
*----------------------------------------------------------------------------*/
|
||||
if (pCxCmd->inputName == NULL) {
|
||||
if (pCxCmd->prompt != NULL) {
|
||||
(void)printf("%s", pCxCmd->prompt);
|
||||
(void)fflush(stdout);
|
||||
}
|
||||
|
||||
#ifndef vxWorks
|
||||
/*----------------------------------------------------------------------------
|
||||
* under SunOS, with lightweight processes, just doing a simple
|
||||
* gets() call would block the pod. Instead, under SunOS, do a
|
||||
* select() to check for input available.
|
||||
*---------------------------------------------------------------------------*/
|
||||
fdSetWidth = getdtablesize();
|
||||
while (1) {
|
||||
if (*pStopFlag != 0)
|
||||
break;
|
||||
fdSetTimeout.tv_sec = 0;
|
||||
fdSetTimeout.tv_usec = 0;
|
||||
FD_ZERO(&fdSet);
|
||||
FD_SET(fileno(stdin), &fdSet);
|
||||
|
||||
if (select(fdSetWidth, &fdSet, NULL, NULL, &fdSetTimeout) != 0)
|
||||
break; /* input's ready !!! */
|
||||
taskSleep(SELF, 1, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (*pStopFlag != 0)
|
||||
pCxCmd->line[0] = '\0';
|
||||
else {
|
||||
if (fgets(pCxCmd->line, 80, pCxCmd->input) == NULL) {
|
||||
if (pCxCmd->inputName != NULL) {
|
||||
(void)printf("EOF on source'd file: %s\n", pCxCmd->inputName);
|
||||
}
|
||||
else {
|
||||
(void)printf("^D\n");
|
||||
pCxCmd->inputEOF = 1;
|
||||
}
|
||||
clearerr(pCxCmd->input);
|
||||
cmdCloseContext(ppCxCmd);
|
||||
pCxCmd = *ppCxCmd;
|
||||
}
|
||||
else if (pCxCmd->inputName != NULL)
|
||||
(void)printf("%s", pCxCmd->line);
|
||||
}
|
||||
|
||||
pCxCmd->pLine = pCxCmd->line;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME cmdCloseContext - closes a command context
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Closes a command context. The action depends on source of input:
|
||||
*
|
||||
* keyboard (or socket):
|
||||
* o store "quit\n" in the line buffer
|
||||
*
|
||||
* source'd file:
|
||||
* o close out this "source level"
|
||||
* o move to the previous "source level"
|
||||
* o store '\0' in the line buffer
|
||||
*
|
||||
* RETURNS
|
||||
* void
|
||||
*
|
||||
* BUGS
|
||||
* o text
|
||||
*
|
||||
*-*/
|
||||
void
|
||||
cmdCloseContext(ppCxCmd)
|
||||
CX_CMD **ppCxCmd; /* IO ptr to pointer to command context */
|
||||
{
|
||||
CX_CMD *pCxCmd; /* temp pointer */
|
||||
|
||||
assert(ppCxCmd != NULL);
|
||||
|
||||
if ((*ppCxCmd)->inputName == NULL)
|
||||
strcpy((*ppCxCmd)->line, "quit\n");
|
||||
else {
|
||||
(void)fclose((*ppCxCmd)->input);
|
||||
assert((*ppCxCmd)->pPrev != NULL);
|
||||
pCxCmd = (*ppCxCmd)->pPrev;
|
||||
GenFree((char *)(*ppCxCmd));
|
||||
*ppCxCmd = pCxCmd;
|
||||
(*ppCxCmd)->line[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME cmdSource - process a ``source'' command
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Processes a "source fileName" command. A new command context is
|
||||
* built and set up for reading from the named file. If an error
|
||||
* is detected, the present command context is preserved.
|
||||
*
|
||||
* RETURNS
|
||||
* void
|
||||
*
|
||||
*-*/
|
||||
void
|
||||
cmdSource(ppCxCmd)
|
||||
CX_CMD **ppCxCmd; /* IO ptr to pointer to command context. The
|
||||
pCommand item is assumed to point to the
|
||||
source command. This routine scans for
|
||||
the file name. */
|
||||
{
|
||||
CX_CMD *pCxCmdNew; /* new command context structure */
|
||||
CX_CMD *pCxCmd; /* present command context structure */
|
||||
|
||||
pCxCmd = *ppCxCmd;
|
||||
pCxCmd->fldLen =
|
||||
nextNonSpaceField(&pCxCmd->pLine, &pCxCmd->pField, &pCxCmd->delim);
|
||||
if (pCxCmd->fldLen <= 1) {
|
||||
(void)printf("you must specify a file name\n");
|
||||
return;
|
||||
}
|
||||
if ((pCxCmdNew = (CX_CMD *)GenMalloc(sizeof(CX_CMD))) == NULL) {
|
||||
(void)printf("couldn't malloc command structure\n");
|
||||
return;
|
||||
}
|
||||
*pCxCmdNew = *pCxCmd; /* inherit useful info from present context */
|
||||
if ((pCxCmdNew->input = fopen(pCxCmd->pField, "r")) == NULL) {
|
||||
(void)printf("couldn't open file\n");
|
||||
GenFree((char *)pCxCmdNew);
|
||||
return;
|
||||
}
|
||||
pCxCmdNew->pPrev = pCxCmd;
|
||||
pCxCmdNew->inputName = pCxCmd->pField;
|
||||
*ppCxCmd = pCxCmdNew;
|
||||
}
|
||||
515
src/libCom/ezsSockSubr.c
Normal file
515
src/libCom/ezsSockSubr.c
Normal file
@@ -0,0 +1,515 @@
|
||||
/* $Id$
|
||||
* Author: Roger A. Cole
|
||||
* Date: 11-23-90
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 11-23-90 rac initial version
|
||||
* .01 06-18-91 rac installed in SCCS
|
||||
*
|
||||
* make options
|
||||
* -DvxWorks makes a version for VxWorks
|
||||
* -DNDEBUG don't compile assert() checking
|
||||
* -DDEBUG compile various debug code, including checks on
|
||||
* malloc'd memory
|
||||
*/
|
||||
/*+/mod***********************************************************************
|
||||
* TITLE ezsSockSubr.c - easy-to-use socket routines
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This set of routines supports using Internet sockets for transferring
|
||||
* text, with a bias toward use by server/client programs.
|
||||
*
|
||||
* All of these routines use the sockets as TCP/IP sockets, with the
|
||||
* sockets specified as SOCK_STREAM.
|
||||
*
|
||||
* QUICK REFERENCE
|
||||
* #include <ezsSockSubr.h>
|
||||
* int ezsCheckFdRead( fd )
|
||||
* int ezsCheckFpRead( fp )
|
||||
* int ezsConnectToServer( >pServerSock, portNum, hostName )
|
||||
* int ezsCreateListenSocket( >pListenSock, portNum )
|
||||
* int ezsFopenToFd( pFp, pFd )
|
||||
* int ezsFreopenToFd( fp, pFd, >pOldFd )
|
||||
* int ezsListenExclusiveUse( pClientSock, pListenSock, pInUseFlag,
|
||||
* >clientName, greetingMsg )
|
||||
* void ezsSleep( seconds, usec )
|
||||
*
|
||||
* BUGS
|
||||
* o doesn't provide a way for client to distinguish between server output
|
||||
* to stdout and stderr, since if server redirects those streams to the
|
||||
* same socket, their individual identity is lost
|
||||
* o needs examples
|
||||
*-***************************************************************************/
|
||||
|
||||
#include <genDefs.h>
|
||||
#include <ezsSockSubr.h>
|
||||
#ifdef vxWorks
|
||||
# include <vxWorks.h>
|
||||
# include <stdioLib.h>
|
||||
# include <ioLib.h>
|
||||
# include <taskLib.h>
|
||||
# include <types.h>
|
||||
# include <utime.h>
|
||||
# include <socket.h>
|
||||
# include <inetLib.h>
|
||||
# include <in.h>
|
||||
# include <ctype.h>
|
||||
#else
|
||||
# include <stdio.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/time.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <netdb.h>
|
||||
# include <ctype.h>
|
||||
#endif
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME ezsCheckFpRead - check fp to see if read is possible
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Checks the specified stream to see if a read operation is possible.
|
||||
*
|
||||
* ezsCheckFdRead(fd) performs a similar function for fd's.
|
||||
*
|
||||
* RETURNS
|
||||
* >0 if a read can be done
|
||||
* 0 if a read can't presently be done
|
||||
*
|
||||
* BUGS
|
||||
* o due to restrictions in VxWorks 4.0.2, cannot be used for stdin,
|
||||
* stdout, or stderr
|
||||
*
|
||||
*-*/
|
||||
int
|
||||
ezsCheckFpRead(fp)
|
||||
FILE *fp; /* I pointer to FILE to check for "input available" */
|
||||
{
|
||||
#ifdef vxWorks
|
||||
if (fp == stdin) assertAlways(0);
|
||||
else if (fp == stdout) assertAlways(0);
|
||||
else if (fp == stderr) assertAlways(0);
|
||||
#endif
|
||||
|
||||
return(ezsCheckFdRead(fileno(fp)));
|
||||
}
|
||||
ezsCheckFdRead(fd)
|
||||
int fd;
|
||||
{
|
||||
fd_set readbits, other;
|
||||
struct timeval timer;
|
||||
int ret;
|
||||
|
||||
timer.tv_sec = 0;
|
||||
timer.tv_usec = 0;
|
||||
FD_ZERO(&readbits);
|
||||
FD_ZERO(&other);
|
||||
FD_SET(fd, &readbits);
|
||||
|
||||
ret = select(fd+1, &readbits, &other, &other, &timer);
|
||||
#ifdef vxWorks
|
||||
return ret;
|
||||
#else
|
||||
if (FD_ISSET(fd, &readbits))
|
||||
return 1;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME ezsConnectToServer - attempt to connect via socket to server
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* RETURNS
|
||||
* 0, or
|
||||
* -1 if an error occurs, or
|
||||
* -2 if the host name can't be found or the server rejects the
|
||||
* connection. The message buffer will contain a relevant message.
|
||||
*
|
||||
* BUGS
|
||||
* o under VxWorks 4.0.2, if the server is on the same machine as the
|
||||
* client, then the connect will fail unless the machine's name is
|
||||
* in the host table
|
||||
*
|
||||
* SEE ALSO
|
||||
*
|
||||
* EXAMPLE
|
||||
*
|
||||
*-*/
|
||||
int
|
||||
ezsConnectToServer(pServerSock, portNum, hostName, message)
|
||||
int *pServerSock; /* O ptr to socket connected to server */
|
||||
int portNum; /* I port number of server */
|
||||
char *hostName; /* I name (or Internet address) of host on which
|
||||
the server runs */
|
||||
char *message; /* O message from server (dimension of 80 assumed) */
|
||||
{
|
||||
struct sockaddr_in server;
|
||||
struct hostent *hp;
|
||||
struct hostent *gethostbyname();
|
||||
int i;
|
||||
|
||||
assert(pServerSock != NULL);
|
||||
assert(portNum > 0);
|
||||
assert(hostName != NULL);
|
||||
assert(message != NULL);
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* set up to create the socket and connect it to the server
|
||||
*----------------------------------------------------------------------------*/
|
||||
bzero(&server, sizeof(server));
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_port = htons(portNum);
|
||||
|
||||
if (isdigit(hostName[0]))
|
||||
server.sin_addr.s_addr = inet_addr(hostName);
|
||||
else {
|
||||
#ifdef vxWorks
|
||||
if ((server.sin_addr.s_addr = hostGetByName(hostName)) == ERROR) {
|
||||
sprintf(message, "host not in VxWorks host table: %s", hostName);
|
||||
return -2;
|
||||
}
|
||||
#else
|
||||
if ((hp = gethostbyname(hostName)) == NULL) {
|
||||
sprintf(message, "host unknown: %s", hostName);
|
||||
return -2;
|
||||
}
|
||||
bcopy(hp->h_addr, &server.sin_addr, hp->h_length);
|
||||
#endif
|
||||
}
|
||||
|
||||
*pServerSock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (*pServerSock < 0)
|
||||
return -1;
|
||||
if (connect(*pServerSock, &server, sizeof(server)) < 0) {
|
||||
close(*pServerSock);
|
||||
*pServerSock = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* now, with connection completed to server, wait for the message from
|
||||
* server--the message will either identify the server, or else indicate
|
||||
* that the connection is rejected.
|
||||
*----------------------------------------------------------------------------*/
|
||||
if ((i=read(*pServerSock, message, 79)) <= 0) {
|
||||
close(*pServerSock);
|
||||
*pServerSock = -1;
|
||||
sprintf(message, "connection rejected");
|
||||
return -2;
|
||||
}
|
||||
message[i] = '\0';
|
||||
if (strncmp(message, "***", 3) == 0) {
|
||||
close(*pServerSock);
|
||||
*pServerSock = -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME ezsCreateListenSocket - create socket to listen for connections
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Create a socket to be used by a server to listen for connections
|
||||
* by potential clients. The socket is bound to the caller-specified
|
||||
* port number.
|
||||
*
|
||||
* The port number specified, in conjunction with the name of the
|
||||
* host, constitutes a network "address" at which the server can be
|
||||
* reached.
|
||||
*
|
||||
* Ideally, the port number and service name would be registered with
|
||||
* the system manager, who would place the information in the
|
||||
* /etc/services file. If this is done, then getservbyname(3N) can be
|
||||
* used by a potential client to determine the proper port number to
|
||||
* use. In actual practice, potential clients would "know" what port
|
||||
* number to use by means of an include file provided by the service
|
||||
* for compiling clients.
|
||||
*
|
||||
* RETURNS
|
||||
* 0, or
|
||||
* -1 if an error occurs (errno will have error code)
|
||||
*
|
||||
* SEE ALSO
|
||||
*
|
||||
* EXAMPLE
|
||||
*
|
||||
*-*/
|
||||
int
|
||||
ezsCreateListenSocket(pListenSock, portNum)
|
||||
int *pListenSock; /* O ptr to socket for listening for connects */
|
||||
int portNum; /* I number of service's port */
|
||||
{
|
||||
struct sockaddr_in server; /* temporary Internet socket structure */
|
||||
|
||||
assert(pListenSock != NULL);
|
||||
assert(portNum > 0);
|
||||
|
||||
if ((*pListenSock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
return -1;
|
||||
|
||||
bzero(&server, sizeof(server));
|
||||
server.sin_family = AF_INET; /* internet */
|
||||
server.sin_addr.s_addr = INADDR_ANY; /* anybody can connect */
|
||||
server.sin_port = htons(portNum); /* server's port */
|
||||
if (bind(*pListenSock, (struct sockaddr *)&server, sizeof(server)) < 0) {
|
||||
close(*pListenSock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(*pListenSock, 1) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME ezsFopenToFd - open a specified stream to an fd
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Open a stream to an fd. Typically, this is used to open a stream
|
||||
* to a socket.
|
||||
*
|
||||
* This routine should not be used for stdin, stdout, or stderr. For
|
||||
* these streams, ezsFreopenToFd() should be used.
|
||||
*
|
||||
* RETURNS
|
||||
* 0, or
|
||||
* -1 if errors are encountered (errno has error code)
|
||||
*
|
||||
* BUGS
|
||||
* o the stream is always opened in "r+" (update) mode
|
||||
*
|
||||
* SEE ALSO
|
||||
* ezsFreopenToFd(), ezsFrestoreToOldFd()
|
||||
*
|
||||
*-*/
|
||||
int
|
||||
ezsFopenToFd(pFp, pFd)
|
||||
FILE **pFp; /* O pointer to pointer to new FILE */
|
||||
int *pFd; /* I pointer tofd to be used by file pointer */
|
||||
{
|
||||
assert(pFp != NULL);
|
||||
assert(pFd != NULL);
|
||||
|
||||
if ((*pFp=fdopen(*pFd, "r+")) == NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME ezsFreopenToFd - reopen a specified stream to an fd
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Reopens a stream (assumed to presently be open) to an fd. Typically,
|
||||
* this is used in a server program to redirect stdin, stdout, or stderr
|
||||
* to use a socket.
|
||||
*
|
||||
* Under VxWorks, this is a pseudo re-open, which applies only to
|
||||
* the current task. If a "program" consists of several tasks, each
|
||||
* task must re-direct its I/O. Typically, one task will supply a
|
||||
* non-NULL pOldFd argument, and other tasks will use NULL.
|
||||
*
|
||||
* RETURNS
|
||||
* 0, or
|
||||
* -1 if errors are encountered (errno has error code)
|
||||
* -2 if illegal stream is used
|
||||
*
|
||||
* BUGS
|
||||
* o the only streams which are handled are stdin, stdout, and stderr
|
||||
* o stdout and stderr are line buffered under VxWorks, and output won't
|
||||
* get sent (even if fflush() is used, as of 4.0.2) until '\n' is sent.
|
||||
*
|
||||
* SEE ALSO
|
||||
* ezsFopenToFd(), ezsFrestoreToOldFd()
|
||||
*
|
||||
* EXAMPLE
|
||||
*
|
||||
*-*/
|
||||
int
|
||||
ezsFreopenToFd(fp, pFd, pOldFd)
|
||||
FILE *fp; /* IO pointer to FILE, such as stdin or stdout */
|
||||
int *pFd; /* I pointer to fd to be used by file pointer */
|
||||
int *pOldFd; /* O NULL, or pointer to place to store fd
|
||||
previously used by file pointer */
|
||||
{
|
||||
int fdNumber;
|
||||
|
||||
assert(fp != NULL);
|
||||
assert(pFd != NULL);
|
||||
|
||||
if (fp == stdin) fdNumber = 0;
|
||||
else if (fp == stdout) fdNumber = 1;
|
||||
else if (fp == stderr) fdNumber = 2;
|
||||
else return -2;
|
||||
|
||||
#ifdef vxWorks
|
||||
if (pOldFd != NULL)
|
||||
*pOldFd = ioTaskStdGet(0, fdNumber);
|
||||
ioTaskStdSet(0, fdNumber, *pFd);
|
||||
#else
|
||||
if (pOldFd != NULL) {
|
||||
if ((*pOldFd = dup(fileno(fp))) < 0)
|
||||
return -1;
|
||||
}
|
||||
if (dup2(*pFd, fileno(fp)) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME ezsListenExclusiveUse - listen for client connect; allow only 1
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Checks to see if a client connect request is queued. If so, the
|
||||
* action depends on whether a client is presently connected:
|
||||
*
|
||||
* o if no client is presently connected, then the connection is made:
|
||||
* - a socket is created to converse with the client,
|
||||
* - a greeting message is sent to the new client,
|
||||
* - the inUseFlag is set to 1, and
|
||||
* - the new socket is returned to the caller
|
||||
* o if a client is presently connected, then the connection is
|
||||
* refused, with a rejection message sent to the hopeful new client.
|
||||
* The rejection message has the form "*** server inuse by host",
|
||||
* where "host" is the name of the host from which the present client
|
||||
* is connected.
|
||||
*
|
||||
* This routine simply polls the listen socket. It must be called
|
||||
* periodically. Only one queued request is processed on each call.
|
||||
*
|
||||
* RETURNS
|
||||
* -1 if an error occurs
|
||||
*
|
||||
* BUGS
|
||||
* o text
|
||||
*
|
||||
* SEE ALSO
|
||||
*
|
||||
* EXAMPLE
|
||||
*
|
||||
*-*/
|
||||
int
|
||||
ezsListenExclusiveUse(pClientSock, pListenSock, pInUseFlag, name, greetMsg)
|
||||
int *pClientSock; /* IO ptr to socket (to be) connected to client */
|
||||
int *pListenSock; /* I socket for listening for connects */
|
||||
int *pInUseFlag; /* I ptr to flag; 1 indicates server already engaged */
|
||||
char *name; /* O ptr to buf[30] where client name will go */
|
||||
char *greetMsg; /* I greeting message to sent to new client */
|
||||
{
|
||||
int i;
|
||||
static char inUseText[80];
|
||||
int connSock; /* socket connected to potential client */
|
||||
struct sockaddr_in clientAddr;/* address of client socket */
|
||||
struct hostent *clientHost;
|
||||
char *clientHostAddr;
|
||||
char clientHostAddrText[30];
|
||||
char clientBuf[80];
|
||||
|
||||
if (ezsCheckFdRead(*pListenSock)) {
|
||||
i = sizeof(clientAddr);
|
||||
connSock = accept(*pListenSock, (struct sockaddr *)&clientAddr, &i);
|
||||
if (connSock < 0)
|
||||
return -1;
|
||||
if (*pInUseFlag) {
|
||||
/*-----------------------------------------------------------------------------
|
||||
* server is already engaged; send rejection message to hopeful client
|
||||
*----------------------------------------------------------------------------*/
|
||||
write(connSock, inUseText, strlen(inUseText));
|
||||
close(connSock);
|
||||
}
|
||||
else {
|
||||
/*-----------------------------------------------------------------------------
|
||||
* server available; consummate connection:
|
||||
* o set inUseFlag to 1
|
||||
* o build a rejection message to send if other clients attempt connect
|
||||
* o send greeting message to new client
|
||||
*----------------------------------------------------------------------------*/
|
||||
#ifndef vxWorks
|
||||
clientHost =
|
||||
gethostbyaddr((char *)&clientAddr.sin_addr, i, AF_INET);
|
||||
if (clientHost != NULL)
|
||||
sprintf(clientHostAddrText, "%s", clientHost->h_name);
|
||||
else {
|
||||
#endif
|
||||
clientHostAddr = inet_ntoa(clientAddr.sin_addr);
|
||||
sprintf(clientHostAddrText, "%s", clientHostAddr);
|
||||
#ifndef vxWorks
|
||||
}
|
||||
#endif
|
||||
(void)strcpy(name, clientHostAddrText);
|
||||
sprintf(inUseText, "*** server in use by %s", clientHostAddrText);
|
||||
write(connSock, greetMsg, strlen(greetMsg));
|
||||
*pClientSock = connSock;
|
||||
*pInUseFlag = 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME ezsSleep - sleep
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The current task sleeps for the specified time.
|
||||
*
|
||||
* This routine should not be used by programs implemented with the
|
||||
* UNIX lwp (light-weight process) library--taskSleep() in genTaskSubr.c
|
||||
* should be used, instead.
|
||||
*
|
||||
* RETURNS
|
||||
* void
|
||||
*
|
||||
* SEE ALSO
|
||||
* taskSleep()
|
||||
*
|
||||
*-*/
|
||||
void
|
||||
ezsSleep(seconds, usec)
|
||||
int seconds; /* I number of seconds (added to usec) to sleep */
|
||||
int usec; /* I number of micro-sec (added to sec) to sleep */
|
||||
{
|
||||
#ifndef vxWorks
|
||||
usleep((unsigned)(seconds*1000000 + usec));
|
||||
#else
|
||||
int ticks;
|
||||
static int ticksPerSec=0;
|
||||
static int usecPerTick;
|
||||
|
||||
if (ticksPerSec == 0) {
|
||||
ticksPerSec = sysClkRateGet();
|
||||
usecPerTick = 1000000 / ticksPerSec;
|
||||
}
|
||||
|
||||
ticks = seconds*ticksPerSec + usec/usecPerTick + 1;
|
||||
taskDelay(ticks);
|
||||
#endif
|
||||
}
|
||||
333
src/libCom/genSubr.c
Normal file
333
src/libCom/genSubr.c
Normal file
@@ -0,0 +1,333 @@
|
||||
/* $Id$
|
||||
* Author: Roger A. Cole
|
||||
* Date: 03-29-90
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 03-29-90 rac initial version
|
||||
* .01 06-18-91 rac installed in SCCS
|
||||
*
|
||||
* make options
|
||||
* -DvxWorks makes a version for VxWorks
|
||||
* -DNDEBUG don't compile assert() checking
|
||||
* -DDEBUG compile various debug code, including checks on
|
||||
* malloc'd memory
|
||||
*/
|
||||
/*+/mod***********************************************************************
|
||||
* TITLE genSubr.c - some general use routines
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This file contains some routines which are generally useful for
|
||||
* EPICS programs. Some routines are for SunOS vs. VxWorks
|
||||
* compatibility.
|
||||
*
|
||||
* SEE ALSO
|
||||
* genDefs.h
|
||||
*-***************************************************************************/
|
||||
#include <genDefs.h>
|
||||
|
||||
#ifdef vxWorks
|
||||
# include <vxWorks.h>
|
||||
# include <stdioLib.h>
|
||||
# include <taskLib.h>
|
||||
# include <sigLib.h>
|
||||
#else
|
||||
# include <stdio.h>
|
||||
# include <signal.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*+/macro*********************************************************************
|
||||
* NAME assert - check assertion
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Checks to see if an expression is true. If the expression is false,
|
||||
* an error message is printed and a signal is raised (SIGABRT or, for
|
||||
* VxWorks, SIGUSR1).
|
||||
*
|
||||
* This is actually a macro provided by genDefs.h . If the preprocessor
|
||||
* symbol NDEBUG is defined, then the expression isn't evaluated or
|
||||
* checked.
|
||||
*
|
||||
* USAGE
|
||||
* assert(expression);
|
||||
* assertAlways(expression); (same as assert(), but isn't disabled
|
||||
* by defining NDEBUG)
|
||||
*
|
||||
* RETURNS
|
||||
* void
|
||||
*
|
||||
* NOTES
|
||||
* 1. Since evaluation of the expression is conditional (depending on
|
||||
* whether NDEBUG is defined), it is poor practice to use expressions
|
||||
* which have side effects.
|
||||
* 2. assertAlways(0) is recommended rather than abort().
|
||||
*
|
||||
*-*/
|
||||
/*----------------------------------------------------------------------------
|
||||
* assertFail - handle assertion failure
|
||||
* For SunOS, call abort().
|
||||
* For VxWorks, try to deliver a SIGUSR1 signal. If that's not
|
||||
* possible, generate a bus error.
|
||||
*---------------------------------------------------------------------------*/
|
||||
int
|
||||
assertFail(fileName, lineNum)
|
||||
char *fileName;
|
||||
int lineNum;
|
||||
{
|
||||
(void)fprintf(stderr, "assertFail: in file %s line %d\n",
|
||||
fileName, lineNum);
|
||||
#ifdef vxWorks
|
||||
if (kill(taskIdSelf(), SIGUSR1) == ERROR) {
|
||||
int *j;
|
||||
j = (int *)(-1);
|
||||
j = (int *)(*j);
|
||||
}
|
||||
exit(1);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME genMalloc - malloc() and free() 'pre-processor' with "guards"
|
||||
*
|
||||
* DESCRIPTION
|
||||
* These routines support catching overwriting a block of memory
|
||||
* obtained by malloc(). A 'guard' field is added at the beginning
|
||||
* and end of the block of memory when genMalloc() is called to
|
||||
* allocate the block. The 'guard' field is checked by genFree().
|
||||
*
|
||||
* genMalloc() works the same as malloc(), returning a pointer to
|
||||
* the 'usable' part of the memory block. (I.e., the guard fields are
|
||||
* 'hidden' from the caller.)
|
||||
*
|
||||
* genFree() works the same as free(), except it checks to see if
|
||||
* the guard field has been clobbered.
|
||||
*
|
||||
* A third routine, genBufCheck() allows checking at arbitrary times
|
||||
* (even from dbx) on whether a block has been clobbered.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#if 0 /* a simple demonstration of usage */
|
||||
main()
|
||||
{
|
||||
int *x;
|
||||
int i;
|
||||
|
||||
x = (int *)genMalloc(100);
|
||||
genBufCheck(x);
|
||||
for (i=0; i<26; i++)
|
||||
*(x+i) = i;
|
||||
genFree(x);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
# define CHK_MALLOC_FILL_PATTERN 1
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* malloc a block with the following layout, with the block and guard
|
||||
* fields aligned on longword boundaries
|
||||
*
|
||||
* longword 0 nLong for block, including this longword and the
|
||||
* 'guard' longwords
|
||||
* longword 1 &longword 0
|
||||
* user bytes
|
||||
* longword n &longword 0
|
||||
*---------------------------------------------------------------------------*/
|
||||
char *genMalloc(nBytes)
|
||||
int nBytes;
|
||||
{
|
||||
long *ptrL;
|
||||
int i;
|
||||
unsigned nLong, sizeC;
|
||||
|
||||
nLong = 3 + (nBytes+sizeof(long)-1)/sizeof(long);
|
||||
sizeC = nLong * sizeof(long);
|
||||
ptrL = (long *)malloc(sizeC);
|
||||
if (ptrL != NULL) {
|
||||
for (i=0; i<sizeC; )
|
||||
((char *)ptrL)[i++] = CHK_MALLOC_FILL_PATTERN;
|
||||
*ptrL = nLong;
|
||||
*(ptrL+1) = *(ptrL+nLong-1) = (long)ptrL;
|
||||
return (char *)(ptrL+2);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void genBufCheck(ptr)
|
||||
void *ptr;
|
||||
{
|
||||
long *ptrL;
|
||||
unsigned nLong;
|
||||
|
||||
assert(ptr != NULL);
|
||||
ptrL = (long *)ptr - 2;
|
||||
if (*(ptrL+1) != (long)ptrL) {
|
||||
(void)fprintf(stderr, "genBufCheck: guard at begin clobbered\n");
|
||||
assertAlways(0);
|
||||
}
|
||||
nLong = *ptrL;
|
||||
if (*(ptrL+nLong-1) != (long)ptrL) {
|
||||
(void)fprintf(stderr, "genBufCheck: guard at end clobbered\n");
|
||||
assertAlways(0);
|
||||
}
|
||||
}
|
||||
|
||||
void genFree(ptr)
|
||||
void *ptr;
|
||||
{
|
||||
long *ptrL;
|
||||
|
||||
genBufCheck(ptr);
|
||||
ptrL = (long *)ptr - 2;
|
||||
(void)free((char *)ptrL);
|
||||
return;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME genShellCommand - issue a command to the "sh" shell
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Issues a command to the Bourne shell, "sh". The text which results
|
||||
* from executing the command is returned in the buffer supplied by
|
||||
* the caller.
|
||||
*
|
||||
* RETURNS
|
||||
* void
|
||||
*
|
||||
* NOTES
|
||||
* 1. Any errors which are explicitly detected by this routine result in
|
||||
* an error message in the caller's result buffer.
|
||||
* 2. This routine will result in a SIGCHLD signal, which the caller will
|
||||
* have to handle.
|
||||
* 3. If no output results from executing the command, then resultBuf[0]
|
||||
* will be set to '\0'.
|
||||
*
|
||||
*-*/
|
||||
#ifndef vxWorks
|
||||
void
|
||||
genShellCommand(cmdBuf, resultBuf, resultDim)
|
||||
char *cmdBuf; /* I line to send to shell */
|
||||
char *resultBuf; /* O buffer to hold result of shell command */
|
||||
int resultDim; /* I size of result buffer */
|
||||
{
|
||||
FILE *shellPipe;
|
||||
int i;
|
||||
|
||||
if ((shellPipe = popen(cmdBuf, "r")) == NULL) {
|
||||
strcpy(resultBuf, "couldn't issue shell command\n");
|
||||
return;
|
||||
}
|
||||
i = fread(resultBuf, 1, resultDim-1, shellPipe);
|
||||
resultBuf[i] = '\0';
|
||||
pclose(shellPipe);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME genSigInit - initialize for catching signals
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Set up for catching signals.
|
||||
*
|
||||
* RETURNS
|
||||
* void
|
||||
*
|
||||
* BUGS
|
||||
* o it isn't clear how multiple calls fit in with SunOS lwp library
|
||||
*
|
||||
* NOTES
|
||||
* 1. Under VxWorks, assert() generates SIGUSR1, rather than the
|
||||
* customary UNIX SIGABRT.
|
||||
*
|
||||
* EXAMPLE
|
||||
* #include <setjmp.h>
|
||||
* #include <signal.h> (or <sigLib.h> for VxWorks)
|
||||
*
|
||||
* jmp_buf mySigEnv;
|
||||
*
|
||||
* void myHandler(sigNum)
|
||||
* int sigNum;
|
||||
* {
|
||||
* signal(sigNum, SIG_DFL);
|
||||
* longjmp(mySigEnv, sigNum);
|
||||
* }
|
||||
*
|
||||
* main()
|
||||
* {
|
||||
* int sigNum;
|
||||
*
|
||||
* genSigInit(myHandler);
|
||||
* if ((sigNum = setjmp(mySigEnv)) != 0)
|
||||
* goto sigOccurred;
|
||||
* .
|
||||
* .
|
||||
* exit(0);
|
||||
* sigOccurred:
|
||||
* printf("signal %d detected\n", sigNum);
|
||||
* exit(1);
|
||||
* }
|
||||
*
|
||||
*-*/
|
||||
void
|
||||
genSigInit(handler)
|
||||
void (* handler)(); /* I pointer to signal handler */
|
||||
{
|
||||
(void)signal(SIGTERM, handler); /* SunOS plain kill (not -9) */
|
||||
(void)signal(SIGQUIT, handler); /* SunOS ^\ */
|
||||
(void)signal(SIGINT, handler); /* SunOS ^C */
|
||||
(void)signal(SIGILL, handler); /* illegal instruction */
|
||||
#ifndef vxWorks
|
||||
(void)signal(SIGABRT, handler); /* SunOS assert */
|
||||
#else
|
||||
(void)signal(SIGUSR1, handler); /* VxWorks assert */
|
||||
#endif
|
||||
(void)signal(SIGBUS, handler); /* bus error */
|
||||
(void)signal(SIGSEGV, handler); /* segmentation violation */
|
||||
(void)signal(SIGFPE, handler); /* arithmetic exception */
|
||||
(void)signal(SIGPIPE, handler); /* write to disconnected socket */
|
||||
}
|
||||
|
||||
#ifdef vxWorks
|
||||
/*+/subr**********************************************************************
|
||||
* NAME perror - print message corresponding to errno
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Under VxWorks, provides the capability provided by perror() under
|
||||
* UNIX. (This routine isn't present in genLib except for VxWorks
|
||||
* version.)
|
||||
*
|
||||
*-*/
|
||||
perror(str)
|
||||
char *str; /* I string to print in conjunction with error message */
|
||||
{
|
||||
if (str != NULL)
|
||||
(void)printf("%s: ", str);
|
||||
printErrno(0);
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user