Imported Upstream version 2.6.1p1
[debian/amanda] / common-src / util.c
index bb27cfac0618d1af986bd06eae9a231d61111a0e..1c1856a94119e3bddd34cc8fbdbc83454e5c7070 100644 (file)
 
 #include "amanda.h"
 #include "util.h"
+#include <regex.h>
 #include "arglist.h"
 #include "clock.h"
-
-/*#define NET_READ_DEBUG*/
-
-#ifdef NET_READ_DEBUG
-#define netprintf(x)    dbprintf(x)
-#else
-#define netprintf(x)
-#endif
+#include "sockaddr-util.h"
+#include "conffile.h"
+#include "base64.h"
 
 static int make_socket(sa_family_t family);
-static int connect_port(struct sockaddr_storage *addrp, in_port_t port, char *proto,
-                       struct sockaddr_storage *svaddr, int nonblock);
-
-/*
- * 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);
-}
+static int connect_port(sockaddr_union *addrp, in_port_t port, char *proto,
+                       sockaddr_union *svaddr, int nonblock);
 
 static int
 make_socket(
@@ -117,12 +51,11 @@ make_socket(
     int r;
 #endif
 
+    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_time(NULL),
-                  strerror(save_errno)));
+        dbprintf(_("make_socket: socket() failed: %s\n"), strerror(save_errno));
         errno = save_errno;
         return -1;
     }
@@ -136,9 +69,8 @@ make_socket(
     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_time(NULL),
-                 strerror(errno)));
+       dbprintf(_("make_socket: setsockopt(SO_REUSEADDR) failed: %s\n"),
+                 strerror(errno));
        errno = save_errno;
     }
 #endif
@@ -148,9 +80,8 @@ make_socket(
                   (void *)&on, SIZEOF(on));
     if (r == -1) {
        save_errno = errno;
-       dbprintf(("%s: make_socket: setsockopt() failed: %s\n",
-                  debug_prefix_time(NULL),
-                  strerror(save_errno)));
+       dbprintf(_("make_socket: setsockopt() failed: %s\n"),
+                  strerror(save_errno));
        aclose(s);
        errno = save_errno;
        return -1;
@@ -166,11 +97,11 @@ make_socket(
 /* return -1     on failure */
 int
 connect_portrange(
-    struct sockaddr_storage *addrp,
+    sockaddr_union *addrp,
     in_port_t          first_port,
     in_port_t          last_port,
     char *             proto,
-    struct sockaddr_storage *svaddr,
+    sockaddr_union *svaddr,
     int                        nonblock)
 {
     int                        s;
@@ -178,6 +109,7 @@ 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 */
@@ -189,6 +121,8 @@ connect_portrange(
            if(s > 0) {
                return s;
            }
+           if (errno != EAGAIN && errno != EBUSY)
+               save_errno = errno;
        }
     }
 
@@ -200,13 +134,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;
 }
 
@@ -217,58 +152,62 @@ connect_portrange(
 /* return >0: this is the connected socket */
 int
 connect_port(
-    struct sockaddr_storage *addrp,
+    sockaddr_union *addrp,
     in_port_t                  port,
     char *             proto,
-    struct sockaddr_storage *svaddr,
+    sockaddr_union *svaddr,
     int                        nonblock)
 {
     int                        save_errno;
     struct servent *   servPort;
-    socklen_t          len;
-    socklen_t          socklen;
+    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(SU_GET_FAMILY(addrp))) == -1) return -2;
 
-    if ((s = make_socket(addrp->ss_family)) == -1) return -2;
-
-    SS_SET_PORT(addrp, port);
+    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_time(NULL),
-                 strerror(save_errno)));
+       dbprintf(_("connect_port: getsockname() failed: %s\n"),
+                 strerror(save_errno));
        aclose(s);
        errno = save_errno;
        return -1;
