/* logmsg.C (c) Copyright Ivan Warren, 2003-2012 */ /* (c) Copyright TurboHercules, SAS 2010-2011 */ /* logmsg frontend routing */ /* */ /* Released under "The Q Public License Version 1" */ /* (http://www.hercules-390.org/herclic.html) as modifications to */ /* Hercules. */ #include "hstdinc.h" #define _HUTIL_DLL_ #define _LOGMSG_C_ #include "hercules.h" #define BFR_CHUNKSIZE (256) /******************************************/ /* UTILITY MACRO BFR_VSNPRINTF */ /* Original design by Fish */ /* Modified by Jay Maynard */ /* Further modification by Ivan Warren */ /* */ /* Purpose : set 'bfr' to contain */ /* a C string based on a message format */ /* and a va_list of args. */ /* bfr must be free()d when over with */ /* this macro can ONLY be used from the */ /* topmost variable arg function */ /* that is the va_list cannot be passed */ /* as a parameter from another function */ /* since va_xxx functions behavio(u)r */ /* seems to be undefined in those cases */ /* char *bfr; must be originally defined */ /* int siz; must be defined and cont- */ /* ain a start size */ /* va_list vl; must be defined and init- */ /* ialised with va_start */ /* char *msg; is the message format */ /* int rc; to contain final size */ /******************************************/ #if defined(_MSVC_) #define BFR_VSNPRINTF() \ bfr=(char *)calloc(1,siz); \ rc=-1; \ while(bfr&&rc<0) \ { \ va_start(vl,msg); \ rc=_vsnprintf_s(bfr,siz,siz-1,msg,vl); \ va_end(vl); \ if(rc>=0 && rc 65536 ) break; \ bfr=realloc(bfr,siz); \ } \ if ( bfr != NULL && strlen(bfr) == 0 && strlen(msg) != 0 ) \ { \ free(bfr); \ bfr = strdup(msg); \ } \ else \ { \ if ( bfr != NULL ) \ { \ char *p = strdup( bfr ); \ free( bfr ); \ bfr = p; \ } \ } \ ASSERT(bfr) #else #define BFR_VSNPRINTF() \ bfr=(char*)calloc(1,siz); \ rc=-1; \ while(bfr&&rc<0) \ { \ va_start(vl,msg); \ rc=vsnprintf(bfr,siz,msg,vl); \ va_end(vl); \ if(rc>=0 && rc 65536 ) break; \ bfr=realloc(bfr,siz); \ } \ if ( bfr != NULL && strlen(bfr) == 0 && strlen(msg) != 0 ) \ { \ free(bfr); \ bfr = strdup(msg); \ } \ else \ { \ if ( bfr != NULL ) \ { \ char *p = strdup( bfr ); \ free( bfr ); \ bfr = p; \ } \ } \ ASSERT(bfr) #endif static LOCK log_route_lock; #define MAX_LOG_ROUTES MAX_CPU_ENGINES+4 typedef struct _LOG_ROUTES { TID t; LOG_WRITER *w; LOG_CLOSER *c; void *u; } LOG_ROUTES; LOG_ROUTES log_routes[MAX_LOG_ROUTES]; static int log_route_inited=0; static void log_route_init(void) { int i; if(log_route_inited) { return; } initialize_lock(&log_route_lock); for(i=0;i 10 && SNCMP(bfr,"HHC",3) && (bfr[8] == 'S' || bfr[8] == 'E' || bfr[8] == 'W') ) errmsg = TRUE; #if defined( OPTION_MSGCLR ) if ( !strlen(color) ) { if ( errmsg ) color = ""; else color = ""; } #else color = ""; #endif // defined( OPTION_MSGCLR ) if ( lvl & MLVL_DEBUG ) { #if defined( OPTION_MSGCLR ) if (strlen(color) > 0 && !sysblk.shutdown && sysblk.panel_init && !sysblk.daemon_mode) MSGBUF(prefix, "%s" MLVL_DEBUG_PRINTF_PATTERN, color, file, line); else #endif MSGBUF(prefix, MLVL_DEBUG_PRINTF_PATTERN, file, line); } else { #if defined( OPTION_MSGCLR ) if (strlen(color) > 0 && !sysblk.shutdown && sysblk.panel_init && !sysblk.daemon_mode) { MSGBUF(prefix, "%s", color ); } #endif // defined( OPTION_MSGCLR ) } if(bfr) { size_t l = strlen(prefix)+strlen(bfr)+256; msgbuf = calloc(1,l); if (msgbuf) { if ( strlen(bfr) > 10 && SNCMP(bfr, "HHC", 3) ) snprintf( msgbuf, l-1, "%s%s", prefix, ( sysblk.emsg & EMSG_TEXT ) ? &bfr[10] : bfr ); else snprintf( msgbuf, l-1, "%s%s", prefix, bfr ); log_write( 0, msgbuf ); free(msgbuf); } free(bfr); } if ( errmsg && !MLVL(DEBUG) ) logmsg("HHC00007" "I" " " HHC00007 "\n", function, file, line); #ifdef NEED_LOGMSG_FFLUSH fflush(stdout); #endif #ifdef OPTION_MSGLCK if(!sysblk.msggrp || (sysblk.msggrp && !grp)) WRGMSG_OFF; #endif log_wakeup(NULL); } #endif /*defined(OPTION_MSGCLR) || defined(OPTION_MSGHLD)*/ /*-------------------------------------------------------------------*/ /* Log message: Normal routing (panel or buffer, as appropriate) */ /* was logmsg; replaced with macro logmsg */ /*-------------------------------------------------------------------*/ DLL_EXPORT void logmsg(char *msg,...) { char *bfr = NULL; int rc; int siz = 1024; va_list vl; #ifdef NEED_LOGMSG_FFLUSH fflush(stdout); #endif BFR_VSNPRINTF(); if ( bfr ) { if ( !strncmp(bfr, "HHC", 3) && strlen(bfr) > 10 ) log_write( 0, ( sysblk.emsg & EMSG_TEXT ) ? &bfr[10] : bfr ); else log_write( 0, bfr ); } #ifdef NEED_LOGMSG_FFLUSH fflush(stdout); #endif if ( bfr ) { free(bfr); } } // BHe I want to remove these functions for simplification #if 0 /*-------------------------------------------------------------------*/ /* Log message: Panel only (no logmsg routing) */ /*-------------------------------------------------------------------*/ DLL_EXPORT void logmsgp(char *msg,...) { char *bfr=NULL; char *ptr; int rc; int siz=1024; va_list vl; #ifdef NEED_LOGMSG_FFLUSH fflush(stdout); #endif BFR_VSNPRINTF(); if(bfr) { if ( !strncmp(bfr, "HHC", 3) && strlen(bfr) > 10 ) log_write( 1, ( sysblk.emsg & EMSG_TEXT ) ? &bfr[10] : bfr ); else log_write( 1, bfr ); } #ifdef NEED_LOGMSG_FFLUSH fflush(stdout); #endif if(bfr) { free(bfr); } } /*-------------------------------------------------------------------*/ /* Log message: Both panel and logmsg routing */ /*-------------------------------------------------------------------*/ DLL_EXPORT void logmsgb(char *msg,...) { char *bfr=NULL; char *ptr; int rc; int siz=1024; va_list vl; #ifdef NEED_LOGMSG_FFLUSH fflush(stdout); #endif BFR_VSNPRINTF(); if(bfr) { if ( !strncmp(bfr, "HHC", 3) && strlen(bfr) > 10 ) log_write( 2, ( sysblk.emsg & EMSG_TEXT ) ? &bfr[10] : bfr ); else log_write( 2, bfr ); } #ifdef NEED_LOGMSG_FFLUSH fflush(stdout); #endif if(bfr) { free(bfr); } } #endif #if defined(OPTION_MSGCLR) || defined(OPTION_MSGHLD) /*-------------------------------------------------------------------*/ /* Log message: Device trace */ /*-------------------------------------------------------------------*/ DLL_EXPORT void logdevtr(DEVBLK *dev,char *msg,...) { char *bfr=NULL; int rc; int siz=1024; va_list vl; #ifdef NEED_LOGMSG_FFLUSH fflush(stdout); #endif if(dev->ccwtrace||dev->ccwstep) { BFR_VSNPRINTF(); if(bfr) { if ( !strncmp(bfr, "HHC", 3) && strlen(bfr) > 10 ) log_write( 2, ( sysblk.emsg & EMSG_TEXT ) ? &bfr[10] : bfr ); else log_write( 2, bfr ); } } #ifdef NEED_LOGMSG_FFLUSH fflush(stdout); #endif if(bfr) { free(bfr); } } /* end function logdevtr */ #endif /*defined(OPTION_MSGCLR) || defined(OPTION_MSGHLD)*/ #if defined(OPTION_MSGCLR) || defined(OPTION_MSGHLD) /* panel : 0 - No, 1 - Only, 2 - Also */ DLL_EXPORT void log_write(int panel,char *msg) { /* (log_write function proper starts here) */ int slot; char *ptr; size_t pl; char *pszMSG; char *pLeft, *pRight; int nLeft; if ( msg == NULL || strlen(msg) == 0 ) return; pLeft = msg; nLeft = (int)strlen(msg); #if defined( OPTION_MSGCLR ) /* strip color part of message */ /* Remove " 5 && strncasecmp( pLeft, "', nLeft-4 )) != NULL ) { pLeft++; nLeft -= (int)(pLeft - (char*)msg); } #endif // defined( OPTION_MSGCLR ) // Route logmsg to stdout if the logpipe has not been initialised if(!logger_syslogfd[LOG_WRITE]) { printf( "%s", pLeft ); return; } pl = strlen(msg) * 2; ptr = malloc( pl ); ASSERT( ptr != NULL ); if ( ptr == NULL ) pszMSG = msg; else { struct timeval now; time_t tt; char hhmmss[10]; gettimeofday( &now, NULL ); tt = now.tv_sec; strlcpy( hhmmss, ctime(&tt)+11, sizeof(hhmmss) ); ptr[0] = '\0'; if ( sysblk.emsg & EMSG_TS && !SNCMP( msg, "' ); pRight++; if ( strlen(pRight) > 10 && ( SNCMP(pRight, "HHC", 3) || SNCMP(&pRight[17], "HHC", 3) ) ) { memset(ptr, 0, sizeof(ptr)); strlcpy( ptr, msg, (pRight-msg)+1 ); strlcat( ptr, hhmmss, pl ); strlcat( ptr, pRight, pl ); pszMSG = ptr; } else pszMSG = msg; } else pszMSG = msg; } log_route_init(); if ( panel == 1 ) { write_pipe( logger_syslogfd[LOG_WRITE], pszMSG, strlen(pszMSG) ); } else { obtain_lock(&log_route_lock); slot = log_route_search(thread_id()); release_lock(&log_route_lock); if ( panel == 2 ) { write_pipe( logger_syslogfd[LOG_WRITE], pszMSG, strlen(pszMSG) ); if (nLeft && slot >= 0) { log_routes[slot].w(log_routes[slot].u,pLeft); } } else if ( slot < 0 ) { write_pipe( logger_syslogfd[LOG_WRITE], pszMSG, strlen(pszMSG) ); } else { if (nLeft) { log_routes[slot].w(log_routes[slot].u,pLeft); } } } if ( ptr != NULL ) free(ptr); return; } #else /*defined(OPTION_MSGCLR) || defined(OPTION_MSGHLD)*/ /* panel : 0 - No, 1 - Only, 2 - Also */ DLL_EXPORT void log_write(int panel,char *msg) { /* (log_write function proper starts here) */ int slot; log_route_init(); if(panel==1) { write_pipe( logger_syslogfd[LOG_WRITE], msg, strlen(msg) ); return; } obtain_lock(&log_route_lock); slot=log_route_search(thread_id()); release_lock(&log_route_lock); if(slot<0 || panel>0) { write_pipe( logger_syslogfd[LOG_WRITE], msg, strlen(msg) ); if(slot<0) return; } log_routes[slot].w(log_routes[slot].u,msg); return; } #endif /*defined(OPTION_MSGCLR) || defined(OPTION_MSGHLD)*/ /* capture log output routine series */ /* log_capture is a sample of how to */ /* use log rerouting. */ /* log_capture takes 2 args : */ /* a ptr to a function taking 1 parm */ /* the function parm */ struct log_capture_data { char *obfr; size_t sz; }; DLL_EXPORT void log_capture_writer(void *vcd,char *msg) { struct log_capture_data *cd; if(!vcd||!msg)return; cd=(struct log_capture_data *)vcd; if(cd->sz==0) { cd->sz=strlen(msg)+1; cd->obfr=malloc(cd->sz); cd->obfr[0]=0; } else { cd->sz+=strlen(msg); cd->obfr=realloc(cd->obfr,cd->sz); } strlcat(cd->obfr,msg,cd->sz); return; } DLL_EXPORT void log_capture_closer(void *vcd) { UNREFERENCED(vcd); return; } DLL_EXPORT char *log_capture(CAPTUREFUNC *func,void *p) { struct log_capture_data cd; cd.obfr=NULL; cd.sz=0; log_open(log_capture_writer,log_capture_closer,&cd); func(p); log_close(); return(cd.obfr); } DLL_EXPORT int log_capture_rc(CAPTUREFUNC *func,char *p,char **resp) { int rc; struct log_capture_data cd = {0,0}; log_open(log_capture_writer,log_capture_closer,&cd); rc = (int)(uintptr_t)func(p); log_close(); *resp = cd.obfr; return rc; } #if defined( OPTION_MSGCLR ) /*-------------------------------------------------------------------*/ /* Skip past "" message prefix... */ /* Input: */ /* ppsz pointer to char* pointing to message */ /* Output: */ /* ppsz updated *ppsz --> msg following ' ); if (p) *ppsz = ++p; } return (int)strlen( *ppsz ); } #endif /*defined( OPTION_MSGCLR )*/