Imported Upstream version 3.3.3
[debian/amanda] / client-src / client_util.c
index 5dc4974f8f31dd586f8f2f79468af9eb53e4a8ab..bbd94b5e8667dcd684903bf8894d32efcac29123 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
  * Copyright (c) 1991-1998 University of Maryland at College Park
+ * Copyright (c) 2007-2012 Zmanda, Inc.  All Rights Reserved.
  * All Rights Reserved.
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
@@ -66,6 +67,13 @@ fixup_relative(
     return newname;
 }
 
+/* GDestroyFunc for a hash table whose values are GSLists contianing malloc'd
+ * strings */
+static void
+destroy_slist_free_full(gpointer list) {
+    slist_free_full((GSList *)list, g_free);
+}
+
 
 static char *
 get_name(
@@ -433,9 +441,9 @@ build_include(
        
     if (nb_exp == 0) {
        quoted = quote_string(dle->disk);
-       dbprintf(_("No include for %s\n"), quoted);
+       dbprintf(_("Nothing found to include for disk %s\n"), quoted);
        if (verbose && dle->include_optional == 0) {
-           g_printf(_("ERROR [No include for %s]\n"), quoted);
+           g_printf(_("ERROR [Nothing found to include for disk %s]\n"), quoted);
        }
        amfree(quoted);
     }
@@ -710,6 +718,174 @@ application_property_add_to_argv(
     return;
 }
 
+typedef struct {
+    dle_t *dle;
+    char *name;
+    proplist_t dle_proplist;
+    int verbose;
+    int good;
+} merge_property_t;
+
+static void
+merge_property(
+    gpointer key_p,
+    gpointer value_p,
+    gpointer user_data_p)
+{
+    char *property_s = key_p;
+    property_t *conf_property = value_p;
+    merge_property_t *merge_p = user_data_p;
+    property_t *dle_property = g_hash_table_lookup(merge_p->dle_proplist,
+                                                  property_s);
+    GSList *value;
+    char *qdisk = quote_string(merge_p->dle->disk);
+
+    if (dle_property) {
+       if (dle_property->priority && conf_property->priority) {
+           if (merge_p->verbose) {
+               g_fprintf(stdout,
+                        _("ERROR %s (%s) Both server client have priority for property '%s'.\n"),
+                        qdisk, merge_p->name, property_s);
+           }
+           g_debug("ERROR %s (%s) Both server client have priority for property '%s'.", qdisk, merge_p->name, property_s);
+           merge_p->good = 0;
+           /* Use client property */
+           g_hash_table_remove(merge_p->dle_proplist, key_p);
+            g_hash_table_insert(merge_p->dle_proplist, key_p, conf_property);
+       } else if (dle_property->priority) {
+           if (merge_p->verbose) {
+               g_fprintf(stdout,
+                        _("ERROR %s (%s) Server set priority for property '%s' but client set the property.\n"),
+                        qdisk, merge_p->name, property_s);
+           }
+           g_debug("%s (%s) Server set priority for property '%s' but client set the property.", qdisk, merge_p->name, property_s);
+           /* use server property */
+       } else if (conf_property->priority) {
+           if (merge_p->verbose) {
+               g_fprintf(stdout,
+                        _("ERROR %s (%s) Client set priority for property '%s' but server set the property.\n"),
+                        qdisk, merge_p->name, property_s);
+           }
+           g_debug("%s (%s) Client set priority for property '%s' but server set the property.", qdisk, merge_p->name, property_s);
+           /* Use client property */
+           g_hash_table_remove(merge_p->dle_proplist, key_p);
+            g_hash_table_insert(merge_p->dle_proplist, key_p, conf_property);
+       } else if (!conf_property->append) {
+           if (merge_p->verbose) {
+               g_fprintf(stdout,
+                        _("ERROR %s (%s) Both server and client set property '%s', using client value.\n"),
+                        qdisk, merge_p->name, property_s);
+           }
+           g_debug("%s (%s) Both server and client set property '%s', using client value.", qdisk, merge_p->name, property_s);
+           /* Use client property */
+           g_hash_table_remove(merge_p->dle_proplist, key_p);
+            g_hash_table_insert(merge_p->dle_proplist, key_p, conf_property);
+       } else { /* merge */
+           for (value = conf_property->values; value != NULL;
+                value = value->next) {
+               dle_property->values = g_slist_append(dle_property->values,
+                                                     value->data);
+           }
+       }
+    } else { /* take value from conf */
+        g_hash_table_insert(merge_p->dle_proplist, key_p, conf_property);
+    }
+}
+
+int
+merge_properties(
+    dle_t      *dle,
+    char       *name,
+    proplist_t  dle_proplist,
+    proplist_t  conf_proplist,
+    int         verbose)
+{
+    merge_property_t merge_p = {dle, name, dle_proplist, verbose, 1};
+
+    if (conf_proplist != NULL) {
+       g_hash_table_foreach(conf_proplist,
+                             &merge_property,
+                             &merge_p);
+    }
+
+    return merge_p.good;
+}
+
+int
+merge_dles_properties(
+    dle_t *dles,
+    int verbose)
+{
+    dle_t         *dle;
+    application_t *app;
+    GSList        *scriptlist;
+    pp_script_t   *pp_script;
+    int            good = 1;
+
+    for (dle=dles; dle != NULL; dle=dle->next) {
+        if (dle->program_is_application_api) {
+           app = NULL;
+           if (dle->application_client_name &&
+               strlen(dle->application_client_name) > 0) {
+               app = lookup_application(dle->application_client_name);
+               if (!app) {
+                   char *qamname = quote_string(dle->disk);
+                   char *errmsg = vstrallocf("Application '%s' not found on client",
+                                             dle->application_client_name);
+                   char *qerrmsg = quote_string(errmsg);
+                   good = 0;
+                   if (verbose) {
+                       g_fprintf(stdout, _("ERROR %s %s\n"), qamname, qerrmsg);
+                   }
+                   g_debug("%s: %s", qamname, qerrmsg);
+                   amfree(qamname);
+                   amfree(errmsg);
+                   amfree(qerrmsg);
+               }
+           } else {
+               app = lookup_application(dle->program);
+           }
+            if (app) {
+                merge_properties(dle, dle->program,
+                                dle->application_property,
+                                application_get_property(app),
+                                verbose);
+            }
+        }
+        for (scriptlist = dle->scriptlist; scriptlist != NULL;
+             scriptlist = scriptlist->next) {
+            script_t *script =  scriptlist->data;
+           pp_script = NULL;
+           if (script->client_name && strlen(script->client_name) > 0) {
+               pp_script = lookup_pp_script(script->client_name);
+               if (!pp_script) {
+                   char *qamname = quote_string(dle->disk);
+                   char *errmsg = vstrallocf("Script '%s' not found on client",
+                                             script->client_name);
+                   char *qerrmsg = quote_string(errmsg);
+                   good = 0;
+                   if (verbose) {
+                       g_fprintf(stderr, _("ERROR %s %s\n"), qamname, qerrmsg);
+                   }
+                   g_debug("%s: %s", qamname, qerrmsg);
+                   amfree(qamname);
+                   amfree(errmsg);
+                   amfree(qerrmsg);
+               }
+           } else {
+               pp_script = lookup_pp_script(script->plugin);
+           }
+            if (pp_script) {
+               merge_properties(dle, script->plugin,
+                                script->property,
+                                pp_script_get_property(pp_script),
+                                verbose);
+           }
+        }
+    }
+    return good;
+}
+
 backup_support_option_t *
 backup_support_option(
     char       *program,
@@ -991,7 +1167,7 @@ run_client_script(
        levellist_t levellist;
        char number[NUM_STR_SIZE];
        for (levellist=dle->levellist; levellist; levellist=levellist->next) {
-           level_t *alevel = (level_t *)levellist->data;
+           am_level_t *alevel = (am_level_t *)levellist->data;
            g_ptr_array_add(argv_ptr, stralloc("--level"));
            g_snprintf(number, SIZEOF(number), "%d", alevel->level);
            g_ptr_array_add(argv_ptr, stralloc(number));
@@ -1009,7 +1185,7 @@ run_client_script(
     script->result = g_new0(client_script_result_t, 1);
     script->result->proplist =
                  g_hash_table_new_full(g_str_hash, g_str_equal,
-                                       &g_free, &g_slist_free_full_gpointer);
+                                       &g_free, &destroy_slist_free_full);
     script->result->output = g_ptr_array_new();
     script->result->err = g_ptr_array_new();
 
@@ -1083,6 +1259,7 @@ run_client_script(
 }
 
 void run_client_script_output(gpointer data, gpointer user_data);
+void run_client_script_output_backup(gpointer data, gpointer user_data);
 void run_client_script_err_amcheck(gpointer data, gpointer user_data);
 void run_client_script_err_estimate(gpointer data, gpointer user_data);
 void run_client_script_err_backup(gpointer data, gpointer user_data);
@@ -1106,6 +1283,19 @@ run_client_script_output(
     }
 }
 
+void
+run_client_script_output_backup(
+    gpointer data,
+    gpointer user_data)
+{
+    char            *line = data;
+    script_output_t *so   = user_data;
+
+    if (line && so->stream) {
+       g_fprintf(so->stream, "| %s\n", line);
+    }
+}
+
 void
 run_client_script_err_amcheck(
     gpointer data,
@@ -1170,31 +1360,27 @@ run_client_scripts(
     GSList          *scriptlist;
     script_t        *script;
     GFunc            client_script_err = NULL;
+    GFunc            client_script_out = NULL;
     script_output_t  so = { streamout, dle };
 
     for (scriptlist = dle->scriptlist; scriptlist != NULL;
         scriptlist = scriptlist->next) {
        script = (script_t *)scriptlist->data;
        run_client_script(script, execute_on, g_options, dle);
-       if (script->result && script->result->output) {
-           g_ptr_array_foreach(script->result->output,
-                               run_client_script_output,
-                               &so);
-           g_ptr_array_free(script->result->output, TRUE);
-           script->result->output = NULL;
-       }
-       if (script->result && script->result->err) {
+       if (script->result) {
            switch (execute_on) {
            case EXECUTE_ON_PRE_DLE_AMCHECK:
            case EXECUTE_ON_PRE_HOST_AMCHECK:
            case EXECUTE_ON_POST_DLE_AMCHECK:
            case EXECUTE_ON_POST_HOST_AMCHECK:
+                client_script_out = run_client_script_output;
                 client_script_err = run_client_script_err_amcheck;
                 break;
            case EXECUTE_ON_PRE_DLE_ESTIMATE:
            case EXECUTE_ON_PRE_HOST_ESTIMATE:
            case EXECUTE_ON_POST_DLE_ESTIMATE:
            case EXECUTE_ON_POST_HOST_ESTIMATE:
+                client_script_out = run_client_script_output;
                 if (am_has_feature(g_options->features,
                                    fe_sendsize_rep_warning)) {
                     client_script_err = run_client_script_err_estimate;
@@ -1204,6 +1390,7 @@ run_client_scripts(
            case EXECUTE_ON_PRE_HOST_BACKUP:
            case EXECUTE_ON_POST_DLE_BACKUP:
            case EXECUTE_ON_POST_HOST_BACKUP:
+                client_script_out = run_client_script_output_backup;
                 client_script_err = run_client_script_err_backup;
                 break;
            case EXECUTE_ON_PRE_RECOVER:
@@ -1211,17 +1398,28 @@ run_client_scripts(
            case EXECUTE_ON_PRE_LEVEL_RECOVER:
            case EXECUTE_ON_POST_LEVEL_RECOVER:
            case EXECUTE_ON_INTER_LEVEL_RECOVER:
+                client_script_out = run_client_script_output;
                 client_script_err = run_client_script_err_recover;
            }
-           if (client_script_err != NULL) {
-               g_ptr_array_foreach(script->result->err,
-                                   client_script_err,
-                                   &so);
+           if (script->result->output) {
+               if (client_script_out) {
+                   g_ptr_array_foreach(script->result->output,
+                                       client_script_out,
+                                       &so);
+               }
+               g_ptr_array_free(script->result->output, TRUE);
+               script->result->output = NULL;
+           }
+           if (script->result->err) {
+               if (client_script_err != NULL) {
+                   g_ptr_array_foreach(script->result->err,
+                                       client_script_err,
+                                       &so);
+               }
+               g_ptr_array_free(script->result->err, TRUE);
+               script->result->err = NULL;
            }
-           g_ptr_array_free(script->result->err, TRUE);
-           script->result->err = NULL;
        }
-       amfree(script->result);
     }
 }
 
@@ -1251,7 +1449,6 @@ run_calcsize(
     FILE        *dumpout = NULL;
     int          dumpsince;
     char        *errmsg = NULL;
-    off_t        size = (off_t)1;
     char        *line = NULL;
     amwait_t     wait_status;
     int          len;
@@ -1347,7 +1544,7 @@ run_calcsize(
 
     match_expr = vstralloc(" %d SIZE %lld", NULL);
     len = strlen(qdisk);
-    for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
+    for(; (line = agets(dumpout)) != NULL; free(line)) {
        long long size_ = (long long)0;
        if (line[0] == '\0' || (int)strlen(line) <= len)
            continue;
@@ -1358,7 +1555,6 @@ run_calcsize(
            dbprintf(_("estimate size for %s level %d: %lld KB\n"),
                     qdisk, level, size_);
        }
-       size = (off_t)size_;
     }
     amfree(match_expr);
 
@@ -1402,11 +1598,10 @@ common_exit:
     amfree(errmsg);
     g_ptr_array_free_full(argv_ptr);
     amfree(cmd);
-
 }
 
 
-void
+gboolean
 check_access(
     char *     filename,
     int                mode)
@@ -1423,14 +1618,18 @@ check_access(
     else 
        noun = "access", adjective = "accessible";
 
-    if(access(filename, mode) == -1)
+    if(access(filename, mode) == -1) {
        g_printf(_("ERROR [can not %s %s: %s]\n"), noun, quoted, strerror(errno));
-    else
+       amfree(quoted);
+       return FALSE;
+    } else {
        g_printf(_("OK %s %s\n"), quoted, adjective);
+    }
     amfree(quoted);
+    return TRUE;
 }
 
-void
+gboolean
 check_file(
     char *     filename,
     int                mode)
@@ -1443,6 +1642,7 @@ check_file(
            quoted = quote_string(filename);
            g_printf(_("ERROR [%s is not a file]\n"), quoted);
            amfree(quoted);
+           return FALSE;
        }
     } else {
        int save_errno = errno;
@@ -1450,13 +1650,19 @@ check_file(
        g_printf(_("ERROR [can not stat %s: %s]\n"), quoted,
                 strerror(save_errno));
        amfree(quoted);
+       return FALSE;
     }
     if (getuid() == geteuid()) {
-       check_access(filename, mode);
+       return check_access(filename, mode);
+    } else {
+       quoted = quote_string(filename);
+       g_printf("OK %s\n", quoted);
+       amfree(quoted);
     }
+    return TRUE;
 }
 
-void
+gboolean
 check_dir(
     char *     dirname,
     int                mode)
@@ -1470,6 +1676,7 @@ check_dir(
            quoted = quote_string(dirname);
            g_printf(_("ERROR [%s is not a directory]\n"), quoted);
            amfree(quoted);
+           return FALSE;
        }
     } else {
        int save_errno = errno;
@@ -1477,15 +1684,23 @@ check_dir(
        g_printf(_("ERROR [can not stat %s: %s]\n"), quoted,
                 strerror(save_errno));
        amfree(quoted);
+       return FALSE;
     }
     if (getuid() == geteuid()) {
+       gboolean  result;
        dir = stralloc2(dirname, "/.");
-       check_access(dir, mode);
+       result = check_access(dir, mode);
        amfree(dir);
+       return result;
+    } else {
+       quoted = quote_string(dirname);
+       g_printf("OK %s\n", quoted);
+       amfree(quoted);
     }
+    return TRUE;
 }
 
-void
+gboolean
 check_suid(
     char *     filename)
 {
@@ -1496,18 +1711,25 @@ check_suid(
     if(!stat(filename, &stat_buf)) {
        if(stat_buf.st_uid != 0 ) {
            g_printf(_("ERROR [%s is not owned by root]\n"), quoted);
+           amfree(quoted);
+           return FALSE;
        }
        if((stat_buf.st_mode & S_ISUID) != S_ISUID) {
            g_printf(_("ERROR [%s is not SUID root]\n"), quoted);
+           amfree(quoted);
+           return FALSE;
        }
     }
     else {
        g_printf(_("ERROR [can not stat %s: %s]\n"), quoted, strerror(errno));
+       amfree(quoted);
+       return FALSE;
     }
     amfree(quoted);
 #else
     (void)filename;    /* Quiet unused parameter warning */
 #endif
+    return TRUE;
 }
 
 /*
@@ -1674,39 +1896,3 @@ build_re_table(
     return new_re_table;
 }
 
-typedef struct {
-    proplist_t result;
-} merge_property_t;
-
-static void
-merge_property(
-    gpointer key_p,
-    gpointer value_p,
-    gpointer user_data_p)
-{
-    char *property_s = key_p;
-    GSList *value_s = value_p;
-    merge_property_t *merge_p = user_data_p;
-    GSList *value = g_hash_table_lookup(merge_p->result, property_s);
-
-    if (value) { /* remove old value */
-       g_hash_table_remove(merge_p->result, key_p);
-    }
-    g_hash_table_insert(merge_p->result, key_p, value_s);
-}
-
-void
-merge_properties(
-    proplist_t proplist1,
-    proplist_t proplist2)
-{
-    merge_property_t merge_p = {proplist1};
-
-    if (proplist2 == NULL) {
-       return;
-    }
-    g_hash_table_foreach(proplist2,
-                         &merge_property,
-                         &merge_p);
-}
-