/***************************************************************** ** ** @(#) 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 # include # include # include /* for link(), unlink() */ # include # include # include # include # include # include # include # include #ifdef HAVE_CONFIG_H # include #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 "-". *****************************************************************/ 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, ¶ ) ** 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 \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, ¶); 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