Imported Upstream version 3.2.0
[debian/amanda] / server-src / server_util.c
index 95e57b3cf024a61d61887b91a85dfbb844977ff5..515eea59a84d261e1b37ee180f00eb09d4e6a623 100644 (file)
 #include "amanda.h"
 #include "server_util.h"
 #include "arglist.h"
-#include "token.h"
 #include "logfile.h"
 #include "util.h"
 #include "conffile.h"
 #include "diskfile.h"
+#include "pipespawn.h"
+#include "conffile.h"
+#include "infofile.h"
+#include "sys/wait.h"
 
 const char *cmdstr[] = {
     "BOGUS", "QUIT", "QUITTING", "DONE", "PARTIAL", 
     "START", "FILE-DUMP", "PORT-DUMP", "CONTINUE", "ABORT",/* dumper cmds */
     "FAILED", "TRY-AGAIN", "NO-ROOM", "RQ-MORE-DISK",  /* dumper results */
     "ABORT-FINISHED", "BAD-COMMAND",                   /* dumper results */
-    "START-TAPER", "FILE-WRITE", "PORT-WRITE",         /* taper cmds */
-    "PORT", "TAPE-ERROR", "TAPER-OK", "SPLIT-NEEDNEXT", /* taper results */
-    "SPLIT-CONTINUE",
+    "START-TAPER", "FILE-WRITE", "NEW-TAPE", "NO-NEW-TAPE",
+     
+    "PARTDONE", "PORT-WRITE", "DUMPER-STATUS",             /* taper cmds */
+    "PORT", "TAPE-ERROR", "TAPER-OK",                   /* taper results */
+    "REQUEST-NEW-TAPE", "DIRECTTCP-PORT", "TAKE-SCRIBE-FROM",
+    "START-SCAN", "LAST_TOK",
     NULL
 };
 
 
-cmd_t
-getcmd(
-    struct cmdargs *   cmdargs)
+struct cmdargs *
+getcmd(void)
 {
     char *line;
     cmd_t cmd_i;
-
-    assert(cmdargs != NULL);
+    struct cmdargs *cmdargs = g_new0(struct cmdargs, 1);
 
     if (isatty(0)) {
-       printf("%s> ", get_pname());
+       g_printf("%s> ", get_pname());
        fflush(stdout);
-        line = readline(NULL);
+        line = agets(stdin);
     } else {
         line = agets(stdin);
     }
@@ -69,36 +73,65 @@ getcmd(
        line = stralloc("QUIT");
     }
 
-    cmdargs->argc = split(line, cmdargs->argv,
-       (int)(sizeof(cmdargs->argv) / sizeof(cmdargs->argv[0])), " ");
+    dbprintf(_("getcmd: %s\n"), line);
+
+    cmdargs->argv = split_quoted_strings(line);
+    cmdargs->argc = g_strv_length(cmdargs->argv);
+    cmdargs->cmd = BOGUS;
+
     amfree(line);
 
-#if DEBUG
-    {
-       int i;
-       fprintf(stderr,"argc = %d\n", cmdargs->argc);
-       for (i = 0; i < cmdargs->argc+1; i++)
-           fprintf(stderr,"argv[%d] = \"%s\"\n", i, cmdargs->argv[i]);
+    if (cmdargs->argc < 1) {
+       return cmdargs;
     }
-#endif
-
-    if (cmdargs->argc < 1)
-       return (BOGUS);
 
     for(cmd_i=BOGUS; cmdstr[cmd_i] != NULL; cmd_i++)
-       if(strcmp(cmdargs->argv[1], cmdstr[cmd_i]) == 0)
-           return (cmd_i);
-    return (BOGUS);
+       if(strcmp(cmdargs->argv[0], cmdstr[cmd_i]) == 0) {
+           cmdargs->cmd = cmd_i;
+           return cmdargs;
+       }
+    return cmdargs;
 }
 
+struct cmdargs *
+get_pending_cmd(void)
+{
+    SELECT_ARG_TYPE ready;
+    struct timeval  to;
+    int             nfound;
+
+    FD_ZERO(&ready);
+    FD_SET(0, &ready);
+    to.tv_sec = 0;
+    to.tv_usec = 0;
+
+    nfound = select(1, &ready, NULL, NULL, &to);
+    if (nfound && FD_ISSET(0, &ready)) {
+        return getcmd();
+    } else {
+       return NULL;
+    }
+}
+
+void
+free_cmdargs(
+    struct cmdargs *cmdargs)
+{
+    if (!cmdargs)
+       return;
+    if (cmdargs->argv)
+       g_strfreev(cmdargs->argv);
+    g_free(cmdargs);
+}
 
 printf_arglist_function1(void putresult, cmd_t, result, const char *, format)
 {
     va_list argp;
 
     arglist_start(argp, format);
-    printf("%s ",cmdstr[result]);
-    vprintf(format, argp);
+    dbprintf(_("putresult: %d %s\n"), result, cmdstr[result]);
+    g_printf("%s ", cmdstr[result]);
+    g_vprintf(format, argp);
     fflush(stdout);
     arglist_end(argp);
 }
@@ -122,6 +155,8 @@ amhost_get_security_conf(
        return ((am_host_t *)arg)->disks->amandad_path;
     else if(strcmp(string, "client_username")==0)
        return ((am_host_t *)arg)->disks->client_username;
+    else if(strcmp(string, "client_port")==0)
+       return ((am_host_t *)arg)->disks->client_port;
     else if(strcmp(string, "ssh_keys")==0)
        return ((am_host_t *)arg)->disks->ssh_keys;
 
@@ -171,16 +206,367 @@ int check_infofile(
                    }
                }
                if (other_dle_match == 0) {
-                   if(mkpdir(infofile, (mode_t)02755, (uid_t)-1,
-                             (gid_t)-1) == -1) 
+                   if(mkpdir(infofile, (mode_t)0755, (uid_t)-1,
+                             (gid_t)-1) == -1) {
                        *errmsg = vstralloc("Can't create directory for ",
                                            infofile, NULL);
                        return -1;
+                   }
                    if(copy_file(infofile, old_infofile, errmsg) == -1) 
                        return -1;
                }
            }
