1 /* LOGMSG.C     (c) Copyright Ivan Warren, 2003-2006                 */
2 /*              logmsg frontend routing                              */
3 
4 #include "hstdinc.h"
5 
6 #define _HUTIL_DLL_
7 #define _LOGMSG_C_
8 
9 #include "hercules.h"
10 
11 #define  BFR_CHUNKSIZE    (256)
12 
13 /******************************************/
14 /* UTILITY MACRO BFR_VSNPRINTF            */
15 /* Original design by Fish                */
16 /* Modified by Jay Maynard                */
17 /* Further modification by Ivan Warren    */
18 /*                                        */
19 /* Purpose : set 'bfr' to contain         */
20 /*  a C string based on a message format  */
21 /*  and a va_list of args.                */
22 /*  bfr must be free()d when over with    */
23 /*  this macro can ONLY be used from the  */
24 /*  topmost variable arg function         */
25 /*  that is the va_list cannot be passed  */
26 /*  as a parameter from another function  */
27 /*  since va_xxx functions behavio(u)r    */
28 /*  seems to be undefined in those cases  */
29 /* char *bfr; must be originally defined  */
30 /* int siz;    must be defined and cont-  */
31 /*             ain a start size           */
32 /* va_list vl; must be defined and init-  */
33 /*             ialised with va_start      */
34 /* char *msg; is the message format       */
35 /* int    rc; to contain final size       */
36 /******************************************/
37 
38 #define  BFR_VSNPRINTF()                  \
39     bfr=malloc(siz);                      \
40     rc=-1;                                \
41     while(bfr&&rc<0)                      \
42     {                                     \
43         va_start(vl,msg);                 \
44         rc=vsnprintf(bfr,siz,msg,vl);     \
45         va_end(vl);                       \
46         if(rc>=0 && rc<siz)               \
47             break;                        \
48         rc=-1;                            \
49         siz+=BFR_CHUNKSIZE;               \
50         bfr=realloc(bfr,siz);             \
51     }
52 
53 static LOCK log_route_lock;
54 
55 #define MAX_LOG_ROUTES 16
56 typedef struct _LOG_ROUTES
57 {
58     TID t;
59     LOG_WRITER *w;
60     LOG_CLOSER *c;
61     void *u;
62 } LOG_ROUTES;
63 
64 LOG_ROUTES log_routes[MAX_LOG_ROUTES];
65 
66 static int log_route_inited=0;
67 
log_route_init(void)68 static void log_route_init(void)
69 {
70     int i;
71     if(log_route_inited)
72     {
73         return;
74     }
75     initialize_lock(&log_route_lock);
76     for(i=0;i<MAX_LOG_ROUTES;i++)
77     {
78         log_routes[i].t=0;
79         log_routes[i].w=NULL;
80         log_routes[i].c=NULL;
81         log_routes[i].u=NULL;
82     }
83     log_route_inited=1;
84     return;
85 }
86 /* LOG Routing functions */
log_route_search(TID t)87 static int log_route_search(TID t)
88 {
89     int i;
90     for(i=0;i<MAX_LOG_ROUTES;i++)
91     {
92         if(log_routes[i].t==t)
93         {
94             if(t==0)
95             {
96                 log_routes[i].t=(TID)1;
97             }
98             return(i);
99         }
100     }
101     return(-1);
102 }
103 
104 /* Open a log redirection Driver route on a per-thread basis         */
105 /* Up to 16 concurent threads may have an alternate logging route    */
106 /* opened                                                            */
log_open(LOG_WRITER * lw,LOG_CLOSER * lc,void * uw)107 DLL_EXPORT int log_open(LOG_WRITER *lw,LOG_CLOSER *lc,void *uw)
108 {
109     int slot;
110     log_route_init();
111     obtain_lock(&log_route_lock);
112     slot=log_route_search((TID)0);
113     if(slot<0)
114     {
115         release_lock(&log_route_lock);
116         return(-1);
117     }
118     log_routes[slot].t=thread_id();
119     log_routes[slot].w=lw;
120     log_routes[slot].c=lc;
121     log_routes[slot].u=uw;
122     release_lock(&log_route_lock);
123     return(0);
124 }
125 
log_close(void)126 DLL_EXPORT void log_close(void)
127 {
128     int slot;
129     log_route_init();
130     obtain_lock(&log_route_lock);
131     slot=log_route_search(thread_id());
132     if(slot<0)
133     {
134         release_lock(&log_route_lock);
135         return;
136     }
137     log_routes[slot].c(log_routes[slot].u);
138     log_routes[slot].t=0;
139     log_routes[slot].w=NULL;
140     log_routes[slot].c=NULL;
141     log_routes[slot].u=NULL;
142     release_lock(&log_route_lock);
143     return;
144 }
145 
146 /*-------------------------------------------------------------------*/
147 /* Log message: Normal routing (panel or buffer, as appropriate)     */
148 /*-------------------------------------------------------------------*/
logmsg(char * msg,...)149 DLL_EXPORT void logmsg(char *msg,...)
150 {
151     char *bfr=NULL;
152     int rc;
153     int siz=1024;
154     va_list vl;
155   #ifdef NEED_LOGMSG_FFLUSH
156     fflush(stdout);
157   #endif
158     BFR_VSNPRINTF();
159     if(bfr)
160         log_write(0,bfr);
161   #ifdef NEED_LOGMSG_FFLUSH
162     fflush(stdout);
163   #endif
164     if(bfr)
165     {
166         free(bfr);
167     }
168 }
169 
170 /*-------------------------------------------------------------------*/
171 /* Log message: Panel only (no logmsg routing)                       */
172 /*-------------------------------------------------------------------*/
logmsgp(char * msg,...)173 DLL_EXPORT void logmsgp(char *msg,...)
174 {
175     char *bfr=NULL;
176     int rc;
177     int siz=1024;
178     va_list vl;
179   #ifdef NEED_LOGMSG_FFLUSH
180     fflush(stdout);
181   #endif
182     BFR_VSNPRINTF();
183     if(bfr)
184         log_write(1,bfr);
185   #ifdef NEED_LOGMSG_FFLUSH
186     fflush(stdout);
187   #endif
188     if(bfr)
189     {
190         free(bfr);
191     }
192 }
193 
194 /*-------------------------------------------------------------------*/
195 /* Log message: Both panel and logmsg routing                        */
196 /*-------------------------------------------------------------------*/
logmsgb(char * msg,...)197 DLL_EXPORT void logmsgb(char *msg,...)
198 {
199     char *bfr=NULL;
200     int rc;
201     int siz=1024;
202     va_list vl;
203   #ifdef NEED_LOGMSG_FFLUSH
204     fflush(stdout);
205   #endif
206     BFR_VSNPRINTF();
207     if(bfr)
208         log_write(2,bfr);
209   #ifdef NEED_LOGMSG_FFLUSH
210     fflush(stdout);
211   #endif
212     if(bfr)
213     {
214         free(bfr);
215     }
216 }
217 
218 /*-------------------------------------------------------------------*/
219 /* Log message: Device trace                                         */
220 /*-------------------------------------------------------------------*/
logdevtr(DEVBLK * dev,char * msg,...)221 DLL_EXPORT void logdevtr(DEVBLK *dev,char *msg,...)
222 {
223     char *bfr=NULL;
224     int rc;
225     int siz=1024;
226     va_list vl;
227   #ifdef NEED_LOGMSG_FFLUSH
228     fflush(stdout);
229   #endif
230     if(dev->ccwtrace||dev->ccwstep)
231     {
232         logmsg("%4.4X:",dev->devnum);
233         BFR_VSNPRINTF();
234         if(bfr)
235             log_write(2,bfr);
236     }
237   #ifdef NEED_LOGMSG_FFLUSH
238     fflush(stdout);
239   #endif
240     if(bfr)
241     {
242         free(bfr);
243     }
244 } /* end function logdevtr */
245 
246 /* panel : 0 - No, 1 - Only, 2 - Also */
log_write(int panel,char * msg)247 DLL_EXPORT void log_write(int panel,char *msg)
248 {
249 
250 /* (log_write function proper starts here) */
251     int slot;
252     log_route_init();
253     if(panel==1)
254     {
255         write_pipe( logger_syslogfd[LOG_WRITE], msg, strlen(msg) );
256         return;
257     }
258     obtain_lock(&log_route_lock);
259     slot=log_route_search(thread_id());
260     release_lock(&log_route_lock);
261     if(slot<0 || panel>0)
262     {
263         write_pipe( logger_syslogfd[LOG_WRITE], msg, strlen(msg) );
264         if(slot<0)
265             return;
266     }
267     log_routes[slot].w(log_routes[slot].u,msg);
268     return;
269 }
270 
271 /* capture log output routine series */
272 /* log_capture is a sample of how to */
273 /* use log rerouting.                */
274 /* log_capture takes 2 args :        */
275 /*   a ptr to a function taking 1 parm */
276 /*   the function parm               */
277 struct log_capture_data
278 {
279     char *obfr;
280     size_t sz;
281 };
282 
log_capture_writer(void * vcd,char * msg)283 DLL_EXPORT void log_capture_writer(void *vcd,char *msg)
284 {
285     struct log_capture_data *cd;
286     if(!vcd||!msg)return;
287     cd=(struct log_capture_data *)vcd;
288     if(cd->sz==0)
289     {
290         cd->sz=strlen(msg)+1;
291         cd->obfr=malloc(cd->sz);
292         cd->obfr[0]=0;
293     }
294     else
295     {
296         cd->sz+=strlen(msg);
297         cd->obfr=realloc(cd->obfr,cd->sz);
298     }
299     strcat(cd->obfr,msg);
300     return;
301 }
log_capture_closer(void * vcd)302 DLL_EXPORT void log_capture_closer(void *vcd)
303 {
304     UNREFERENCED(vcd);
305     return;
306 }
307 
log_capture(void * (* fun)(void *),void * p)308 DLL_EXPORT char *log_capture(void *(*fun)(void *),void *p)
309 {
310     struct log_capture_data cd;
311     cd.obfr=NULL;
312     cd.sz=0;
313     log_open(log_capture_writer,log_capture_closer,&cd);
314     fun(p);
315     log_close();
316     return(cd.obfr);
317 }
318