X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=common-src%2Futil.c;h=3564d6b195b87da5d9c6bdf83c7df6ae4b49057f;hb=71325c297e0436e9930a3e129a26696e78c27f62;hp=0eafec0b74d6822f7305e453b69c498eac97f789;hpb=1194fb66aa28d9929c3f2bef3cc6c1c3f40a60a4;p=debian%2Famanda diff --git a/common-src/util.c b/common-src/util.c index 0eafec0..3564d6b 100644 --- a/common-src/util.c +++ b/common-src/util.c @@ -24,11 +24,41 @@ * file named AUTHORS, in the root directory of this distribution. */ /* - * $Id: util.c,v 1.17 2006/01/14 04:37:19 paddy_s Exp $ + * $Id: util.c,v 1.42.2.4 2006/09/21 11:12:21 martinea Exp $ */ #include "amanda.h" #include "util.h" +#include "arglist.h" +#include "clock.h" + +int allow_overwrites; +int token_pushed; + +tok_t tok, pushed_tok; +val_t tokenval; +keytab_t *keytable; + +int conf_line_num, got_parserror; +FILE *conf_conf = (FILE *)NULL; +char *conf_confname = NULL; +char *conf_line = NULL; +char *conf_char = NULL; + +/*#define NET_READ_DEBUG*/ + +#ifdef NET_READ_DEBUG +#define netprintf(x) dbprintf(x) +#else +#define netprintf(x) +#endif + +static int make_socket(void); +static int connect_port(struct sockaddr_in *addrp, in_port_t port, char *proto, + struct sockaddr_in *svaddr, int nonblock); + +int conftoken_getc(void); +int conftoken_ungetc(int c); /* * Keep calling read() until we've read buflen's worth of data, or EOF, @@ -37,10 +67,10 @@ * Returns the number of bytes read, 0 on EOF, or negative on error. */ ssize_t -fullread(fd, vbuf, buflen) - int fd; - void *vbuf; - size_t buflen; +fullread( + int fd, + void * vbuf, + size_t buflen) { ssize_t nread, tot = 0; char *buf = vbuf; /* cast to char so we can ++ it */ @@ -70,10 +100,10 @@ fullread(fd, vbuf, buflen) * Returns the number of bytes written, or negative on error. */ ssize_t -fullwrite(fd, vbuf, buflen) - int fd; - const void *vbuf; - size_t buflen; +fullwrite( + int fd, + const void *vbuf, + size_t buflen) { ssize_t nwritten, tot = 0; const char *buf = vbuf; /* cast to char so we can ++ it */ @@ -92,6 +122,210 @@ fullwrite(fd, vbuf, buflen) return (tot); } +static int +make_socket(void) +{ + int s; + int save_errno; +#if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR) + int on=1; + int r; +#endif + + if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + save_errno = errno; + dbprintf(("%s: make_socket: socket() failed: %s\n", + debug_prefix(NULL), + strerror(save_errno))); + errno = save_errno; + return -1; + } + if (s < 0 || s >= (int)FD_SETSIZE) { + aclose(s); + errno = EMFILE; /* out of range */ + return -1; + } + +#ifdef USE_REUSEADDR + r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (r < 0) { + save_errno = errno; + dbprintf(("%s: stream_server: setsockopt(SO_REUSEADDR) failed: %s\n", + debug_prefix(NULL), + strerror(errno))); + errno = save_errno; + } +#endif + +#ifdef SO_KEEPALIVE + r = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, + (void *)&on, SIZEOF(on)); + if (r == -1) { + save_errno = errno; + dbprintf(("%s: make_socket: setsockopt() failed: %s\n", + debug_prefix(NULL), + strerror(save_errno))); + aclose(s); + errno = save_errno; + return -1; + } +#endif + + return s; +} + +/* addrp is my address */ +/* svaddr is the address of the remote machine */ +/* return socket on success */ +/* return -1 on failure */ +int +connect_portrange( + struct sockaddr_in *addrp, + in_port_t first_port, + in_port_t last_port, + char * proto, + struct sockaddr_in *svaddr, + int nonblock) +{ + int s; + in_port_t port; + static in_port_t port_in_use[1024]; + static int nb_port_in_use = 0; + int i; + + assert(first_port <= last_port); + + /* Try a port already used */ + for(i=0; i < nb_port_in_use; i++) { + port = port_in_use[i]; + if(port >= first_port && port <= last_port) { + s = connect_port(addrp, port, proto, svaddr, nonblock); + if(s == -2) return -1; + if(s > 0) { + return s; + } + } + } + + /* Try a port in the range */ + for (port = first_port; port <= last_port; port++) { + s = connect_port(addrp, port, proto, svaddr, nonblock); + if(s == -2) return -1; + if(s > 0) { + port_in_use[nb_port_in_use++] = port; + return s; + } + } + + dbprintf(("%s: connect_portrange: all ports between %d and %d busy\n", + debug_prefix_time(NULL), + first_port, + last_port)); + errno = EAGAIN; + return -1; +} + +/* addrp is my address */ +/* svaddr is the address of the remote machine */ +/* return -2: Don't try again */ +/* return -1: Try with another port */ +/* return >0: this is the connected socket */ +int +connect_port( + struct sockaddr_in *addrp, + in_port_t port, + char * proto, + struct sockaddr_in *svaddr, + int nonblock) +{ + int save_errno; + struct servent * servPort; + socklen_t len; + int s; + + servPort = getservbyport((int)htons(port), proto); + if (servPort != NULL && !strstr(servPort->s_name, "amanda")) { + dbprintf(("%s: connect_port: Skip port %d: Owned by %s.\n", + debug_prefix_time(NULL), port, servPort->s_name)); + return -1; + } + + if(servPort == NULL) + dbprintf(("%s: connect_port: Try port %d: Available - \n", + debug_prefix_time(NULL), port)); + else { + dbprintf(("%s: connect_port: Try port %d: Owned by %s - \n", + debug_prefix_time(NULL), port, servPort->s_name)); + } + + if ((s = make_socket()) == -1) return -2; + + addrp->sin_port = (in_port_t)htons(port); + + if (bind(s, (struct sockaddr *)addrp, sizeof(*addrp)) != 0) { + save_errno = errno; + aclose(s); + if (save_errno != EADDRINUSE) { + dbprintf(("errno %d strerror %s\n", + errno, strerror(errno))); + errno = save_errno; + return -2; + } + errno = save_errno; + return -1; + } + + /* find out what port was actually used */ + + len = sizeof(*addrp); + if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) { + save_errno = errno; + dbprintf(("%s: connect_port: getsockname() failed: %s\n", + debug_prefix(NULL), + strerror(save_errno))); + aclose(s); + errno = save_errno; + return -1; + } + + if (nonblock) + fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0)|O_NONBLOCK); + if (connect(s, (struct sockaddr *)svaddr, + (socklen_t)sizeof(*svaddr)) == -1 && !nonblock) { + save_errno = errno; + dbprintf(("%s: connect_portrange: connect from %s.%d failed\n", + debug_prefix_time(NULL), + inet_ntoa(addrp->sin_addr), + ntohs(addrp->sin_port), + strerror(save_errno))); + dbprintf(("%s: connect_portrange: connect to %s.%d failed: %s\n", + debug_prefix_time(NULL), + inet_ntoa(svaddr->sin_addr), + ntohs(svaddr->sin_port), + strerror(save_errno))); + aclose(s); + errno = save_errno; + if (save_errno == ECONNREFUSED || + save_errno == EHOSTUNREACH || + save_errno == ENETUNREACH || + save_errno == ETIMEDOUT) { + return -2 ; + } + return -1; + } + + dbprintf(("%s: connected to %s.%d\n", + debug_prefix_time(NULL), + inet_ntoa(svaddr->sin_addr), + ntohs(svaddr->sin_port))); + dbprintf(("%s: our side is %s.%d\n", + debug_prefix(NULL), + inet_ntoa(addrp->sin_addr), + ntohs(addrp->sin_port))); + return s; +} + + /* * Bind to a port in the given range. Takes a begin,end pair of port numbers. * @@ -99,67 +333,59 @@ fullwrite(fd, vbuf, buflen) * on success. */ int -bind_portrange(s, addrp, first_port, last_port, proto) - int s; - struct sockaddr_in *addrp; - int first_port, last_port; - char *proto; +bind_portrange( + int s, + struct sockaddr_in *addrp, + in_port_t first_port, + in_port_t last_port, + char * proto) { - int port, cnt; - const int num_ports = last_port - first_port + 1; - int save_errno; + in_port_t port; + in_port_t cnt; struct servent *servPort; + const in_port_t num_ports = (in_port_t)(last_port - first_port + 1); - assert(first_port > 0 && first_port <= last_port && last_port < 65536); + assert(first_port <= last_port); /* * We pick a different starting port based on our pid and the current * time to avoid always picking the same reserved port twice. */ - port = ((getpid() + time(0)) % num_ports) + first_port; + port = (in_port_t)(((getpid() + time(0)) % num_ports) + first_port); + /* * Scan through the range, trying all available ports that are either * not taken in /etc/services or registered for *amanda*. Wrap around * if we don't happen to start at the beginning. */ for (cnt = 0; cnt < num_ports; cnt++) { - servPort = getservbyport(htons(port), proto); - if((servPort == NULL) || strstr(servPort->s_name, "amanda")){ - dbprintf(("%s: bind_portrange2: trying port=%d\n", + servPort = getservbyport((int)htons(port), proto); + if ((servPort == NULL) || strstr(servPort->s_name, "amanda")) { + if (servPort == NULL) { + dbprintf(("%s: bind_portrange2: Try port %d: Available - ", debug_prefix_time(NULL), port)); - addrp->sin_port = htons(port); - if (bind(s, (struct sockaddr *)addrp, sizeof(*addrp)) >= 0) + } else { + dbprintf(("%s: bind_portrange2: Try port %d: Owned by %s - ", + debug_prefix_time(NULL), port, servPort->s_name)); + } + addrp->sin_port = (in_port_t)htons(port); + if (bind(s, (struct sockaddr *)addrp, (socklen_t)sizeof(*addrp)) >= 0) { + dbprintf(("Success\n")); return 0; - /* - * If the error was something other then port in use, stop. - */ - if (errno != EADDRINUSE) - break; + } + dbprintf(("%s\n", strerror(errno))); + } else { + dbprintf(("%s: bind_portrange2: Skip port %d: Owned by %s.\n", + debug_prefix_time(NULL), port, servPort->s_name)); } if (++port > last_port) port = first_port; } - if (cnt == num_ports) { - dbprintf(("%s: bind_portrange: all ports between %d and %d busy\n", + dbprintf(("%s: bind_portrange: all ports between %d and %d busy\n", debug_prefix_time(NULL), first_port, last_port)); - errno = EAGAIN; - } else if (last_port < IPPORT_RESERVED - && getuid() != 0 - && errno == EACCES) { - /* - * Do not bother with an error message in this case because it - * is expected. - */ - } else { - save_errno = errno; - dbprintf(("%s: bind_portrange: port %d: %s\n", - debug_prefix_time(NULL), - port, - strerror(errno))); - errno = save_errno; - } + errno = EAGAIN; return -1; } @@ -167,20 +393,23 @@ bind_portrange(s, addrp, first_port, last_port, proto) * Construct a datestamp (YYYYMMDD) from a time_t. */ char * -construct_datestamp(t) - time_t *t; +construct_datestamp( + time_t *t) { struct tm *tm; - char datestamp[3*NUM_STR_SIZE]; + char datestamp[3 * NUM_STR_SIZE]; time_t when; - if(t == NULL) { + if (t == NULL) { when = time((time_t *)NULL); } else { when = *t; } tm = localtime(&when); - snprintf(datestamp, sizeof(datestamp), + if (!tm) + return stralloc("19000101"); + + snprintf(datestamp, SIZEOF(datestamp), "%04d%02d%02d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday); return stralloc(datestamp); } @@ -189,22 +418,2250 @@ construct_datestamp(t) * Construct a timestamp (YYYYMMDDHHMMSS) from a time_t. */ char * -construct_timestamp(t) - time_t *t; +construct_timestamp( + time_t *t) { struct tm *tm; - char timestamp[6*NUM_STR_SIZE]; + char timestamp[6 * NUM_STR_SIZE]; time_t when; - if(t == NULL) { + if (t == NULL) { when = time((time_t *)NULL); } else { when = *t; } tm = localtime(&when); - snprintf(timestamp, sizeof(timestamp), + if (!tm) + return stralloc("19000101000000"); + + snprintf(timestamp, SIZEOF(timestamp), "%04d%02d%02d%02d%02d%02d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); return stralloc(timestamp); } + + +int +needs_quotes( + const char * str) +{ + return (match("[ \t\f\r\n\"]", str) != 0); +} + + +/* + * For backward compatibility we are trying for minimal quoting. + * We only quote a string if it contains whitespace or is misquoted... + */ + +char * +quote_string( + const char *str) +{ + char * s; + char * ret; + + if ((str == NULL) || (*str == '\0')) { + ret = stralloc("\"\""); + } else if ((match("[\\\"[:space:][:cntrl:]]", str)) == 0) { + /* + * String does not need to be quoted since it contains + * neither whitespace, control or quote characters. + */ + ret = stralloc(str); + } else { + /* + * Allocate maximum possible string length. + * (a string of all quotes plus room for leading ", trailing " and NULL) + */ + ret = s = alloc((strlen(str) * 2) + 2 + 1); + *(s++) = '"'; + while (*str != '\0') { + if (*str == '\t') { + *(s++) = '\\'; + *(s++) = 't'; + str++; + continue; + } else if (*str == '\n') { + *(s++) = '\\'; + *(s++) = 'n'; + str++; + continue; + } else if (*str == '\r') { + *(s++) = '\\'; + *(s++) = 'r'; + str++; + continue; + } else if (*str == '\f') { + *(s++) = '\\'; + *(s++) = 'f'; + str++; + continue; + } + if (*str == '"') + *(s++) = '\\'; + *(s++) = *(str++); + } + *(s++) = '"'; + *s = '\0'; + } + return (ret); +} + + +char * +unquote_string( + const char *str) +{ + char * ret; + + if ((str == NULL) || (*str == '\0')) { + ret = stralloc(""); + } else { + char * in; + char * out; + + ret = in = out = stralloc(str); + while (*in != '\0') { + if (*in == '"') { + in++; + continue; + } + + if (*in == '\\') { + in++; + if (*in == 'n') { + in++; + *(out++) = '\n'; + continue; + } else if (*in == 't') { + in++; + *(out++) = '\t'; + continue; + } else if (*in == 'r') { + in++; + *(out++) = '\r'; + continue; + } else if (*in == 'f') { + in++; + *(out++) = '\f'; + continue; + } + } + *(out++) = *(in++); + } + *out = '\0'; + } + return (ret); +} + +char * +sanitize_string( + const char *str) +{ + char * s; + char * ret; + + if ((str == NULL) || (*str == '\0')) { + ret = stralloc(""); + } else { + ret = stralloc(str); + for (s = ret; *s != '\0'; s++) { + if (iscntrl(*s)) + *s = '?'; + } + } + return (ret); +} + +char * +strquotedstr(void) +{ + char * tok = strtok(NULL, " "); + + if ((tok != NULL) && (tok[0] == '"')) { + char * t; + size_t len; + + len = strlen(tok); + do { + t = strtok(NULL, " "); + tok[len] = ' '; + len = strlen(tok); + } while ((t != NULL) && + (tok[len - 1] != '"') && (tok[len - 2] != '\\')); + } + return tok; +} + +ssize_t +hexdump( + const char *buffer, + size_t len) +{ + ssize_t rc = -1; + + FILE *stream = popen("od -w10 -c -x -", "w"); + + if (stream != NULL) { + fflush(stdout); + rc = (ssize_t)fwrite(buffer, len, 1, stream); + if (ferror(stream)) + rc = -1; + fclose(stream); + } + return rc; +} + +/* + Return 0 if the following characters are present + * ( ) < > [ ] , ; : ! $ \ / " + else returns 1 +*/ + +int +validate_mailto( + const char *mailto) +{ + return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto); +} + + +t_conf_var * +get_np( + t_conf_var *get_var, + int parm) +{ + t_conf_var *np; + + for(np = get_var; np->token != CONF_UNKNOWN; np++) { + if(np->parm == parm) + break; + } + + if(np->token == CONF_UNKNOWN) { + error("error [unknown getconf_np parm: %d]", parm); + /* NOTREACHED */ + } + return np; +} + +void +get_simple( + val_t *var, + tok_t type) +{ + ckseen(&var->seen); + + switch(type) { + case CONF_STRING: + case CONF_IDENT: + get_conftoken(type); + var->v.s = newstralloc(var->v.s, tokenval.v.s); + malloc_mark(var->v.s); + break; + + case CONF_INT: + var->v.i = get_int(); + break; + + case CONF_LONG: + var->v.l = get_long(); + break; + + case CONF_SIZE: + var->v.size = get_size(); + break; + + case CONF_AM64: + var->v.am64 = get_am64_t(); + break; + + case CONF_BOOL: + var->v.i = get_bool(); + break; + + case CONF_REAL: + get_conftoken(CONF_REAL); + var->v.r = tokenval.v.r; + break; + + case CONF_TIME: + var->v.t = get_time(); + break; + + default: + error("error [unknown get_simple type: %d]", type); + /* NOTREACHED */ + } + return; +} + +time_t +get_time(void) +{ + time_t hhmm; + + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_INT: +#if SIZEOF_TIME_T < SIZEOF_INT + if ((off_t)tokenval.v.i >= (off_t)TIME_MAX) + conf_parserror("value too large"); +#endif + hhmm = (time_t)tokenval.v.i; + break; + + case CONF_LONG: +#if SIZEOF_TIME_T < SIZEOF_LONG + if ((off_t)tokenval.v.l >= (off_t)TIME_MAX) + conf_parserror("value too large"); +#endif + hhmm = (time_t)tokenval.v.l; + break; + + case CONF_SIZE: +#if SIZEOF_TIME_T < SIZEOF_SSIZE_T + if ((off_t)tokenval.v.size >= (off_t)TIME_MAX) + conf_parserror("value too large"); +#endif + hhmm = (time_t)tokenval.v.size; + break; + + case CONF_AM64: +#if SIZEOF_TIME_T < SIZEOF_LONG_LONG + if ((off_t)tokenval.v.am64 >= (off_t)TIME_MAX) + conf_parserror("value too large"); +#endif + hhmm = (time_t)tokenval.v.am64; + break; + + case CONF_AMINFINITY: + hhmm = TIME_MAX; + break; + + default: + conf_parserror("a time is expected"); + hhmm = 0; + break; + } + return hhmm; +} + +keytab_t numb_keytable[] = { + { "B", CONF_MULT1 }, + { "BPS", CONF_MULT1 }, + { "BYTE", CONF_MULT1 }, + { "BYTES", CONF_MULT1 }, + { "DAY", CONF_MULT1 }, + { "DAYS", CONF_MULT1 }, + { "INF", CONF_AMINFINITY }, + { "K", CONF_MULT1K }, + { "KB", CONF_MULT1K }, + { "KBPS", CONF_MULT1K }, + { "KBYTE", CONF_MULT1K }, + { "KBYTES", CONF_MULT1K }, + { "KILOBYTE", CONF_MULT1K }, + { "KILOBYTES", CONF_MULT1K }, + { "KPS", CONF_MULT1K }, + { "M", CONF_MULT1M }, + { "MB", CONF_MULT1M }, + { "MBPS", CONF_MULT1M }, + { "MBYTE", CONF_MULT1M }, + { "MBYTES", CONF_MULT1M }, + { "MEG", CONF_MULT1M }, + { "MEGABYTE", CONF_MULT1M }, + { "MEGABYTES", CONF_MULT1M }, + { "G", CONF_MULT1G }, + { "GB", CONF_MULT1G }, + { "GBPS", CONF_MULT1G }, + { "GBYTE", CONF_MULT1G }, + { "GBYTES", CONF_MULT1G }, + { "GIG", CONF_MULT1G }, + { "GIGABYTE", CONF_MULT1G }, + { "GIGABYTES", CONF_MULT1G }, + { "MPS", CONF_MULT1M }, + { "TAPE", CONF_MULT1 }, + { "TAPES", CONF_MULT1 }, + { "WEEK", CONF_MULT7 }, + { "WEEKS", CONF_MULT7 }, + { NULL, CONF_IDENT } +}; + +int +get_int(void) +{ + int val; + keytab_t *save_kt; + + save_kt = keytable; + keytable = numb_keytable; + + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_INT: + val = tokenval.v.i; + break; + + case CONF_LONG: +#if SIZEOF_INT < SIZEOF_LONG + if ((off_t)tokenval.v.l > (off_t)INT_MAX) + conf_parserror("value too large"); + if ((off_t)tokenval.v.l < (off_t)INT_MIN) + conf_parserror("value too small"); +#endif + val = (int)tokenval.v.l; + break; + + case CONF_SIZE: +#if SIZEOF_INT < SIZEOF_SSIZE_T + if ((off_t)tokenval.v.size > (off_t)INT_MAX) + conf_parserror("value too large"); + if ((off_t)tokenval.v.size < (off_t)INT_MIN) + conf_parserror("value too small"); +#endif + val = (int)tokenval.v.size; + break; + + case CONF_AM64: +#if SIZEOF_INT < SIZEOF_LONG_LONG + if (tokenval.v.am64 > (off_t)INT_MAX) + conf_parserror("value too large"); + if (tokenval.v.am64 < (off_t)INT_MIN) + conf_parserror("value too small"); +#endif + val = (int)tokenval.v.am64; + break; + + case CONF_AMINFINITY: + val = INT_MAX; + break; + + default: + conf_parserror("an int is expected"); + val = 0; + break; + } + + /* get multiplier, if any */ + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_NL: /* multiply by one */ + case CONF_END: + case CONF_MULT1: + case CONF_MULT1K: + break; + + case CONF_MULT7: + if (val > (INT_MAX / 7)) + conf_parserror("value too large"); + if (val < (INT_MIN / 7)) + conf_parserror("value too small"); + val *= 7; + break; + + case CONF_MULT1M: + if (val > (INT_MAX / 1024)) + conf_parserror("value too large"); + if (val < (INT_MIN / 1024)) + conf_parserror("value too small"); + val *= 1024; + break; + + case CONF_MULT1G: + if (val > (INT_MAX / (1024 * 1024))) + conf_parserror("value too large"); + if (val < (INT_MIN / (1024 * 1024))) + conf_parserror("value too small"); + val *= 1024 * 1024; + break; + + default: /* it was not a multiplier */ + unget_conftoken(); + break; + } + + keytable = save_kt; + return val; +} + +long +get_long(void) +{ + long val; + keytab_t *save_kt; + + save_kt = keytable; + keytable = numb_keytable; + + get_conftoken(CONF_ANY); + + switch(tok) { + case CONF_LONG: + val = tokenval.v.l; + break; + + case CONF_INT: +#if SIZEOF_LONG < SIZEOF_INT + if ((off_t)tokenval.v.i > (off_t)LONG_MAX) + conf_parserror("value too large"); + if ((off_t)tokenval.v.i < (off_t)LONG_MIN) + conf_parserror("value too small"); +#endif + val = (long)tokenval.v.i; + break; + + case CONF_SIZE: +#if SIZEOF_LONG < SIZEOF_SSIZE_T + if ((off_t)tokenval.v.size > (off_t)LONG_MAX) + conf_parserror("value too large"); + if ((off_t)tokenval.v.size < (off_t)LONG_MIN) + conf_parserror("value too small"); +#endif + val = (long)tokenval.v.size; + break; + + case CONF_AM64: +#if SIZEOF_LONG < SIZEOF_LONG_LONG + if (tokenval.v.am64 > (off_t)LONG_MAX) + conf_parserror("value too large"); + if (tokenval.v.am64 < (off_t)LONG_MIN) + conf_parserror("value too small"); +#endif + val = (long)tokenval.v.am64; + break; + + case CONF_AMINFINITY: + val = (long)LONG_MAX; + break; + + default: + conf_parserror("a long is expected"); + val = 0; + break; + } + + /* get multiplier, if any */ + get_conftoken(CONF_ANY); + + switch(tok) { + case CONF_NL: /* multiply by one */ + case CONF_MULT1: + case CONF_MULT1K: + break; + + case CONF_MULT7: + if (val > (LONG_MAX / 7L)) + conf_parserror("value too large"); + if (val < (LONG_MIN / 7L)) + conf_parserror("value too small"); + val *= 7L; + break; + + case CONF_MULT1M: + if (val > (LONG_MAX / 1024L)) + conf_parserror("value too large"); + if (val < (LONG_MIN / 1024L)) + conf_parserror("value too small"); + val *= 1024L; + break; + + case CONF_MULT1G: + if (val > (LONG_MAX / (1024L * 1024L))) + conf_parserror("value too large"); + if (val < (LONG_MIN / (1024L * 1024L))) + conf_parserror("value too small"); + val *= 1024L * 1024L; + break; + + default: /* it was not a multiplier */ + unget_conftoken(); + break; + } + + keytable = save_kt; + return val; +} + +ssize_t +get_size(void) +{ + ssize_t val; + keytab_t *save_kt; + + save_kt = keytable; + keytable = numb_keytable; + + get_conftoken(CONF_ANY); + + switch(tok) { + case CONF_SIZE: + val = tokenval.v.size; + break; + + case CONF_INT: +#if SIZEOF_SIZE_T < SIZEOF_INT + if ((off_t)tokenval.v.i > (off_t)SSIZE_MAX) + conf_parserror("value too large"); + if ((off_t)tokenval.v.i < (off_t)SSIZE_MIN) + conf_parserror("value too small"); +#endif + val = (ssize_t)tokenval.v.i; + break; + + case CONF_LONG: +#if SIZEOF_SIZE_T < SIZEOF_LONG + if ((off_t)tokenval.v.l > (off_t)SSIZE_MAX) + conf_parserror("value too large"); + if ((off_t)tokenval.v.l < (off_t)SSIZE_MIN) + conf_parserror("value too small"); +#endif + val = (ssize_t)tokenval.v.l; + break; + + case CONF_AM64: +#if SIZEOF_SIZE_T < SIZEOF_LONG_LONG + if (tokenval.v.am64 > (off_t)SSIZE_MAX) + conf_parserror("value too large"); + if (tokenval.v.am64 < (off_t)SSIZE_MIN) + conf_parserror("value too small"); +#endif + val = (ssize_t)tokenval.v.am64; + break; + + case CONF_AMINFINITY: + val = (ssize_t)SSIZE_MAX; + break; + + default: + conf_parserror("an integer is expected"); + val = 0; + break; + } + + /* get multiplier, if any */ + get_conftoken(CONF_ANY); + + switch(tok) { + case CONF_NL: /* multiply by one */ + case CONF_MULT1: + case CONF_MULT1K: + break; + + case CONF_MULT7: + if (val > (ssize_t)(SSIZE_MAX / 7)) + conf_parserror("value too large"); + if (val < (ssize_t)(SSIZE_MIN / 7)) + conf_parserror("value too small"); + val *= (ssize_t)7; + break; + + case CONF_MULT1M: + if (val > (ssize_t)(SSIZE_MAX / (ssize_t)1024)) + conf_parserror("value too large"); + if (val < (ssize_t)(SSIZE_MIN / (ssize_t)1024)) + conf_parserror("value too small"); + val *= (ssize_t)1024; + break; + + case CONF_MULT1G: + if (val > (ssize_t)(SSIZE_MAX / (1024 * 1024))) + conf_parserror("value too large"); + if (val < (ssize_t)(SSIZE_MIN / (1024 * 1024))) + conf_parserror("value too small"); + val *= (ssize_t)(1024 * 1024); + break; + + default: /* it was not a multiplier */ + unget_conftoken(); + break; + } + + keytable = save_kt; + return val; +} + +off_t +get_am64_t(void) +{ + off_t val; + keytab_t *save_kt; + + save_kt = keytable; + keytable = numb_keytable; + + get_conftoken(CONF_ANY); + + switch(tok) { + case CONF_INT: + val = (off_t)tokenval.v.i; + break; + + case CONF_LONG: + val = (off_t)tokenval.v.l; + break; + + case CONF_SIZE: + val = (off_t)tokenval.v.size; + break; + + case CONF_AM64: + val = tokenval.v.am64; + break; + + case CONF_AMINFINITY: + val = AM64_MAX; + break; + + default: + conf_parserror("an am64 is expected %d", tok); + val = 0; + break; + } + + /* get multiplier, if any */ + get_conftoken(CONF_ANY); + + switch(tok) { + case CONF_NL: /* multiply by one */ + case CONF_MULT1: + case CONF_MULT1K: + break; + + case CONF_MULT7: + if (val > AM64_MAX/7 || val < AM64_MIN/7) + conf_parserror("value too large"); + val *= 7; + break; + + case CONF_MULT1M: + if (val > AM64_MAX/1024 || val < AM64_MIN/1024) + conf_parserror("value too large"); + val *= 1024; + break; + + case CONF_MULT1G: + if (val > AM64_MAX/(1024*1024) || val < AM64_MIN/(1024*1024)) + conf_parserror("value too large"); + val *= 1024*1024; + break; + + default: /* it was not a multiplier */ + unget_conftoken(); + break; + } + + keytable = save_kt; + + return val; +} + +keytab_t bool_keytable[] = { + { "Y", CONF_ATRUE }, + { "YES", CONF_ATRUE }, + { "T", CONF_ATRUE }, + { "TRUE", CONF_ATRUE }, + { "ON", CONF_ATRUE }, + { "N", CONF_AFALSE }, + { "NO", CONF_AFALSE }, + { "F", CONF_AFALSE }, + { "FALSE", CONF_AFALSE }, + { "OFF", CONF_AFALSE }, + { NULL, CONF_IDENT } +}; + +int +get_bool(void) +{ + int val; + keytab_t *save_kt; + + save_kt = keytable; + keytable = bool_keytable; + + get_conftoken(CONF_ANY); + + switch(tok) { + case CONF_INT: + if (tokenval.v.i != 0) + val = 1; + else + val = 0; + break; + + case CONF_LONG: + if (tokenval.v.l != 0L) + val = 1; + else + val = 0; + break; + + case CONF_SIZE: + if (tokenval.v.size != (size_t)0) + val = 1; + else + val = 0; + break; + + case CONF_AM64: + if (tokenval.v.am64 != (off_t)0) + val = 1; + else + val = 0; + break; + + case CONF_ATRUE: + val = 1; + break; + + case CONF_AFALSE: + val = 0; + break; + + case CONF_NL: + unget_conftoken(); + val = 2; /* no argument - most likely TRUE */ + break; + default: + unget_conftoken(); + val = 3; /* a bad argument - most likely TRUE */ + conf_parserror("YES, NO, TRUE, FALSE, ON, OFF expected"); + break; + } + + keytable = save_kt; + return val; +} + +void +ckseen( + int *seen) +{ + if (*seen && !allow_overwrites && conf_line_num != -2) { + conf_parserror("duplicate parameter, prev def on line %d", *seen); + } + *seen = conf_line_num; +} + +printf_arglist_function(void conf_parserror, const char *, format) +{ + va_list argp; + + /* print error message */ + + if(conf_line) + fprintf(stderr, "argument \"%s\": ", conf_line); + else + fprintf(stderr, "\"%s\", line %d: ", conf_confname, conf_line_num); + arglist_start(argp, format); + vfprintf(stderr, format, argp); + arglist_end(argp); + fputc('\n', stderr); + + got_parserror = 1; +} + +tok_t +lookup_keyword( + char * str) +{ + keytab_t *kwp; + + /* switch to binary search if performance warrants */ + + for(kwp = keytable; kwp->keyword != NULL; kwp++) { + if (strcmp(kwp->keyword, str) == 0) break; + } + return kwp->token; +} + +char tkbuf[4096]; + +/* push the last token back (can only unget ANY tokens) */ +void +unget_conftoken(void) +{ + token_pushed = 1; + pushed_tok = tok; + tok = CONF_UNKNOWN; + return; +} + +int +conftoken_getc(void) +{ + if(conf_line == NULL) + return getc(conf_conf); + if(*conf_char == '\0') + return -1; + return(*conf_char++); +} + +int +conftoken_ungetc( + int c) +{ + if(conf_line == NULL) + return ungetc(c, conf_conf); + else if(conf_char > conf_line) { + if(c == -1) + return c; + conf_char--; + if(*conf_char != c) { + error("*conf_char != c : %c %c", *conf_char, c); + /* NOTREACHED */ + } + } else { + error("conf_char == conf_line"); + /* NOTREACHED */ + } + return c; +} + +void +get_conftoken( + tok_t exp) +{ + int ch, d; + off_t am64; + char *buf; + char *tmps; + int token_overflow; + int inquote = 0; + int escape = 0; + int sign; + + if (token_pushed) { + token_pushed = 0; + tok = pushed_tok; + + /* + ** If it looked like a key word before then look it + ** up again in the current keyword table. + */ + switch(tok) { + case CONF_LONG: case CONF_AM64: case CONF_SIZE: + case CONF_INT: case CONF_REAL: case CONF_STRING: + case CONF_LBRACE: case CONF_RBRACE: case CONF_COMMA: + case CONF_NL: case CONF_END: case CONF_UNKNOWN: + case CONF_TIME: + break; + + default: + if (exp == CONF_IDENT) + tok = CONF_IDENT; + else + tok = lookup_keyword(tokenval.v.s); + break; + } + } + else { + ch = conftoken_getc(); + + while(ch != EOF && ch != '\n' && isspace(ch)) + ch = conftoken_getc(); + if (ch == '#') { /* comment - eat everything but eol/eof */ + while((ch = conftoken_getc()) != EOF && ch != '\n') { + (void)ch; /* Quiet empty loop complaints */ + } + } + + if (isalpha(ch)) { /* identifier */ + buf = tkbuf; + token_overflow = 0; + do { + if (islower(ch)) ch = toupper(ch); + if (buf < tkbuf+sizeof(tkbuf)-1) { + *buf++ = (char)ch; + } else { + *buf = '\0'; + if (!token_overflow) { + conf_parserror("token too long: %.20s...", tkbuf); + } + token_overflow = 1; + } + ch = conftoken_getc(); + } while(isalnum(ch) || ch == '_' || ch == '-'); + + if (ch != EOF && conftoken_ungetc(ch) == EOF) { + if (ferror(conf_conf)) { + conf_parserror("Pushback of '%c' failed: %s", + ch, strerror(ferror(conf_conf))); + } else { + conf_parserror("Pushback of '%c' failed: EOF", ch); + } + } + *buf = '\0'; + + tokenval.v.s = tkbuf; + + if (token_overflow) tok = CONF_UNKNOWN; + else if (exp == CONF_IDENT) tok = CONF_IDENT; + else tok = lookup_keyword(tokenval.v.s); + } + else if (isdigit(ch)) { /* integer */ + sign = 1; + +negative_number: /* look for goto negative_number below sign is set there */ + am64 = 0; + do { + am64 = am64 * 10 + (ch - '0'); + ch = conftoken_getc(); + } while (isdigit(ch)); + + if (ch != '.') { + if (exp == CONF_INT) { + tok = CONF_INT; + tokenval.v.i = sign * (int)am64; + } else if (exp == CONF_LONG) { + tok = CONF_LONG; + tokenval.v.l = (long)sign * (long)am64; + } else if (exp != CONF_REAL) { + tok = CONF_AM64; + tokenval.v.am64 = (off_t)sign * am64; + } else { + /* automatically convert to real when expected */ + tokenval.v.r = (double)sign * (double)am64; + tok = CONF_REAL; + } + } else { + /* got a real number, not an int */ + tokenval.v.r = sign * (double) am64; + am64 = 0; + d = 1; + ch = conftoken_getc(); + while (isdigit(ch)) { + am64 = am64 * 10 + (ch - '0'); + d = d * 10; + ch = conftoken_getc(); + } + tokenval.v.r += sign * ((double)am64) / d; + tok = CONF_REAL; + } + + if (ch != EOF && conftoken_ungetc(ch) == EOF) { + if (ferror(conf_conf)) { + conf_parserror("Pushback of '%c' failed: %s", + ch, strerror(ferror(conf_conf))); + } else { + conf_parserror("Pushback of '%c' failed: EOF", ch); + } + } + } else switch(ch) { + case '"': /* string */ + buf = tkbuf; + token_overflow = 0; + inquote = 1; + *buf++ = (char)ch; + while (inquote && ((ch = conftoken_getc()) != EOF)) { + if (ch == '\n') { + if (!escape) + break; + escape = 0; + buf--; /* Consume escape in buffer */ + } else if (ch == '\\') { + escape = 1; + } else { + if (ch == '"') { + if (!escape) + inquote = 0; + } + escape = 0; + } + + if(buf >= &tkbuf[sizeof(tkbuf) - 1]) { + if (!token_overflow) { + conf_parserror("string too long: %.20s...", tkbuf); + } + token_overflow = 1; + break; + } + *buf++ = (char)ch; + } + *buf = '\0'; + + /* + * A little manuver to leave a fully unquoted, unallocated string + * in tokenval.v.s + */ + tmps = unquote_string(tkbuf); + strncpy(tkbuf, tmps, sizeof(tkbuf)); + amfree(tmps); + tokenval.v.s = tkbuf; + + tok = (token_overflow) ? CONF_UNKNOWN : + (exp == CONF_IDENT) ? CONF_IDENT : CONF_STRING; + break; + + case '-': + ch = conftoken_getc(); + if (isdigit(ch)) { + sign = -1; + goto negative_number; + } + else { + if (ch != EOF && conftoken_ungetc(ch) == EOF) { + if (ferror(conf_conf)) { + conf_parserror("Pushback of '%c' failed: %s", + ch, strerror(ferror(conf_conf))); + } else { + conf_parserror("Pushback of '%c' failed: EOF", ch); + } + } + tok = CONF_UNKNOWN; + } + break; + + case ',': + tok = CONF_COMMA; + break; + + case '{': + tok = CONF_LBRACE; + break; + + case '}': + tok = CONF_RBRACE; + break; + + case '\n': + tok = CONF_NL; + break; + + case EOF: + tok = CONF_END; + break; + + default: + tok = CONF_UNKNOWN; + break; + } + } + + if (exp != CONF_ANY && tok != exp) { + char *str; + keytab_t *kwp; + + switch(exp) { + case CONF_LBRACE: + str = "\"{\""; + break; + + case CONF_RBRACE: + str = "\"}\""; + break; + + case CONF_COMMA: + str = "\",\""; + break; + + case CONF_NL: + str = "end of line"; + break; + + case CONF_END: + str = "end of file"; + break; + + case CONF_INT: + str = "an integer"; + break; + + case CONF_REAL: + str = "a real number"; + break; + + case CONF_STRING: + str = "a quoted string"; + break; + + case CONF_IDENT: + str = "an identifier"; + break; + + default: + for(kwp = keytable; kwp->keyword != NULL; kwp++) { + if (exp == kwp->token) + break; + } + if (kwp->keyword == NULL) + str = "token not"; + else + str = kwp->keyword; + break; + } + conf_parserror("%s is expected", str); + tok = exp; + if (tok == CONF_INT) + tokenval.v.i = 0; + else + tokenval.v.s = ""; + } +} + + +void +read_string( + t_conf_var *np, + val_t *val) +{ + np = np; + ckseen(&val->seen); + get_conftoken(CONF_STRING); + val->v.s = newstralloc(val->v.s, tokenval.v.s); +} + +void +read_ident( + t_conf_var *np, + val_t *val) +{ + np = np; + ckseen(&val->seen); + get_conftoken(CONF_IDENT); + val->v.s = newstralloc(val->v.s, tokenval.v.s); +} + +void +read_int( + t_conf_var *np, + val_t *val) +{ + np = np; + ckseen(&val->seen); + val->v.i = get_int(); +} + +void +read_long( + t_conf_var *np, + val_t *val) +{ + np = np; + ckseen(&val->seen); + val->v.l = get_long(); +} + +void +read_size( + t_conf_var *np, + val_t *val) +{ + np = np; + ckseen(&val->seen); + val->v.size = get_size(); +} + +void +read_am64( + t_conf_var *np, + val_t *val) +{ + np = np; + ckseen(&val->seen); + val->v.am64 = get_am64_t(); +} + +void +read_bool( + t_conf_var *np, + val_t *val) +{ + np = np; + ckseen(&val->seen); + val->v.i = get_bool(); +} + +void +read_real( + t_conf_var *np, + val_t *val) +{ + np = np; + ckseen(&val->seen); + get_conftoken(CONF_REAL); + val->v.r = tokenval.v.r; +} + +void +read_time( + t_conf_var *np, + val_t *val) +{ + np = np; + ckseen(&val->seen); + val->v.t = get_time(); +} + +void +copy_val_t( + val_t *valdst, + val_t *valsrc) +{ + if(valsrc->seen) { + valdst->type = valsrc->type; + valdst->seen = valsrc->seen; + switch(valsrc->type) { + case CONFTYPE_INT: + case CONFTYPE_BOOL: + case CONFTYPE_COMPRESS: + case CONFTYPE_ENCRYPT: + case CONFTYPE_HOLDING: + case CONFTYPE_ESTIMATE: + case CONFTYPE_STRATEGY: + case CONFTYPE_TAPERALGO: + case CONFTYPE_PRIORITY: + valdst->v.i = valsrc->v.i; + break; + + case CONFTYPE_LONG: + valdst->v.l = valsrc->v.l; + break; + + case CONFTYPE_SIZE: + valdst->v.size = valsrc->v.size; + break; + + case CONFTYPE_AM64: + valdst->v.am64 = valsrc->v.am64; + break; + + case CONFTYPE_REAL: + valdst->v.r = valsrc->v.r; + break; + + case CONFTYPE_RATE: + valdst->v.rate[0] = valsrc->v.rate[0]; + valdst->v.rate[1] = valsrc->v.rate[1]; + break; + + case CONFTYPE_IDENT: + case CONFTYPE_STRING: + valdst->v.s = stralloc(valsrc->v.s); + break; + + case CONFTYPE_TIME: + valdst->v.t = valsrc->v.t; + break; + + case CONFTYPE_SL: + valdst->v.sl = duplicate_sl(valsrc->v.sl); + break; + + case CONFTYPE_EXINCLUDE: + valdst->v.exinclude.type = valsrc->v.exinclude.type; + valdst->v.exinclude.optional = valsrc->v.exinclude.optional; + valdst->v.exinclude.sl = duplicate_sl(valsrc->v.exinclude.sl); + break; + } + } +} + +void +free_val_t( + val_t *val) +{ + switch(val->type) { + case CONFTYPE_INT: + case CONFTYPE_BOOL: + case CONFTYPE_COMPRESS: + case CONFTYPE_ENCRYPT: + case CONFTYPE_HOLDING: + case CONFTYPE_ESTIMATE: + case CONFTYPE_STRATEGY: + case CONFTYPE_SIZE: + case CONFTYPE_TAPERALGO: + case CONFTYPE_PRIORITY: + case CONFTYPE_LONG: + case CONFTYPE_AM64: + case CONFTYPE_REAL: + case CONFTYPE_RATE: + break; + + case CONFTYPE_IDENT: + case CONFTYPE_STRING: + amfree(val->v.s); + break; + + case CONFTYPE_TIME: + break; + + case CONFTYPE_SL: + free_sl(val->v.sl); + break; + + case CONFTYPE_EXINCLUDE: + free_sl(val->v.exinclude.sl); + break; + } + val->seen = 0; +} + +char * +taperalgo2str( + int taperalgo) +{ + if(taperalgo == ALGO_FIRST) return "FIRST"; + if(taperalgo == ALGO_FIRSTFIT) return "FIRSTFIT"; + if(taperalgo == ALGO_LARGEST) return "LARGEST"; + if(taperalgo == ALGO_LARGESTFIT) return "LARGESTFIT"; + if(taperalgo == ALGO_SMALLEST) return "SMALLEST"; + if(taperalgo == ALGO_LAST) return "LAST"; + return "UNKNOWN"; +} + +static char buffer_conf_print[1025]; + +char * +conf_print( + val_t *val) +{ + struct tm *stm; + int pos; + + buffer_conf_print[0] = '\0'; + switch(val->type) { + case CONFTYPE_INT: + snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%d", val->v.i); + break; + + case CONFTYPE_LONG: + snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%ld", val->v.l); + break; + + case CONFTYPE_SIZE: + snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), SSIZE_T_FMT, + (SSIZE_T_FMT_TYPE)val->v.size); + break; + + case CONFTYPE_AM64: + snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), OFF_T_FMT , + (OFF_T_FMT_TYPE)val->v.am64); + break; + + case CONFTYPE_REAL: + snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%0.5f" , val->v.r); + break; + + case CONFTYPE_RATE: + snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%0.5f %0.5f" , val->v.rate[0], val->v.rate[1]); + break; + + case CONFTYPE_IDENT: + if(val->v.s) { + strncpy(buffer_conf_print, val->v.s, SIZEOF(buffer_conf_print)); + buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0'; + } else + buffer_conf_print[0] = '\0'; + break; + + case CONFTYPE_STRING: + buffer_conf_print[0] = '"'; + if(val->v.s) { + strncpy(&buffer_conf_print[1], val->v.s, + SIZEOF(buffer_conf_print) - 1); + buffer_conf_print[SIZEOF(buffer_conf_print) - 2] = '\0'; + buffer_conf_print[strlen(buffer_conf_print)] = '"'; + } else { + buffer_conf_print[1] = '"'; + buffer_conf_print[2] = '\0'; + } + break; + + case CONFTYPE_TIME: + stm = localtime(&val->v.t); + if (stm) { + snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), + "%d%02d%02d", stm->tm_hour, stm->tm_min, stm->tm_sec); + } else { + strcpy(buffer_conf_print, "00000"); + } + break; + + case CONFTYPE_SL: + buffer_conf_print[0] = '\0'; + break; + + case CONFTYPE_EXINCLUDE: + buffer_conf_print[0] = '\0'; + if(val->v.exinclude.type == 0) + strncpy(buffer_conf_print, "LIST ", SIZEOF(buffer_conf_print)); + else + strncpy(buffer_conf_print, "FILE ", SIZEOF(buffer_conf_print)); + pos = 5; + if(val->v.exinclude.optional == 1) + strncpy(&buffer_conf_print[pos], "OPTIONAL ", SIZEOF(buffer_conf_print)); + pos += 9; + break; + + case CONFTYPE_BOOL: + if(val->v.i) + strncpy(buffer_conf_print, "yes", SIZEOF(buffer_conf_print)); + else + strncpy(buffer_conf_print, "no", SIZEOF(buffer_conf_print)); + break; + + case CONFTYPE_STRATEGY: + switch(val->v.i) { + case DS_SKIP: + strncpy(buffer_conf_print, "SKIP", SIZEOF(buffer_conf_print)); + break; + + case DS_STANDARD: + strncpy(buffer_conf_print, "STANDARD", SIZEOF(buffer_conf_print)); + break; + + case DS_NOFULL: + strncpy(buffer_conf_print, "NOFULL", SIZEOF(buffer_conf_print)); + break; + + case DS_NOINC: + strncpy(buffer_conf_print, "NOINC", SIZEOF(buffer_conf_print)); + break; + + case DS_HANOI: + strncpy(buffer_conf_print, "HANOI", SIZEOF(buffer_conf_print)); + break; + + case DS_INCRONLY: + strncpy(buffer_conf_print, "INCRONLY", SIZEOF(buffer_conf_print)); + break; + } + break; + + case CONFTYPE_COMPRESS: + switch(val->v.i) { + case COMP_NONE: + strncpy(buffer_conf_print, "NONE", SIZEOF(buffer_conf_print)); + break; + + case COMP_FAST: + strncpy(buffer_conf_print, "CLIENT FAST", SIZEOF(buffer_conf_print)); + break; + + case COMP_BEST: + strncpy(buffer_conf_print, "CLIENT BEST", SIZEOF(buffer_conf_print)); + break; + + case COMP_CUST: + strncpy(buffer_conf_print, "CLIENT CUSTOM", SIZEOF(buffer_conf_print)); + break; + + case COMP_SERV_FAST: + strncpy(buffer_conf_print, "SERVER FAST", SIZEOF(buffer_conf_print)); + break; + + case COMP_SERV_BEST: + strncpy(buffer_conf_print, "SERVER FAST", SIZEOF(buffer_conf_print)); + break; + + case COMP_SERV_CUST: + strncpy(buffer_conf_print, "SERVER CUSTOM", SIZEOF(buffer_conf_print)); + break; + } + break; + + case CONFTYPE_ESTIMATE: + switch(val->v.i) { + case ES_CLIENT: + strncpy(buffer_conf_print, "CLIENT", SIZEOF(buffer_conf_print)); + break; + + case ES_SERVER: + strncpy(buffer_conf_print, "SERVER", SIZEOF(buffer_conf_print)); + break; + + case ES_CALCSIZE: + strncpy(buffer_conf_print, "CALCSIZE", SIZEOF(buffer_conf_print)); + break; + } + break; + + case CONFTYPE_ENCRYPT: + switch(val->v.i) { + case ENCRYPT_NONE: + strncpy(buffer_conf_print, "NONE", SIZEOF(buffer_conf_print)); + break; + + case ENCRYPT_CUST: + strncpy(buffer_conf_print, "CLIENT", SIZEOF(buffer_conf_print)); + break; + + case ENCRYPT_SERV_CUST: + strncpy(buffer_conf_print, "SERVER", SIZEOF(buffer_conf_print)); + break; + } + break; + + case CONFTYPE_HOLDING: + switch(val->v.i) { + case HOLD_NEVER: + strncpy(buffer_conf_print, "NEVER", SIZEOF(buffer_conf_print)); + break; + + case HOLD_AUTO: + strncpy(buffer_conf_print, "AUTO", SIZEOF(buffer_conf_print)); + break; + + case HOLD_REQUIRED: + strncpy(buffer_conf_print, "REQUIRED", SIZEOF(buffer_conf_print)); + break; + } + break; + + case CONFTYPE_TAPERALGO: + strncpy(buffer_conf_print, taperalgo2str(val->v.i), SIZEOF(buffer_conf_print)); + break; + + case CONFTYPE_PRIORITY: + switch(val->v.i) { + case 0: + strncpy(buffer_conf_print, "LOW", SIZEOF(buffer_conf_print)); + break; + + case 1: + strncpy(buffer_conf_print, "MEDIUM", SIZEOF(buffer_conf_print)); + break; + + case 2: + strncpy(buffer_conf_print, "HIGH", SIZEOF(buffer_conf_print)); + break; + } + break; + } + buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0'; + return buffer_conf_print; +} + +void +conf_init_string( + val_t *val, + char *s) +{ + val->seen = 0; + val->type = CONFTYPE_STRING; + if(s) + val->v.s = stralloc(s); + else + val->v.s = NULL; +} + +void +conf_init_ident( + val_t *val, + char *s) +{ + val->seen = 0; + val->type = CONFTYPE_IDENT; + if(s) + val->v.s = stralloc(s); + else + val->v.s = NULL; +} + +void +conf_init_int( + val_t *val, + int i) +{ + val->seen = 0; + val->type = CONFTYPE_INT; + val->v.i = i; +} + +void +conf_init_bool( + val_t *val, + int i) +{ + val->seen = 0; + val->type = CONFTYPE_BOOL; + val->v.i = i; +} + +void +conf_init_strategy( + val_t *val, + int i) +{ + val->seen = 0; + val->type = CONFTYPE_STRATEGY; + val->v.i = i; +} + +void +conf_init_estimate( + val_t *val, + int i) +{ + val->seen = 0; + val->type = CONFTYPE_ESTIMATE; + val->v.i = i; +} + +void +conf_init_taperalgo( + val_t *val, + int i) +{ + val->seen = 0; + val->type = CONFTYPE_TAPERALGO; + val->v.i = i; +} + +void +conf_init_priority( + val_t *val, + int i) +{ + val->seen = 0; + val->type = CONFTYPE_PRIORITY; + val->v.i = i; +} + +void +conf_init_compress( + val_t *val, + comp_t i) +{ + val->seen = 0; + val->type = CONFTYPE_COMPRESS; + val->v.i = (int)i; +} + +void +conf_init_encrypt( + val_t *val, + encrypt_t i) +{ + val->seen = 0; + val->type = CONFTYPE_ENCRYPT; + val->v.i = (int)i; +} + +void +conf_init_holding( + val_t *val, + dump_holdingdisk_t i) +{ + val->seen = 0; + val->type = CONFTYPE_HOLDING; + val->v.i = (int)i; +} + +void +conf_init_long( + val_t *val, + long l) +{ + val->seen = 0; + val->type = CONFTYPE_LONG; + val->v.l = l; +} + +void +conf_init_size( + val_t *val, + ssize_t sz) +{ + val->seen = 0; + val->type = CONFTYPE_SIZE; + val->v.size = sz; +} + +void +conf_init_am64( + val_t *val, + off_t l) +{ + val->seen = 0; + val->type = CONFTYPE_AM64; + val->v.am64 = l; +} + +void +conf_init_real( + val_t *val, + double r) +{ + val->seen = 0; + val->type = CONFTYPE_REAL; + val->v.r = r; +} + +void +conf_init_rate( + val_t *val, + double r1, + double r2) +{ + val->seen = 0; + val->type = CONFTYPE_RATE; + val->v.rate[0] = r1; + val->v.rate[1] = r2; +} + +void +conf_init_time( + val_t *val, + time_t t) +{ + val->seen = 0; + val->type = CONFTYPE_TIME; + val->v.t = t; +} + +void +conf_init_sl( + val_t *val, + sl_t *sl) +{ + val->seen = 0; + val->type = CONFTYPE_AM64; + val->v.sl = sl; +} + +void +conf_init_exinclude( + val_t *val) +{ + val->seen = 0; + val->type = CONFTYPE_EXINCLUDE; + val->v.exinclude.type = 0; + val->v.exinclude.optional = 0; + val->v.exinclude.sl = NULL; +} + +void +conf_set_string( + val_t *val, + char *s) +{ + val->seen = -1; + val->type = CONFTYPE_STRING; + amfree(val->v.s); + val->v.s = stralloc(s); +} + +void +conf_set_int( + val_t *val, + int i) +{ + val->seen = -1; + val->type = CONFTYPE_INT; + val->v.i = i; +} + +void +conf_set_bool( + val_t *val, + int i) +{ + val->seen = -1; + val->type = CONFTYPE_BOOL; + val->v.i = i; +} + +void +conf_set_compress( + val_t *val, + comp_t i) +{ + val->seen = -1; + val->type = CONFTYPE_COMPRESS; + val->v.i = (int)i; +} + +void +conf_set_encrypt( + val_t *val, + encrypt_t i) +{ + val->seen = -1; + val->type = CONFTYPE_COMPRESS; + val->v.i = (int)i; +} + +void +conf_set_holding( + val_t *val, + dump_holdingdisk_t i) +{ + val->seen = -1; + val->type = CONFTYPE_HOLDING; + val->v.i = (int)i; +} + +void +conf_set_strategy( + val_t *val, + int i) +{ + val->seen = -1; + val->type = CONFTYPE_STRATEGY; + val->v.i = i; +} + + +int +get_conftype_int( + val_t *val) +{ + if (val->type != CONFTYPE_INT) { + error("get_conftype_int: val.type is not CONFTYPE_INT"); + /*NOTREACHED*/ + } + return val->v.i; +} + +long +get_conftype_long( + val_t *val) +{ + if (val->type != CONFTYPE_LONG) { + error("get_conftype_long: val.type is not CONFTYPE_LONG"); + /*NOTREACHED*/ + } + return val->v.l; +} + +off_t +get_conftype_am64( + val_t *val) +{ + if (val->type != CONFTYPE_AM64) { + error("get_conftype_am64: val.type is not CONFTYPE_AM64"); + /*NOTREACHED*/ + } + return val->v.am64; +} + +double +get_conftype_real( + val_t *val) +{ + if (val->type != CONFTYPE_REAL) { + error("get_conftype_real: val.type is not CONFTYPE_REAL"); + /*NOTREACHED*/ + } + return val->v.r; +} + +char * +get_conftype_string( + val_t *val) +{ + if (val->type != CONFTYPE_STRING) { + error("get_conftype_string: val.type is not CONFTYPE_STRING"); + /*NOTREACHED*/ + } + return val->v.s; +} + +char * +get_conftype_ident( + val_t *val) +{ + if (val->type != CONFTYPE_IDENT) { + error("get_conftype_ident: val.type is not CONFTYPE_IDENT"); + /*NOTREACHED*/ + } + return val->v.s; +} + +time_t +get_conftype_time( + val_t *val) +{ + if (val->type != CONFTYPE_TIME) { + error("get_conftype_time: val.type is not CONFTYPE_TIME"); + /*NOTREACHED*/ + } + return val->v.t; +} + +ssize_t +get_conftype_size( + val_t *val) +{ + if (val->type != CONFTYPE_SIZE) { + error("get_conftype_size: val.type is not CONFTYPE_SIZE"); + /*NOTREACHED*/ + } + return val->v.size; +} + +sl_t * +get_conftype_sl( + val_t *val) +{ + if (val->type != CONFTYPE_SL) { + error("get_conftype_size: val.type is not CONFTYPE_SL"); + /*NOTREACHED*/ + } + return val->v.sl; +} + +int +get_conftype_bool( + val_t *val) +{ + if (val->type != CONFTYPE_BOOL) { + error("get_conftype_bool: val.type is not CONFTYPE_BOOL"); + /*NOTREACHED*/ + } + return val->v.i; +} + +int +get_conftype_hold( + val_t *val) +{ + if (val->type != CONFTYPE_HOLDING) { + error("get_conftype_hold: val.type is not CONFTYPE_HOLDING"); + /*NOTREACHED*/ + } + return val->v.i; +} + +int +get_conftype_compress( + val_t *val) +{ + if (val->type != CONFTYPE_COMPRESS) { + error("get_conftype_compress: val.type is not CONFTYPE_COMPRESS"); + /*NOTREACHED*/ + } + return val->v.i; +} + +int +get_conftype_encrypt( + val_t *val) +{ + if (val->type != CONFTYPE_ENCRYPT) { + error("get_conftype_encrypt: val.type is not CONFTYPE_ENCRYPT"); + /*NOTREACHED*/ + } + return val->v.i; +} + +int +get_conftype_estimate( + val_t *val) +{ + if (val->type != CONFTYPE_ESTIMATE) { + error("get_conftype_extimate: val.type is not CONFTYPE_ESTIMATE"); + /*NOTREACHED*/ + } + return val->v.i; +} + +int +get_conftype_strategy( + val_t *val) +{ + if (val->type != CONFTYPE_STRATEGY) { + error("get_conftype_strategy: val.type is not CONFTYPE_STRATEGY"); + /*NOTREACHED*/ + } + return val->v.i; +} + +int +get_conftype_taperalgo( + val_t *val) +{ + if (val->type != CONFTYPE_TAPERALGO) { + error("get_conftype_taperalgo: val.type is not CONFTYPE_TAPERALGO"); + /*NOTREACHED*/ + } + return val->v.i; +} + +int +get_conftype_priority( + val_t *val) +{ + if (val->type != CONFTYPE_PRIORITY) { + error("get_conftype_priority: val.type is not CONFTYPE_PRIORITY"); + /*NOTREACHED*/ + } + return val->v.i; +} + +exinclude_t +get_conftype_exinclude( + val_t *val) +{ + if (val->type != CONFTYPE_EXINCLUDE) { + error("get_conftype_exinclude: val.type is not CONFTYPE_EXINCLUDE"); + /*NOTREACHED*/ + } + return val->v.exinclude; +} + + +void +dump_sockaddr( + struct sockaddr_in * sa) +{ + dbprintf(("%s: (sockaddr_in *)%p = { %d, %d, %s }\n", + debug_prefix_time(NULL), sa, sa->sin_family, + (int)ntohs(sa->sin_port), + inet_ntoa(sa->sin_addr))); +} + +void +read_block( + command_option_t *command_options, + t_conf_var *read_var, + keytab_t *keytab, + val_t *valarray, + char *prefix, + char *errormsg, + int read_brace, + void (*copy_function)(void)) +{ + t_conf_var *np; + int saved_conf_line_num; + int done; + + if(read_brace) { + get_conftoken(CONF_LBRACE); + get_conftoken(CONF_NL); + } + + done = 0; + do { + conf_line_num += 1; + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_RBRACE: + done = 1; + break; + case CONF_NL: /* empty line */ + break; + case CONF_END: /* end of file */ + done = 1; + break; + case CONF_IDENT: + case CONF_STRING: + if(copy_function) + copy_function(); + else + conf_parserror("ident not expected"); + break; + default: + { + for(np = read_var; np->token != CONF_UNKNOWN; np++) + if(np->token == tok) break; + + if(np->token == CONF_UNKNOWN) + conf_parserror(errormsg); + else { + np->read_function(np, &valarray[np->parm]); + if(np->validate) + np->validate(np, &valarray[np->parm]); + } + } + } + if(tok != CONF_NL && tok != CONF_END && tok != CONF_RBRACE) + get_conftoken(CONF_NL); + } while(!done); + + /* overwrite with command line option */ + saved_conf_line_num = conf_line_num; + command_overwrite(command_options, read_var, keytab, valarray, prefix); + conf_line_num = saved_conf_line_num; +} + +void +command_overwrite( + command_option_t *command_options, + t_conf_var *overwrite_var, + keytab_t *keytab, + val_t *valarray, + char *prefix) +{ + t_conf_var *np; + keytab_t *kt; + char *myprefix; + command_option_t *command_option; + + if(!command_options) return; + + for(np = overwrite_var; np->token != CONF_UNKNOWN; np++) { + for(kt = keytab; kt->token != CONF_UNKNOWN; kt++) + if(kt->token == np->token) break; + + if(kt->token == CONF_UNKNOWN) { + error("read_conf: invalid token"); + /* NOTREACHED */ + } + + for(command_option = command_options; command_option->name != NULL; + command_option++) { + myprefix = stralloc2(prefix, kt->keyword); + if(strcasecmp(myprefix, command_option->name) == 0) { + command_option->used = 1; + valarray[np->parm].seen = -2; + if(np->type == CONFTYPE_STRING && + command_option->value[0] != '"') { + conf_line = vstralloc("\"", command_option->value, "\"", + NULL); + } + else { + conf_line = stralloc(command_option->value); + } + conf_char = conf_line; + token_pushed = 0; + conf_line_num = -2; + np->read_function(np, &valarray[np->parm]); + amfree(conf_line); + conf_line = conf_char = NULL; + + if(np->validate) + np->validate(np, &valarray[np->parm]); + } + amfree(myprefix); + } + } +} + +void +free_new_argv( + int new_argc, + char **new_argv) +{ + int i; + for(i=0; i