@@ -278,14 +217,12 @@ connect_port(
        fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0)|O_NONBLOCK);
     if (connect(s, (struct sockaddr *)svaddr, SS_LEN(svaddr)) == -1 && !nonblock) {
        save_errno = errno;
-       dbprintf(("%s: connect_portrange: connect from %s failed: %s\n",
-                 debug_prefix_time(NULL),
+       dbprintf(_("connect_portrange: Connect from %s failed: %s\n"),
                  str_sockaddr(addrp),
-                 strerror(save_errno)));
-       dbprintf(("%s: connect_portrange: connect to %s failed: %s\n",
-                 debug_prefix_time(NULL),
+                 strerror(save_errno));
+       dbprintf(_("connect_portrange: connect to %s failed: %s\n"),
                  str_sockaddr(svaddr),
-                 strerror(save_errno)));
+                 strerror(save_errno));
        aclose(s);
        errno = save_errno;
        if (save_errno == ECONNREFUSED ||
@@ -297,12 +234,10 @@ connect_port(
        return -1;
     }
 
-    dbprintf(("%s: connected to %s\n",
-              debug_prefix_time(NULL),
-              str_sockaddr(svaddr)));
-    dbprintf(("%s: our side is %s\n",
-              debug_prefix_time(NULL),
-              str_sockaddr(addrp)));
+    dbprintf(_("connected to %s\n"),
+              str_sockaddr(svaddr));
+    dbprintf(_("our side is %s\n"),
+              str_sockaddr(addrp));
     return s;
 }
 
@@ -316,16 +251,17 @@ connect_port(
 int
 bind_portrange(
     int                        s,
-    struct sockaddr_storage *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 socklen;
+    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);
 
@@ -343,85 +279,87 @@ bind_portrange(
     for (cnt = 0; cnt < num_ports; cnt++) {
        servPort = getservbyport((int)htons(port), proto);
        if ((servPort == NULL) || strstr(servPort->s_name, "amanda")) {
-           if (servPort == NULL) {
-               dbprintf(("%s: bind_portrange2: Try  port %d: Available   - ",
-                     debug_prefix_time(NULL), port));
-           } else {
-               dbprintf(("%s: bind_portrange2: Try  port %d: Owned by %s - ",
-                     debug_prefix_time(NULL), port, servPort->s_name));
-           }
-           SS_SET_PORT(addrp, port);
+           SU_SET_PORT(addrp, port);
            socklen = SS_LEN(addrp);
            if (bind(s, (struct sockaddr *)addrp, socklen) >= 0) {
-               dbprintf(("Success\n"));
+               if (servPort == NULL) {
+                   dbprintf(_("bind_portrange2: Try  port %d: Available - Success\n"), port);
+               } else {
+                   dbprintf(_("bind_portrange2: Try  port %d: Owned by %s - Success.\n"), port, servPort->s_name);
+               }
                return 0;
            }
-           dbprintf(("%s\n", strerror(errno)));
+           if (errno != EAGAIN && errno != EBUSY)
+               save_errno = errno;
+           if (servPort == NULL) {
+               dbprintf(_("bind_portrange2: Try  port %d: Available - %s\n"),
+                       port, strerror(errno));
+           } else {
+               dbprintf(_("bind_portrange2: Try  port %d: Owned by %s - %s\n"),
+                       port, servPort->s_name, strerror(errno));
+           }
        } else {
-               dbprintf(("%s: bind_portrange2: Skip port %d: Owned by %s.\n",
-                     debug_prefix_time(NULL), port, servPort->s_name));
+               dbprintf(_("bind_portrange2: Skip port %d: Owned by %s.\n"),
+                     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),
+    dbprintf(_("bind_portrange: all ports between %d and %d busy\n"),
                  first_port,
-                 last_port));
-    errno = EAGAIN;
+                 last_port);
+    errno = save_errno;
     return -1;
 }
 
 /*
- * Construct a datestamp (YYYYMMDD) from a time_t.
+ * Writes out the entire iovec
  */
-char *
-construct_datestamp(
-    time_t *t)
+ssize_t
+full_writev(
+    int                        fd,
+    struct iovec *     iov,
+    int                        iovcnt)
 {
-    struct tm *tm;
-    char datestamp[3 * NUM_STR_SIZE];
-    time_t when;
+    ssize_t delta, n, total;
 
-    if (t == NULL) {
-       when = time((time_t *)NULL);
-    } else {
-       when = *t;
-    }
-    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);
-}
+    assert(iov != NULL);
 
-/*
- * Construct a timestamp (YYYYMMDDHHMMSS) from a time_t.
- */
-char *
-construct_timestamp(
-    time_t *t)
-{
-    struct tm *tm;
-    char timestamp[6 * NUM_STR_SIZE];
-    time_t when;
-
-    if (t == NULL) {
-       when = time((time_t *)NULL);
-    } else {
-       when = *t;
+    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;
+           }
+       }
     }
