michael@0: /** michael@0: util.c michael@0: michael@0: michael@0: Copyright (C) 2001-2003, Network Resonance, Inc. michael@0: Copyright (C) 2006, Network Resonance, Inc. michael@0: All Rights Reserved michael@0: michael@0: Redistribution and use in source and binary forms, with or without michael@0: modification, are permitted provided that the following conditions michael@0: are met: michael@0: michael@0: 1. Redistributions of source code must retain the above copyright michael@0: notice, this list of conditions and the following disclaimer. michael@0: 2. Redistributions in binary form must reproduce the above copyright michael@0: notice, this list of conditions and the following disclaimer in the michael@0: documentation and/or other materials provided with the distribution. michael@0: 3. Neither the name of Network Resonance, Inc. nor the name of any michael@0: contributors to this software may be used to endorse or promote michael@0: products derived from this software without specific prior written michael@0: permission. michael@0: michael@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' michael@0: AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE michael@0: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE michael@0: ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE michael@0: LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR michael@0: CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF michael@0: SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS michael@0: INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN michael@0: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) michael@0: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE michael@0: POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: michael@0: ekr@rtfm.com Wed Dec 26 17:19:36 2001 michael@0: */ michael@0: michael@0: michael@0: static char *RCSSTRING __UNUSED__ ="$Id: util.c,v 1.5 2007/11/21 00:09:13 adamcain Exp $"; michael@0: michael@0: #ifndef WIN32 michael@0: #include michael@0: #include michael@0: #include michael@0: #endif michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #ifdef OPENSSL michael@0: #include michael@0: #endif michael@0: #include "nr_common.h" michael@0: #include "r_common.h" michael@0: #include "registry.h" michael@0: #include "util.h" michael@0: #include "r_log.h" michael@0: michael@0: int nr_util_default_log_facility=LOG_COMMON; michael@0: michael@0: int nr_get_filename(base,name,namep) michael@0: char *base; michael@0: char *name; michael@0: char **namep; michael@0: { michael@0: int len=strlen(base)+strlen(name)+2; michael@0: char *ret=0; michael@0: int _status; michael@0: michael@0: if(!(ret=(char *)RMALLOC(len))) michael@0: ABORT(R_NO_MEMORY); michael@0: if(base[strlen(base)-1]!='/'){ michael@0: sprintf(ret,"%s/%s",base,name); michael@0: } michael@0: else{ michael@0: sprintf(ret,"%s%s",base,name); michael@0: } michael@0: *namep=ret; michael@0: _status=0; michael@0: abort: michael@0: return(_status); michael@0: } michael@0: michael@0: #if 0 michael@0: int read_RSA_private_key(base,name,keyp) michael@0: char *base; michael@0: char *name; michael@0: RSA **keyp; michael@0: { michael@0: char *keyfile=0; michael@0: BIO *bio=0; michael@0: FILE *fp=0; michael@0: RSA *rsa=0; michael@0: int r,_status; michael@0: michael@0: /* Load the keyfile */ michael@0: if(r=get_filename(base,name,&keyfile)) michael@0: ABORT(r); michael@0: if(!(fp=fopen(keyfile,"r"))) michael@0: ABORT(R_NOT_FOUND); michael@0: if(!(bio=BIO_new(BIO_s_file()))) michael@0: ABORT(R_NO_MEMORY); michael@0: BIO_set_fp(bio,fp,BIO_NOCLOSE); michael@0: michael@0: if(!(rsa=PEM_read_bio_RSAPrivateKey(bio,0,0,0))) michael@0: ABORT(R_NOT_FOUND); michael@0: michael@0: *keyp=rsa; michael@0: _status=0; michael@0: abort: michael@0: return(_status); michael@0: } michael@0: #endif michael@0: michael@0: michael@0: void nr_errprintf_log(const char *format,...) michael@0: { michael@0: va_list ap; michael@0: michael@0: va_start(ap,format); michael@0: michael@0: r_vlog(nr_util_default_log_facility,LOG_ERR,format,ap); michael@0: michael@0: va_end(ap); michael@0: } michael@0: michael@0: void nr_errprintf_log2(void *ignore, const char *format,...) michael@0: { michael@0: va_list ap; michael@0: michael@0: va_start(ap,format); michael@0: michael@0: r_vlog(nr_util_default_log_facility,LOG_ERR,format,ap); michael@0: michael@0: va_end(ap); michael@0: } michael@0: michael@0: michael@0: int nr_fwrite_all(FILE *fp,UCHAR *buf,int len) michael@0: { michael@0: int r,_status; michael@0: michael@0: while(len){ michael@0: r=fwrite(buf,1,len,fp); michael@0: if(r==0) michael@0: ABORT(R_IO_ERROR); michael@0: michael@0: len-=r; michael@0: buf+=r; michael@0: } michael@0: michael@0: _status=0; michael@0: abort: michael@0: return(_status); michael@0: } michael@0: michael@0: int nr_read_data(fd,buf,len) michael@0: int fd; michael@0: char *buf; michael@0: int len; michael@0: { michael@0: int r,_status; michael@0: michael@0: while(len){ michael@0: r=NR_SOCKET_READ(fd,buf,len); michael@0: if(r<=0) michael@0: ABORT(R_EOD); michael@0: michael@0: buf+=r; michael@0: len-=r; michael@0: } michael@0: michael@0: michael@0: _status=0; michael@0: abort: michael@0: return(_status); michael@0: } michael@0: michael@0: #ifdef WIN32 michael@0: // TODO michael@0: #else michael@0: int nr_drop_privileges(char *username) michael@0: { michael@0: int _status; michael@0: michael@0: /* Drop privileges */ michael@0: if ((getuid() == 0) || geteuid()==0) { michael@0: struct passwd *passwd; michael@0: michael@0: if ((passwd = getpwnam(CAPTURE_USER)) == 0){ michael@0: r_log(LOG_GENERIC,LOG_EMERG,"Couldn't get user %s",CAPTURE_USER); michael@0: ABORT(R_INTERNAL); michael@0: } michael@0: michael@0: if(setuid(passwd->pw_uid)!=0){ michael@0: r_log(LOG_GENERIC,LOG_EMERG,"Couldn't drop privileges"); michael@0: ABORT(R_INTERNAL); michael@0: } michael@0: } michael@0: michael@0: _status=0; michael@0: abort: michael@0: return(_status); michael@0: } michael@0: #endif michael@0: michael@0: int nr_bin2hex(UCHAR *in,int len,UCHAR *out) michael@0: { michael@0: while(len){ michael@0: sprintf((char*)out,"%.2x",in[0] & 0xff); michael@0: michael@0: in+=1; michael@0: out+=2; michael@0: michael@0: len--; michael@0: } michael@0: michael@0: return(0); michael@0: } michael@0: michael@0: int nr_hex_ascii_dump(Data *data) michael@0: { michael@0: UCHAR *ptr=data->data; michael@0: int len=data->len; michael@0: michael@0: while(len){ michael@0: int i; michael@0: int bytes=MIN(len,16); michael@0: michael@0: for(i=0;i michael@0: michael@0: int nr_rm_tree(char *path) michael@0: { michael@0: FTS *fts=0; michael@0: FTSENT *p; michael@0: int failed=0; michael@0: int _status; michael@0: char *argv[2]; michael@0: michael@0: argv[0]=path; michael@0: argv[1]=0; michael@0: michael@0: if(!(fts=fts_open(argv,0,NULL))){ michael@0: r_log_e(LOG_COMMON,LOG_ERR,"Couldn't open directory %s",path); michael@0: ABORT(R_FAILED); michael@0: } michael@0: michael@0: while(p=fts_read(fts)){ michael@0: switch(p->fts_info){ michael@0: case FTS_D: michael@0: break; michael@0: case FTS_DOT: michael@0: break; michael@0: case FTS_ERR: michael@0: r_log_e(LOG_COMMON,LOG_ERR,"Problem reading %s",p->fts_path); michael@0: break; michael@0: default: michael@0: r_log(LOG_COMMON,LOG_DEBUG,"Removing %s",p->fts_path); michael@0: errno=0; michael@0: if(remove(p->fts_path)){ michael@0: r_log_e(LOG_COMMON,LOG_ERR,"Problem removing %s",p->fts_path); michael@0: failed=1; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if(failed) michael@0: ABORT(R_FAILED); michael@0: michael@0: _status=0; michael@0: abort: michael@0: if(fts) fts_close(fts); michael@0: return(_status); michael@0: } michael@0: #endif michael@0: michael@0: int nr_write_pid_file(char *pid_filename) michael@0: { michael@0: FILE *fp; michael@0: int _status; michael@0: michael@0: if(!pid_filename) michael@0: ABORT(R_BAD_ARGS); michael@0: michael@0: unlink(pid_filename); michael@0: michael@0: if(!(fp=fopen(pid_filename,"w"))){ michael@0: r_log(LOG_GENERIC,LOG_CRIT,"Couldn't open PID file: %s",strerror(errno)); michael@0: ABORT(R_NOT_FOUND); michael@0: } michael@0: michael@0: fprintf(fp,"%d\n",getpid()); michael@0: michael@0: fclose(fp); michael@0: michael@0: chmod(pid_filename,S_IRUSR | S_IRGRP | S_IROTH); michael@0: michael@0: _status=0; michael@0: abort: michael@0: return(_status); michael@0: } michael@0: #endif michael@0: michael@0: int nr_reg_uint4_fetch_and_check(NR_registry key, UINT4 min, UINT4 max, int log_fac, int die, UINT4 *val) michael@0: { michael@0: int r,_status; michael@0: UINT4 my_val; michael@0: michael@0: if(r=NR_reg_get_uint4(key,&my_val)){ michael@0: r_log(log_fac,LOG_ERR,"Couldn't get key '%s', error %d",key,r); michael@0: ABORT(r); michael@0: } michael@0: michael@0: if((min>0) && (my_valmax){ michael@0: r_log(log_fac,LOG_ERR,"Invalid value for key '%s'=%lu, (max = %lu)",key,(unsigned long)my_val,(unsigned long)max); michael@0: ABORT(R_BAD_DATA); michael@0: } michael@0: michael@0: *val=my_val; michael@0: _status=0; michael@0: michael@0: abort: michael@0: if(die && _status){ michael@0: r_log(log_fac,LOG_CRIT,"Exiting due to invalid configuration (key '%s')",key); michael@0: exit(1); michael@0: } michael@0: return(_status); michael@0: } michael@0: michael@0: int nr_reg_uint8_fetch_and_check(NR_registry key, UINT8 min, UINT8 max, int log_fac, int die, UINT8 *val) michael@0: { michael@0: int r,_status; michael@0: UINT8 my_val; michael@0: michael@0: if(r=NR_reg_get_uint8(key,&my_val)){ michael@0: r_log(log_fac,LOG_ERR,"Couldn't get key '%s', error %d",key,r); michael@0: ABORT(r); michael@0: } michael@0: michael@0: if(my_valmax){ michael@0: r_log(log_fac,LOG_ERR,"Invalid value for key '%s'=%llu, (max = %llu)",key,my_val,max); michael@0: ABORT(R_BAD_DATA); michael@0: } michael@0: michael@0: *val=my_val; michael@0: _status=0; michael@0: michael@0: abort: michael@0: if(die && _status){ michael@0: r_log(log_fac,LOG_CRIT,"Exiting due to invalid configuration (key '%s')",key); michael@0: exit(1); michael@0: } michael@0: return(_status); michael@0: } michael@0: michael@0: #if defined(LINUX) || defined(WIN32) michael@0: /*- michael@0: * Copyright (c) 1998 Todd C. Miller michael@0: * All rights reserved. michael@0: * michael@0: * Redistribution and use in source and binary forms, with or without michael@0: * modification, are permitted provided that the following conditions michael@0: * are met: michael@0: * 1. Redistributions of source code must retain the above copyright michael@0: * notice, this list of conditions and the following disclaimer. michael@0: * 2. Redistributions in binary form must reproduce the above copyright michael@0: * notice, this list of conditions and the following disclaimer in the michael@0: * documentation and/or other materials provided with the distribution. michael@0: * 3. The name of the author may not be used to endorse or promote products michael@0: * derived from this software without specific prior written permission. michael@0: * michael@0: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, michael@0: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY michael@0: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL michael@0: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, michael@0: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, michael@0: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; michael@0: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, michael@0: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR michael@0: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF michael@0: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: */ michael@0: michael@0: michael@0: /* michael@0: * Appends src to string dst of size siz (unlike strncat, siz is the michael@0: * full size of dst, not space left). At most siz-1 characters michael@0: * will be copied. Always NUL terminates (unless siz <= strlen(dst)). michael@0: * Returns strlen(src) + MIN(siz, strlen(initial dst)). michael@0: * If retval >= siz, truncation occurred. michael@0: */ michael@0: size_t michael@0: strlcat(dst, src, siz) michael@0: char *dst; michael@0: const char *src; michael@0: size_t siz; michael@0: { michael@0: char *d = dst; michael@0: const char *s = src; michael@0: size_t n = siz; michael@0: size_t dlen; michael@0: michael@0: /* Find the end of dst and adjust bytes left but don't go past end */ michael@0: while (n-- != 0 && *d != '\0') michael@0: d++; michael@0: dlen = d - dst; michael@0: n = siz - dlen; michael@0: michael@0: if (n == 0) michael@0: return(dlen + strlen(s)); michael@0: while (*s != '\0') { michael@0: if (n != 1) { michael@0: *d++ = *s; michael@0: n--; michael@0: } michael@0: s++; michael@0: } michael@0: *d = '\0'; michael@0: michael@0: return(dlen + (s - src)); /* count does not include NUL */ michael@0: } michael@0: michael@0: #endif /* LINUX or WIN32 */ michael@0: michael@0: #if defined(USE_OWN_INET_NTOP) || defined(WIN32) michael@0: #include michael@0: #ifdef WIN32 michael@0: #include michael@0: #ifndef EAFNOSUPPORT michael@0: #define EAFNOSUPPORT WSAEAFNOSUPPORT michael@0: #endif michael@0: #else michael@0: #include michael@0: #endif michael@0: #define INET6 michael@0: michael@0: /* inet_ntop implementation from NetBSD */ michael@0: michael@0: /* michael@0: * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") michael@0: * Copyright (c) 1996-1999 by Internet Software Consortium. michael@0: * michael@0: * Permission to use, copy, modify, and distribute this software for any michael@0: * purpose with or without fee is hereby granted, provided that the above michael@0: * copyright notice and this permission notice appear in all copies. michael@0: * michael@0: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES michael@0: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF michael@0: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR michael@0: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES michael@0: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN michael@0: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT michael@0: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. michael@0: */ michael@0: michael@0: #if !defined(NS_INADDRSZ) michael@0: # define NS_INADDRSZ 4 michael@0: #endif michael@0: #if !defined(NS_IN6ADDRSZ) michael@0: # define NS_IN6ADDRSZ 16 michael@0: #endif michael@0: #if !defined(NS_INT16SZ) michael@0: # define NS_INT16SZ 2 michael@0: #endif michael@0: michael@0: /* michael@0: * WARNING: Don't even consider trying to compile this on a system where michael@0: * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. michael@0: */ michael@0: michael@0: static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size); michael@0: #ifdef INET6 michael@0: static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size); michael@0: #endif /* INET6 */ michael@0: michael@0: /* char * michael@0: * inet_ntop(af, src, dst, size) michael@0: * convert a network format address to presentation format. michael@0: * return: michael@0: * pointer to presentation format address (`dst'), or NULL (see errno). michael@0: * author: michael@0: * Paul Vixie, 1996. michael@0: */ michael@0: const char * michael@0: inet_ntop(int af, const void *src, char *dst, size_t size) michael@0: { michael@0: michael@0: switch (af) { michael@0: case AF_INET: michael@0: return (inet_ntop4(src, dst, size)); michael@0: #ifdef INET6 michael@0: case AF_INET6: michael@0: return (inet_ntop6(src, dst, size)); michael@0: #endif /* INET6 */ michael@0: default: michael@0: errno = EAFNOSUPPORT; michael@0: return (NULL); michael@0: } michael@0: /* NOTREACHED */ michael@0: } michael@0: michael@0: /* const char * michael@0: * inet_ntop4(src, dst, size) michael@0: * format an IPv4 address, more or less like inet_ntoa() michael@0: * return: michael@0: * `dst' (as a const) michael@0: * notes: michael@0: * (1) uses no statics michael@0: * (2) takes a unsigned char* not an in_addr as input michael@0: * author: michael@0: * Paul Vixie, 1996. michael@0: */ michael@0: static const char * michael@0: inet_ntop4(const unsigned char *src, char *dst, size_t size) michael@0: { michael@0: char tmp[sizeof "255.255.255.255"]; michael@0: int l; michael@0: michael@0: l = snprintf(tmp, sizeof(tmp), "%u.%u.%u.%u", michael@0: src[0], src[1], src[2], src[3]); michael@0: if (l <= 0 || (size_t) l >= size) { michael@0: errno = ENOSPC; michael@0: return (NULL); michael@0: } michael@0: strlcpy(dst, tmp, size); michael@0: return (dst); michael@0: } michael@0: michael@0: #ifdef INET6 michael@0: /* const char * michael@0: * inet_ntop6(src, dst, size) michael@0: * convert IPv6 binary address into presentation (printable) format michael@0: * author: michael@0: * Paul Vixie, 1996. michael@0: */ michael@0: static const char * michael@0: inet_ntop6(const unsigned char *src, char *dst, size_t size) michael@0: { michael@0: /* michael@0: * Note that int32_t and int16_t need only be "at least" large enough michael@0: * to contain a value of the specified size. On some systems, like michael@0: * Crays, there is no such thing as an integer variable with 16 bits. michael@0: * Keep this in mind if you think this function should have been coded michael@0: * to use pointer overlays. All the world's not a VAX. michael@0: */ michael@0: char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; michael@0: char *tp, *ep; michael@0: struct { int base, len; } best, cur; michael@0: unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; michael@0: int i; michael@0: int advance; michael@0: michael@0: /* michael@0: * Preprocess: michael@0: * Copy the input (bytewise) array into a wordwise array. michael@0: * Find the longest run of 0x00's in src[] for :: shorthanding. michael@0: */ michael@0: memset(words, '\0', sizeof words); michael@0: for (i = 0; i < NS_IN6ADDRSZ; i++) michael@0: words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); michael@0: best.base = -1; michael@0: cur.base = -1; michael@0: best.len = -1; /* XXX gcc */ michael@0: cur.len = -1; /* XXX gcc */ michael@0: for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { michael@0: if (words[i] == 0) { michael@0: if (cur.base == -1) michael@0: cur.base = i, cur.len = 1; michael@0: else michael@0: cur.len++; michael@0: } else { michael@0: if (cur.base != -1) { michael@0: if (best.base == -1 || cur.len > best.len) michael@0: best = cur; michael@0: cur.base = -1; michael@0: } michael@0: } michael@0: } michael@0: if (cur.base != -1) { michael@0: if (best.base == -1 || cur.len > best.len) michael@0: best = cur; michael@0: } michael@0: if (best.base != -1 && best.len < 2) michael@0: best.base = -1; michael@0: michael@0: /* michael@0: * Format the result. michael@0: */ michael@0: tp = tmp; michael@0: ep = tmp + sizeof(tmp); michael@0: for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { michael@0: /* Are we inside the best run of 0x00's? */ michael@0: if (best.base != -1 && i >= best.base && michael@0: i < (best.base + best.len)) { michael@0: if (i == best.base) michael@0: *tp++ = ':'; michael@0: continue; michael@0: } michael@0: /* Are we following an initial run of 0x00s or any real hex? */ michael@0: if (i != 0) { michael@0: if (tp + 1 >= ep) michael@0: return (NULL); michael@0: *tp++ = ':'; michael@0: } michael@0: /* Is this address an encapsulated IPv4? */ michael@0: if (i == 6 && best.base == 0 && michael@0: (best.len == 6 || michael@0: (best.len == 7 && words[7] != 0x0001) || michael@0: (best.len == 5 && words[5] == 0xffff))) { michael@0: if (!inet_ntop4(src+12, tp, (size_t)(ep - tp))) michael@0: return (NULL); michael@0: tp += strlen(tp); michael@0: break; michael@0: } michael@0: advance = snprintf(tp, (size_t)(ep - tp), "%x", words[i]); michael@0: if (advance <= 0 || advance >= ep - tp) michael@0: return (NULL); michael@0: tp += advance; michael@0: } michael@0: /* Was it a trailing run of 0x00's? */ michael@0: if (best.base != -1 && (best.base + best.len) == michael@0: (NS_IN6ADDRSZ / NS_INT16SZ)) { michael@0: if (tp + 1 >= ep) michael@0: return (NULL); michael@0: *tp++ = ':'; michael@0: } michael@0: if (tp + 1 >= ep) michael@0: return (NULL); michael@0: *tp++ = '\0'; michael@0: michael@0: /* michael@0: * Check for overflow, copy, and we're done. michael@0: */ michael@0: if ((size_t)(tp - tmp) > size) { michael@0: errno = ENOSPC; michael@0: return (NULL); michael@0: } michael@0: strlcpy(dst, tmp, size); michael@0: return (dst); michael@0: } michael@0: #endif /* INET6 */ michael@0: michael@0: #endif michael@0: michael@0: #ifdef WIN32 michael@0: #include michael@0: /* this is only millisecond-accurate, but that should be OK */ michael@0: michael@0: int gettimeofday(struct timeval *tv, void *tz) michael@0: { michael@0: SYSTEMTIME st; michael@0: FILETIME ft; michael@0: ULARGE_INTEGER u; michael@0: michael@0: GetLocalTime (&st); michael@0: michael@0: /* strangely, the FILETIME is the number of 100 nanosecond (0.1 us) intervals michael@0: * since the Epoch */ michael@0: SystemTimeToFileTime(&st, &ft); michael@0: u.HighPart = ft.dwHighDateTime; michael@0: u.LowPart = ft.dwLowDateTime; michael@0: michael@0: tv->tv_sec = (long) (u.QuadPart / 10000000L); michael@0: tv->tv_usec = (long) (st.wMilliseconds * 1000);; michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: int snprintf(char *buffer, size_t n, const char *format, ...) michael@0: { michael@0: va_list argp; michael@0: int ret; michael@0: va_start(argp, format); michael@0: ret = _vscprintf(format, argp); michael@0: vsnprintf_s(buffer, n, _TRUNCATE, format, argp); michael@0: va_end(argp); michael@0: return ret; michael@0: } michael@0: michael@0: #endif michael@0: