1 /* HSCUTL.C     (c) Copyright Ivan Warren & Others, 2003-2009        */
2 /*              Hercules Platform Port & Misc Functions              */
3 
4 /*-------------------------------------------------------------------*/
5 /* Implementation of functions used in Hercules that may             */
6 /* be missing on some platform ports, or other convenient            */
7 /* miscellaneous global utility functions.                           */
8 /*-------------------------------------------------------------------*/
9 
10 /* (c) 2003-2006 Ivan Warren & Others -- Released under the Q Public */
11 /* License -- This file is portion of the HERCULES S/370, S/390 and  */
12 /* z/Architecture emulator                                           */
13 
14 #include "hstdinc.h"
15 
16 #define _HSCUTL_C_
17 #define _HUTIL_DLL_
18 
19 #include "hercules.h"
20 
21 #if defined(NEED_GETOPT_WRAPPER)
22 /*
23                   GETOPT DYNAMIC LINKING KLUDGE...
24 
25   For some odd reason, on some platforms (namely windows & possibly
26   Darwin) dynamically linking to the libc imports STATIC versions
27   of 'getopt' and 'getopt_long' into the link-edited shared library.
28   If any program then link edits against BOTH the shared library AND
29   libc, then the linker complains about 'getopt' and/or 'getopt_long'
30   being defined multiple times. In an effort to overcome this, I am
31   defining a stub version of 'getopt' and 'getop_long' that can be
32   called by loadable modules instead.
33 
34   -- Ivan
35 
36 
37   ** ZZ FIXME: the above needs to be re-verified to see whether it is
38   ** still true or not. I suspect it may no longer be true due to the
39   ** subtle bug fixed in the "_HC_CHECK_NEED_GETOPT_WRAPPER" m4 macro
40   ** in the "./autoconf/hercules.m4" member. -- Fish, Feb 2005
41 
42 */
43 
44 int herc_opterr=0;
45 char *herc_optarg=NULL;
46 int herc_optopt=0;
47 int herc_optind=1;
48 #if defined(NEED_GETOPT_OPTRESET)
49 int herc_optreset=0;
50 #endif
51 
herc_getopt(int ac,char * const av[],const char * opt)52 DLL_EXPORT int herc_getopt(int ac,char * const av[],const char *opt)
53 {
54     int rc;
55 #if defined(NEED_GETOPT_OPTRESET)
56     optreset=herc_optreset;
57 #endif
58     rc=getopt(ac,av,opt);
59 #if defined(NEED_GETOPT_OPTRESET)
60     herc_optreset=optreset;
61 #endif
62     herc_optarg=optarg;
63     herc_optind=optind;
64     herc_optopt=optind;
65     herc_opterr=optind;
66     return(rc);
67 }
68 
69 #if defined(HAVE_GETOPT_LONG)
70 struct option; // (fwd ref)
71 int getopt_long (int, char *const *, const char *, const struct option *, int *);
72 struct option; // (fwd ref)
herc_getopt_long(int ac,char * const av[],const char * opt,const struct option * lo,int * li)73 DLL_EXPORT int herc_getopt_long(int ac,
74                      char * const av[],
75                      const char *opt,
76                      const struct option *lo,
77                      int *li)
78 {
79     int rc;
80 #if defined(NEED_GETOPT_OPTRESET)
81     optreset=herc_optreset;
82 #endif
83     optind=herc_optind;
84     rc=getopt_long(ac,av,opt,lo,li);
85 #if defined(NEED_GETOPT_OPTRESET)
86     herc_optreset=optreset;
87 #endif
88     herc_optarg=optarg;
89     herc_optind=optind;
90     herc_optopt=optind;
91     herc_opterr=optind;
92     return(rc);
93 }
94 #endif /* HAVE_GETOPT_LONG */
95 
96 #endif /* NEED_GETOPT_WRAPPER */
97 
98 #if !defined(WIN32) && !defined(HAVE_STRERROR_R)
99 static LOCK strerror_lock;
strerror_r_init(void)100 DLL_EXPORT void strerror_r_init(void)
101 {
102     initialize_lock(&strerror_lock);
103 }
strerror_r(int err,char * bfr,size_t sz)104 DLL_EXPORT int strerror_r(int err,char *bfr,size_t sz)
105 {
106     char *wbfr;
107     obtain_lock(&strerror_lock);
108     wbfr=strerror(err);
109     if(wbfr==NULL || (int)wbfr==-1)
110     {
111         release_lock(&strerror_lock);
112         return(-1);
113     }
114     if(sz<=strlen(wbfr))
115     {
116         errno=ERANGE;
117         release_lock(&strerror_lock);
118         return(-1);
119     }
120     strncpy(bfr,wbfr,sz);
121     release_lock(&strerror_lock);
122     return(0);
123 }
124 #endif // !defined(HAVE_STRERROR_R)
125 
126 #if !defined(HAVE_STRLCPY)
127 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
128 
129 /*  ** NOTE **  returns 'size_t' and NOT 'char*' like strncpy! */
130 /*
131  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
132  *
133  * Permission to use, copy, modify, and distribute this software for any
134  * purpose with or without fee is hereby granted, provided that the above
135  * copyright notice and this permission notice appear in all copies.
136  *
137  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
138  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
139  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
140  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
141  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
142  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
143  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
144  */
145 
146 #if defined(LIBC_SCCS) && !defined(lint)
147 static char *rcsid = "$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $";
148 #endif /* LIBC_SCCS and not lint */
149 
150 /*
151  * Copy src to string dst of size siz.  At most siz-1 characters
152  * will be copied.  Always NUL terminates (unless siz == 0).
153  * Returns strlen(src); if retval >= siz, truncation occurred.
154  */
155 
156 /*  ** NOTE **  returns 'size_t' and NOT 'char*' like strncpy! */
157 
158 DLL_EXPORT size_t
strlcpy(char * dst,const char * src,size_t siz)159 strlcpy(char *dst, const char *src, size_t siz)
160 {
161  register char *d = dst;
162  register const char *s = src;
163  register size_t n = siz;
164 
165  /* Copy as many bytes as will fit */
166  if (n != 0 && --n != 0) {
167   do {
168    if ((*d++ = *s++) == 0)
169     break;
170   } while (--n != 0);
171  }
172 
173  /* Not enough room in dst, add NUL and traverse rest of src */
174  if (n == 0) {
175   if (siz != 0)
176    *d = '\0';  /* NUL-terminate dst */
177   while (*s++)
178    ;
179  }
180 
181  return(s - src - 1); /* count does not include NUL */
182 }
183 #endif // !defined(HAVE_STRLCPY)
184 
185 #if !defined(HAVE_STRLCAT)
186 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
187 
188 /*  ** NOTE **  returns 'size_t' and NOT 'char*' like strncpy! */
189 /*
190  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
191  *
192  * Permission to use, copy, modify, and distribute this software for any
193  * purpose with or without fee is hereby granted, provided that the above
194  * copyright notice and this permission notice appear in all copies.
195  *
196  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
197  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
198  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
199  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
200  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
201  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
202  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
203  */
204 
205 #if defined(LIBC_SCCS) && !defined(lint)
206 static char *rcsid = "$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $";
207 #endif /* LIBC_SCCS and not lint */
208 
209 /*
210  * Appends src to string dst of size siz (unlike strncat, siz is the
211  * full size of dst, not space left).  At most siz-1 characters
212  * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
213  * Returns strlen(src) + MIN(siz, strlen(initial dst)).
214  * If retval >= siz, truncation occurred.
215  */
216 
217 /*  ** NOTE **  returns 'size_t' and NOT 'char*' like strncat! */
218 
219 DLL_EXPORT size_t
strlcat(char * dst,const char * src,size_t siz)220 strlcat(char *dst, const char *src, size_t siz)
221 {
222  register char *d = dst;
223  register const char *s = src;
224  register size_t n = siz;
225  size_t dlen;
226 
227  /* Find the end of dst and adjust bytes left but don't go past end */
228  while (n-- != 0 && *d != '\0')
229   d++;
230  dlen = d - dst;
231  n = siz - dlen;
232 
233  if (n == 0)
234   return(dlen + strlen(s));
235  while (*s != '\0') {
236   if (n != 1) {
237    *d++ = *s;
238    n--;
239   }
240   s++;
241  }
242  *d = '\0';
243 
244  return(dlen + (s - src)); /* count does not include NUL */
245 }
246 #endif // !defined(HAVE_STRLCAT)
247 
248 #if defined(OPTION_CONFIG_SYMBOLS)
249 
250 /* The following structures are defined herein because they are private structures */
251 /* that MUST be opaque to the outside world                                        */
252 
253 typedef struct _SYMBOL_TOKEN
254 {
255     char *var;
256     char *val;
257 } SYMBOL_TOKEN;
258 
259 #define SYMBOL_TABLE_INCREMENT  256
260 #define SYMBOL_BUFFER_GROWTH    256
261 #define MAX_SYMBOL_SIZE         31
262 #define SYMBOL_QUAL_1   '$'
263 #define SYMBOL_QUAL_2   '('
264 #define SYMBOL_QUAL_3   ')'
265 
266 static SYMBOL_TOKEN **symbols=NULL;
267 static int symbol_count=0;
268 static int symbol_max=0;
269 
270 /* This function retrieves or allocates a new SYMBOL_TOKEN */
get_symbol_token(const char * sym,int alloc)271 static SYMBOL_TOKEN *get_symbol_token(const char *sym,int alloc)
272 {
273     SYMBOL_TOKEN        *tok;
274     int i;
275 
276     for(i=0;i<symbol_count;i++)
277     {
278         tok=symbols[i];
279         if(tok==NULL)
280         {
281             continue;
282         }
283         if(strcmp(symbols[i]->var,sym)==0)
284         {
285             return(symbols[i]);
286         }
287     }
288     if(!alloc)
289     {
290         return(NULL);
291     }
292     if(symbol_count>=symbol_max)
293     {
294         symbol_max+=SYMBOL_TABLE_INCREMENT;
295         if(symbols==NULL)
296         {
297         symbols=malloc(sizeof(SYMBOL_TOKEN *)*symbol_max);
298         if(symbols==NULL)
299         {
300             symbol_max=0;
301             symbol_count=0;
302             return(NULL);
303         }
304         }
305         else
306         {
307         symbols=realloc(symbols,sizeof(SYMBOL_TOKEN *)*symbol_max);
308         if(symbols==NULL)
309         {
310             symbol_max=0;
311             symbol_count=0;
312             return(NULL);
313         }
314         }
315     }
316     tok=malloc(sizeof(SYMBOL_TOKEN));
317     if(tok==NULL)
318     {
319         return(NULL);
320     }
321     tok->var=malloc(MIN(MAX_SYMBOL_SIZE+1,strlen(sym)+1));
322     if(tok->var==NULL)
323     {
324         free(tok);
325         return(NULL);
326     }
327     strncpy(tok->var,sym,MIN(MAX_SYMBOL_SIZE+1,strlen(sym)+1));
328     tok->val=NULL;
329     symbols[symbol_count]=tok;
330     symbol_count++;
331     return(tok);
332 }
333 
set_symbol(const char * sym,const char * value)334 DLL_EXPORT void set_symbol(const char *sym,const char *value)
335 {
336     SYMBOL_TOKEN        *tok;
337     tok=get_symbol_token(sym,1);
338     if(tok==NULL)
339     {
340         return;
341     }
342     if(tok->val!=NULL)
343     {
344         free(tok->val);
345     }
346     tok->val=malloc(strlen(value)+1);
347     if(tok->val==NULL)
348     {
349         return;
350     }
351     strcpy(tok->val,value);
352     return;
353 }
354 
get_symbol(const char * sym)355 DLL_EXPORT const char *get_symbol(const char *sym)
356 {
357     char *val;
358     SYMBOL_TOKEN        *tok;
359     tok=get_symbol_token(sym,0);
360     if(tok==NULL)
361     {
362         val=getenv(sym);
363         return(val);
364     }
365     return(tok->val);
366 }
367 
buffer_addchar_and_alloc(char ** bfr,char c,int * ix_p,int * max_p)368 static void buffer_addchar_and_alloc(char **bfr,char c,int *ix_p,int *max_p)
369 {
370     char *buf;
371     int ix;
372     int mx;
373     buf=*bfr;
374     ix=*ix_p;
375     mx=*max_p;
376     if((ix+1)>=mx)
377     {
378         mx+=SYMBOL_BUFFER_GROWTH;
379         if(buf==NULL)
380         {
381             buf=malloc(mx);
382         }
383         else
384         {
385             buf=realloc(buf,mx);
386         }
387         *bfr=buf;
388         *max_p=mx;
389     }
390     buf[ix++]=c;
391     buf[ix]=0;
392     *ix_p=ix;
393     return;
394 }
append_string(char ** bfr,char * text,int * ix_p,int * max_p)395 static void append_string(char **bfr,char *text,int *ix_p,int *max_p)
396 {
397     int i;
398     for(i=0;text[i]!=0;i++)
399     {
400         buffer_addchar_and_alloc(bfr,text[i],ix_p,max_p);
401     }
402     return;
403 }
404 
append_symbol(char ** bfr,char * sym,int * ix_p,int * max_p)405 static void append_symbol(char **bfr,char *sym,int *ix_p,int *max_p)
406 {
407     char *txt;
408     txt=(char *)get_symbol(sym);
409     if(txt==NULL)
410     {
411         txt="**UNRESOLVED**";
412     }
413     append_string(bfr,txt,ix_p,max_p);
414     return;
415 }
416 
resolve_symbol_string(const char * text)417 DLL_EXPORT char *resolve_symbol_string(const char *text)
418 {
419     char *resstr;
420     int curix,maxix;
421     char cursym[MAX_SYMBOL_SIZE+1];
422     int cursymsize=0;
423     int q1,q2;
424     int i;
425 
426     /* Quick check - look for QUAL1 ('$') or QUAL2 ('(').. if not found, return the string as-is */
427     if(!strchr(text,SYMBOL_QUAL_1) || !strchr(text,SYMBOL_QUAL_2))
428     {
429         /* Malloc anyway - the caller will free() */
430         resstr=malloc(strlen(text)+1);
431         strcpy(resstr,text);
432         return(resstr);
433     }
434     q1=0;
435     q2=0;
436     curix=0;
437     maxix=0;
438     resstr=NULL;
439     for(i=0;text[i]!=0;i++)
440     {
441         if(q1)
442         {
443             if(text[i]==SYMBOL_QUAL_2)
444             {
445                 q2=1;
446                 q1=0;
447                 continue;
448             }
449             q1=0;
450             buffer_addchar_and_alloc(&resstr,SYMBOL_QUAL_1,&curix,&maxix);
451             buffer_addchar_and_alloc(&resstr,text[i],&curix,&maxix);
452             continue;
453         }
454         if(q2)
455         {
456             if(text[i]==SYMBOL_QUAL_3)
457             {
458                 append_symbol(&resstr,cursym,&curix,&maxix);
459                 cursymsize=0;
460                 q2=0;
461                 continue;
462             }
463             if(cursymsize<MAX_SYMBOL_SIZE)
464             {
465                 cursym[cursymsize++]=text[i];
466                 cursym[cursymsize]=0;
467             }
468             continue;
469         }
470         if(text[i]==SYMBOL_QUAL_1)
471         {
472             q1=1;
473             continue;
474         }
475         buffer_addchar_and_alloc(&resstr,text[i],&curix,&maxix);
476     }
477     if(!resstr)
478     {
479         /* Malloc anyway - the caller will free() */
480         resstr=malloc(strlen(text)+1);
481         strcpy(resstr,text);
482     }
483     return(resstr);
484 }
485 
486 /* (called by defsym panel command) */
list_all_symbols(void)487 DLL_EXPORT void list_all_symbols(void)
488 {
489     SYMBOL_TOKEN* tok; int i;
490     for ( i=0; i < symbol_count; i++ )
491     {
492         tok = symbols[i];
493         if (tok)
494             logmsg("HHCPN042I %s=%s\n", tok->var, tok->val ? tok->val : "");
495     }
496     return;
497 }
498 
kill_all_symbols(void)499 DLL_EXPORT void kill_all_symbols(void)
500 {
501     SYMBOL_TOKEN        *tok;
502     int i;
503     for(i=0;i<symbol_count;i++)
504     {
505         tok=symbols[i];
506         if(tok==NULL)
507         {
508             continue;
509         }
510         free(tok->val);
511 
512         /* Show FREE has been carried out.                      @PJJ */
513         tok->val = NULL;
514 
515         if(tok->var!=NULL)
516         {
517             free(tok->var);
518 
519             /* Show FREE has been carried out.                  @PJJ */
520             tok->var = NULL;
521 
522         }
523         free(tok);
524         symbols[i]=NULL;
525     }
526     free(symbols);
527     symbol_count=0;
528     symbol_max=0;
529     return;
530 }
531 
532 #endif /* #if defined(OPTION_CONFIG_SYMBOLS) */
533 
534 /* Subtract 'beg_timeval' from 'end_timeval' yielding 'dif_timeval' */
535 /* Return code: success == 0, error == -1 (difference was negative) */
536 
timeval_subtract(struct timeval * beg_timeval,struct timeval * end_timeval,struct timeval * dif_timeval)537 DLL_EXPORT int timeval_subtract
538 (
539     struct timeval *beg_timeval,
540     struct timeval *end_timeval,
541     struct timeval *dif_timeval
542 )
543 {
544     struct timeval begtime;
545     struct timeval endtime;
546     ASSERT ( beg_timeval -> tv_sec >= 0  &&  beg_timeval -> tv_usec >= 0 );
547     ASSERT ( end_timeval -> tv_sec >= 0  &&  end_timeval -> tv_usec >= 0 );
548 
549     memcpy(&begtime,beg_timeval,sizeof(struct timeval));
550     memcpy(&endtime,end_timeval,sizeof(struct timeval));
551 
552     dif_timeval->tv_sec = endtime.tv_sec - begtime.tv_sec;
553 
554     if (endtime.tv_usec >= begtime.tv_usec)
555     {
556         dif_timeval->tv_usec = endtime.tv_usec - begtime.tv_usec;
557     }
558     else
559     {
560         dif_timeval->tv_sec--;
561         dif_timeval->tv_usec = (endtime.tv_usec + 1000000) - begtime.tv_usec;
562     }
563 
564     return ((dif_timeval->tv_sec < 0 || dif_timeval->tv_usec < 0) ? -1 : 0);
565 }
566 
567 /* Add 'dif_timeval' to 'accum_timeval' (use to accumulate elapsed times) */
568 /* Return code: success == 0, error == -1 (accum_timeval result negative) */
569 
timeval_add(struct timeval * dif_timeval,struct timeval * accum_timeval)570 DLL_EXPORT int timeval_add
571 (
572     struct timeval *dif_timeval,
573     struct timeval *accum_timeval
574 )
575 {
576     ASSERT ( dif_timeval   -> tv_sec >= 0  &&  dif_timeval   -> tv_usec >= 0 );
577     ASSERT ( accum_timeval -> tv_sec >= 0  &&  accum_timeval -> tv_usec >= 0 );
578 
579     accum_timeval->tv_sec  += dif_timeval->tv_sec;
580     accum_timeval->tv_usec += dif_timeval->tv_usec;
581 
582     if (accum_timeval->tv_usec > 1000000)
583     {
584         int nsec = accum_timeval->tv_usec / 1000000;
585         accum_timeval->tv_sec  += nsec;
586         accum_timeval->tv_usec -= nsec * 1000000;
587     }
588 
589     return ((accum_timeval->tv_sec < 0 || accum_timeval->tv_usec < 0) ? -1 : 0);
590 }
591 
592 /*
593   Easier to use timed_wait_condition that waits for
594   the specified relative amount of time without you
595   having to build an absolute timeout time yourself
596 */
timed_wait_condition_relative_usecs(COND * pCOND,LOCK * pLOCK,U32 usecs,struct timeval * pTV)597 DLL_EXPORT int timed_wait_condition_relative_usecs
598 (
599     COND*            pCOND,     // ptr to condition to wait on
600     LOCK*            pLOCK,     // ptr to controlling lock (must be held!)
601     U32              usecs,     // max #of microseconds to wait
602     struct timeval*  pTV        // [OPTIONAL] ptr to tod value (may be NULL)
603 )
604 {
605     struct timespec timeout_timespec;
606     struct timeval  now;
607 
608     if (!pTV)
609     {
610         pTV = &now;
611         gettimeofday( pTV, NULL );
612     }
613 
614     timeout_timespec.tv_sec  = pTV->tv_sec  + ( usecs / 1000000 );
615     timeout_timespec.tv_nsec = pTV->tv_usec + ( usecs % 1000000 );
616 
617     if ( timeout_timespec.tv_nsec > 1000000 )
618     {
619         timeout_timespec.tv_sec  += timeout_timespec.tv_nsec / 1000000;
620         timeout_timespec.tv_nsec %=                            1000000;
621     }
622 
623     timeout_timespec.tv_nsec *= 1000;
624 
625     return timed_wait_condition( pCOND, pLOCK, &timeout_timespec );
626 }
627 
628 /*********************************************************************
629   The following couple of Hercules 'utility' functions may be defined
630   elsewhere depending on which host platform we're being built for...
631   For Windows builds (e.g. MingW32), the functionality for the below
632   functions is defined in 'w32util.c'. For other host build platforms
633   (e.g. Linux, Apple, etc), the functionality for the below functions
634   is defined right here in 'hscutil.c'...
635  *********************************************************************/
636 
637 #if !defined(_MSVC_)
638 
639 /* THIS module (hscutil.c) is to provide the below functionality.. */
640 
641 /*
642   Returns outpath as a host filesystem compatible filename path.
643   This is a Cygwin-to-MSVC transitional period helper function.
644   On non-Windows platforms it simply copies inpath to outpath.
645   On Windows it converts inpath of the form "/cygdrive/x/foo.bar"
646   to outpath in the form "x:/foo.bar" for Windows compatibility.
647 */
hostpath(char * outpath,const char * inpath,size_t buffsize)648 DLL_EXPORT char *hostpath( char *outpath, const char *inpath, size_t buffsize )
649 {
650     if (inpath && outpath && buffsize > 1)
651         strlcpy( outpath, inpath, buffsize );
652     else if (outpath && buffsize)
653         *outpath = 0;
654     return outpath;
655 }
656 
657 /* Poor man's  "fcntl( fd, F_GETFL )"... */
658 /* (only returns access-mode flags and not any others) */
get_file_accmode_flags(int fd)659 DLL_EXPORT int get_file_accmode_flags( int fd )
660 {
661     int flags = fcntl( fd, F_GETFL );
662     return ( flags & O_ACCMODE );
663 }
664 
665 /* Set socket to blocking or non-blocking mode... */
socket_set_blocking_mode(int sfd,int blocking_mode)666 DLL_EXPORT int socket_set_blocking_mode( int sfd, int blocking_mode )
667 {
668     int flags = fcntl( sfd, F_GETFL );
669 
670     if ( blocking_mode )
671         flags &= ~O_NONBLOCK;
672     else
673         flags |=  O_NONBLOCK;
674 
675     return fcntl( sfd, F_SETFL, flags );
676 }
677 
678 /* Initialize/Deinitialize sockets package... */
socket_init(void)679 int  socket_init   ( void ) { return 0; }
socket_deinit(void)680 DLL_EXPORT int  socket_deinit ( void ) { return 0; }
681 
682 /* Determine whether a file descriptor is a socket or not... */
683 /* (returns 1==true if it's a socket, 0==false otherwise)    */
socket_is_socket(int sfd)684 DLL_EXPORT int socket_is_socket( int sfd )
685 {
686     struct stat st;
687     return ( fstat( sfd, &st ) == 0 && S_ISSOCK( st.st_mode ) );
688 }
689 /* Set the SO_KEEPALIVE option and timeout values for a
690    socket connection to detect when client disconnects */
socket_keepalive(int sfd,int idle_time,int probe_interval,int probe_count)691 void socket_keepalive( int sfd, int idle_time, int probe_interval,
692         int probe_count )
693 {
694     int rc, optval = 1;
695     rc = setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
696     if (rc) logmsg("HHCUT001I SO_KEEPALIVE rc=%d %s\n", rc, strerror(errno));
697 
698   #if defined(TCP_KEEPALIVE)
699     optval = idle_time;
700     rc = setsockopt(sfd, IPPROTO_TCP, TCP_KEEPALIVE, &optval, sizeof(optval));
701     if (rc) logmsg("HHCUT002I TCP_KEEPALIVE rc=%d %s\n", rc, strerror(errno));
702   #elif defined(TCP_KEEPIDLE)
703     optval = idle_time;
704     rc = setsockopt(sfd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, sizeof(optval));
705     if (rc) logmsg("HHCUT003I TCP_KEEPIDLE rc=%d %s\n", rc, strerror(errno));
706   #else
707     UNREFERENCED(idle_time);
708   #endif
709 
710   #if defined(TCP_KEEPINTVL)
711     optval = probe_interval;
712     rc = setsockopt(sfd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, sizeof(optval));
713     if (rc) logmsg("HHCUT004I TCP_KEEPINTVL rc=%d %s\n", rc, strerror(errno));
714   #else
715     UNREFERENCED(probe_interval);
716   #endif
717 
718   #if defined(TCP_KEEPCNT)
719     optval = probe_count;
720     rc = setsockopt(sfd, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval));
721     if (rc) logmsg("HHCUT005I TCP_KEEPCNT rc=%d %s\n", rc, strerror(errno));
722   #else
723     UNREFERENCED(probe_count);
724   #endif
725 }
726 
727 /* Hercules file open */
hopen(const char * path,int oflag,...)728 DLL_EXPORT int hopen(const char* path, int oflag, ...)
729 {
730     int pmode = 0;
731     if (oflag & O_CREAT)
732     {
733         va_list vargs;
734         va_start(vargs, oflag);
735         pmode = va_arg(vargs, int);
736     }
737     return open(path, oflag, pmode);
738 }
739 
740 #endif // !defined(_MSVC_)
741 
742 //////////////////////////////////////////////////////////////////////////////////////////
743 // (testing)
744 
cause_crash()745 DLL_EXPORT void cause_crash()
746 {
747     static int x = 0; x = x / x - x;
748 }
749 
750 //////////////////////////////////////////////////////////////////////////////////////////
751 
752 
753 /*******************************************/
754 /* Read/Write to socket functions          */
755 /*******************************************/
hgetc(int s)756 DLL_EXPORT int hgetc(int s)
757 {
758     char c;
759     int rc;
760     rc=recv(s,&c,1,0);
761     if(rc<1)
762     {
763         return EOF;
764     }
765     return c;
766 }
767 
hgets(char * b,size_t c,int s)768 DLL_EXPORT char * hgets(char *b,size_t c,int s)
769 {
770     size_t ix=0;
771     while(ix<c)
772     {
773         b[ix]=hgetc(s);
774 //      if(b[ix]==EOF)         /* GCC Warning: always false     @PJJ */
775 //                             /* due to -Wtype-limits;         @PJJ */
776         if ((int)b[ix] == EOF) /* Corrected.                    @PJJ */
777         {
778             return NULL;
779         }
780         b[ix+1]=0;
781         if(b[ix]=='\n')
782         {
783             return(b);
784         }
785         ix++;
786     }
787     return NULL;
788 }
789 
hwrite(int s,const char * bfr,size_t sz)790 DLL_EXPORT int hwrite(int s,const char *bfr,size_t sz)
791 {
792     return send(s,bfr,(int)sz,0); /* (int) cast is for _WIN64 */
793 }
794 
hprintf(int s,char * fmt,...)795 DLL_EXPORT int hprintf(int s,char *fmt,...)
796 {
797     char *bfr;
798     size_t bsize=1024;
799     int rc;
800     va_list vl;
801 
802     bfr=malloc(bsize);
803     while(1)
804     {
805         if(!bfr)
806         {
807             return -1;
808         }
809         va_start(vl,fmt);
810         rc=vsnprintf(bfr,bsize,fmt,vl);
811         va_end(vl);
812         if(rc<(int)bsize)
813         {
814             break;
815         }
816         bsize+=1024;
817         bfr=realloc(bfr,bsize);
818     }
819     rc=hwrite(s,bfr,strlen(bfr));
820     free(bfr);
821     return rc;
822 }
823 
824 /* Posix 1003.1e capabilities support */
825 
826 #if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_SYS_PRCTL_H) && defined(OPTION_CAPABILITIES)
827 /*-------------------------------------------------------------------*/
828 /* DROP root privileges but retain a capability                      */
829 /*-------------------------------------------------------------------*/
drop_privileges(int capa)830 DLL_EXPORT int drop_privileges(int capa)
831 {
832     uid_t    uid;
833     gid_t    gid;
834     cap_t   c;
835     int rc;
836     int failed;
837     cap_value_t v;
838     int have_capt;
839 
840     /* If *real* userid is root, no need to do all this */
841     uid=getuid();
842     if(!uid) return 0;
843 
844     failed=1;
845     have_capt=0;
846     do
847     {
848         c=cap_init();
849         if(!c) break;
850         have_capt=1;
851         v=capa;
852         rc=cap_set_flag(c,CAP_EFFECTIVE,1,&v,CAP_SET);
853         if(rc<0) break;
854         rc=cap_set_flag(c,CAP_INHERITABLE,1,&v,CAP_SET);
855         if(rc<0) break;
856         rc=cap_set_flag(c,CAP_PERMITTED,1,&v,CAP_SET);
857         if(rc<0) break;
858         rc=cap_set_proc(c);
859         if(rc<0) break;
860         rc=prctl(PR_SET_KEEPCAPS,1);
861         if(rc<0) break;
862         failed=0;
863     } while(0);
864     gid=getgid();
865     setregid(gid,gid);
866     setreuid(uid,uid);
867     if(!failed)
868     {
869         rc=cap_set_proc(c);
870         if(rc<0) failed=1;
871     }
872 
873     if(have_capt)
874         cap_free(c);
875 
876     return failed;
877 }
878 /*-------------------------------------------------------------------*/
879 /* DROP all capabilities                                             */
880 /*-------------------------------------------------------------------*/
drop_all_caps(void)881 DLL_EXPORT int drop_all_caps(void)
882 {
883     uid_t    uid;
884     cap_t   c;
885     int rc;
886     int failed;
887     int have_capt;
888 
889     /* If *real* userid is root, no need to do all this */
890     uid=getuid();
891     if(!uid) return 0;
892 
893     failed=1;
894     have_capt=0;
895     do
896     {
897         c=cap_from_text("all-eip");
898         if(!c) break;
899         have_capt=1;
900         rc=cap_set_proc(c);
901         if(rc<0) break;
902         failed=0;
903     } while(0);
904 
905     if(have_capt)
906         cap_free(c);
907 
908     return failed;
909 }
910 #endif
911