/*****************************************************************
**
** @(#) misc.c -- helper functions for the dnssec zone key tools
**
** Copyright (c) Jan 2005, Holger Zuleger HZnet. All rights reserved.
**
** This software is open source.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** Redistributions of source code must retain the above copyright notice,
** this list of conditions and the following disclaimer.
**
** Redistributions in binary form must reproduce the above copyright notice,
** this list of conditions and the following disclaimer in the documentation
** and/or other materials provided with the distribution.
**
** Neither the name of Holger Zuleger HZnet nor the names of its contributors may
** be used to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
** POSSIBILITY OF SUCH DAMAGE.
**
*****************************************************************/
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <unistd.h> /* for link(), unlink() */
# include <ctype.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <time.h>
# include <utime.h>
# include <assert.h>
# include <errno.h>
# include <fcntl.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
# include "config_zkt.h"
# include "zconf.h"
# include "log.h"
# include "debug.h"
#define extern
# include "misc.h"
#undef extern
# define TAINTEDCHARS "`$@;&<>|"
extern const char *progname;
/*****************************************************************
** getnameappendix (progname, basename)
** return a pointer to the substring in progname subsequent
** following "<basename>-".
*****************************************************************/
const char *getnameappendix (const char *progname, const char *basename)
{
const char *p;
int baselen;
assert (progname != NULL);
assert (basename != NULL);
if ( (p = strrchr (progname, '/')) != NULL )
p++;
else
p = progname;
baselen = strlen (basename);
if ( strncmp (p, basename, baselen-1) == 0 && *(p+baselen) == '-' )
{
p += baselen + 1;
if ( *p )
return p;
}
return NULL;
}
/*****************************************************************
** getdefconfname (view)
** returns a pointer to a dynamic string containing the
** default configuration file name
*****************************************************************/
const char *getdefconfname (const char *view)
{
char *p;
char *file;
char *buf;
int size;
if ( (file = getenv ("ZKT_CONFFILE")) == NULL )
file = CONFIG_FILE;
dbg_val2 ("getdefconfname (%s) file = %s\n", view ? view : "NULL", file);
if ( view == NULL || *view == '\0' || (p = strrchr (file, '.')) == NULL )
return strdup (file);
size = strlen (file) + strlen (view) + 1 + 1;
if ( (buf = malloc (size)) == NULL )
return strdup (file);
dbg_val1 ("0123456789o123456789o123456789\tsize=%d\n", size);
dbg_val4 ("%.*s-%s%s\n", p - file, file, view, p);
snprintf (buf, size, "%.*s-%s%s", p - file, file, view, p);
return buf;
}
/*****************************************************************
** domain_canonicdup (s)
** returns NULL or a pointer to a dynamic string containing the
** canonic (all lower case letters and ending with a '.')
** domain name
*****************************************************************/
char *domain_canonicdup (const char *s)
{
char *new;
char *p;
int len;
int add_dot;
if ( s == NULL )
return NULL;
add_dot = 0;
len = strlen (s);
if ( len > 0 && s[len-1] != '.' )
add_dot = len++;
if ( (new = p = malloc (len + 1)) == NULL )
return NULL;
while ( *s )
*p++ = tolower (*s++);
if ( add_dot )
*p++ = '.';
*p = '\0';
return new;
}
#if 0 /* replaced by domain_canonicdup */
/*****************************************************************
** str_tolowerdup (s)
*****************************************************************/
char *str_tolowerdup (const char *s)
{
char *new;
char *p;
if ( s == NULL || (new = p = malloc (strlen (s) + 1)) == NULL )
return NULL;
while ( *s )
*p++ = tolower (*s++);
*p = '\0';
return new;
}
#endif
/*****************************************************************
** str_delspace (s)
** Remove in string 's' all white space char
*****************************************************************/
char *str_delspace (char *s)
{
char *start;
char *p;
if ( !s ) /* no string present ? */
return NULL;
start = s;
for ( p = s; *p; p++ )
if ( !isspace (*p) )
*s++ = *p; /* copy each nonspace */
*s = '\0'; /* terminate string */
return start;
}
/*****************************************************************
** in_strarr (str, arr, cnt)
** check if string array 'arr' contains the string 'str'
** return 1 if true or 'arr' or 'str' is empty, otherwise 0
*****************************************************************/
int in_strarr (const char *str, char *const arr[], int cnt)
{
if ( arr == NULL || cnt <= 0 )
return 1;
if ( str == NULL || *str == '\0' )
return 0;
while ( --cnt >= 0 )
if ( strcmp (str, arr[cnt]) == 0 )
return 1;
return 0;
}
/*****************************************************************
** str_untaint (s)
** Remove in string 's' all TAINTED chars
*****************************************************************/
char *str_untaint (char *str)
{
char *p;
assert (str != NULL);
for ( p = str; *p; p++ )
if ( strchr (TAINTEDCHARS, *p) )
*p = ' ';
return str;
}
/*****************************************************************
** str_chop (str, c)
** delete all occurrences of char 'c' at the end of string 's'
*****************************************************************/
char *str_chop (char *str, char c)
{
int len;
assert (str != NULL);
len = strlen (str) - 1;
while ( len >= 0 && str[len] == c )
str[len--] = '\0';
return str;
}
/*****************************************************************
** parseurl (url, &proto, &host, &port, &para )
** parses the given url (e.g. "proto://host.with.domain:port/para")
** and set the pointer variables to the corresponding part of the string.
*****************************************************************/
void parseurl (char *url, char **proto, char **host, char **port, char **para)
{
char *start;
char *p;
assert ( url != NULL );
/* parse protocol */
if ( (p = strchr (url, ':')) == NULL ) /* no protocol string given ? */
p = url;
else /* looks like a protocol string */
if ( p[1] == '/' && p[2] == '/' ) /* protocol string ? */
{
*p = '\0';
p += 3;
if ( proto )
*proto = url;
}
else /* no protocol string found ! */
p = url;
/* parse host */
if ( *p == '[' ) /* ipv6 address as hostname ? */
{
for ( start = ++p; *p && *p != ']'; p++ )
;
if ( *p )
*p++ = '\0';
}
else
for ( start = p; *p && *p != ':' && *p != '/'; p++ )
;
if ( host )
*host = start;
/* parse port */
if ( *p == ':' )
{
*p++ = '\0';
for ( start = p; *p && isdigit (*p); p++ )
;
if ( *p )
*p++ = '\0';
if ( port )
*port = start;
}
if ( *p == '/' )
*p++ = '\0';
if ( *p && para )
*para = p;
}
/*****************************************************************
** splitpath (path, pathsize, filename)
** if filename is build of "path/file" then copy filename to path
** and split of the filename part.
** return pointer to filename part in path or NULL if path is too
** small to hold "path+filename"
*****************************************************************/
const char *splitpath (char *path, size_t psize, const char *filename)
{
char *p;
if ( !path )
return NULL;
*path = '\0';
if ( !filename )
return filename;
if ( (p = strrchr (filename, '/')) ) /* file arg contains path ? */
{
if ( strlen (filename) + 1 > psize )
return filename;
strcpy (path, filename); /* copy whole filename to path */
path[p-filename] = '\0'; /* split of the file part */
filename = ++p;
}
return filename;
}
/*****************************************************************
** pathname (path, size, dir, file, ext)
** Concatenate 'dir', 'file' and 'ext' (if not null) to build
** a pathname, and store the result in the character array
** with length 'size' pointed to by 'path'.
*****************************************************************/
char *pathname (char *path, size_t size, const char *dir, const char *file, const char *ext)
{
int len;
if ( path == NULL || file == NULL )
return path;
len = strlen (file) + 1;
if ( dir )
len += strlen (dir);
if ( ext )
len += strlen (ext);
if ( len > size )
return path;
*path = '\0';
if ( dir && *dir )
{
len = sprintf (path, "%s", dir);
if ( path[len-1] != '/' )
{
path[len++] = '/';
path[len] = '\0';
}
}
strcat (path, file);
if ( ext )
strcat (path, ext);
return path;
}
/*****************************************************************
** is_directory (name)
** Check if the given pathname 'name' exists and is a directory.
** returns 0 | 1
*****************************************************************/
int is_directory (const char *name)
{
struct stat st;
if ( !name || !*name )
return 0;
return ( stat (name, &st) == 0 && S_ISDIR (st.st_mode) );
}
/*****************************************************************
** fileexist (name)
** Check if a file with the given pathname 'name' exists.
** returns 0 | 1
*****************************************************************/
int fileexist (const char *name)
{
struct stat st;
return ( stat (name, &st) == 0 && S_ISREG (st.st_mode) );
}
/*****************************************************************
** filesize (name)
** return the size of the file with the given pathname 'name'.
** returns -1 if the file not exist
*****************************************************************/
size_t filesize (const char *name)
{
struct stat st;
if ( stat (name, &st) == -1 )
return -1L;
return ( st.st_size );
}
/*****************************************************************
** is_keyfilename (name)
** Check if the given name looks like a dnssec (public)
** keyfile name. Returns 0 | 1
*****************************************************************/
int is_keyfilename (const char *name)
{
int len;
if ( name == NULL || *name != 'K' )
return 0;
len = strlen (name);
if ( len > 4 && strcmp (&name[len - 4], ".key") == 0 )
return 1;
return 0;
}
/*****************************************************************
** is_dotfilename (name)
** Check if the given pathname 'name' looks like "." or "..".
** Returns 0 | 1
*****************************************************************/
int is_dotfilename (const char *name)
{
if ( name && (
(name[0] == '.' && name[1] == '\0') ||
(name[0] == '.' && name[1] == '.' && name[2] == '\0')) )
return 1;
return 0;
}
/*****************************************************************
** touch (name, sec)
** Set the modification time of the given pathname 'fname' to
** 'sec'. Returns 0 on success.
*****************************************************************/
int touch (const char *fname, time_t sec)
{
struct utimbuf utb;
utb.actime = utb.modtime = sec;
return utime (fname, &utb);
}
/*****************************************************************
** linkfile (fromfile, tofile)
*****************************************************************/
int linkfile (const char *fromfile, const char *tofile)
{
int ret;
/* fprintf (stderr, "linkfile (%s, %s)\n", fromfile, tofile); */
if ( (ret = link (fromfile, tofile)) == -1 && errno == EEXIST )
if ( unlink (tofile) == 0 )
ret = link (fromfile, tofile);
return ret;
}
/*****************************************************************
** copyfile (fromfile, tofile, dnskeyfile)
** copy fromfile into tofile.
** Add (optional) the content of dnskeyfile to tofile.
*****************************************************************/
int copyfile (const char *fromfile, const char *tofile, const char *dnskeyfile)
{
FILE *infp;
FILE *outfp;
int c;
/* fprintf (stderr, "copyfile (%s, %s)\n", fromfile, tofile); */
if ( (infp = fopen (fromfile, "r")) == NULL )
return -1;
if ( (outfp = fopen (tofile, "w")) == NULL )
{
fclose (infp);
return -2;
}
while ( (c = getc (infp)) != EOF )
putc (c, outfp);
fclose (infp);
if ( dnskeyfile && *dnskeyfile && (infp = fopen (dnskeyfile, "r")) != NULL )
{
while ( (c = getc (infp)) != EOF )
putc (c, outfp);
fclose (infp);
}
fclose (outfp);
return 0;
}
/*****************************************************************
** copyzonefile (fromfile, tofile, dnskeyfile)
** copy a already signed zonefile and replace all zone DNSKEY
** resource records by one "$INCLUDE dnskey.db" line
*****************************************************************/
int copyzonefile (const char *fromfile, const char *tofile, const char *dnskeyfile)
{
FILE *infp;
FILE *outfp;
int len;
int dnskeys;
int multi_line_dnskey;
int bufoverflow;
char buf[1024];
char *p;
if ( fromfile == NULL )
infp = stdin;
else
if ( (infp = fopen (fromfile, "r")) == NULL )
return -1;
if ( tofile == NULL )
outfp = stdout;
else
if ( (outfp = fopen (tofile, "w")) == NULL )
{
if ( fromfile )
fclose (infp);
return -2;
}
multi_line_dnskey = 0;
dnskeys = 0;
bufoverflow = 0;
while ( fgets (buf, sizeof buf, infp) != NULL )
{
p = buf;
if ( !bufoverflow && !multi_line_dnskey && (*p == '@' || isspace (*p)) ) /* check if DNSKEY RR */
{
do
p++;
while ( isspace (*p) ) ;
/* skip TTL */
while ( isdigit (*p) )
p++;
while ( isspace (*p) )
p++;
/* skip Class */
if ( strncasecmp (p, "IN", 2) == 0 )
{
p += 2;
while ( isspace (*p) )
p++;
}
if ( strncasecmp (p, "DNSKEY", 6) == 0 ) /* bingo! */
{
dnskeys++;
p += 6;
while ( *p )
{
if ( *p == '(' )
multi_line_dnskey = 1;
if ( *p == ')' )
multi_line_dnskey = 0;
p++;
}
if ( dnskeys == 1 )
fprintf (outfp, "$INCLUDE %s\n", dnskeyfile);
}
else
fputs (buf, outfp);
}
else
{
if ( bufoverflow )
fprintf (stderr, "!! buffer overflow in copyzonefile() !!\n");
if ( !multi_line_dnskey )
fputs (buf, outfp);
else
{
while ( *p && *p != ')' )
p++;
if ( *p == ')' )
multi_line_dnskey = 0;
}
}
len = strlen (buf);
bufoverflow = buf[len-1] != '\n'; /* line too long ? */
}
if ( fromfile )
fclose (infp);
if ( tofile )
fclose (outfp);
return 0;
}
/*****************************************************************
** cmpfile (file1, file2)
** returns -1 on error, 1 if the files differ and 0 if they
** are identical.
*****************************************************************/
int cmpfile (const char *file1, const char *file2)
{
FILE *fp1;
FILE *fp2;
int c1;
int c2;
/* fprintf (stderr, "cmpfile (%s, %s)\n", file1, file2); */
if ( (fp1 = fopen (file1, "r")) == NULL )
return -1;
if ( (fp2 = fopen (file2, "r")) == NULL )
{
fclose (fp1);
return -1;
}
do {
c1 = getc (fp1);
c2 = getc (fp2);
} while ( c1 != EOF && c2 != EOF && c1 == c2 );
fclose (fp1);
fclose (fp2);
if ( c1 == c2 )
return 0;
return 1;
}
/*****************************************************************
** file_age (fname)
*****************************************************************/
int file_age (const char *fname)
{
time_t curr = time (NULL);
time_t mtime = file_mtime (fname);
return curr - mtime;
}
/*****************************************************************
** file_mtime (fname)
*****************************************************************/
time_t file_mtime (const char *fname)
{
struct stat st;
if ( stat (fname, &st) < 0 )
return 0;
return st.st_mtime;
}
/*****************************************************************
** is_exec_ok (prog)
** Check if we are running as root or if the file owner of
** "prog" do not match the current user or the file permissions
** allows file modification for others then the owner.
** The same condition will be checked for the group ownership.
** return 1 if the execution of the command "prog" will not
** open a big security whole, 0 otherwise
*****************************************************************/
int is_exec_ok (const char *prog)
{
uid_t curr_uid;
struct stat st;
if ( stat (prog, &st) < 0 )
return 0;
curr_uid = getuid ();
if ( curr_uid == 0 ) /* don't run the cmd if we are root */
return 0;
/* if the file owner and the current user matches and */
/* the file mode is not writable except for the owner, we are save */
if ( curr_uid == st.st_uid && (st.st_mode & (S_IWGRP | S_IWOTH)) == 0 )
return 1;
/* if the file group and the current group matches and */
/* the file mode is not writable except for the group, we are also save */
if ( getgid() != st.st_gid && (st.st_mode & (S_IWUSR | S_IWOTH)) == 0 )
return 1;
return 0;
}
/*****************************************************************
** fatal (fmt, ...)
*****************************************************************/
void fatal (char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if ( progname )
fprintf (stderr, "%s: ", progname);
vfprintf (stderr, fmt, ap);
va_end(ap);
exit (127);
}
/*****************************************************************
** error (fmt, ...)
*****************************************************************/
void error (char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf (stderr, fmt, ap);
va_end(ap);
}
/*****************************************************************
** logmesg (fmt, ...)
*****************************************************************/
void logmesg (char *fmt, ...)
{
va_list ap;
#if defined (LOG_WITH_PROGNAME) && LOG_WITH_PROGNAME
fprintf (stdout, "%s: ", progname);
#endif
va_start(ap, fmt);
vfprintf (stdout, fmt, ap);
va_end(ap);
}
/*****************************************************************
** verbmesg (verblvl, conf, fmt, ...)
*****************************************************************/
void verbmesg (int verblvl, const zconf_t *conf, char *fmt, ...)
{
char str[511+1];
va_list ap;
str[0] = '\0';
va_start(ap, fmt);
vsnprintf (str, sizeof (str), fmt, ap);
va_end(ap);
//fprintf (stderr, "verbmesg (%d stdout=%d filelog=%d str = :%s:\n", verblvl, conf->verbosity, conf->verboselog, str);
if ( verblvl <= conf->verbosity ) /* check if we have to print this to stdout */
logmesg (str);
str_chop (str, '\n');
if ( verblvl <= conf->verboselog ) /* check logging to syslog and/or file */
lg_mesg (LG_DEBUG, str);
}
/*****************************************************************
** logflush ()
*****************************************************************/
void logflush ()
{
fflush (stdout);
}
/*****************************************************************
** timestr2time (timestr)
** timestr should look like "20071211223901" for 12 dec 2007 22:39:01
*****************************************************************/
time_t timestr2time (const char *timestr)
{
struct tm t;
time_t sec;
// fprintf (stderr, "timestr = \"%s\"\n", timestr);
if ( sscanf (timestr, "%4d%2d%2d%2d%2d%2d",
&t.tm_year, &t.tm_mon, &t.tm_mday,
&t.tm_hour, &t.tm_min, &t.tm_sec) != 6 )
return 0L;
t.tm_year -= 1900;
t.tm_mon -= 1;
t.tm_isdst = 0;
#if defined(HAVE_TIMEGM) && HAVE_TIMEGM
sec = timegm (&t);
#else
{
char tzstr[31+1];
char *tz;
tz = getenv("TZ");
snprintf (tzstr, sizeof (tzstr), "TZ=%s", "UTC");
putenv (tzstr);
tzset();
sec = mktime(&t);
if (tz)
snprintf (tzstr, sizeof (tzstr), "TZ=%s", tz);
else
snprintf (tzstr, sizeof (tzstr), "TZ=%s", "");
putenv (tzstr);
tzset();
}
#endif
return sec < 0L ? 0L : sec;
}
/*****************************************************************
** time2str (sec, precison)
** sec is seconds since 1.1.1970
** precison is currently either 's' (for seconds) or 'm' (minutes)
*****************************************************************/
char *time2str (time_t sec, int precision)
{
struct tm *t;
static char timestr[31+1]; /* 27+1 should be enough */
#if defined(HAVE_STRFTIME) && HAVE_STRFTIME
char tformat[127+1];
timestr[0] = '\0';
if ( sec <= 0L )
return timestr;
t = localtime (&sec);
if ( precision == 's' )
strcpy (tformat, "%b %d %Y %T");
else
strcpy (tformat, "%b %d %Y %R");
# if PRINT_TIMEZONE
strcat (tformat, " %z");
# endif
strftime (timestr, sizeof (timestr), tformat, t);
#else /* no strftime available */
static char *mstr[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
timestr[0] = '\0';
if ( sec <= 0L )
return timestr;
t = localtime (&sec);
# if PRINT_TIMEZONE
{
int h, s;
s = abs (t->tm_gmtoff);
h = t->tm_gmtoff / 3600;
s = t->tm_gmtoff % 3600;
if ( precision == 's' )
snprintf (timestr, sizeof (timestr), "%s %2d %4d %02d:%02d:%02d %c%02d%02d",
mstr[t->tm_mon], t->tm_mday, t->tm_year + 1900,
t->tm_hour, t->tm_min, t->tm_sec,
t->tm_gmtoff < 0 ? '-': '+',
h, s);
else
snprintf (timestr, sizeof (timestr), "%s %2d %4d %02d:%02d %c%02d%02d",
mstr[t->tm_mon], t->tm_mday, t->tm_year + 1900,
t->tm_hour, t->tm_min,
t->tm_gmtoff < 0 ? '-': '+',
h, s);
}
# else
if ( precision == 's' )
snprintf (timestr, sizeof (timestr), "%s %2d %4d %02d:%02d:%02d",
mstr[t->tm_mon], t->tm_mday, t->tm_year + 1900,
t->tm_hour, t->tm_min, t->tm_sec);
else
snprintf (timestr, sizeof (timestr), "%s %2d %4d %02d:%02d",
mstr[t->tm_mon], t->tm_mday, t->tm_year + 1900,
t->tm_hour, t->tm_min);
# endif
#endif
return timestr;
}
/*****************************************************************
** time2isostr (sec, precison)
** sec is seconds since 1.1.1970
** precison is currently either 's' (for seconds) or 'm' (minutes)
*****************************************************************/
char *time2isostr (time_t sec, int precision)
{
struct tm *t;
static char timestr[31+1]; /* 27+1 should be enough */
timestr[0] = '\0';
if ( sec <= 0L )
return timestr;
t = gmtime (&sec);
if ( precision == 's' )
snprintf (timestr, sizeof (timestr), "%4d%02d%02d%02d%02d%02d",
t->tm_year + 1900, t->tm_mon+1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec);
else
snprintf (timestr, sizeof (timestr), "%4d%02d%02d%02d%02d",
t->tm_year + 1900, t->tm_mon+1, t->tm_mday,
t->tm_hour, t->tm_min);
return timestr;
}
/*****************************************************************
** age2str (sec)
** !!Attention: This function is not reentrant
*****************************************************************/
char *age2str (time_t sec)
{
static char str[20+1]; /* "2y51w6d23h50m55s" == 16+1 chars */
int len;
int strsize = sizeof (str);
len = 0;
# if PRINT_AGE_WITH_YEAR
if ( sec / (YEARSEC) > 0 )
{
len += snprintf (str+len, strsize - len, "%1luy", sec / YEARSEC );
sec %= (YEARSEC);
}
else
len += snprintf (str+len, strsize - len, " ");
# endif
if ( sec / WEEKSEC > 0 )
{
len += snprintf (str+len, strsize - len, "%2luw", (ulong) sec / WEEKSEC );
sec %= WEEKSEC;
}
else
len += snprintf (str+len, strsize - len, " ");
if ( sec / DAYSEC > 0 )
{
len += snprintf (str+len, strsize - len, "%2lud", sec / (ulong)DAYSEC);
sec %= DAYSEC;
}
else
len += snprintf (str+len, strsize - len, " ");
if ( sec / HOURSEC > 0 )
{
len += snprintf (str+len, strsize - len, "%2luh", sec / (ulong)HOURSEC);
sec %= HOURSEC;
}
else
len += snprintf (str+len, strsize - len, " ");
if ( sec / MINSEC > 0 )
{
len += snprintf (str+len, strsize - len, "%2lum", sec / (ulong)MINSEC);
sec %= MINSEC;
}
else
len += snprintf (str+len, strsize - len, " ");
if ( sec > 0 )
snprintf (str+len, strsize - len, "%2lus", (ulong) sec);
else
len += snprintf (str+len, strsize - len, " ");
return str;
}
/*****************************************************************
** start_timer ()
*****************************************************************/
time_t start_timer ()
{
return (time(NULL));
}
/*****************************************************************
** stop_timer ()
*****************************************************************/
time_t stop_timer (time_t start)
{
time_t stop = time (NULL);
return stop - start;
}
/****************************************************************
**
** int gensalt (saltstr, sizeofsaltstr, bits)
**
** generate a random hexstring of 'bits' salt and store it
** in saltstr. return 1 on success, otherwise 0.
**
*****************************************************************/
int gensalt (char *salt, size_t saltsize, int saltbits, unsigned int seed)
{
static char hexstr[] = "0123456789ABCDEF";
int saltlen = 0; /* current length of salt in hex nibbles */
int i;
int hex;
if ( seed == 0 )
srandom (seed = (unsigned int)time (NULL));
saltlen = saltbits / 4;
if ( saltlen+1 > saltsize )
return 0;
for ( i = 0; i < saltlen; i++ )
{
hex = random () % 16;
assert ( hex >= 0 && hex < 16 );
salt[i] = hexstr[hex];
}
salt[i] = '\0';
return 1;
}
#ifdef COPYZONE_TEST
const char *progname;
main (int argc, char *argv[])
{
progname = *argv;
if ( copyzonefile (argv[1], NULL) < 0 )
error ("can't copy zone file %s\n", argv[1]);
}
#endif
#ifdef URL_TEST
const char *progname;
main (int argc, char *argv[])
{
char *proto;
char *host;
char *port;
char *para;
char url[1024];
progname = *argv;
proto = host = port = para = NULL;
if ( --argc <= 0 )
{
fprintf (stderr, "usage: url_test <url>\n");
fprintf (stderr, "e.g.: url_test http://www.hznet.de:80/zkt\n");
exit (1);
}
strcpy (url, argv[1]);
parseurl (url, &proto, &host, &port, &para);
if ( proto )
printf ("proto: \"%s\"\n", proto);
if ( host )
printf ("host: \"%s\"\n", host);
if ( port )
printf ("port: \"%s\"\n", port);
if ( para )
printf ("para: \"%s\"\n", para);
}
#endif