+           amfree(old_hostinfodir);
+           amfree(old_diskdir);
+           amfree(old_infofile);
        }
+       amfree(diskdir);
+       amfree(hostinfodir);
+       amfree(infofile);
     }
     return 0;
 }
+
+void
+run_server_script(
+    pp_script_t  *pp_script,
+    execute_on_t  execute_on,
+    char         *config,
+    disk_t      *dp,
+    int           level)
+{
+    pid_t      scriptpid;
+    int        scriptin, scriptout, scripterr;
+    char      *cmd;
+    char      *command = NULL;
+    GPtrArray *argv_ptr = g_ptr_array_new();
+    FILE      *streamout;
+    char      *line;
+    char      *plugin;
+    char       level_number[NUM_STR_SIZE];
+
+    if ((pp_script_get_execute_on(pp_script) & execute_on) == 0)
+       return;
+    if (pp_script_get_execute_where(pp_script) != ES_SERVER)
+       return;
+
+    plugin = pp_script_get_plugin(pp_script);
+    cmd = vstralloc(APPLICATION_DIR, "/", plugin, NULL);
+    g_ptr_array_add(argv_ptr, stralloc(plugin));
+
+    switch (execute_on) {
+    case EXECUTE_ON_PRE_DLE_AMCHECK:
+       command = "PRE-DLE-AMCHECK";
+       break;
+    case EXECUTE_ON_PRE_HOST_AMCHECK:
+       command = "PRE-HOST-AMCHECK";
+       break;
+    case EXECUTE_ON_POST_DLE_AMCHECK:
+       command = "POST-DLE-AMCHECK";
+       break;
+    case EXECUTE_ON_POST_HOST_AMCHECK:
+       command = "POST-HOST-AMCHECK";
+       break;
+    case EXECUTE_ON_PRE_DLE_ESTIMATE:
+       command = "PRE-DLE-ESTIMATE";
+       break;
+    case EXECUTE_ON_PRE_HOST_ESTIMATE:
+       command = "PRE-HOST-ESTIMATE";
+       break;
+    case EXECUTE_ON_POST_DLE_ESTIMATE:
+       command = "POST-DLE-ESTIMATE";
+       break;
+    case EXECUTE_ON_POST_HOST_ESTIMATE:
+       command = "POST-HOST-ESTIMATE";
+       break;
+    case EXECUTE_ON_PRE_DLE_BACKUP:
+       command = "PRE-DLE-BACKUP";
+       break;
+    case EXECUTE_ON_PRE_HOST_BACKUP:
+       command = "PRE-HOST-BACKUP";
+       break;
+    case EXECUTE_ON_POST_DLE_BACKUP:
+       command = "POST-DLE-BACKUP";
+       break;
+    case EXECUTE_ON_POST_HOST_BACKUP:
+       command = "POST-HOST-BACKUP";
+       break;
+    case EXECUTE_ON_PRE_RECOVER:
+    case EXECUTE_ON_POST_RECOVER:
+    case EXECUTE_ON_PRE_LEVEL_RECOVER:
+    case EXECUTE_ON_POST_LEVEL_RECOVER:
+    case EXECUTE_ON_INTER_LEVEL_RECOVER:
+       {
+            // ERROR these script can't be executed on server.
+            return;
+       }
+    }
+
+    g_ptr_array_add(argv_ptr, stralloc(command));
+    g_ptr_array_add(argv_ptr, stralloc("--execute-where"));
+    g_ptr_array_add(argv_ptr, stralloc("server"));
+
+    if (config) {
+       g_ptr_array_add(argv_ptr, stralloc("--config"));
+       g_ptr_array_add(argv_ptr, stralloc(config));
+    }
+    if (dp->host->hostname) {
+       g_ptr_array_add(argv_ptr, stralloc("--host"));
+       g_ptr_array_add(argv_ptr, stralloc(dp->host->hostname));
+    }
+    if (dp->name) {
+       g_ptr_array_add(argv_ptr, stralloc("--disk"));
+       g_ptr_array_add(argv_ptr, stralloc(dp->name));
+    }
+    if (dp->device) {
+       g_ptr_array_add(argv_ptr, stralloc("--device"));
+       g_ptr_array_add(argv_ptr, stralloc(dp->device));
+    }
+    if (level >= 0) {
+       g_snprintf(level_number, SIZEOF(level_number), "%d", level);
+       g_ptr_array_add(argv_ptr, stralloc("--level"));
+       g_ptr_array_add(argv_ptr, stralloc(level_number));
+    }
+
+    property_add_to_argv(argv_ptr, pp_script_get_property(pp_script));
+    g_ptr_array_add(argv_ptr, NULL);
+
+    scripterr = fileno(stderr);
+    scriptpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE, 0, &scriptin,
+                          &scriptout, &scripterr,
+                          (char **)argv_ptr->pdata);
+    close(scriptin);
+
+    streamout = fdopen(scriptout, "r");
+    if (streamout) {
+       while((line = agets(streamout)) != NULL) {
+           dbprintf("script: %s\n", line);
+           amfree(line);
+       }
+    }
+    fclose(streamout);
+    waitpid(scriptpid, NULL, 0);
+    g_ptr_array_free_full(argv_ptr);
+    amfree(cmd);
+}
+
+
+void
+run_server_scripts(
+    execute_on_t  execute_on,
+    char         *config,
+    disk_t      *dp,
+    int           level)
+{
+    identlist_t pp_scriptlist;
+
+    for (pp_scriptlist = dp->pp_scriptlist; pp_scriptlist != NULL;
+        pp_scriptlist = pp_scriptlist->next) {
+       pp_script_t *pp_script = lookup_pp_script((char *)pp_scriptlist->data);
+       g_assert(pp_script != NULL);
+       run_server_script(pp_script, execute_on, config, dp, level);
+    }
+}
+
+void
+run_amcleanup(
+    char *config_name)
+{
+    pid_t amcleanup_pid;
+    char *amcleanup_program;
+    char *amcleanup_options[4];
+
+    switch(amcleanup_pid = fork()) {
+       case -1:
+           return;
+           break;
+       case  0: /* child process */
+           amcleanup_program = vstralloc(sbindir, "/", "amcleanup", NULL);
+           amcleanup_options[0] = amcleanup_program;
+           amcleanup_options[1] = "-p";
+           amcleanup_options[2] = config_name;
+           amcleanup_options[3] = NULL;
+           execve(amcleanup_program, amcleanup_options, safe_env());
+           error("exec %s: %s", amcleanup_program, strerror(errno));
+           /*NOTREACHED*/
+       default:
+           break;
+    }
+    waitpid(amcleanup_pid, NULL, 0);
+}
+
+char *
+get_master_process(
+    char *logfile)
+{
+    FILE *log;
+    char line[1024];
+    char *s, ch;
+    char *process_name;
+
+    log = fopen(logfile, "r");
+    if (!log)
+       return stralloc("UNKNOWN");
+
+    while(fgets(line, 1024, log)) {
+       if (strncmp_const(line, "INFO ") == 0) {
+           s = line+5;
+           ch = *s++;
+           process_name = s-1;
+           skip_non_whitespace(s, ch);
+           s[-1] = '\0';
+           skip_whitespace(s, ch);
+           skip_non_whitespace(s, ch);
+           s[-1] = '\0';
+           skip_whitespace(s, ch);
+           if (strncmp_const(s-1, "pid ") == 0) {
+               process_name = stralloc(process_name);
+               fclose(log);
+               return process_name;
+           }
+       }
+    }
+    fclose(log);
+    return stralloc("UNKNOWN");
+}
+
+
+gint64
+internal_server_estimate(
+    disk_t *dp,
+    info_t *info,
+    int     level,
+    int    *stats)
+{
+    int    j;
+    gint64 size = 0;
+
+    *stats = 0;
+
+    if (level == 0) { /* use latest level 0, should do extrapolation */
+       gint64 est_size = (gint64)0;
+       int nb_est = 0;
+
+       for (j=NB_HISTORY-2; j>=0; j--) {
+           if (info->history[j].level == 0) {
+               if (info->history[j].size < (gint64)0) continue;
+               est_size = info->history[j].size;
+               nb_est++;
+           }
+       }
+       if (nb_est > 0) {
+           size = est_size;
+           *stats = 1;
+       } else if (info->inf[level].size > (gint64)1000) { /* stats */
+           size = info->inf[level].size;
+           *stats = 1;
+       } else {
+           char *conf_tapetype = getconf_str(CNF_TAPETYPE);
+           tapetype_t *tape = lookup_tapetype(conf_tapetype);
+           size = (gint64)1000000;
+           if (size > tapetype_get_length(tape)/2)
+               size = tapetype_get_length(tape)/2;
+           *stats = 0;
+       }
+    } else if (level == info->last_level) {
+       /* means of all X day at the same level */
+       #define NB_DAY 30
+       int nb_day = 0;
+       gint64 est_size_day[NB_DAY];
+       int nb_est_day[NB_DAY];
+
+       for (j=0; j<NB_DAY; j++) {
+           est_size_day[j] = (gint64)0;
+           nb_est_day[j] = 0;
+       }
+
+       for (j=NB_HISTORY-2; j>=0; j--) {
+           if (info->history[j].level <= 0) continue;
+           if (info->history[j].size < (gint64)0) continue;
+           if (info->history[j].level == info->history[j+1].level) {
+               if (nb_day <NB_DAY-1) nb_day++;
+               est_size_day[nb_day] += info->history[j].size;
+               nb_est_day[nb_day]++;
+           } else {
+               nb_day=0;
+           }
+       }
+       nb_day = info->consecutive_runs + 1;
+       if (nb_day > NB_DAY-1) nb_day = NB_DAY-1;
+
+       while (nb_day > 0 && nb_est_day[nb_day] == 0) nb_day--;
+
+       if (nb_est_day[nb_day] > 0) {
+           size = est_size_day[nb_day] / (gint64)nb_est_day[nb_day];
+           *stats = 1;
+       }
+       else if (info->inf[level].size > (gint64)1000) { /* stats */
+           size = info->inf[level].size;
+           *stats = 1;
+       }
+       else {
+           int level0_stat;
+           gint64 level0_size;
+           char *conf_tapetype = getconf_str(CNF_TAPETYPE);
+           tapetype_t *tape = lookup_tapetype(conf_tapetype);
+
+            level0_size = internal_server_estimate(dp, info, 0, &level0_stat);
+           size = (gint64)10000;
+           if (size > tapetype_get_length(tape)/2)
+               size = tapetype_get_length(tape)/2;
+           if (size > level0_size/2)
+               size = level0_size/2;
+           *stats = 0;
+       }
+    }
+    else if (level == info->last_level + 1) {
+       /* means of all first day at a new level */
+       gint64 est_size = (gint64)0;
+       int nb_est = 0;
+
+       for (j=NB_HISTORY-2; j>=0; j--) {
+           if (info->history[j].level <= 0) continue;
+           if (info->history[j].size < (gint64)0) continue;
+           if (info->history[j].level == info->history[j+1].level + 1 ) {
+               est_size += info->history[j].size;
+               nb_est++;
+           }
+       }
+       if (nb_est > 0) {
+           size = est_size / (gint64)nb_est;
+           *stats = 1;
+       } else if (info->inf[level].size > (gint64)1000) { /* stats */
+           size = info->inf[level].size;
+           *stats = 1;
+       } else {
+           int level0_stat;
+           gint64 level0_size;
+           char *conf_tapetype = getconf_str(CNF_TAPETYPE);
+           tapetype_t *tape = lookup_tapetype(conf_tapetype);
+
+            level0_size = internal_server_estimate(dp, info, 0, &level0_stat);
+           size = (gint64)100000;
+           if (size > tapetype_get_length(tape)/2)
+               size = tapetype_get_length(tape)/2;
+           if (size > level0_size/2)
+               size = level0_size/2;
+           *stats = 0;
+       }
+    }
+
+    return size;
+}
+
+int
+server_can_do_estimate(
+    disk_t *dp,
+    info_t *info,
+    int     level)
+{
+    gint64  size;
+    int     stats;
+
+    size = internal_server_estimate(dp, info, level, &stats);
+    return stats;
+}
+