lintian doesn't like orphan packages with uploaders...
[debian/amanda] / server-src / amflush.c
index 4515e67298480a93325060f7dfb1795e7145f86d..481ff289966e4fe495da10b5d423bea40290b9de 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
  */
 #include "amanda.h"
 
+#include "match.h"
+#include "find.h"
 #include "conffile.h"
 #include "diskfile.h"
 #include "tapefile.h"
 #include "logfile.h"
 #include "clock.h"
-#include "version.h"
 #include "holding.h"
-#include "driverio.h"
 #include "server_util.h"
 #include "timestamp.h"
+#include "getopt.h"
+
+static struct option long_options[] = {
+    {"version"         , 0, NULL,  1},
+    {"exact-match"     , 0, NULL,  2},
+    {NULL, 0, NULL, 0}
+};
 
 static char *conf_logdir;
 FILE *driver_stream;
@@ -79,7 +87,6 @@ main(
     pid_t driver_pid, reporter_pid;
     amwait_t exitcode;
     int opt;
-    dumpfile_t file;
     GSList *holding_list=NULL, *holding_file;
     int driver_pipe[2];
     char date_string[100];
@@ -91,8 +98,11 @@ main(
     char *tpchanger;
     char *qdisk, *qhname;
     GSList *datestamp_list = NULL;
-    config_overwrites_t *cfg_ovr;
+    config_overrides_t *cfg_ovr;
     char **config_options;
+    find_result_t *holding_files;
+    disklist_t holding_disklist = { NULL, NULL };
+    gboolean exact_match = FALSE;
 
     /*
      * Configure program for internationalization:
@@ -113,23 +123,28 @@ main(
 
     dbopen(DBG_SUBDIR_SERVER);
 
-    erroutput_type = ERR_INTERACTIVE;
+    add_amanda_log_handler(amanda_log_stderr);
     foreground = 0;
     batch = 0;
     redirect = 1;
 
     /* process arguments */
 
-    cfg_ovr = new_config_overwrites(argc/2);
-    while((opt = getopt(argc, argv, "bfso:D:")) != EOF) {
+    cfg_ovr = new_config_overrides(argc/2);
+    while((opt = getopt_long(argc, argv, "bfso:D:", long_options, NULL)) != EOF) {
        switch(opt) {
+       case 1  : printf("amflush-%s\n", VERSION);
+                 return(0);
+                 break;
+       case 2  : exact_match = TRUE;
+                 break;
        case 'b': batch = 1;
                  break;
        case 'f': foreground = 1;
                  break;
        case 's': redirect = 0;
                  break;
-       case 'o': add_config_overwrite_opt(cfg_ovr, optarg);
+       case 'o': add_config_override_opt(cfg_ovr, optarg);
                  break;
        case 'D': if (datearg == NULL)
                      datearg = alloc(21*SIZEOF(char *));
@@ -150,28 +165,41 @@ main(
     }
 
     if(argc < 1) {
-       error(_("Usage: amflush%s [-b] [-f] [-s] [-D date]* <confdir> [host [disk]* ]* [-o configoption]*"), versionsuffix());
+       error(_("Usage: amflush [-b] [-f] [-s] [-D date]* [--exact-match] [-o configoption]* <confdir> [host [disk]* ]*"));
        /*NOTREACHED*/
     }
 
-    config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_FATAL,
+    set_config_overrides(cfg_ovr);
+    config_init(CONFIG_INIT_EXPLICIT_NAME,
                argv[0]);
-    apply_config_overwrites(cfg_ovr);
-    check_running_as(RUNNING_AS_DUMPUSER);
-
-    dbrename(config_name, DBG_SUBDIR_SERVER);
 
     conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE));
-    if (read_diskfile(conf_diskfile, &diskq) < 0) {
-       error(_("could not read disklist file \"%s\""), conf_diskfile);
-       /*NOTREACHED*/
+    read_diskfile(conf_diskfile, &diskq);
+    amfree(conf_diskfile);
+
+    if (config_errors(NULL) >= CFGERR_WARNINGS) {
+       config_print_errors();
+       if (config_errors(NULL) >= CFGERR_ERRORS) {
+           g_critical(_("errors processing config file"));
+       }
     }
-    errstr = match_disklist(&diskq, argc-1, argv+1);
+
+    check_running_as(RUNNING_AS_DUMPUSER);
+
+    dbrename(get_config_name(), DBG_SUBDIR_SERVER);
+
+    /* load DLEs from the holding disk, in case there's anything to flush there */
+    search_holding_disk(&holding_files, &holding_disklist);
+    /* note that the dumps are added to the global disklist, so we need not
+     * consult holding_files or holding_disklist after this.  The holding-only
+     * dumps will be filtered properly by match_disklist, setting the dp->todo
+     * flag appropriately. */
+
+    errstr = match_disklist(&diskq, exact_match, argc-1, argv+1);
     if (errstr) {
        g_printf(_("%s"),errstr);
        amfree(errstr);
     }
-    amfree(conf_diskfile);
 
     conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST));
     if(read_tapelist(conf_tapelist)) {
@@ -193,17 +221,17 @@ main(
     conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
     conf_logfile = vstralloc(conf_logdir, "/log", NULL);
     if (access(conf_logfile, F_OK) == 0) {
-       error(_("%s exists: amdump or amflush is already running, or you must run amcleanup"), conf_logfile);
+       run_amcleanup(get_config_name());
+    }
+    if (access(conf_logfile, F_OK) == 0) {
+       char *process_name = get_master_process(conf_logfile);
+       error(_("%s exists: %s is already running, or you must run amcleanup"), conf_logfile, process_name);
        /*NOTREACHED*/
     }
-    amfree(conf_logfile);
 
-    driver_program = vstralloc(amlibexecdir, "/", "driver", versionsuffix(),
-                              NULL);
-    reporter_program = vstralloc(sbindir, "/", "amreport", versionsuffix(),
-                                NULL);
-    logroll_program = vstralloc(amlibexecdir, "/", "amlogroll", versionsuffix(),
-                               NULL);
+    driver_program = vstralloc(amlibexecdir, "/", "driver", NULL);
+    reporter_program = vstralloc(sbindir, "/", "amreport", NULL);
+    logroll_program = vstralloc(amlibexecdir, "/", "amlogroll", NULL);
 
     tapedev = getconf_str(CNF_TAPEDEV);
     tpchanger = getconf_str(CNF_TPCHANGER);
@@ -231,7 +259,7 @@ main(
                    stralloc((char *)datestamp->data),
                    g_compare_strings);
        }
-       g_slist_free_full(all_datestamps);
+       slist_free_full(all_datestamps, g_free);
     }
     else {
        /* otherwise, in batch mode, use all datestamps */
@@ -255,14 +283,30 @@ main(
        exit(1);
     }
 
+    if (access(conf_logfile, F_OK) == 0) {
+       char *process_name = get_master_process(conf_logfile);
+       error(_("%s exists: someone started %s"), conf_logfile, process_name);
+       /*NOTREACHED*/
+    }
+    log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
+
     if(!batch) confirm(datestamp_list);
 
     for(dp = diskq.head; dp != NULL; dp = dp->next) {
        if(dp->todo) {
-           char *qname;
-           qname = quote_string(dp->name);
-           log_add(L_DISK, "%s %s", dp->host->hostname, qname);
-           amfree(qname);
+           /* is it holding_list */
+           for (holding_file=holding_list; holding_file != NULL;
+                                           holding_file = holding_file->next) {
+               dumpfile_t file;
+               holding_file_get_dumpfile((char *)holding_file->data, &file);
+               if (g_str_equal(dp->host->hostname, file.name) &&
+                   g_str_equal(dp->name, file.disk)) {
+                   char *qname;
+                   qname = quote_string(dp->name);
+                   log_add(L_DISK, "%s %s", dp->host->hostname, qname);
+                   amfree(qname);
+               }
+           }
        }
     }
 
@@ -275,8 +319,8 @@ main(
 
     if(!foreground) detach();
 
-    erroutput_type = (ERR_AMANDALOG|ERR_INTERACTIVE);
-    set_logerror(logerror);
+    add_amanda_log_handler(amanda_log_stderr);
+    add_amanda_log_handler(amanda_log_trace_log);
     today = time(NULL);
     tm = localtime(&today);
     if (tm) {
@@ -305,7 +349,7 @@ main(
        close(driver_pipe[1]);
        config_options = get_config_options(3);
        config_options[0] = "driver";
-       config_options[1] = config_name;
+       config_options[1] = get_config_name();
        config_options[2] = "nodump";
        safe_fd(-1, 0);
        execve(driver_program, config_options, safe_env());
@@ -324,20 +368,24 @@ main(
     g_fprintf(driver_stream, "DATE %s\n", amflush_timestamp);
     for(holding_file=holding_list; holding_file != NULL;
                                   holding_file = holding_file->next) {
+       dumpfile_t file;
        holding_file_get_dumpfile((char *)holding_file->data, &file);
 
        if (holding_file_size((char *)holding_file->data, 1) <= 0) {
+           g_debug("%s is empty - ignoring", (char *)holding_file->data);
            log_add(L_INFO, "%s: removing file with no data.",
                    (char *)holding_file->data);
            holding_file_unlink((char *)holding_file->data);
+           dumpfile_free_data(&file);
            continue;
        }
 
+       /* search_holding_disk should have already ensured that every
+        * holding dumpfile has an entry in the dynamic disklist */
        dp = lookup_disk(file.name, file.disk);
-       if (!dp) {
-           error("dp == NULL");
-           /*NOTREACHED*/
-       }
+       assert(dp != NULL);
+
+       /* but match_disklist may have indicated we should not flush it */
        if (dp->todo == 0) continue;
 
        qdisk = quote_string(file.disk);
@@ -349,6 +397,8 @@ main(
                file.datestamp,
                file.dumplevel,
                qhname);
+
+       g_debug("flushing '%s'", (char *)holding_file->data);
        g_fprintf(driver_stream,
                "FLUSH %s %s %s %d %s\n",
                file.name,
@@ -358,6 +408,7 @@ main(
                qhname);
        amfree(qdisk);
        amfree(qhname);
+       dumpfile_free_data(&file);
     }
     g_fprintf(stderr, "ENDFLUSH\n"); fflush(stderr);
     g_fprintf(driver_stream, "ENDFLUSH\n"); fflush(driver_stream);
@@ -377,9 +428,9 @@ main(
        }
     }
 
-    g_slist_free_full(datestamp_list);
+    slist_free_full(datestamp_list, g_free);
     datestamp_list = NULL;
-    g_slist_free_full(holding_list);
+    slist_free_full(holding_list, g_free);
     holding_list = NULL;
 
     if(redirect) { /* rename errfile */
@@ -441,9 +492,10 @@ main(
        /*
         * This is the child process.
         */
-       config_options = get_config_options(2);
+       config_options = get_config_options(3);
        config_options[0] = "amreport";
-       config_options[1] = config_name;
+       config_options[1] = get_config_name();
+        config_options[2] = "--from-amdump";
        safe_fd(-1, 0);
        execve(reporter_program, config_options, safe_env());
        error(_("cannot exec %s: %s"), reporter_program, strerror(errno));
@@ -465,13 +517,15 @@ main(
        }
     }
 
+    log_add(L_INFO, "pid-done %ld", (long)getpid());
+
     /*
      * Call amlogroll to rename the log file to its datestamped version.
      * Since we exec at this point, our exit code will be that of amlogroll.
      */
     config_options = get_config_options(2);
     config_options[0] = "amlogroll";
-    config_options[1] = config_name;
+    config_options[1] = get_config_name();
     safe_fd(-1, 0);
     execve(logroll_program, config_options, safe_env());
     error(_("cannot exec %s: %s"), logroll_program, strerror(errno));
@@ -486,7 +540,7 @@ get_letter_from_user(void)
     int r, ch;
 
     fflush(stdout); fflush(stderr);
-    while((ch = getchar()) != EOF && ch != '\n' && isspace(ch)) {
+    while((ch = getchar()) != EOF && ch != '\n' && g_ascii_isspace(ch)) {
        (void)ch; /* Quite lint */
     }
     if(ch == '\n') {
@@ -556,19 +610,19 @@ pick_datestamp(void)
 
            a = answer;
            while ((ch = *a++) != '\0') {
-               if (!isspace(ch))
+               if (!g_ascii_isspace(ch))
                    break;
            }
 
            /* rewrite the selected list into r_datestamp_list, then copy it over
             * to datestamp_list */
            do {
-               if (isspace(ch) || ch == ',') {
+               if (g_ascii_isspace(ch) || ch == ',') {
                    continue;
                }
                chupper = (char)toupper(ch);
                if (chupper < 'A' || chupper > max_char) {
-                   g_slist_free_full(r_datestamp_list);
+                   slist_free_full(r_datestamp_list, g_free);
                    r_datestamp_list = NULL;
                    break;
                }
@@ -576,7 +630,7 @@ pick_datestamp(void)
                                           stralloc(datestamps[chupper - 'A']));
            } while ((ch = *a++) != '\0');
            if (r_datestamp_list && ch == '\0') {
-               g_slist_free_full(datestamp_list);
+               slist_free_full(datestamp_list, g_free);
                datestamp_list = r_datestamp_list;
                break;
            }
@@ -638,6 +692,7 @@ confirm(GSList *datestamp_list)
     }
 
     g_printf(_("Ok, quitting.  Run amflush again when you are ready.\n"));
+    log_add(L_INFO, "pid-done %ld", (long)getpid());
     exit(1);
 }
 
@@ -649,7 +704,7 @@ redirect_stderr(void)
 
     fflush(stdout); fflush(stderr);
     errfile = vstralloc(conf_logdir, "/amflush", NULL);
-    if((fderr = open(errfile, O_WRONLY| O_CREAT | O_TRUNC, 0600)) == -1) {
+    if((fderr = open(errfile, O_WRONLY| O_APPEND | O_CREAT | O_TRUNC, 0600)) == -1) {
        error(_("could not open %s: %s"), errfile, strerror(errno));
        /*NOTREACHED*/
     }