2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1999 University of Maryland at College Park
4 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of U.M. not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. U.M. makes no representations about the
14 * suitability of this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Authors: the Amanda Development Team. Its members are listed in a
25 * file named AUTHORS, in the root directory of this distribution.
28 * $Id: server_util.c,v 1.17 2006/05/25 01:47:20 johnfranks Exp $
33 #include "server_util.h"
39 #include "pipespawn.h"
44 const char *cmdstr[] = {
45 "BOGUS", "QUIT", "QUITTING", "DONE", "PARTIAL",
46 "START", "FILE-DUMP", "PORT-DUMP", "CONTINUE", "ABORT",/* dumper cmds */
47 "FAILED", "TRY-AGAIN", "NO-ROOM", "RQ-MORE-DISK", /* dumper results */
48 "ABORT-FINISHED", "BAD-COMMAND", /* dumper results */
49 "START-TAPER", "FILE-WRITE", "NEW-TAPE", "NO-NEW-TAPE",
51 "PARTDONE", "PORT-WRITE", "DUMPER-STATUS", /* taper cmds */
52 "PORT", "TAPE-ERROR", "TAPER-OK", /* taper results */
53 "REQUEST-NEW-TAPE", "DIRECTTCP-PORT", "TAKE-SCRIBE-FROM",
54 "START-SCAN", "CLOSE-VOLUME", "LAST_TOK",
64 struct cmdargs *cmdargs = g_new0(struct cmdargs, 1);
67 g_printf("%s> ", get_pname());
74 line = stralloc("QUIT");
77 dbprintf(_("getcmd: %s\n"), line);
79 cmdargs->argv = split_quoted_strings(line);
80 cmdargs->argc = g_strv_length(cmdargs->argv);
85 if (cmdargs->argc < 1) {
89 for(cmd_i=BOGUS; cmdstr[cmd_i] != NULL; cmd_i++)
90 if(strcmp(cmdargs->argv[0], cmdstr[cmd_i]) == 0) {
100 SELECT_ARG_TYPE ready;
109 nfound = select(1, &ready, NULL, NULL, &to);
110 if (nfound && FD_ISSET(0, &ready)) {
119 struct cmdargs *cmdargs)
124 g_strfreev(cmdargs->argv);
128 printf_arglist_function1(void putresult, cmd_t, result, const char *, format)
132 arglist_start(argp, format);
133 dbprintf(_("putresult: %d %s\n"), result, cmdstr[result]);
134 g_printf("%s ", cmdstr[result]);
135 g_vprintf(format, argp);
141 amhost_get_security_conf(
145 if(!string || !*string)
148 if(strcmp(string, "krb5principal")==0)
149 return(getconf_str(CNF_KRB5PRINCIPAL));
150 else if(strcmp(string, "krb5keytab")==0)
151 return(getconf_str(CNF_KRB5KEYTAB));
153 if(!arg || !((am_host_t *)arg)->disks) return(NULL);
155 if(strcmp(string, "amandad_path")==0)
156 return ((am_host_t *)arg)->disks->amandad_path;
157 else if(strcmp(string, "client_username")==0)
158 return ((am_host_t *)arg)->disks->client_username;
159 else if(strcmp(string, "client_port")==0)
160 return ((am_host_t *)arg)->disks->client_port;
161 else if(strcmp(string, "ssh_keys")==0)
162 return ((am_host_t *)arg)->disks->ssh_keys;
173 char *hostinfodir, *old_hostinfodir, *Xhostinfodir;
174 char *diskdir, *old_diskdir, *Xdiskdir;
175 char *infofile, *old_infofile, *Xinfofile;
179 if (stat(infodir, &statbuf) != 0) {
183 for (dp = dl->head; dp != NULL; dp = dp->next) {
184 hostinfodir = sanitise_filename(dp->host->hostname);
185 diskdir = sanitise_filename(dp->name);
186 infofile = vstralloc(infodir, "/", hostinfodir, "/", diskdir,
188 if (stat(infofile, &statbuf) == -1 && errno == ENOENT) {
189 old_hostinfodir = old_sanitise_filename(dp->host->hostname);
190 old_diskdir = old_sanitise_filename(dp->name);
191 old_infofile = vstralloc(infodir, old_hostinfodir, "/",
192 old_diskdir, "/info", NULL);
193 if (stat(old_infofile, &statbuf) == 0) {
196 while (diskp != NULL) {
197 Xhostinfodir = sanitise_filename(diskp->host->hostname);
198 Xdiskdir = sanitise_filename(diskp->name);
199 Xinfofile = vstralloc(infodir, "/", Xhostinfodir, "/",
200 Xdiskdir, "/info", NULL);
201 if (strcmp(old_infofile, Xinfofile) == 0) {
209 if (other_dle_match == 0) {
210 if(mkpdir(infofile, (mode_t)0755, (uid_t)-1,
212 *errmsg = vstralloc("Can't create directory for ",
216 if(copy_file(infofile, old_infofile, errmsg) == -1)
220 amfree(old_hostinfodir);
222 amfree(old_infofile);
233 pp_script_t *pp_script,
234 execute_on_t execute_on,
240 int scriptin, scriptout, scripterr;
242 char *command = NULL;
243 GPtrArray *argv_ptr = g_ptr_array_new();
247 char level_number[NUM_STR_SIZE];
248 struct stat cmd_stat;
251 if ((pp_script_get_execute_on(pp_script) & execute_on) == 0)
253 if (pp_script_get_execute_where(pp_script) != ES_SERVER)
256 plugin = pp_script_get_plugin(pp_script);
258 cmd = vstralloc(APPLICATION_DIR, "/", plugin, NULL);
259 result = stat(cmd, &cmd_stat);
261 dbprintf("Can't stat script '%s': %s\n", cmd, strerror(errno));
263 cmd = vstralloc(get_config_dir(), "/application/", plugin, NULL);
264 result = stat(cmd, &cmd_stat);
266 dbprintf("Can't stat script '%s': %s\n", cmd, strerror(errno));
268 cmd = vstralloc(CONFIG_DIR, "/application/", plugin, NULL);
269 result = stat(cmd, &cmd_stat);
271 dbprintf("Can't stat script '%s': %s\n", cmd, strerror(errno));
273 cmd = vstralloc(APPLICATION_DIR, "/", plugin, NULL);
278 g_ptr_array_add(argv_ptr, stralloc(plugin));
280 switch (execute_on) {
281 case EXECUTE_ON_PRE_AMCHECK:
282 command = "PRE-AMCHECK";
284 case EXECUTE_ON_PRE_DLE_AMCHECK:
285 command = "PRE-DLE-AMCHECK";
287 case EXECUTE_ON_PRE_HOST_AMCHECK:
288 command = "PRE-HOST-AMCHECK";
290 case EXECUTE_ON_POST_AMCHECK:
291 command = "POST-AMCHECK";
293 case EXECUTE_ON_POST_DLE_AMCHECK:
294 command = "POST-DLE-AMCHECK";
296 case EXECUTE_ON_POST_HOST_AMCHECK:
297 command = "POST-HOST-AMCHECK";
299 case EXECUTE_ON_PRE_ESTIMATE:
300 command = "PRE-ESTIMATE";
302 case EXECUTE_ON_PRE_DLE_ESTIMATE:
303 command = "PRE-DLE-ESTIMATE";
305 case EXECUTE_ON_PRE_HOST_ESTIMATE:
306 command = "PRE-HOST-ESTIMATE";
308 case EXECUTE_ON_POST_ESTIMATE:
309 command = "POST-ESTIMATE";
311 case EXECUTE_ON_POST_DLE_ESTIMATE:
312 command = "POST-DLE-ESTIMATE";
314 case EXECUTE_ON_POST_HOST_ESTIMATE:
315 command = "POST-HOST-ESTIMATE";
317 case EXECUTE_ON_PRE_BACKUP:
318 command = "PRE-BACKUP";
320 case EXECUTE_ON_PRE_DLE_BACKUP:
321 command = "PRE-DLE-BACKUP";
323 case EXECUTE_ON_PRE_HOST_BACKUP:
324 command = "PRE-HOST-BACKUP";
326 case EXECUTE_ON_POST_BACKUP:
327 command = "POST-BACKUP";
329 case EXECUTE_ON_POST_DLE_BACKUP:
330 command = "POST-DLE-BACKUP";
332 case EXECUTE_ON_POST_HOST_BACKUP:
333 command = "POST-HOST-BACKUP";
335 case EXECUTE_ON_PRE_RECOVER:
336 case EXECUTE_ON_POST_RECOVER:
337 case EXECUTE_ON_PRE_LEVEL_RECOVER:
338 case EXECUTE_ON_POST_LEVEL_RECOVER:
339 case EXECUTE_ON_INTER_LEVEL_RECOVER:
341 // ERROR these script can't be executed on server.
346 g_ptr_array_add(argv_ptr, stralloc(command));
347 g_ptr_array_add(argv_ptr, stralloc("--execute-where"));
348 g_ptr_array_add(argv_ptr, stralloc("server"));
351 g_ptr_array_add(argv_ptr, stralloc("--config"));
352 g_ptr_array_add(argv_ptr, stralloc(config));
354 if (dp->host->hostname) {
355 g_ptr_array_add(argv_ptr, stralloc("--host"));
356 g_ptr_array_add(argv_ptr, stralloc(dp->host->hostname));
359 g_ptr_array_add(argv_ptr, stralloc("--disk"));
360 g_ptr_array_add(argv_ptr, stralloc(dp->name));
363 g_ptr_array_add(argv_ptr, stralloc("--device"));
364 g_ptr_array_add(argv_ptr, stralloc(dp->device));
367 g_snprintf(level_number, SIZEOF(level_number), "%d", level);
368 g_ptr_array_add(argv_ptr, stralloc("--level"));
369 g_ptr_array_add(argv_ptr, stralloc(level_number));
372 property_add_to_argv(argv_ptr, pp_script_get_property(pp_script));
373 g_ptr_array_add(argv_ptr, NULL);
375 scripterr = fileno(stderr);
376 scriptpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE, 0, &scriptin,
377 &scriptout, &scripterr,
378 (char **)argv_ptr->pdata);
381 streamout = fdopen(scriptout, "r");
383 while((line = agets(streamout)) != NULL) {
384 dbprintf("script: %s\n", line);
389 waitpid(scriptpid, NULL, 0);
390 g_ptr_array_free_full(argv_ptr);
396 run_server_dle_scripts(
397 execute_on_t execute_on,
402 identlist_t pp_scriptlist;
404 for (pp_scriptlist = dp->pp_scriptlist; pp_scriptlist != NULL;
405 pp_scriptlist = pp_scriptlist->next) {
406 pp_script_t *pp_script = lookup_pp_script((char *)pp_scriptlist->data);
407 g_assert(pp_script != NULL);
408 run_server_script(pp_script, execute_on, config, dp, level);
413 run_server_host_scripts(
414 execute_on_t execute_on,
418 identlist_t pp_scriptlist;
421 GHashTable* executed = g_hash_table_new_full(g_str_hash, g_str_equal,
423 for (dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
425 for (pp_scriptlist = dp->pp_scriptlist; pp_scriptlist != NULL;
426 pp_scriptlist = pp_scriptlist->next) {
428 pp_script_t *pp_script = lookup_pp_script((char *)pp_scriptlist->data);
429 g_assert(pp_script != NULL);
430 if (pp_script_get_single_execution(pp_script)) {
431 todo = g_hash_table_lookup(executed,
432 pp_script_get_plugin(pp_script))
436 run_server_script(pp_script, execute_on, config, dp, -1);
437 if (pp_script_get_single_execution(pp_script)) {
438 g_hash_table_insert(executed,
439 pp_script_get_plugin(pp_script),
447 g_hash_table_destroy(executed);
451 run_server_global_scripts(
452 execute_on_t execute_on,
455 identlist_t pp_scriptlist;
459 GHashTable* executed = g_hash_table_new_full(g_str_hash, g_str_equal,
461 for (host = get_hostlist(); host != NULL; host = host->next) {
462 for (dp = host->disks; dp != NULL; dp = dp->hostnext) {
464 for (pp_scriptlist = dp->pp_scriptlist; pp_scriptlist != NULL;
465 pp_scriptlist = pp_scriptlist->next) {
467 pp_script_t *pp_script =
468 lookup_pp_script((char *)pp_scriptlist->data);
469 g_assert(pp_script != NULL);
470 if (pp_script_get_single_execution(pp_script)) {
471 todo = g_hash_table_lookup(executed,
472 pp_script_get_plugin(pp_script)) == NULL;
475 run_server_script(pp_script, execute_on, config,
477 if (pp_script_get_single_execution(pp_script)) {
478 g_hash_table_insert(executed,
479 pp_script_get_plugin(pp_script),
487 g_hash_table_destroy(executed);
495 char *amcleanup_program;
496 char *amcleanup_options[4];
498 switch(amcleanup_pid = fork()) {
502 case 0: /* child process */
503 amcleanup_program = vstralloc(sbindir, "/", "amcleanup", NULL);
504 amcleanup_options[0] = amcleanup_program;
505 amcleanup_options[1] = "-p";
506 amcleanup_options[2] = config_name;
507 amcleanup_options[3] = NULL;
508 execve(amcleanup_program, amcleanup_options, safe_env());
509 error("exec %s: %s", amcleanup_program, strerror(errno));
514 waitpid(amcleanup_pid, NULL, 0);
526 log = fopen(logfile, "r");
528 return stralloc("UNKNOWN");
530 while(fgets(line, 1024, log)) {
531 if (strncmp_const(line, "INFO ") == 0) {
535 skip_non_whitespace(s, ch);
537 skip_whitespace(s, ch);
538 skip_non_whitespace(s, ch);
540 skip_whitespace(s, ch);
541 if (strncmp_const(s-1, "pid ") == 0) {
542 process_name = stralloc(process_name);
549 return stralloc("UNKNOWN");
554 internal_server_estimate(
565 if (level == 0) { /* use latest level 0, should do extrapolation */
566 gint64 est_size = (gint64)0;
569 for (j=NB_HISTORY-2; j>=0; j--) {
570 if (info->history[j].level == 0) {
571 if (info->history[j].size < (gint64)0) continue;
572 est_size = info->history[j].size;
579 } else if (info->inf[level].size > (gint64)1000) { /* stats */
580 size = info->inf[level].size;
583 char *conf_tapetype = getconf_str(CNF_TAPETYPE);
584 tapetype_t *tape = lookup_tapetype(conf_tapetype);
585 size = (gint64)1000000;
586 if (size > tapetype_get_length(tape)/2)
587 size = tapetype_get_length(tape)/2;
590 } else if (level == info->last_level) {
591 /* means of all X day at the same level */
594 gint64 est_size_day[NB_DAY];
595 int nb_est_day[NB_DAY];
597 for (j=0; j<NB_DAY; j++) {
598 est_size_day[j] = (gint64)0;
602 for (j=NB_HISTORY-2; j>=0; j--) {
603 if (info->history[j].level <= 0) continue;
604 if (info->history[j].size < (gint64)0) continue;
605 if (info->history[j].level == info->history[j+1].level) {
606 if (nb_day <NB_DAY-1) nb_day++;
607 est_size_day[nb_day] += info->history[j].size;
608 nb_est_day[nb_day]++;
613 nb_day = info->consecutive_runs + 1;
614 if (nb_day > NB_DAY-1) nb_day = NB_DAY-1;
616 while (nb_day > 0 && nb_est_day[nb_day] == 0) nb_day--;
618 if (nb_est_day[nb_day] > 0) {
619 size = est_size_day[nb_day] / (gint64)nb_est_day[nb_day];
622 else if (info->inf[level].size > (gint64)1000) { /* stats */
623 size = info->inf[level].size;
629 char *conf_tapetype = getconf_str(CNF_TAPETYPE);
630 tapetype_t *tape = lookup_tapetype(conf_tapetype);
632 level0_size = internal_server_estimate(dp, info, 0, &level0_stat);
633 size = (gint64)10000;
634 if (size > tapetype_get_length(tape)/2)
635 size = tapetype_get_length(tape)/2;
636 if (level0_size > 0 && dp->strategy != DS_NOFULL) {
637 if (size > level0_size/2)
638 size = level0_size/2;
643 else if (level == info->last_level + 1) {
644 /* means of all first day at a new level */
645 gint64 est_size = (gint64)0;
648 for (j=NB_HISTORY-2; j>=0; j--) {
649 if (info->history[j].level <= 0) continue;
650 if (info->history[j].size < (gint64)0) continue;
651 if (info->history[j].level == info->history[j+1].level + 1 ) {
652 est_size += info->history[j].size;
657 size = est_size / (gint64)nb_est;
659 } else if (info->inf[level].size > (gint64)1000) { /* stats */
660 size = info->inf[level].size;
665 char *conf_tapetype = getconf_str(CNF_TAPETYPE);
666 tapetype_t *tape = lookup_tapetype(conf_tapetype);
668 level0_size = internal_server_estimate(dp, info, 0, &level0_stat);
669 size = (gint64)100000;
670 if (size > tapetype_get_length(tape)/2)
671 size = tapetype_get_length(tape)/2;
672 if (level0_size > 0 && dp->strategy != DS_NOFULL) {
673 if (size > level0_size/2)
674 size = level0_size/2;
679 char *conf_tapetype = getconf_str(CNF_TAPETYPE);
680 tapetype_t *tape = lookup_tapetype(conf_tapetype);
681 size = (gint64)100000;
682 if (size > tapetype_get_length(tape)/2)
683 size = tapetype_get_length(tape)/2;
690 server_can_do_estimate(
697 internal_server_estimate(dp, info, level, &stats);