* 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 <regex.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,
- * 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 <glib.h>
+#include <string.h>
+
+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;
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;
}
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
(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;
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;
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];
if(s > 0) {
return s;
}
+ if (errno != EAGAIN && errno != EBUSY)
+ save_errno = errno;
}
}
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;
}
/* 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;
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 ||
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;
}
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);
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.
*(s++) = 'f';
str++;
continue;
+ } else if (*str == '\\') {
+ *(s++) = '\\';
+ *(s++) = '\\';
+ str++;
+ continue;
}
if (*str == '"')
*(s++) = '\\';
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++);
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)
} 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);
}
/*
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<new_argc; i++)
- amfree(new_argv[i]);
- amfree(new_argv);
-}
-
-
-#ifndef HAVE_LIBREADLINE
-/*
- * simple readline() replacements
- */
-
-char *
-readline(
- const char *prompt)
-{
- printf("%s", prompt);
- fflush(stdout);
- fflush(stderr);
- return agets(stdin);
-}
-
-void
-add_history(
- const char *line)
-{
- (void)line; /* Quite unused parameter warning */
-}
-#endif