Red Hat issue 1021948: snprintf API change

This commit is contained in:
Gerhard Rieger 2014-01-26 17:45:09 +01:00
parent 52e8a5ec2b
commit cf39583b25
8 changed files with 74 additions and 53 deletions

View file

@ -62,6 +62,11 @@ porting:
use getgrouplist() when available instead of sequence of calls to
getgrent()
Red Hat issue 1021948: snprintf API change;
Implemented xio_snprintf() function as wrapper that tries to emulate C99
behaviour on old glibc systems, and adapted all affected calls
appropriately
docu:
libwrap always logs to syslog

View file

@ -1,5 +1,5 @@
/* source: compat.h */
/* Copyright Gerhard Rieger 2001-2011 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __compat_h_included
@ -622,34 +622,4 @@
extern const char *hstrerror(int);
#endif
/*****************************************************************************/
/* here are the declarations of compat.c */
#if !HAVE_SIGACTION
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
} ;
struct siginfo {
int si_signo;
int si_errno;
int si_code;
pid_t si_pid;
uid_t si_uid;
int si_status;
/*clock_t si_utime;*/
/*clock_t si_stime;*/
sigval_t si_value;
int si_int;
void *si_ptr;
void *si_addr;
/*int si_band;*/
/*int si_fd;*/
} ;
extern int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
#endif /* !HAVE_SIGACTION */
#endif /* !defined(__compat_h_included) */

View file

@ -439,6 +439,9 @@
/* is uint64_t already defined? */
#undef HAVE_TYPE_UINT64
/* Define if snprintf() returns required len on truncation (C-99 conform) */
#undef HAVE_C99_SNPRINTF
/* Define if you have the printf "Z" modifier */
#undef HAVE_FORMAT_Z

View file

