Red Hat issue 1021948: snprintf API change

This commit is contained in:
Gerhard Rieger 2014-03-26 15:05:28 +01:00
parent 1d8b6bbb9b
commit 622b6b22f4
8 changed files with 74 additions and 53 deletions

View file

@ -152,6 +152,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
libwrap always logs to syslog
added actual text version of GPLv2

View file

@ -1,5 +1,5 @@
/* source: compat.h */
/* Copyright Gerhard Rieger 2001-2012 */
/* 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

@ -438,6 +438,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

@ -1300,11 +1300,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(){
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; /* errno is valid */
}
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 */
>= 0 textlen) {
errno = ENOSPC; return NULL; /* errno is valid */
}
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;
}

19
utils.c
View file

@ -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

@ -1,5 +1,5 @@
/* source: utils.h */
/* Copyright Gerhard Rieger 2001-2008 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __utils_h_included
@ -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';
}