-    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);
+    return (total);
 }
 
 
@@ -447,7 +385,7 @@ quote_string(
 
     if ((str == NULL) || (*str == '\0')) {
        ret = stralloc("\"\"");
-    } else if ((match("[\\\"[:space:][:cntrl:]]", str)) == 0) {
+    } else if ((match("[:\'\\\"[:space:][:cntrl:]]", str)) == 0) {
        /*
         * String does not need to be quoted since it contains
         * neither whitespace, control or quote characters.
@@ -535,6 +473,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++);
@@ -544,62 +495,102 @@ unquote_string(
     return (ret);
 }
 
-char *
-sanitize_string(
-    const char *str)
+gchar **
+split_quoted_strings(
+    const gchar *string)
 {
-    char * s;
-    char * ret;
-
-    if ((str == NULL) || (*str == '\0')) {
-       ret = stralloc("");
-    } else {
-       ret = stralloc(str);
-       for (s = ret; *s != '\0'; s++) {
-           if (iscntrl(*s))
-               *s = '?';
+    char *local = g_strdup(string);
+    char *start = local;
+    char *p = local;
+    char **result;
+    GPtrArray *strs = g_ptr_array_new();
+    int iq = 0;
+
+    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++;
     }
-    return (ret);
+    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, FALSE); /* FALSE => don't free strings */
+    g_free(local);
+
+    return result;
 }
 
 char *
-strquotedstr(void)
+strquotedstr(char **saveptr)
 {
-    char *  tok = strtok(NULL, " ");
-
-    if ((tok != NULL) && (tok[0] == '"')) {
-       char *  t;
-       size_t  len;
-
-        len = strlen(tok);
-       do {
-           t = strtok(NULL, " ");
+    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);
-       } while ((t != NULL) &&
-                (tok[len - 1] != '"') && (tok[len - 2] != '\\'));
+       }
+       if (!in_backslash) {
+           if (*p == '"')
+               in_quote = !in_quote;
+           else if (*p == '\\') {
+               in_backslash = 1;
+           }
+       } else {
+          in_backslash = 0;
+       }
+       p++;
     }
     return tok;
 }
 
