38 static unsigned short ioc_log_port;
39 static long ioc_log_file_limit;
40 static char ioc_log_file_name[512];
41 static char ioc_log_file_command[256];
62 #define IOCLS_ERROR (-1) 65 static void acceptNewClient (
void *pParam);
66 static void readFromClient(
void *pParam);
68 static int getConfig(
void);
70 static void handleLogFileError(
void);
71 static void envFailureNotify(
const ENV_PARAM *pparam);
73 static void writeMessagesToLog (
struct iocLogClient *pclient);
77 static void sighupHandler(
int);
78 static void serviceSighupRequest(
void *pParam);
79 static int getDirectory(
void);
80 static int sighupPipe[2];
92 struct sockaddr_in serverAddr;
101 fprintf(
stderr,
"iocLogServer: EPICS environment underspecified\n");
102 fprintf(
stderr,
"iocLogServer: failed to initialize\n");
107 calloc(1,
sizeof *pserver);
109 fprintf(
stderr,
"iocLogServer: %s\n", strerror(errno));
115 fprintf(
stderr,
"iocLogServer: %s\n", strerror(errno));
127 fprintf(
stderr,
"iocLogServer: sock create err: %s\n", sockErrBuf);
135 memset((
void *)&serverAddr, 0,
sizeof serverAddr);
136 serverAddr.sin_family = AF_INET;
137 serverAddr.sin_port = htons(ioc_log_port);
140 status = bind ( pserver->
sock,
141 (
struct sockaddr *)&serverAddr,
142 sizeof (serverAddr) );
146 fprintf(
stderr,
"iocLogServer: bind err: %s\n", sockErrBuf );
148 "iocLogServer: a server is already installed on port %u?\n",
149 (
unsigned)ioc_log_port);
154 status = listen(pserver->
sock, 10);
158 fprintf(
stderr,
"iocLogServer: listen err %s\n", sockErrBuf);
174 fprintf(
stderr,
"iocLogServer: ioctl FIONBIO err %s\n", sockErrBuf);
179 status = setupSIGHUP(pserver);
185 status = openLogFile(pserver);
188 "File access problems to `%s' because `%s'\n",
202 "iocLogServer: failed to add read callback\n");
220 static const time_t invalidTime = (time_t) -1;
221 time_t theLatestTime = invalidTime;
222 long latestFilePos = -1;
241 convertStatus = fscanf (
242 pserver->
poutfile,
" %*s %*s %15s %d %d:%d:%d %d %*[^\n] ",
243 month, &theDate.tm_mday, &theDate.tm_hour,
244 &theDate.tm_min, &theDate.tm_sec, &theDate.tm_year);
245 if (convertStatus==6) {
246 static const char *pMonths[] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
247 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"};
248 static const unsigned nMonths =
sizeof(pMonths)/
sizeof(pMonths[0]);
249 time_t lineTime = (time_t) -1;
252 for (iMonth=0; iMonth<nMonths; iMonth++) {
253 if ( strcmp (pMonths[iMonth], month)==0 ) {
254 theDate.tm_mon = iMonth;
258 if (iMonth<nMonths) {
259 static const int tm_epoch_year = 1900;
260 if (theDate.tm_year>tm_epoch_year) {
261 theDate.tm_year -= tm_epoch_year;
262 theDate.tm_isdst = -1;
263 lineTime = mktime (&theDate);
264 if ( lineTime != invalidTime ) {
265 if (theLatestTime == invalidTime ||
266 difftime(lineTime, theLatestTime)>=0) {
267 latestFilePos = ftell (pserver->
poutfile);
268 theLatestTime = lineTime;
274 nChar = strftime (date,
sizeof(date),
"%a %b %d %H:%M:%S %Y\n", &theDate);
276 fprintf (
stderr,
"iocLogServer: strange date in log file: %s\n", date);
279 fprintf (
stderr,
"iocLogServer: strange date in log file\n");
284 fprintf (
stderr,
"iocLogServer: strange year in log file: %d\n", theDate.tm_year);
288 fprintf (
stderr,
"iocLogServer: strange month in log file: %s\n", month);
297 while ( c!=EOF && c!=
'\n' ) {
310 if (latestFilePos != -1) {
311 status = fseek (pserver->
poutfile, latestFilePos, SEEK_SET);
329 if (theLatestTime==invalidTime) {
331 fprintf (
stderr,
"iocLogServer: **** Warning ****\n");
332 fprintf (
stderr,
"iocLogServer: no recognizable dates in \"%s\"\n",
334 fprintf (
stderr,
"iocLogServer: logging at end of file\n");
355 pserver->
poutfile = fopen(ioc_log_file_name,
"r+");
359 ret =
truncateFile (ioc_log_file_name, ioc_log_file_limit);
363 pserver->
poutfile = fopen(ioc_log_file_name,
"r+");
366 pserver->
poutfile = fopen(ioc_log_file_name,
"w");
373 strcpy (pserver->
outfile, ioc_log_file_name);
376 return seekLatestLine (pserver);
384 static void handleLogFileError(
void)
387 "iocLogServer: log file access problem (errno=%s)\n",
398 static void acceptNewClient (
void *pParam )
403 struct sockaddr_in addr;
407 pclient = (
struct iocLogClient * ) malloc (
sizeof ( *pclient ) );
412 addrSize =
sizeof ( addr );
415 static unsigned acceptErrCount;
416 static int lastErrno;
425 if ( acceptErrCount % 1000 || lastErrno != thisErrno ) {
429 lastErrno = thisErrno;
446 fprintf(
stderr,
"%s:%d ioctl FBIO client er %s\n",
447 __FILE__, __LINE__, sockErrBuf);
463 "%s %s ----- Client Connect -----\n",
467 handleLogFileError();
485 fprintf(
stderr,
"Keepalive option set failed\n");
493 fprintf (
stderr,
"%s:%d shutdown err %s\n", __FILE__, __LINE__,
510 fprintf(
stderr,
"%s:%d client fdmgr_add_callback() failed\n",
524 static void readFromClient(
void *pParam)
532 size = (int) (
sizeof(pclient->
recvbuf) - pclient->
nChar);
533 recvLength = recv(pclient->
insock,
537 if (recvLength <= 0) {
551 "%s:%d socket=%d size=%d read error=%s\n",
552 __FILE__, __LINE__, pclient->
insock,
559 freeLogClient (pclient);
563 pclient->
nChar += (size_t) recvLength;
565 writeMessagesToLog (pclient);
571 static void writeMessagesToLog (
struct iocLogClient *pclient)
574 size_t lineIndex = 0;
582 if ( lineIndex >= pclient->
nChar ) {
597 nchar = pclient->
nChar - lineIndex;
598 for ( crIndex = lineIndex; crIndex < pclient->
nChar; crIndex++ ) {
599 if ( pclient->
recvbuf[crIndex] ==
'\n' ) {
603 if ( crIndex < pclient->
nChar ) {
604 nchar = crIndex - lineIndex;
607 nchar = pclient->
nChar - lineIndex;
608 if ( nchar <
sizeof ( pclient->
recvbuf ) ) {
609 if ( lineIndex != 0 ) {
610 pclient->
nChar = nchar;
612 & pclient->
recvbuf[lineIndex], nchar);
621 nTotChar = strlen(pclient->
name) +
623 assert (nTotChar <= INT_MAX);
624 ntci = (int) nTotChar;
634 if ( status == EOF ) {
635 handleLogFileError();
642 "ioc log server: resetting the file pointer\n" );
662 handleLogFileError();
665 if (status != ntci) {
666 fprintf(
stderr,
"iocLogServer: didnt calculate number of characters correctly?\n");
670 lineIndex += nchar+1u;
684 fprintf(
stderr,
"iocLogServer: nil message disconnect\n");
691 if (pclient->
nChar) {
698 writeMessagesToLog (pclient);
706 fprintf(
stderr,
"%s:%d fdmgr_clear_callback() failed\n",
730 pTimeString = ctime (&sec);
749 static int getConfig(
void)
759 ioc_log_port = (
unsigned short) param;
762 ioc_log_port = 7004U;
767 &ioc_log_file_limit);
769 if (ioc_log_file_limit < 0) {
775 ioc_log_file_limit = 10000;
780 sizeof ioc_log_file_name,
792 sizeof ioc_log_file_command,
793 ioc_log_file_command);
805 static void envFailureNotify(
const ENV_PARAM *pparam)
808 "iocLogServer: EPICS environment variable `%s' undefined\n",
818 struct sigaction sigact;
820 status = getDirectory();
822 fprintf(
stderr,
"iocLogServer: failed to determine log file " 831 sigact.sa_handler = sighupHandler;
832 sigemptyset (&sigact.sa_mask);
834 if (sigaction(SIGHUP, &sigact,
NULL)){
835 fprintf(
stderr,
"iocLogServer: %s\n", strerror(errno));
839 status = pipe(sighupPipe);
842 "iocLogServer: failed to create pipe because `%s'\n",
851 serviceSighupRequest,
855 "iocLogServer: failed to add SIGHUP callback\n");
867 static void sighupHandler(
int signo)
869 const char msg[] =
"SIGHUP\n";
870 const ssize_t bytesWritten = write(sighupPipe[1], msg,
sizeof(msg));
871 if (bytesWritten !=
sizeof(msg)) {
872 fprintf(
stderr,
"iocLogServer: failed to write to SIGHUP pipe because " 873 "`%s'\n", strerror(errno));
883 static void serviceSighupRequest(
void *pParam)
892 if (
read(sighupPipe[0], buff,
sizeof buff) <= 0) {
893 fprintf(
stderr,
"iocLogServer: failed to read from SIGHUP pipe because " 894 "`%s'\n", strerror(errno));
900 status = getDirectory();
902 fprintf(
stderr,
"iocLogServer: failed to determine new log " 910 status = openLogFile(pserver);
913 "File access problems to `%s' because `%s'\n",
917 strcpy(ioc_log_file_name, pserver->
outfile);
918 status = openLogFile(pserver);
921 "File access problems to `%s' because `%s'\n",
928 "iocLogServer: re-opened old log file %s\n",
934 "iocLogServer: opened new log file %s\n",
947 static int getDirectory(
void)
953 if (ioc_log_file_command[0] !=
'\0') {
958 pipe = popen(ioc_log_file_command,
"r");
961 "Problem executing `%s' because `%s'\n",
962 ioc_log_file_command,
966 if (fgets(dir,
sizeof(dir), pipe) ==
NULL) {
968 "Problem reading o/p from `%s' because `%s'\n",
969 ioc_log_file_command,
980 for (i=0; dir[
i] !=
'\n' && dir[
i] !=
'\0'; i++)
985 if (i > 1 && dir[i-1] ==
'/') dir[i-1] =
'\0';
990 if (dir[0] !=
'\0') {
991 char *
name = ioc_log_file_name;
992 char *slash = strrchr(ioc_log_file_name,
'/');
995 if (slash !=
NULL) name = slash + 1;
997 sprintf(ioc_log_file_name,
"%s/%s",dir,temp);
LIBCOM_API void epicsStdCall epicsSocketDestroy(SOCKET s)
LIBCOM_API int epicsStdCall fdmgr_pend_event(fdctx *pfdctx, struct timeval *ptimeout)
#define SOCK_ECONNABORTED
#define assert(exp)
Declare that a condition should be true.
An EPICS-specific replacement for ANSI C's assert.
char * name
Name of the parameter.
LIBCOM_API const ENV_PARAM EPICS_IOC_LOG_FILE_COMMAND
Routines to get and set EPICS environment parameters.
LIBCOM_API enum TF_RETURN truncateFile(const char *pFileName, unsigned long size)
Miscellaneous macro definitions.
A structure to hold a single environment parameter.
void epicsSocketConvertErrnoToString(char *pBuf, unsigned bufSize)
#define socket_ioctl(A, B, C)
LIBCOM_API SOCKET epicsStdCall epicsSocketCreate(int domain, int type, int protocol)
LIBCOM_API void epicsStdCall epicsSocketEnableAddressReuseDuringTimeWaitState(SOCKET s)
LIBCOM_API int epicsStdCall epicsSocketAccept(int sock, struct sockaddr *pAddr, osiSocklen_t *addrlen)
BSD and SRV5 Unix timestamp.
LIBCOM_API int epicsStdCall fdmgr_clear_callback(fdctx *pfdctx, SOCKET fd, enum fdi_type fdi)
void date(const char *format)
LIBCOM_API const ENV_PARAM EPICS_IOC_LOG_FILE_LIMIT
struct ioc_log_server * pserver
LIBCOM_API int epicsStdCall fdmgr_add_callback(fdctx *pfdctx, SOCKET fd, enum fdi_type fdi, pCallBackFDMgr pFunc, void *pParam)
LIBCOM_API fdctx *epicsStdCall fdmgr_init(void)
LIBCOM_API long epicsStdCall envGetLongConfigParam(const ENV_PARAM *pParam, long *pLong)
Get value of a long configuration parameter.
unsigned epicsStdCall ipAddrToA(const struct sockaddr_in *paddr, char *pBuf, unsigned bufSize)
LIBCOM_API char *epicsStdCall envGetConfigParam(const ENV_PARAM *pParam, int bufDim, char *pBuf)
Get value of a configuration parameter.
LIBCOM_API const ENV_PARAM EPICS_IOC_LOG_FILE_NAME
LIBCOM_API const ENV_PARAM EPICS_IOC_LOG_PORT