X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=common-src%2Futil.c;h=9ca0b4db604d249ffdbd737e614b49c60cc706df;hb=b116e9366c7b2ea2c2eb53b0a13df4090e176235;hp=3564d6b195b87da5d9c6bdf83c7df6ae4b49057f;hpb=71325c297e0436e9930a3e129a26696e78c27f62;p=debian%2Famanda diff --git a/common-src/util.c b/common-src/util.c index 3564d6b..9ca0b4d 100644 --- a/common-src/util.c +++ b/common-src/util.c @@ -24,106 +24,30 @@ * file named AUTHORS, in the root directory of this distribution. */ /* - * $Id: util.c,v 1.42.2.4 2006/09/21 11:12:21 martinea Exp $ + * $Id: util.c,v 1.42 2006/08/24 01:57:15 paddy_s Exp $ */ #include "amanda.h" #include "util.h" +#include "match.h" +#include #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, - * or we get an error. - * - * Returns the number of bytes read, 0 on EOF, or negative on error. - */ -ssize_t -fullread( - int fd, - void * vbuf, - size_t buflen) -{ - ssize_t nread, tot = 0; - char *buf = vbuf; /* cast to char so we can ++ it */ - - while (buflen > 0) { - nread = read(fd, buf, buflen); - if (nread < 0) { - if ((errno == EINTR) || (errno == EAGAIN)) - continue; - return ((tot > 0) ? tot : -1); - } - - if (nread == 0) - break; - - tot += nread; - buf += nread; - buflen -= nread; - } - return (tot); -} - -/* - * Keep calling write() until we've written buflen's worth of data, - * or we get an error. - * - * Returns the number of bytes written, or negative on error. - */ -ssize_t -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 */ - - while (buflen > 0) { - nwritten = write(fd, buf, buflen); - if (nwritten < 0) { - if ((errno == EINTR) || (errno == EAGAIN)) - continue; - return ((tot > 0) ? tot : -1); - } - tot += nwritten; - buf += nwritten; - buflen -= nwritten; - } - return (tot); -} +#include "sockaddr-util.h" +#include "conffile.h" +#include "base64.h" +#include "stream.h" +#include "pipespawn.h" +#include +#include + +static int make_socket(sa_family_t family); +static int connect_port(sockaddr_union *addrp, in_port_t port, char *proto, + sockaddr_union *svaddr, int nonblock); static int -make_socket(void) +make_socket( + sa_family_t family) { int s; int save_errno; @@ -132,11 +56,11 @@ make_socket(void) int r; #endif - if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + g_debug("make_socket opening socket with family %d", family); + s = socket(family, SOCK_STREAM, 0); + if (s == -1) { save_errno = errno; - dbprintf(("%s: make_socket: socket() failed: %s\n", - debug_prefix(NULL), - strerror(save_errno))); + dbprintf(_("make_socket: socket() failed: %s\n"), strerror(save_errno)); errno = save_errno; return -1; } @@ -150,9 +74,8 @@ make_socket(void) 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))); + dbprintf(_("make_socket: setsockopt(SO_REUSEADDR) failed: %s\n"), + strerror(errno)); errno = save_errno; } #endif @@ -162,9 +85,8 @@ make_socket(void) (void *)&on, SIZEOF(on)); if (r == -1) { save_errno = errno; - dbprintf(("%s: make_socket: setsockopt() failed: %s\n", - debug_prefix(NULL), - strerror(save_errno))); + dbprintf(_("make_socket: setsockopt() failed: %s\n"), + strerror(save_errno)); aclose(s); errno = save_errno; return -1; @@ -174,17 +96,22 @@ make_socket(void) return s; } +GQuark am_util_error_quark(void) +{ + return g_quark_from_static_string("am-util-error-quark"); +} + /* 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, + sockaddr_union *addrp, in_port_t first_port, in_port_t last_port, char * proto, - struct sockaddr_in *svaddr, + sockaddr_union *svaddr, int nonblock) { int s; @@ -192,9 +119,9 @@ connect_portrange( static in_port_t port_in_use[1024]; static int nb_port_in_use = 0; int i; + int save_errno = EAGAIN; assert(first_port <= last_port); - /* Try a port already used */ for(i=0; i < nb_port_in_use; i++) { port = port_in_use[i]; @@ -204,6 +131,8 @@ connect_portrange( if(s > 0) { return s; } + if (errno != EAGAIN && errno != EBUSY) + save_errno = errno; } } @@ -215,13 +144,14 @@ connect_portrange( port_in_use[nb_port_in_use++] = port; return s; } + if (errno != EAGAIN && errno != EBUSY) + save_errno = errno; } - dbprintf(("%s: connect_portrange: all ports between %d and %d busy\n", - debug_prefix_time(NULL), + dbprintf(_("connect_portrange: All ports between %d and %d are busy.\n"), first_port, - last_port)); - errno = EAGAIN; + last_port); + errno = save_errno; return -1; } @@ -232,57 +162,62 @@ connect_portrange( /* return >0: this is the connected socket */ int connect_port( - struct sockaddr_in *addrp, + sockaddr_union *addrp, in_port_t port, char * proto, - struct sockaddr_in *svaddr, + sockaddr_union *svaddr, int nonblock) { int save_errno; struct servent * servPort; - socklen_t len; + socklen_t_equiv len; + socklen_t_equiv socklen; 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)); + dbprintf(_("connect_port: Skip port %d: owned by %s.\n"), + port, servPort->s_name); + errno = EBUSY; 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; + if ((s = make_socket(SU_GET_FAMILY(addrp))) == -1) return -2; - addrp->sin_port = (in_port_t)htons(port); - - if (bind(s, (struct sockaddr *)addrp, sizeof(*addrp)) != 0) { + SU_SET_PORT(addrp, port); + socklen = SS_LEN(addrp); + if (bind(s, (struct sockaddr *)addrp, socklen) != 0) { save_errno = errno; aclose(s); + if(servPort == NULL) { + dbprintf(_("connect_port: Try port %d: available - %s\n"), + port, strerror(errno)); + } else { + dbprintf(_("connect_port: Try port %d: owned by %s - %s\n"), + port, servPort->s_name, strerror(errno)); + } if (save_errno != EADDRINUSE) { - dbprintf(("errno %d strerror %s\n", - errno, strerror(errno))); errno = save_errno; return -2; } + errno = save_errno; return -1; } + if(servPort == NULL) { + dbprintf(_("connect_port: Try port %d: available - Success\n"), port); + } else { + dbprintf(_("connect_port: Try port %d: owned by %s - Success\n"), + port, servPort->s_name); + } /* 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))); + dbprintf(_("connect_port: getsockname() failed: %s\n"), + strerror(save_errno)); aclose(s); errno = save_errno; return -1; @@ -290,19 +225,14 @@ connect_port( 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) { + if (connect(s, (struct sockaddr *)svaddr, SS_LEN(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))); + dbprintf(_("connect_portrange: Connect from %s failed: %s\n"), + str_sockaddr(addrp), + strerror(save_errno)); + dbprintf(_("connect_portrange: connect to %s failed: %s\n"), + str_sockaddr(svaddr), + strerror(save_errno)); aclose(s); errno = save_errno; if (save_errno == ECONNREFUSED || @@ -314,14 +244,10 @@ connect_port( 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))); + dbprintf(_("connected to %s\n"), + str_sockaddr(svaddr)); + dbprintf(_("our side is %s\n"), + str_sockaddr(addrp)); return s; } @@ -335,15 +261,17 @@ connect_port( int bind_portrange( int s, - struct sockaddr_in *addrp, + sockaddr_union *addrp, in_port_t first_port, in_port_t last_port, char * proto) { in_port_t port; in_port_t cnt; + socklen_t_equiv socklen; struct servent *servPort; const in_port_t num_ports = (in_port_t)(last_port - first_port + 1); + int save_errno = EAGAIN; assert(first_port <= last_port); @@ -361,110 +289,156 @@ bind_portrange( for (cnt = 0; cnt < num_ports; cnt++) { servPort = getservbyport((int)htons(port), proto); if ((servPort == NULL) || strstr(servPort->s_name, "amanda")) { + SU_SET_PORT(addrp, port); + socklen = SS_LEN(addrp); + if (bind(s, (struct sockaddr *)addrp, socklen) >= 0) { + if (servPort == NULL) { + g_debug(_("bind_portrange2: Try port %d: Available - Success"), port); + } else { + g_debug(_("bind_portrange2: Try port %d: Owned by %s - Success."), port, servPort->s_name); + } + return 0; + } + if (errno != EAGAIN && errno != EBUSY) + save_errno = errno; if (servPort == NULL) { - dbprintf(("%s: bind_portrange2: Try port %d: Available - ", - debug_prefix_time(NULL), port)); + g_debug(_("bind_portrange2: Try port %d: Available - %s"), + port, strerror(errno)); } 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; + g_debug(_("bind_portrange2: Try port %d: Owned by %s - %s"), + port, servPort->s_name, strerror(errno)); } - 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)); + g_debug(_("bind_portrange2: Skip port %d: Owned by %s."), + port, servPort->s_name); } if (++port > last_port) port = first_port; } - dbprintf(("%s: bind_portrange: all ports between %d and %d busy\n", - debug_prefix_time(NULL), + g_debug(_("bind_portrange: all ports between %d and %d busy"), first_port, - last_port)); - errno = EAGAIN; + last_port); + errno = save_errno; return -1; } -/* - * Construct a datestamp (YYYYMMDD) from a time_t. - */ -char * -construct_datestamp( - time_t *t) -{ - struct tm *tm; - char datestamp[3 * NUM_STR_SIZE]; - time_t when; - - if (t == NULL) { - when = time((time_t *)NULL); - } else { - when = *t; +int +interruptible_accept( + int sock, + struct sockaddr *addr, + socklen_t *addrlen, + gboolean (*prolong)(gpointer data), + gpointer prolong_data) +{ + SELECT_ARG_TYPE readset; + struct timeval tv; + int nfound; + + if (sock < 0 || sock >= FD_SETSIZE) { + g_debug("interruptible_accept: bad socket %d", sock); + return EBADF; } - tm = localtime(&when); - 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); + memset(&readset, 0, SIZEOF(readset)); + + while (1) { + if (!prolong(prolong_data)) { + errno = 0; + return -1; + } + + FD_ZERO(&readset); + FD_SET(sock, &readset); + + /* try accepting for 1s */ + memset(&tv, 0, SIZEOF(tv)); + tv.tv_sec = 1; + + nfound = select(sock+1, &readset, NULL, NULL, &tv); + if (nfound < 0) { + return -1; + } else if (nfound == 0) { + continue; + } else if (!FD_ISSET(sock, &readset)) { + g_debug("interruptible_accept: select malfunction"); + errno = EBADF; + return -1; + } else { + int rv = accept(sock, addr, addrlen); + if (rv < 0 && errno == EAGAIN) + continue; + return rv; + } + } } /* - * Construct a timestamp (YYYYMMDDHHMMSS) from a time_t. + * Writes out the entire iovec */ -char * -construct_timestamp( - time_t *t) +ssize_t +full_writev( + int fd, + struct iovec * iov, + int iovcnt) { - struct tm *tm; - char timestamp[6 * NUM_STR_SIZE]; - time_t when; - - if (t == NULL) { - when = time((time_t *)NULL); - } else { - when = *t; - } - tm = localtime(&when); - 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); -} + ssize_t delta, n, total; + assert(iov != NULL); -int -needs_quotes( - const char * str) -{ - return (match("[ \t\f\r\n\"]", str) != 0); + total = 0; + while (iovcnt > 0) { + /* + * Write the iovec + */ + n = writev(fd, iov, iovcnt); + if (n < 0) { + if (errno != EINTR) + return (-1); + } + else if (n == 0) { + errno = EIO; + return (-1); + } else { + total += n; + /* + * Iterate through each iov. Figure out what we still need + * to write out. + */ + for (; n > 0; iovcnt--, iov++) { + /* 'delta' is the bytes written from this iovec */ + delta = ((size_t)n < (size_t)iov->iov_len) ? n : (ssize_t)iov->iov_len; + /* subtract from the total num bytes written */ + n -= delta; + assert(n >= 0); + /* subtract from this iovec */ + iov->iov_len -= delta; + iov->iov_base = (char *)iov->iov_base + delta; + /* if this iovec isn't empty, run the writev again */ + if (iov->iov_len > 0) + break; + } + } + } + return (total); } /* - * For backward compatibility we are trying for minimal quoting. - * We only quote a string if it contains whitespace or is misquoted... + * For backward compatibility we are trying for minimal quoting. Unless ALWAYS + * is true, we only quote a string if it contains whitespace or is misquoted... */ char * -quote_string( - const char *str) +quote_string_maybe( + const char *str, + gboolean always) { char * s; char * ret; if ((str == NULL) || (*str == '\0')) { ret = stralloc("\"\""); - } else if ((match("[\\\"[:space:][:cntrl:]]", str)) == 0) { + } else if (!always && (match("[:\'\\\"[:space:][:cntrl:]]", str)) == 0) { /* * String does not need to be quoted since it contains * neither whitespace, control or quote characters. @@ -498,6 +472,11 @@ quote_string( *(s++) = 'f'; str++; continue; + } else if (*str == '\\') { + *(s++) = '\\'; + *(s++) = '\\'; + str++; + continue; } if (*str == '"') *(s++) = '\\'; @@ -547,6 +526,19 @@ unquote_string( in++; *(out++) = '\f'; continue; + } else if (*in >= '0' && *in <= '7') { + char c = 0; + int i = 0; + + while (i < 3 && *in >= '0' && *in <= '7') { + c = (c << 3) + *(in++) - '0'; + i++; + } + if (c) + *(out++) = c; + } else if (*in == '\0') { + /* trailing backslash -- ignore */ + break; } } *(out++) = *(in++); @@ -556,6 +548,91 @@ unquote_string( return (ret); } +gchar ** +split_quoted_strings( + const gchar *string) +{ + char *local; + char *start; + char *p; + char **result; + GPtrArray *strs; + int iq = 0; + + if (!string) + return NULL; + + p = start = local = g_strdup(string); + strs = g_ptr_array_new(); + + while (*p) { + if (!iq && *p == ' ') { + *p = '\0'; + g_ptr_array_add(strs, unquote_string(start)); + start = p+1; + } else if (*p == '\\') { + /* next character is taken literally; if it's a multicharacter + * escape (e.g., \171), that doesn't bother us here */ + p++; + if (!*p) break; + } else if (*p == '\"') { + iq = ! iq; + } + + p++; + } + if (start != string) + g_ptr_array_add(strs, unquote_string(start)); + + /* now convert strs into a strv, by stealing its references to the underlying + * strings */ + result = g_new0(char *, strs->len + 1); + memmove(result, strs->pdata, sizeof(char *) * strs->len); + + g_ptr_array_free(strs, TRUE); /* TRUE => free pdata, strings are not freed */ + g_free(local); + + return result; +} + +char * +strquotedstr(char **saveptr) +{ + char * tok = strtok_r(NULL, " ", saveptr); + size_t len; + int in_quote; + int in_backslash; + char *p, *t; + + if (!tok) + return tok; + len = strlen(tok); + in_quote = 0; + in_backslash = 0; + p = tok; + while (in_quote || in_backslash || *p != '\0') { + if (*p == '\0') { + /* append a new token */ + t = strtok_r(NULL, " ", saveptr); + if (!t) + return NULL; + tok[len] = ' '; + len = strlen(tok); + } + if (!in_backslash) { + if (*p == '"') + in_quote = !in_quote; + else if (*p == '\\') { + in_backslash = 1; + } + } else { + in_backslash = 0; + } + p++; + } + return tok; +} + char * sanitize_string( const char *str) @@ -568,50 +645,314 @@ sanitize_string( } else { ret = stralloc(str); for (s = ret; *s != '\0'; s++) { - if (iscntrl(*s)) + if (iscntrl((int)*s)) *s = '?'; } } return (ret); } -char * -strquotedstr(void) +char *hexencode_string(const char *str) { - char * tok = strtok(NULL, " "); + size_t orig_len, new_len, i; + GString *s; + gchar *ret; + if (!str) { + s = g_string_sized_new(0); + goto cleanup; + } + new_len = orig_len = strlen(str); + for (i = 0; i < orig_len; i++) { + if (!g_ascii_isalnum(str[i])) { + new_len += 2; + } + } + s = g_string_sized_new(new_len); - if ((tok != NULL) && (tok[0] == '"')) { - char * t; - size_t len; + for (i = 0; i < orig_len; i++) { + if (g_ascii_isalnum(str[i])) { + g_string_append_c(s, str[i]); + } else { + g_string_append_printf(s, "%%%02hhx", str[i]); + } + } - len = strlen(tok); - do { - t = strtok(NULL, " "); - tok[len] = ' '; - len = strlen(tok); - } while ((t != NULL) && - (tok[len - 1] != '"') && (tok[len - 2] != '\\')); +cleanup: + ret = s->str; + g_string_free(s, FALSE); + return ret; +} + +char *hexdecode_string(const char *str, GError **err) +{ + size_t orig_len, new_len, i; + GString *s; + gchar *ret; + if (!str) { + s = g_string_sized_new(0); + goto cleanup; } - return tok; + new_len = orig_len = strlen(str); + for (i = 0; i < orig_len; i++) { + if (str[i] == '%') { + new_len -= 2; + } + } + s = g_string_sized_new(new_len); + + for (i = 0; (orig_len > 2) && (i < orig_len-2); i++) { + if (str[i] == '%') { + gchar tmp = 0; + size_t j; + for (j = 1; j < 3; j++) { + tmp <<= 4; + if (str[i+j] >= '0' && str[i+j] <= '9') { + tmp += str[i+j] - '0'; + } else if (str[i+j] >= 'a' && str[i+j] <= 'f') { + tmp += str[i+j] - 'a' + 10; + } else if (str[i+j] >= 'A' && str[i+j] <= 'F') { + tmp += str[i+j] - 'A' + 10; + } else { + /* error */ + g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL, + "Illegal character (non-hex) 0x%02hhx at offset %zd", str[i+j], i+j); + g_string_truncate(s, 0); + goto cleanup; + } + } + if (!tmp) { + g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL, + "Encoded NULL at starting offset %zd", i); + g_string_truncate(s, 0); + goto cleanup; + } + g_string_append_c(s, tmp); + i += 2; + } else { + g_string_append_c(s, str[i]); + } + } + for ( /*nothing*/; i < orig_len; i++) { + if (str[i] == '%') { + g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL, + "'%%' found at offset %zd, but fewer than two characters follow it (%zd)", i, orig_len-i-1); + g_string_truncate(s, 0); + goto cleanup; + } else { + g_string_append_c(s, str[i]); + } + } + +cleanup: + ret = s->str; + g_string_free(s, FALSE); + return ret; +} + +/* Helper for parse_braced_component; this will turn a single element array + * matching /^\d+\.\.\d+$/ into a sequence of numbered array elements. */ +static GPtrArray * +expand_braced_sequence(GPtrArray *arr) +{ + char *elt, *p; + char *l, *r; + int ldigits, rdigits, ndigits; + guint64 start, end; + gboolean leading_zero; + + /* check whether the element matches the pattern */ + /* expand last element of the array only */ + elt = g_ptr_array_index(arr, arr->len-1); + ldigits = 0; + for (l = p = elt; *p && g_ascii_isdigit(*p); p++) + ldigits++; + if (ldigits == 0) + return arr; + if (*(p++) != '.') + return arr; + if (*(p++) != '.') + return arr; + rdigits = 0; + for (r = p; *p && g_ascii_isdigit(*p); p++) + rdigits++; + if (rdigits == 0) + return arr; + if (*p) + return arr; + + /* we have a match, so extract start and end */ + start = g_ascii_strtoull(l, NULL, 10); + end = g_ascii_strtoull(r, NULL, 10); + leading_zero = *l == '0'; + ndigits = MAX(ldigits, rdigits); + if (start > end) + return arr; + + /* sanity check.. */ + if (end - start > 100000) + return arr; + + /* remove last from the array */ + g_ptr_array_remove_index(arr, arr->len - 1); + + /* Add new elements */ + while (start <= end) { + if (leading_zero) { + g_ptr_array_add(arr, g_strdup_printf("%0*ju", + ndigits, (uintmax_t)start)); + } else { + g_ptr_array_add(arr, g_strdup_printf("%ju", (uintmax_t)start)); + } + start++; + } + + return arr; } -ssize_t -hexdump( - const char *buffer, - size_t len) +/* Helper for expand_braced_alternates; returns a list of un-escaped strings + * for the first "component" of str, where a component is a plain string or a + * brace-enclosed set of alternatives. str is pointing to the first character + * of the next component on return. */ +static GPtrArray * +parse_braced_component(char **str) +{ + GPtrArray *result = g_ptr_array_new(); + + if (**str == '{') { + char *p = (*str)+1; + char *local = g_malloc(strlen(*str)+1); + char *current = local; + char *c = current; + + while (1) { + if (*p == '\0' || *p == '{') { + /* unterminated { .. } or extra '{' */ + amfree(local); + g_ptr_array_free(result, TRUE); + return NULL; + } + + if (*p == '}' || *p == ',') { + *c = '\0'; + g_ptr_array_add(result, g_strdup(current)); + result = expand_braced_sequence(result); + current = ++c; + + if (*p == '}') + break; + else + p++; + } + + if (*p == '\\') { + if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',') + p++; + } + *(c++) = *(p++); + } + + amfree(local); + + if (*p) + *str = p+1; + else + *str = p; + } else { + /* no braces -- just un-escape a plain string */ + char *local = g_malloc(strlen(*str)+1); + char *r = local; + char *p = *str; + + while (*p && *p != '{') { + if (*p == '\\') { + if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',') + p++; + } + *(r++) = *(p++); + } + *r = '\0'; + g_ptr_array_add(result, local); + *str = p; + } + + return result; +} + +GPtrArray * +expand_braced_alternates( + char * source) +{ + GPtrArray *rval = g_ptr_array_new(); + + g_ptr_array_add(rval, g_strdup("")); + + while (*source) { + GPtrArray *new_components; + GPtrArray *new_rval; + guint i, j; + + new_components = parse_braced_component(&source); + if (!new_components) { + /* parse error */ + g_ptr_array_free(rval, TRUE); + return NULL; + } + + new_rval = g_ptr_array_new(); + + /* do a cartesian join of rval and new_components */ + for (i = 0; i < rval->len; i++) { + for (j = 0; j < new_components->len; j++) { + g_ptr_array_add(new_rval, g_strconcat( + g_ptr_array_index(rval, i), + g_ptr_array_index(new_components, j), + NULL)); + } + } + + g_ptr_array_free(rval, TRUE); + g_ptr_array_free(new_components, TRUE); + rval = new_rval; + } + + return rval; +} + +char * +collapse_braced_alternates( + GPtrArray *source) { - 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); + GString *result = NULL; + guint i; + + result = g_string_new("{"); + + for (i = 0; i < source->len; i ++) { + const char *str = g_ptr_array_index(source, i); + char *qstr = NULL; + + if (strchr(str, ',') || strchr(str, '\\') || + strchr(str, '{') || strchr(str, '}')) { + const char *s; + char *d; + + s = str; + qstr = d = g_malloc(strlen(str)*2+1); + while (*s) { + if (*s == ',' || *s == '\\' || *s == '{' || *s == '}') + *(d++) = '\\'; + *(d++) = *(s++); + } + *(d++) = '\0'; + } + g_string_append_printf(result, "%s%s", qstr? qstr : str, + (i < source->len-1)? "," : ""); + if (qstr) + g_free(qstr); } - return rc; + + g_string_append(result, "}"); + return g_string_free(result, FALSE); } /* @@ -627,2041 +968,563 @@ validate_mailto( return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto); } - -t_conf_var * -get_np( - t_conf_var *get_var, - int parm) +int copy_file( + char *dst, + char *src, + char **errmsg) { - t_conf_var *np; + int infd, outfd; + int save_errno; + size_t nb; + char buf[32768]; + char *quoted; - for(np = get_var; np->token != CONF_UNKNOWN; np++) { - if(np->parm == parm) - break; + if ((infd = open(src, O_RDONLY)) == -1) { + save_errno = errno; + quoted = quote_string(src); + *errmsg = vstrallocf(_("Can't open file '%s' for reading: %s"), + quoted, strerror(save_errno)); + amfree(quoted); + return -1; } - if(np->token == CONF_UNKNOWN) { - error("error [unknown getconf_np parm: %d]", parm); - /* NOTREACHED */ + if ((outfd = open(dst, O_WRONLY|O_CREAT, 0600)) == -1) { + save_errno = errno; + quoted = quote_string(dst); + *errmsg = vstrallocf(_("Can't open file '%s' for writting: %s"), + quoted, strerror(save_errno)); + amfree(quoted); + close(infd); + return -1; + } + + while((nb=read(infd, &buf, SIZEOF(buf))) > 0) { + if(full_write(outfd,&buf,nb) < nb) { + save_errno = errno; + quoted = quote_string(dst); + *errmsg = vstrallocf(_("Error writing to '%s': %s"), + quoted, strerror(save_errno)); + amfree(quoted); + close(infd); + close(outfd); + return -1; + } + } + + if (errno != 0) { + save_errno = errno; + quoted = quote_string(src); + *errmsg = vstrallocf(_("Error reading from '%s': %s"), + quoted, strerror(save_errno)); + amfree(quoted); + close(infd); + close(outfd); + return -1; } - return np; + + close(infd); + close(outfd); + return 0; } -void -get_simple( - val_t *var, - tok_t type) +#ifndef HAVE_READLINE +/* + * simple readline() replacements, used when we don't have readline + * support from the system. + */ + +char * +readline( + const char *prompt) { - 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; + g_printf("%s", prompt); + fflush(stdout); + fflush(stderr); + return agets(stdin); } -time_t -get_time(void) +void +add_history( + const char *line) { - 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; + (void)line; /* Quiet unused parameter warning */ +} - 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"); +/* Order of preference: readdir64(), readdir(). */ +#if HAVE_DECL_READDIR64 +# define USE_DIRENT64 +# define USE_READDIR64 +#elif HAVE_DECL_READDIR +# define USE_READDIR +#else +# error No readdir() or readdir64() available! #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; +char * portable_readdir(DIR* handle) { - case CONF_AMINFINITY: - hhmm = TIME_MAX; - break; +#ifdef USE_DIRENT64 + struct dirent64 *entry_p; +#else + struct dirent *entry_p; +#endif - default: - conf_parserror("a time is expected"); - hhmm = 0; - break; - } - return hhmm; -} + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; -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 } -}; + g_static_mutex_lock(&mutex); -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"); +#ifdef USE_READDIR + entry_p = readdir(handle); #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"); +#ifdef USE_READDIR64 + entry_p = readdir64(handle); #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; + g_static_mutex_unlock(&mutex); + + if (entry_p == NULL) + return NULL; - default: - conf_parserror("an int is expected"); - val = 0; - break; - } + /* FIXME: According to glibc documentation, d_name may not be + null-terminated in some cases on some very old platforms. Not + sure what to do about that case. */ + return strdup(entry_p->d_name); +} + +int search_directory(DIR * handle, const char * regex, + SearchDirectoryFunctor functor, gpointer user_data) { + int rval = 0; + regex_t compiled_regex; + gboolean done = FALSE; - /* 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; + if (regcomp(&compiled_regex, regex, REG_EXTENDED | REG_NOSUB) != 0) { + regfree(&compiled_regex); + return -1; } - keytable = save_kt; - return val; + rewinddir(handle); + + while (!done) { + char * read_name; + int result; + read_name = portable_readdir(handle); + if (read_name == NULL) { + regfree(&compiled_regex); + return rval; + } + result = regexec(&compiled_regex, read_name, 0, NULL, 0); + if (result == 0) { + rval ++; + done = !functor(read_name, user_data); + } + amfree(read_name); + } + regfree(&compiled_regex); + return rval; } -long -get_long(void) -{ - long val; - keytab_t *save_kt; +char* find_regex_substring(const char* base_string, const regmatch_t match) { + char * rval; + int size; - save_kt = keytable; - keytable = numb_keytable; + size = match.rm_eo - match.rm_so; + rval = malloc(size+1); + memcpy(rval, base_string + match.rm_so, size); + rval[size] = '\0'; - get_conftoken(CONF_ANY); + return rval; +} + +int compare_possibly_null_strings(const char * a, const char * b) { + if (a == b) { + /* NULL or otherwise, they're the same. */ + return 0; + } else if (a == NULL) { + /* b != NULL */ + return -1; + } else if (b == NULL) { + /* a != NULL */ + return 1; + } else { + /* a != NULL != b */ + return strcmp(a, b); + } +} - switch(tok) { - case CONF_LONG: - val = tokenval.v.l; - break; +int +resolve_hostname(const char *hostname, + int socktype, + struct addrinfo **res, + char **canonname) +{ + struct addrinfo hints; + struct addrinfo *myres; + int flags = 0; + int result; + + if (res) *res = NULL; + if (canonname) { + *canonname = NULL; + flags = AI_CANONNAME; + } - 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"); +#ifdef AI_ADDRCONFIG + flags |= AI_ADDRCONFIG; #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; + memset(&hints, 0, sizeof(hints)); +#ifdef WORKING_IPV6 + /* get any kind of addresss */ + hints.ai_family = AF_UNSPEC; +#else + /* even if getaddrinfo supports IPv6, don't let it return + * such an address */ + hints.ai_family = AF_INET; +#endif + hints.ai_flags = flags; + hints.ai_socktype = socktype; + result = getaddrinfo(hostname, NULL, &hints, &myres); + if (result != 0) { + return result; + } - default: - conf_parserror("a long is expected"); - val = 0; - break; + if (canonname && myres && myres->ai_canonname) { + *canonname = stralloc(myres->ai_canonname); } - /* 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; + if (res) { + *res = myres; + } else { + freeaddrinfo(myres); } - keytable = save_kt; - return val; + return result; } -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; +char * +_str_exit_status( + char *subject, + amwait_t status) +{ + if (WIFEXITED(status)) { + int exitstatus = WEXITSTATUS(status); + if (exitstatus == 0) + return vstrallocf(_("%s exited normally"), subject); + else + return vstrallocf(_("%s exited with status %d"), subject, exitstatus); + } - 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"); + if (WIFSIGNALED(status)) { + int signal = WTERMSIG(status); +#ifdef WCOREDUMP + if (WCOREDUMP(status)) + return vstrallocf(_("%s exited after receiving signal %d (core dumped)"), + subject, signal); + else #endif - val = (ssize_t)tokenval.v.am64; - break; - - case CONF_AMINFINITY: - val = (ssize_t)SSIZE_MAX; - break; + return vstrallocf(_("%s exited after receiving signal %d"), + subject, signal); + } - default: - conf_parserror("an integer is expected"); - val = 0; - break; + if (WIFSTOPPED(status)) { + int signal = WSTOPSIG(status); + return vstrallocf(_("%s stopped temporarily after receiving signal %d"), + subject, signal); } - /* 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; +#ifdef WIFCONTINUED + if (WIFCONTINUED(status)) { + return vstrallocf(_("%s was resumed"), subject); } +#endif - keytable = save_kt; - return val; + return vstrallocf(_("%s exited in unknown circumstances"), subject); } -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; +void +check_running_as(running_as_flags who) +{ +#ifdef CHECK_USERID + struct passwd *pw; + uid_t uid_me; + uid_t uid_target; + char *uname_me = NULL; + char *uname_target = NULL; + char *dumpuser; + + uid_me = getuid(); + if ((pw = getpwuid(uid_me)) == NULL) { + error(_("current userid %ld not found in password database"), (long)uid_me); + /* NOTREACHED */ + } + uname_me = stralloc(pw->pw_name); - case CONF_SIZE: - val = (off_t)tokenval.v.size; - break; +#ifndef SINGLE_USERID + if (!(who & RUNNING_AS_UID_ONLY) && uid_me != geteuid()) { + error(_("euid (%lld) does not match uid (%lld); is this program setuid-root when it shouldn't be?"), + (long long int)geteuid(), (long long int)uid_me); + /* NOTREACHED */ + } +#endif - case CONF_AM64: - val = tokenval.v.am64; - break; + switch (who & RUNNING_AS_USER_MASK) { + case RUNNING_AS_ANY: + uid_target = uid_me; + uname_target = uname_me; + amfree(uname_me); + return; + + case RUNNING_AS_ROOT: + uid_target = 0; + uname_target = "root"; + break; + + case RUNNING_AS_DUMPUSER_PREFERRED: + dumpuser = getconf_str(CNF_DUMPUSER); + if ((pw = getpwnam(dumpuser)) != NULL && + uid_me != pw->pw_uid) { + if ((pw = getpwnam(CLIENT_LOGIN)) != NULL && + uid_me == pw->pw_uid) { + /* uid == CLIENT_LOGIN: not ideal, but OK */ + dbprintf(_("NOTE: running as '%s', which is the client" + " user, not the dumpuser ('%s'); forging" + " on anyway\n"), + CLIENT_LOGIN, dumpuser); + uid_target = uid_me; /* force success below */ + break; + } + } + /* FALLTHROUGH */ + + case RUNNING_AS_DUMPUSER: + uname_target = getconf_str(CNF_DUMPUSER); + if ((pw = getpwnam(uname_target)) == NULL) { + error(_("cannot look up dumpuser \"%s\""), uname_target); + /*NOTREACHED*/ + } + uid_target = pw->pw_uid; + break; - case CONF_AMINFINITY: - val = AM64_MAX; - break; + case RUNNING_AS_CLIENT_LOGIN: + uname_target = CLIENT_LOGIN; + if ((pw = getpwnam(uname_target)) == NULL) { + error(_("cannot look up client user \"%s\""), uname_target); + /*NOTREACHED*/ + } + uid_target = pw->pw_uid; + break; - default: - conf_parserror("an am64 is expected %d", tok); - val = 0; - break; + default: + error(_("Unknown check_running_as() call")); + /* NOTREACHED */ } - /* 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; + if (uid_me != uid_target) { + error(_("running as user \"%s\" instead of \"%s\""), uname_me, uname_target); + /*NOTREACHED*/ } + amfree(uname_me); - keytable = save_kt; - - return val; +#else + /* Quiet unused variable warning */ + (void)who; +#endif } -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) +set_root_privs(int need_root) { - int val; - keytab_t *save_kt; - - save_kt = keytable; - keytable = bool_keytable; +#ifndef SINGLE_USERID + static gboolean first_call = TRUE; + static uid_t unpriv = 1; - 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; - } + if (first_call) { + /* save the original real userid (that of our invoker) */ + unpriv = getuid(); - keytable = save_kt; - return val; -} + /* and set all of our userids (including, importantly, the saved + * userid) to 0 */ + setuid(0); -void -ckseen( - int *seen) -{ - if (*seen && !allow_overwrites && conf_line_num != -2) { - conf_parserror("duplicate parameter, prev def on line %d", *seen); + /* don't need to do this next time */ + first_call = FALSE; } - *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); + if (need_root == 1) { + if (geteuid() == 0) return 1; /* already done */ - got_parserror = 1; -} - -tok_t -lookup_keyword( - char * str) -{ - keytab_t *kwp; + if (seteuid(0) == -1) return 0; + /* (we don't switch the group back) */ + } else if (need_root == -1) { + /* make sure the euid is 0 so that we can set the uid */ + if (geteuid() != 0) { + if (seteuid(0) == -1) return 0; + } - /* switch to binary search if performance warrants */ + /* now set the uid to the unprivileged userid */ + if (setuid(unpriv) == -1) return 0; + } else { + if (geteuid() != 0) return 1; /* already done */ - for(kwp = keytable; kwp->keyword != NULL; kwp++) { - if (strcmp(kwp->keyword, str) == 0) break; + /* set the *effective* userid only */ + if (seteuid(unpriv) == -1) return 0; + if (setegid(getgid()) == -1) return 0; } - 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; +#else + (void)need_root; /* Quiet unused variable warning */ +#endif + return 1; } int -conftoken_getc(void) +become_root(void) { - if(conf_line == NULL) - return getc(conf_conf); - if(*conf_char == '\0') - return -1; - return(*conf_char++); -} +#ifndef SINGLE_USERID + /* first, set the effective userid to 0 */ + if (seteuid(0) == -1) return 0; -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; + /* then, set all of the userids to 0 */ + if (setuid(0) == -1) return 0; +#endif + return 1; } -void -get_conftoken( - tok_t exp) +char * +base64_decode_alloc_string( + char *in) { - 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; + char *out; + size_t in_len = strlen(in); + size_t out_len = 3 * (in_len / 4) + 3; - /* - ** 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; - } + out = malloc(out_len); + if (!base64_decode(in, in_len, out, &out_len)) { + amfree(out); + return NULL; } - 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; + out[out_len] = '\0'; - case '\n': - tok = CONF_NL; - break; + return out; +} - case EOF: - tok = CONF_END; - break; - default: - tok = CONF_UNKNOWN; - break; - } +/* A GHFunc (callback for g_hash_table_foreach), + * Store a property and it's value in an ARGV. + * + * @param key_p: (char *) property name. + * @param value_p: (GSList *) property values list. + * @param user_data_p: (char ***) pointer to ARGV. + */ +static void +proplist_add_to_argv( + gpointer key_p, + gpointer value_p, + gpointer user_data_p) +{ + char *property_s = key_p; + property_t *value_s = value_p; + GPtrArray *argv_ptr = user_data_p; + GSList *value; + char *q, *w, *qprop; + + q = stralloc(property_s); + /* convert to lower case */ + for (w=q; *w != '\0'; w++) { + *w = tolower(*w); + if (*w == '_') + *w = '-'; } - - 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 = ""; + qprop = stralloc2("--", q); + amfree(q); + for(value=value_s->values; value != NULL; value = value->next) { + g_ptr_array_add(argv_ptr, stralloc(qprop)); + g_ptr_array_add(argv_ptr, stralloc((char *)value->data)); } + amfree(qprop); } - void -read_string( - t_conf_var *np, - val_t *val) +property_add_to_argv( + GPtrArray *argv_ptr, + GHashTable *proplist) { - np = np; - ckseen(&val->seen); - get_conftoken(CONF_STRING); - val->v.s = newstralloc(val->v.s, tokenval.v.s); + g_hash_table_foreach(proplist, &proplist_add_to_argv, argv_ptr); } -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(); -} +/* + * Process parameters + */ + +static char *pname = NULL; +static char *ptype = NULL; +static pcontext_t pcontext = CONTEXT_DEFAULT; void -read_long( - t_conf_var *np, - val_t *val) +set_pname(char *p) { - np = np; - ckseen(&val->seen); - val->v.l = get_long(); + pname = newstralloc(pname, p); } -void -read_size( - t_conf_var *np, - val_t *val) +char * +get_pname(void) { - np = np; - ckseen(&val->seen); - val->v.size = get_size(); + if (!pname) pname = stralloc("unknown"); + return pname; } void -read_am64( - t_conf_var *np, - val_t *val) +set_ptype(char *p) { - np = np; - ckseen(&val->seen); - val->v.am64 = get_am64_t(); + ptype = newstralloc(ptype, p); } -void -read_bool( - t_conf_var *np, - val_t *val) +char * +get_ptype(void) { - np = np; - ckseen(&val->seen); - val->v.i = get_bool(); + if (!ptype) ptype = stralloc("unknown"); + return ptype; } void -read_real( - t_conf_var *np, - val_t *val) +set_pcontext(pcontext_t pc) { - np = np; - ckseen(&val->seen); - get_conftoken(CONF_REAL); - val->v.r = tokenval.v.r; + pcontext = pc; } -void -read_time( - t_conf_var *np, - val_t *val) +pcontext_t +get_pcontext(void) { - np = np; - ckseen(&val->seen); - val->v.t = get_time(); + return pcontext; } +#ifdef __OpenBSD__ void -copy_val_t( - val_t *valdst, - val_t *valsrc) +openbsd_fd_inform(void) { - 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; - } + int i; + for (i = DATA_FD_OFFSET; i < DATA_FD_OFFSET + DATA_FD_COUNT*2; i++) { + /* a simple fcntl() will cause the library to "look" at this file + * descriptor, which is good enough */ + (void)fcntl(i, F_GETFL); } } +#endif void -free_val_t( - val_t *val) +debug_executing( + GPtrArray *argv_ptr) { - 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; + guint i; + char *cmdline = stralloc((char *)g_ptr_array_index(argv_ptr, 0)); - case CONFTYPE_EXINCLUDE: - free_sl(val->v.exinclude.sl); - break; + for (i = 1; i < argv_ptr->len-1; i++) { + char *arg = g_shell_quote((char *)g_ptr_array_index(argv_ptr, i)); + cmdline = vstrextend(&cmdline, " ", arg, NULL); + amfree(arg); } - 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"; + g_debug("Executing: %s\n", cmdline); + amfree(cmdline); } -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