-ssize_t
-hexdump(
-    const char *buffer,
-    size_t     len)
+char *
+sanitize_string(
+    const char *str)
 {
-    ssize_t rc = -1;
+    char * s;
+    char * ret;
 
-    FILE *stream = popen("od -c -x -", "w");
-       
-    if (stream != NULL) {
-       fflush(stdout);
-       rc = (ssize_t)fwrite(buffer, len, 1, stream);
-       if (ferror(stream))
-           rc = -1;
-       pclose(stream);
+    if ((str == NULL) || (*str == '\0')) {
+       ret = stralloc("");
+    } else {
+       ret = stralloc(str);
+       for (s = ret; *s != '\0'; s++) {
+           if (iscntrl((int)*s))
+               *s = '?';
+       }
     }
-    return rc;
+    return (ret);
 }
 
 /*
@@ -615,138 +606,6 @@ validate_mailto(
     return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto);
 }
 
-
-void
-dump_sockaddr(
-    struct sockaddr_storage *sa)
-{
-#ifdef WORKING_IPV6
-    char ipstr[INET6_ADDRSTRLEN];
-#else
-    char ipstr[INET_ADDRSTRLEN];
-#endif
-    int port;
-
-    port = SS_GET_PORT(sa);
-#ifdef WORKING_IPV6
-    if ( sa->ss_family == (sa_family_t)AF_INET6) {
-       inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr,
-                 ipstr, sizeof(ipstr));
-       dbprintf(("%s: (sockaddr_in6 *)%p = { %d, %d, %s }\n",
-                 debug_prefix_time(NULL), sa,
-                 ((struct sockaddr_in6 *)sa)->sin6_family,
-                 port,
-                 ipstr));
-    } else
-#endif
-    {
-       inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, ipstr,
-                 sizeof(ipstr));
-       dbprintf(("%s: (sockaddr_in *)%p = { %d, %d, %s }\n",
-                 debug_prefix_time(NULL), sa,
-                 ((struct sockaddr_in *)sa)->sin_family,
-                 port,
-                 ipstr));
-    }
-}
-
-
-#ifdef WORKING_IPV6
-static char mystr_sockaddr[INET6_ADDRSTRLEN + 20];
-#else
-static char mystr_sockaddr[INET_ADDRSTRLEN + 20];
-#endif
-
-char *
-str_sockaddr(
-    struct sockaddr_storage *sa)
-{
-#ifdef WORKING_IPV6
-    char ipstr[INET6_ADDRSTRLEN];
-#else
-    char ipstr[INET_ADDRSTRLEN];
-#endif
-    int port;
-
-    port = SS_GET_PORT(sa);
-#ifdef WORKING_IPV6
-    if ( sa->ss_family == (sa_family_t)AF_INET6) {
-       inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr,
-                 ipstr, sizeof(ipstr));
-    } else
-#endif
-    {
-       inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, ipstr,
-                 sizeof(ipstr));
-    }
-    snprintf(mystr_sockaddr,sizeof(mystr_sockaddr),"%s.%d", ipstr, port);
-    return mystr_sockaddr;
-}
-
-
-int
-cmp_sockaddr(
-    struct sockaddr_storage *ss1,
-    struct sockaddr_storage *ss2,
-    int addr_only)
-{
-    /* if addresses are v4mapped, "unmap" them */
-#ifdef WORKING_IPV6
-#ifdef IN6_IS_ADDR_V4MAPPED
-    struct sockaddr_in ss1_v4;
-    struct sockaddr_in ss2_v4;
-
-    if (ss1->ss_family == AF_INET6 &&
-        IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss1)->sin6_addr)) {
-       memset(&ss1_v4, 0, sizeof(struct sockaddr_in));
-       memcpy(&ss1_v4.sin_addr.s_addr,
-              &(((struct sockaddr_in6 *)ss1)->sin6_addr.s6_addr[12]),
-              sizeof(struct in_addr));
-       ss1_v4.sin_family = AF_INET;
-       SS_SET_PORT((struct sockaddr_storage *)&ss1_v4, SS_GET_PORT(ss1));
-       ss1 = (struct sockaddr_storage *)&ss1_v4;
-    }
-
-    if (ss2->ss_family == AF_INET6 &&
-        IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss2)->sin6_addr)) {
-       memset(&ss2_v4, 0, sizeof(struct sockaddr_in));
-       memcpy(&ss2_v4.sin_addr.s_addr,
-              &(((struct sockaddr_in6 *)ss2)->sin6_addr.s6_addr[12]),
-              sizeof(struct in_addr));
-       ss2_v4.sin_family = AF_INET;
-       SS_SET_PORT((struct sockaddr_storage *)&ss2_v4, SS_GET_PORT(ss2));
-       ss2 = (struct sockaddr_storage *)&ss2_v4;
-    }
-#endif
-#endif
-
-    if (ss1->ss_family == ss2->ss_family) {
-        if (addr_only) {
-#ifdef WORKING_IPV6
-            if(ss1->ss_family == (sa_family_t)AF_INET6)
-                return memcmp(
-                    &((struct sockaddr_in6 *)ss1)->sin6_addr,
-                    &((struct sockaddr_in6 *)ss2)->sin6_addr,
-                    sizeof(((struct sockaddr_in6 *)ss1)->sin6_addr));
-            else
-#endif
-                return memcmp(
-                    &((struct sockaddr_in *)ss1)->sin_addr,
-                    &((struct sockaddr_in *)ss2)->sin_addr,
-                    sizeof(((struct sockaddr_in *)ss1)->sin_addr));
-        } else {
-            return memcmp(ss1, ss2, SS_LEN(ss1));
-        }
-    } else {
-        /* compare families to give a total order */
-        if (ss1->ss_family < ss2->ss_family)
-            return -1;
-        else
-            return 1;
-    }
-}
-
-
 int copy_file(
     char  *dst,
     char  *src,
@@ -754,15 +613,15 @@ int copy_file(
 {
     int     infd, outfd;
     int     save_errno;
-    ssize_t nb;
+    size_t nb;
     char    buf[32768];
     char   *quoted;
 
     if ((infd = open(src, O_RDONLY)) == -1) {
        save_errno = errno;
        quoted = quote_string(src);
-       *errmsg = vstralloc("Can't open file ", quoted, " for reading: %s",
-                           strerror(save_errno), NULL);
+       *errmsg = vstrallocf(_("Can't open file '%s' for reading: %s"),
+                           quoted, strerror(save_errno));
        amfree(quoted);
        return -1;
     }
@@ -770,19 +629,19 @@ int copy_file(
     if ((outfd = open(dst, O_WRONLY|O_CREAT, 0600)) == -1) {
        save_errno = errno;
        quoted = quote_string(dst);
-       *errmsg = vstralloc("Can't open file ", quoted, " for writting: %s",
-                           strerror(save_errno), NULL);
+       *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(fullwrite(outfd,&buf,(size_t)nb) < nb) {
+       if(full_write(outfd,&buf,nb) < nb) {
            save_errno = errno;
            quoted = quote_string(dst);
-           *errmsg = vstralloc("Error writing to \"", quoted, "\":",
-                               strerror(save_errno), NULL);
+           *errmsg = vstrallocf(_("Error writing to '%s': %s"),
+                               quoted, strerror(save_errno));
            amfree(quoted);
            close(infd);
            close(outfd);
@@ -790,11 +649,11 @@ int copy_file(
        }
     }
 
-    if (nb < 0) {
+    if (errno != 0) {
        save_errno = errno;
        quoted = quote_string(src);
-       *errmsg = vstralloc("Error reading from \"", quoted, "\":",
-                           strerror(save_errno), NULL);
+       *errmsg = vstrallocf(_("Error reading from '%s': %s"),
+                           quoted, strerror(save_errno));
        amfree(quoted);
        close(infd);
        close(outfd);
@@ -805,16 +664,18 @@ int copy_file(
     close(outfd);
     return 0;
 }
-#ifndef HAVE_LIBREADLINE
+
+#ifndef HAVE_READLINE
 /*
- * simple readline() replacements
+ * simple readline() replacements, used when we don't have readline
+ * support from the system.
  */
 
 char *
 readline(
     const char *prompt)
 {
-    printf("%s", prompt);
+    g_printf("%s", prompt);
     fflush(stdout);
     fflush(stderr);
     return agets(stdin);
@@ -824,6 +685,428 @@ void
 add_history(
     const char *line)
 {
-    (void)line;        /* Quite unused parameter warning */
+    (void)line;        /* Quiet unused parameter warning */
+}
+
+#endif
+
+/* 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
+
+char * portable_readdir(DIR* handle) {
+
+#ifdef USE_DIRENT64
+    struct dirent64 *entry_p;
+#else
+    struct dirent *entry_p;
+#endif
+
+    static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+    g_static_mutex_lock(&mutex);
+
+#ifdef USE_READDIR
+    entry_p = readdir(handle);
+#endif
+#ifdef USE_READDIR64
+    entry_p = readdir64(handle);
+#endif
+
+    g_static_mutex_unlock(&mutex);
+    
+    if (entry_p == NULL)
+        return NULL;
+
+    /* 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;
+
+    if (regcomp(&compiled_regex, regex, REG_EXTENDED | REG_NOSUB) != 0) {
+        regfree(&compiled_regex);
+        return -1;
+    }
+
+    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;
+}
+
+char* find_regex_substring(const char* base_string, const regmatch_t match) {
+    char * rval;
+    int size;
+
+    size = match.rm_eo - match.rm_so;
+    rval = malloc(size+1);
+    memcpy(rval, base_string + match.rm_so, size);
+    rval[size] = '\0';
+
+    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);
+    }
+}
+
+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;
+    }
+
+#ifdef AI_ADDRCONFIG
+    flags |= AI_ADDRCONFIG;
+#endif
+
+    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;
+    }
+
+    if (canonname && myres && myres->ai_canonname) {
+       *canonname = stralloc(myres->ai_canonname);
+    }
+
+    if (res) {
+       *res = myres;
+    } else {
+       freeaddrinfo(myres);
+    }
+
+    return result;
+}
+
+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);
+    }
+
+    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
+           return vstrallocf(_("%s exited after receiving signal %d"),
+               subject, signal);
+    }
+
+    if (WIFSTOPPED(status)) {
+       int signal = WSTOPSIG(status);
+       return vstrallocf(_("%s stopped temporarily after receiving signal %d"),
+           subject, signal);
+    }
+
+#ifdef WIFCONTINUED
+    if (WIFCONTINUED(status)) {
+       return vstrallocf(_("%s was resumed"), subject);
+    }
+#endif
+
+    return vstrallocf(_("%s exited in unknown circumstances"), subject);
+}
+
+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);
+
+#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
+
+    switch (who & RUNNING_AS_USER_MASK) {
+       case RUNNING_AS_ANY:
+           uid_target = uid_me;
+           uname_target = 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 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:
+           error(_("Unknown check_running_as() call"));
+           /* NOTREACHED */
+    }
+
+    if (uid_me != uid_target) {
+       error(_("running as user \"%s\" instead of \"%s\""), uname_me, uname_target);
+       /*NOTREACHED*/
+    }
+    amfree(uname_me);
+
+#else
+    /* Quiet unused variable warning */
+    (void)who;
+#endif
+}
+
+int
+set_root_privs(int need_root)
+{
+#ifndef SINGLE_USERID
+    if (need_root) {
+        if (seteuid(0) == -1) return 0;
+        /* (we don't switch the group back) */
+    } else {
+       if (geteuid() != 0) return 0;
+        if (seteuid(getuid()) == -1) return 0;
+        if (setegid(getgid()) == -1) return 0;
+    }
+#else
+    (void)need_root; /* Quiet unused variable warning */
+#endif
+    return 1;
 }
+
+int
+become_root(void)
+{
+#ifndef SINGLE_USERID
+    // if euid !=0, it set only euid
+    if (setuid(0) == -1) return 0;
+    // will set ruid because euid == 0.
+    if (setuid(0) == -1) return 0;
 #endif
+    return 1;
+}
+
+
+char *
+base64_decode_alloc_string(
+    char *in)
+{
+    char   *out;
+    size_t  in_len = strlen(in);
+    size_t  out_len = 3 * (in_len / 4) + 3;
+
+    out = malloc(out_len);
+    if (!base64_decode(in, in_len, out, &out_len)) {
+       amfree(out);
+       return NULL;
+    }
+    out[out_len] = '\0';
+
+    return out;
+}
+
+
+/* A GHFunc (callback for g_hash_table_foreach) */
+void count_proplist(
+    gpointer key_p G_GNUC_UNUSED,
+    gpointer value_p,
+    gpointer user_data_p)
+{
+    property_t *value_s = value_p;
+    int    *nb = user_data_p;
+    GSList  *value;
+
+    for(value=value_s->values; value != NULL; value = value->next) {
+       (*nb)++;
+    }
+}
+
+/* A GHFunc (callback for g_hash_table_foreach) */
+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;
+    char       ***argv = 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 = '-';
+    }
+    qprop = stralloc2("--", q);
+    amfree(q);
+    for(value=value_s->values; value != NULL; value = value->next) {
+       **argv = stralloc(qprop);
+       (*argv)++;
+       **argv = stralloc((char *)value->data);
+       (*argv)++;
+    }
+    amfree(qprop);
+}
+
+
+/*
+ * Process parameters
+ */
+
+static char *pname = NULL;
+static char *ptype = NULL;
+static pcontext_t pcontext = CONTEXT_DEFAULT; 
+
+void
+set_pname(char *p)
+{
+    pname = newstralloc(pname, p);
+}
+
+char *
+get_pname(void)
+{
+    if (!pname) pname = stralloc("unknown");
+    return pname;
+}
+
+void
+set_ptype(char *p)
+{
+    ptype = newstralloc(ptype, p);
+}
+
+char *
+get_ptype(void)
+{
+    if (!ptype) ptype = stralloc("unknown");
+    return ptype;
+}
+
+void
+set_pcontext(pcontext_t pc)
+{
+    pcontext = pc;
+}
+
+pcontext_t
+get_pcontext(void)
+{
+    return pcontext;
+}