@ -1284,11 +1284,29 @@ AC_CHECK_FUNC(SSLv2_server_method, AC_DEFINE(HAVE_SSLv2_server_method), AC_CHECK
dnl Run time checks
AC_MSG_CHECKING(if snprintf conforms to C99)
AC_CACHE_VAL(ac_cv_have_c99_snprintf,
[AC_TRY_RUN([
#include <stdio.h>
#include <stdlib.h>
int main(void){
char s[2];
exit(snprintf(s,2,"ab")!=2);
}],
[ac_cv_have_c99_snprintf=yes],
[ac_cv_have_c99_snprintf=no],
[ac_cv_have_c99_snprintf=no])])
if test $ac_cv_have_c99_snprintf = yes; then
AC_DEFINE(HAVE_C99_SNPRINTF)
fi
AC_MSG_RESULT($ac_cv_have_c99_snprintf)
AC_MSG_CHECKING(if printf has Z modifier)
AC_CACHE_VAL(ac_cv_have_z_modifier,
[AC_TRY_RUN([
#include <stdio.h>
main(){
int main(void){
char s[16];
sprintf(s,"%Zu",1);
exit(strcmp(s,"1"));

View file

@ -173,14 +173,16 @@ char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size
int n;
#if HAVE_STRUCT_SOCKADDR_SALEN
if ((n = snprintf(cp, blen, "LEN=%d ", sau->soa.sa_len)) < 0) {
n = xio_snprintf(cp, blen, "LEN=%d ", sau->soa.sa_len);
if (n < 0 || n >= blen) {
Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
*buff = '\0';
return buff;
}
cp += n, blen -= n;
#endif
if ((n = snprintf(cp, blen, "AF=%d ", sau->soa.sa_family)) < 0) {
n = xio_snprintf(cp, blen, "AF=%d ", sau->soa.sa_family);
if (n < 0 || n >= blen) {
Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
*buff = '\0';
return buff;
@ -204,13 +206,14 @@ char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size
break;
#endif
default:
if ((n = snprintf(cp, blen, "AF=%d ", sa->sa_family)) < 0) {
n = xio_snprintf(cp, blen, "AF=%d ", sa->sa_family);
if (n < 0 || n >= blen) {
Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
*buff = '\0';
return buff;
}
cp += n, blen -= n;
if ((snprintf(cp, blen,
n = xio_snprintf(cp, blen,
"0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
((unsigned char *)sau->soa.sa_data)[0],
((unsigned char *)sau->soa.sa_data)[1],
@ -225,7 +228,8 @@ char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size
((unsigned char *)sau->soa.sa_data)[10],
((unsigned char *)sau->soa.sa_data)[11],
((unsigned char *)sau->soa.sa_data)[12],
((unsigned char *)sau->soa.sa_data)[13])) < 0) {
((unsigned char *)sau->soa.sa_data)[13]);
if (n < 0 || n >= blen) {
Warn("sockaddr_info(): buffer too short");
*buff = '\0';
return buff;
@ -268,9 +272,9 @@ char *sockaddr_unix_info(const struct sockaddr_un *sa, socklen_t salen, char *bu
#if WITH_IP4
/* addr in host byte order! */
char *inet4addr_info(uint32_t addr, char *buff, size_t blen) {
if (snprintf(buff, blen, "%u.%u.%u.%u",
if (xio_snprintf(buff, blen, "%u.%u.%u.%u",
(unsigned int)(addr >> 24), (unsigned int)((addr >> 16) & 0xff),
(unsigned int)((addr >> 8) & 0xff), (unsigned int)(addr & 0xff)) < 0) {
(unsigned int)((addr >> 8) & 0xff), (unsigned int)(addr & 0xff)) >= blen) {
Warn("inet4addr_info(): buffer too short");
buff[blen-1] = '\0';
}
@ -280,12 +284,12 @@ char *inet4addr_info(uint32_t addr, char *buff, size_t blen) {
#if WITH_IP4
char *sockaddr_inet4_info(const struct sockaddr_in *sa, char *buff, size_t blen) {
if (snprintf(buff, blen, "%u.%u.%u.%u:%hu",
if (xio_snprintf(buff, blen, "%u.%u.%u.%u:%hu",
((unsigned char *)&sa->sin_addr.s_addr)[0],
((unsigned char *)&sa->sin_addr.s_addr)[1],
((unsigned char *)&sa->sin_addr.s_addr)[2],
((unsigned char *)&sa->sin_addr.s_addr)[3],
htons(sa->sin_port)) < 0) {
htons(sa->sin_port)) >= blen) {
Warn("sockaddr_inet4_info(): buffer too short");
buff[blen-1] = '\0';
}
@ -301,19 +305,19 @@ const char *inet_ntop(int pf, const void *binaddr,
switch (pf) {
case PF_INET:
if ((retlen =
snprintf(addrtext, textlen, "%u.%u.%u.%u",
xio_snprintf(addrtext, textlen, "%u.%u.%u.%u",
((unsigned char *)binaddr)[0],
((unsigned char *)binaddr)[1],
((unsigned char *)binaddr)[2],
((unsigned char *)binaddr)[3]))
< 0) {
return NULL; /* errno is valid */
>= textlen) {
errno = ENOSPC; return NULL;
}
break;
#if WITH_IP6
case PF_INET6:
if ((retlen =
snprintf(addrtext, textlen, "%x:%x:%x:%x:%x:%x:%x:%x",
xio_snprintf(addrtext, textlen, "%x:%x:%x:%x:%x:%x:%x:%x",
ntohs(((uint16_t *)binaddr)[0]),
ntohs(((uint16_t *)binaddr)[1]),
ntohs(((uint16_t *)binaddr)[2]),
@ -323,8 +327,8 @@ const char *inet_ntop(int pf, const void *binaddr,
ntohs(((uint16_t *)binaddr)[6]),
ntohs(((uint16_t *)binaddr)[7])
))
< 0) {
return NULL; /* errno is valid */
>= textlen) {
errno = ENOSPC; return NULL;
}
break;
#endif /* WITH_IP6 */
@ -341,7 +345,7 @@ const char *inet_ntop(int pf, const void *binaddr,
/* convert the IP6 socket address to human readable form. buff should be at
least 50 chars long. output includes the port number */
char *sockaddr_inet6_info(const struct sockaddr_in6 *sa, char *buff, size_t blen) {
if (snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%hu",
if (xio_snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%hu",
#if HAVE_IP6_SOCKADDR==0
(sa->sin6_addr.s6_addr[0]<<8)+
sa->sin6_addr.s6_addr[1],
@ -405,9 +409,8 @@ char *sockaddr_inet6_info(const struct sockaddr_in6 *sa, char *buff, size_t blen
ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[6]),
ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[7]),
#endif
ntohs(sa->sin6_port)) < 0) {
ntohs(sa->sin6_port)) >= blen) {
Warn("sockaddr_inet6_info(): buffer too short");
buff[blen-1] = '\0';
}
return buff;
}

21
utils.c
View file

@ -1,5 +1,5 @@
/* source: utils.c */
/* Copyright Gerhard Rieger 2001-2009 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
/* useful additions to C library */
@ -161,3 +161,22 @@ char *xiosubstr(char *scratch, const char *str, size_t from, size_t len) {
return scratch0;
}
/* since version 1.7.2.4 socat supports C-99 behaviour of snprintf but still
can handle the old glibc case with -1 return on truncation.
Do not rely on exact return value in case of truncation
*/
int xio_snprintf(char *str, size_t size, const char *format, ...) {
va_list ap;
int result;
va_start(ap, format);
result = vsnprintf(str, size, format, ap);
#if ! HAVE_C99_SNPRINTF
if (result < 0) {
result = size+63; /* indicate truncation with just some guess */
}
#endif /* !HAVE_C99_SNPRINTF */
va_end(ap);
return result;
}

View file

@ -66,4 +66,7 @@ char *sanitize_string(const char *data, /* input data */
extern
char *xiosubstr(char *scratch, const char *str, size_t from, size_t len);
extern
int xio_snprintf(char *str, size_t size, const char *format, ...);
#endif /* !defined(__utils_h_included) */

View file

@ -312,7 +312,7 @@ int xiolog_ancillary_ip6(struct cmsghdr *cmsg, int *num,
/* convert the IP6 socket address to human readable form. buff should be at
least 50 chars long. output includes the port number */
static char *inet6addr_info(const struct in6_addr *sa, char *buff, size_t blen) {
if (snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
if (xio_snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
#if HAVE_IP6_SOCKADDR==0
(sa->s6_addr[0]<<8)+sa->s6_addr[1],
(sa->s6_addr[2]<<8)+sa->s6_addr[3],
@ -368,7 +368,7 @@ static char *inet6addr_info(const struct in6_addr *sa, char *buff, size_t blen)
ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[6]),
ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[7])
#endif
) < 0) {
) >= blen) {
Warn("sockaddr_inet6_info(): buffer too short");
buff[blen-1] = '\0';
}