prepare to upload
[debian/amanda] / common-src / util.c
index 1a812013b77dd2f3cb50d359b8369614bc29739b..b9172ca41950fa716235833f7e2b0c2853fbd957 100644 (file)
@@ -322,6 +322,56 @@ bind_portrange(
     return -1;
 }
 
+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;
+    }
+
+    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;
+       }
+    }
+}
+
 /*
  * Writes out the entire iovec
  */
@@ -388,52 +438,129 @@ quote_string_maybe(
 
     if ((str == NULL) || (*str == '\0')) {
        ret = stralloc("\"\"");
-    } else if (!always && (match("[:\'\\\"[:space:][:cntrl:]]", str)) == 0) {
-       /*
-        * String does not need to be quoted since it contains
-        * neither whitespace, control or quote characters.
-        */
-       ret = stralloc(str);
     } else {
-       /*
-        * Allocate maximum possible string length.
-        * (a string of all quotes plus room for leading ", trailing " and NULL)
-        */
-       ret = s = alloc((strlen(str) * 2) + 2 + 1);
-       *(s++) = '"';
-       while (*str != '\0') {
-            if (*str == '\t') {
-                *(s++) = '\\';
-                *(s++) = 't';
-               str++;
-               continue;
-           } else if (*str == '\n') {
-                *(s++) = '\\';
-                *(s++) = 'n';
-               str++;
-               continue;
-           } else if (*str == '\r') {
-                *(s++) = '\\';
-                *(s++) = 'r';
-               str++;
-               continue;
-           } else if (*str == '\f') {
-                *(s++) = '\\';
-                *(s++) = 'f';
-               str++;
-               continue;
-           } else if (*str == '\\') {
-                *(s++) = '\\';
-                *(s++) = '\\';
-               str++;
-               continue;
-           }
-            if (*str == '"')
-                *(s++) = '\\';
-            *(s++) = *(str++);
+       const char *r;
+       for (r = str; *r; r++) {
+           if (*r == ':' || *r == '\'' || *r == '\\' || *r == '\"' ||
+               *r <= ' ' || *r == 0x7F )
+               always = 1;
+       }
+       if (!always) {
+           /*
+            * String does not need to be quoted since it contains
+            * neither whitespace, control or quote characters.
+            */
+           ret = stralloc(str);
+       } else {
+           /*
+            * Allocate maximum possible string length.
+            * (a string of all quotes plus room for leading ", trailing " and
+            *  NULL)
+            */
+           ret = s = alloc((strlen(str) * 2) + 2 + 1);
+           *(s++) = '"';
+           while (*str != '\0') {
+                if (*str == '\t') {
+                    *(s++) = '\\';
+                    *(s++) = 't';
+                   str++;
+                   continue;
+               } else if (*str == '\n') {
+                    *(s++) = '\\';
+                    *(s++) = 'n';
+                   str++;
+                   continue;
+               } else if (*str == '\r') {
+                    *(s++) = '\\';
+                    *(s++) = 'r';
+                   str++;
+                   continue;
+               } else if (*str == '\f') {
+                    *(s++) = '\\';
+                    *(s++) = 'f';
+                   str++;
+                   continue;
+               } else if (*str == '\\') {
+                    *(s++) = '\\';
+                    *(s++) = '\\';
+                   str++;
+                   continue;
+               }
+                if (*str == '"')
+                    *(s++) = '\\';
+                *(s++) = *(str++);
+            }
+            *(s++) = '"';
+            *s = '\0';
         }
-        *(s++) = '"';
-        *s = '\0';
+    }
+    return (ret);
+}
+
+
+int
+len_quote_string_maybe(
+    const char *str,
+    gboolean always)
+{
+    int   ret;
+
+    if ((str == NULL) || (*str == '\0')) {
+       ret = 0;
+    } else {
+       const char *r;
+       for (r = str; *r; r++) {
+           if (*r == ':' || *r == '\'' || *r == '\\' || *r == '\"' ||
+               *r <= ' ' || *r == 0x7F )
+               always = 1;
+       }
+       if (!always) {
+           /*
+            * String does not need to be quoted since it contains
+            * neither whitespace, control or quote characters.
+            */
+           ret = strlen(str);
+       } else {
+           /*
+            * Allocate maximum possible string length.
+            * (a string of all quotes plus room for leading ", trailing " and
+            *  NULL)
+            */
+           ret = 1;
+               while (*str != '\0') {
+                if (*str == '\t') {
+                    ret++;
+                    ret++;
+                   str++;
+                   continue;
+               } else if (*str == '\n') {
+                    ret++;
+                    ret++;
+                   str++;
+                   continue;
+               } else if (*str == '\r') {
+                    ret++;
+                    ret++;
+                   str++;
+                   continue;
+               } else if (*str == '\f') {
+                    ret++;
+                    ret++;
+                   str++;
+                   continue;
+               } else if (*str == '\\') {
+                    ret++;
+                    ret++;
+                   str++;
+                   continue;
+               }
+                if (*str == '"')
+                   ret++;
+               ret++;
+                str++;
+            }
+           ret++;
+       }
     }
     return (ret);
 }
@@ -539,7 +666,7 @@ split_quoted_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_ptr_array_free(strs, TRUE); /* TRUE => free pdata, strings are not freed */
     g_free(local);
 
     return result;
@@ -699,6 +826,66 @@ cleanup:
     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;
+}
+
 /* 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
@@ -725,6 +912,7 @@ parse_braced_component(char **str)
            if (*p == '}' || *p == ',') {
                *c = '\0';
                g_ptr_array_add(result, g_strdup(current));
+               result = expand_braced_sequence(result);
                current = ++c;
 
                if (*p == '}')
@@ -916,7 +1104,7 @@ int copy_file(
     return 0;
 }
 
-#ifndef HAVE_READLINE
+#ifndef HAVE_LIBREADLINE
 /*
  * simple readline() replacements, used when we don't have readline
  * support from the system.
@@ -1298,23 +1486,15 @@ base64_decode_alloc_string(
 }
 
 
-/* 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(
+/* 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)
@@ -1341,6 +1521,14 @@ void proplist_add_to_argv(
     amfree(qprop);
 }
 
+void
+property_add_to_argv(
+    GPtrArray  *argv_ptr,
+    GHashTable *proplist)
+{
+    g_hash_table_foreach(proplist, &proplist_add_to_argv, argv_ptr);
+}
+
 
 /*
  * Process parameters
@@ -1417,3 +1605,73 @@ debug_executing(
     amfree(cmdline);
 }
 
+char *
+get_first_line(
+    GPtrArray *argv_ptr)
+{
+    char *output_string = NULL;
+    int   inpipe[2], outpipe[2], errpipe[2];
+    int   pid;
+    FILE *out, *err;
+
+    assert(argv_ptr != NULL);
+    assert(argv_ptr->pdata != NULL);
+    assert(argv_ptr->len >= 1);
+
+    if (pipe(inpipe) == -1) {
+       error(_("error [open pipe: %s]"), strerror(errno));
+       /*NOTREACHED*/
+    }
+    if (pipe(outpipe) == -1) {
+       error(_("error [open pipe: %s]"), strerror(errno));
+       /*NOTREACHED*/
+    }
+    if (pipe(errpipe) == -1) {
+       error(_("error [open pipe: %s]"), strerror(errno));
+       /*NOTREACHED*/
+    }
+
+    fflush(stdout);
+    switch(pid = fork()) {
+    case -1:
+       error(_("error [fork: %s]"), strerror(errno));
+       /*NOTREACHED*/
+
+    default:   /* parent process */
+       aclose(inpipe[0]);
+       aclose(outpipe[1]);
+       aclose(errpipe[1]);
+       break;
+
+    case 0: /* child process */
+       aclose(inpipe[1]);
+       aclose(outpipe[0]);
+       aclose(errpipe[0]);
+
+       dup2(inpipe[0], 0);
+       dup2(outpipe[1], 1);
+       dup2(errpipe[1], 2);
+
+       debug_executing(argv_ptr);
+       g_fprintf(stdout, "unknown\n");
+       execv((char *)*argv_ptr->pdata, (char **)argv_ptr->pdata);
+       error(_("error [exec %s: %s]"), (char *)*argv_ptr->pdata, strerror(errno));
+    }
+
+    aclose(inpipe[1]);
+
+    out = fdopen(outpipe[0],"r");
+    err = fdopen(errpipe[0],"r");
+
+    output_string = agets(out);
+    if (!output_string)
+       output_string = agets(err);
+
+    fclose(out);
+    fclose(err);
+
+    waitpid(pid, NULL, 0);
+
+    return output_string;
+}
+