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