Imported Upstream version 2.5.2p1
[debian/amanda] / server-src / cmdline.c
diff --git a/server-src/cmdline.c b/server-src/cmdline.c
new file mode 100644 (file)
index 0000000..74c4079
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2005 Zmanda Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ * 
+ * Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ *
+ * Author: Dustin J. Mitchell <dustin@zmanda.com>
+ */
+/*
+ * $Id$
+ *
+ * Utility routines for handling command lines.
+ */
+
+#include <ctype.h>
+#include "amanda.h"
+#include "cmdline.h"
+#include "holding.h"
+
+dumpspec_t *
+dumpspec_new(
+    char *host, 
+    char *disk, 
+    char *datestamp)
+{
+    dumpspec_t *rv;
+
+    rv = calloc(1, sizeof(*rv));
+    if (!rv) return NULL;
+    if (host) rv->host = stralloc(host);
+    if (disk) rv->disk = stralloc(disk);
+    if (datestamp) rv->datestamp = stralloc(datestamp);
+
+    return rv;
+}
+
+void
+dumpspec_free(
+    dumpspec_t *dumpspec)
+{
+    if (!dumpspec) return;
+    if (dumpspec->host) free(dumpspec->host);
+    if (dumpspec->disk) free(dumpspec->disk);
+    if (dumpspec->datestamp) free(dumpspec->datestamp);
+    free(dumpspec);
+}
+
+void
+dumpspec_free_list(
+    dumpspec_list_t *dumpspec_list)
+{
+    dumpspec_t *dumpspec = (dumpspec_t *)dumpspec_list;
+    dumpspec_t *next;
+
+    while (dumpspec) {
+        next = dumpspec->next;
+        dumpspec_free(dumpspec);
+        dumpspec = next;
+    }
+}
+
+dumpspec_list_t *
+cmdline_parse_dumpspecs(
+    int argc,
+    char **argv)
+{
+    dumpspec_t *dumpspec = NULL, *t;
+    char *errstr;
+    char *name;
+    int optind = 0;
+    enum { ARG_GET_HOST, ARG_GET_DISK, ARG_GET_DATE } arg_state = ARG_GET_HOST;
+
+    while (optind < argc) {
+        name = argv[optind++];
+        switch (arg_state) {
+            case ARG_GET_HOST:
+                if (name[0] != '\0'
+                    && (errstr=validate_regexp(name)) != NULL) {
+                    fprintf(stderr, _("%s: bad hostname regex \"%s\": %s\n"),
+                                   get_pname(), name, errstr);
+                    goto error;
+                }
+                t = dumpspec_new(name, NULL, NULL);
+                t->next = (dumpspec_t *)dumpspec;
+                dumpspec = t;
+                arg_state = ARG_GET_DISK;
+                break;
+
+            case ARG_GET_DISK:
+                if (name[0] != '\0'
+                    && (errstr=validate_regexp(name)) != NULL) {
+                    fprintf(stderr, _("%s: bad diskname regex \"%s\": %s\n"),
+                                   get_pname(), name, errstr);
+                    goto error;
+                }
+                dumpspec->disk = stralloc(name);
+                arg_state = ARG_GET_DATE;
+                break;
+
+            case ARG_GET_DATE:
+                if (name[0] != '\0'
+                    && (errstr=validate_regexp(name)) != NULL) {
+                    fprintf(stderr, _("%s: bad datestamp regex \"%s\": %s\n"),
+                                   get_pname(), name, errstr);
+                    goto error;
+                }
+                dumpspec->datestamp = stralloc(name);
+                arg_state = ARG_GET_HOST;
+                break;
+        }
+    }
+
+    if (dumpspec == NULL) 
+        dumpspec = dumpspec_new("", "", "");
+    return (dumpspec_list_t *)dumpspec;
+
+error:
+    dumpspec_free_list((dumpspec_list_t *)dumpspec);
+    return NULL;
+}
+
+char *
+cmdline_format_dumpspec(
+    dumpspec_t *dumpspec)
+{
+    if (!dumpspec) return NULL;
+    return cmdline_format_dumpspec_components(
+        dumpspec->host,
+        dumpspec->disk,
+        dumpspec->datestamp);
+}
+
+/* Quote str for shell interpretation, being conservative.
+ * Any non-alphanumeric charcacters other than '.' and '/'
+ * trigger surrounding single quotes, and single quotes and
+ * backslashes within those single quotes are escaped.
+ */
+static char *
+quote_dumpspec_string(char *str)
+{
+    char *rv;
+    char *p, *q;
+    int len = 0;
+    int need_single_quotes = 0;
+
+    for (p = str; *p; p++) {
+        if (!isalnum(*p) && *p != '.' && *p != '/') need_single_quotes=1;
+        if (*p == '\'' || *p == '\\') len++; /* extra byte for '\' */
+        len++;
+    }
+    if (need_single_quotes) len += 2;
+
+    q = rv = malloc(len+1);
+    if (need_single_quotes) *(q++) = '\'';
+    for (p = str; *p; p++) {
+        if (*p == '\'' || *p == '\\') *(q++) = '\\';
+        *(q++) = *p;
+    }
+    if (need_single_quotes) *(q++) = '\'';
+    *(q++) = '\0';
+
+    return rv;
+}
+
+char *
+cmdline_format_dumpspec_components(
+    char *host,
+    char *disk,
+    char *datestamp)
+{
+    char *rv = NULL;
+
+    host = host? quote_dumpspec_string(host):NULL;
+    disk = disk? quote_dumpspec_string(disk):NULL;
+    datestamp = datestamp? quote_dumpspec_string(datestamp):NULL;
+
+    if (host) {
+        rv = host;
+        if (disk) {
+            rv = newvstralloc(rv, rv, " ", disk, NULL);
+            amfree(disk);
+            if (datestamp) {
+                rv = newvstralloc(rv, rv, " ", datestamp, NULL);
+                amfree(datestamp);
+            }
+        }
+    }
+    if (disk) amfree(disk);
+    if (datestamp) amfree(datestamp);
+
+    return rv;
+}
+
+sl_t *
+cmdline_match_holding(
+    dumpspec_list_t *dumpspec_list)
+{
+    char *host;
+    char *disk;
+    char *datestamp;
+    filetype_t filetype;
+    dumpspec_t *de;
+    sl_t *holding_files;
+    sle_t *he;
+    sl_t *matching_files = new_sl();
+
+    holding_set_verbosity(0);
+    holding_files = holding_get_files(NULL, NULL, 1);
+
+    for (he = holding_files->first; he != NULL; he = he->next) {
+        filetype = holding_file_read_header(he->name, &host, &disk, NULL, &datestamp);
+        if (filetype != F_DUMPFILE) continue;
+        for (de = (dumpspec_t *)dumpspec_list; de != NULL; de = de->next) {
+            if (de->host && !match_host(de->host, host)) continue;
+            if (de->disk && !match_disk(de->disk, disk)) continue;
+            if (de->datestamp && !match_datestamp(de->datestamp, datestamp)) continue;
+            matching_files = insert_sort_sl(matching_files, he->name);
+            break;
+        }
+    }
+
+    return matching_files;
+}