2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1999 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: server_util.c,v 1.17 2006/05/25 01:47:20 johnfranks Exp $
32 #include "server_util.h"
38 #include "pipespawn.h"
43 const char *cmdstr[] = {
44 "BOGUS", "QUIT", "QUITTING", "DONE", "PARTIAL",
45 "START", "FILE-DUMP", "PORT-DUMP", "CONTINUE", "ABORT",/* dumper cmds */
46 "FAILED", "TRY-AGAIN", "NO-ROOM", "RQ-MORE-DISK", /* dumper results */
47 "ABORT-FINISHED", "BAD-COMMAND", /* dumper results */
48 "START-TAPER", "FILE-WRITE", "NEW-TAPE", "NO-NEW-TAPE",
50 "PARTDONE", "PORT-WRITE", "DUMPER-STATUS", /* taper cmds */
51 "PORT", "TAPE-ERROR", "TAPER-OK", /* taper results */
52 "REQUEST-NEW-TAPE", "DIRECTTCP-PORT", "TAKE-SCRIBE-FROM",
53 "START-SCAN", "LAST_TOK",
63 struct cmdargs *cmdargs = g_new0(struct cmdargs, 1);
66 g_printf("%s> ", get_pname());
73 line = stralloc("QUIT");
76 dbprintf(_("getcmd: %s\n"), line);
78 cmdargs->argv = split_quoted_strings(line);
79 cmdargs->argc = g_strv_length(cmdargs->argv);
84 if (cmdargs->argc < 1) {
88 for(cmd_i=BOGUS; cmdstr[cmd_i] != NULL; cmd_i++)
89 if(strcmp(cmdargs->argv[0], cmdstr[cmd_i]) == 0) {
99 SELECT_ARG_TYPE ready;
108 nfound = select(1, &ready, NULL, NULL, &to);
109 if (nfound && FD_ISSET(0, &ready)) {
118 struct cmdargs *cmdargs)
123 g_strfreev(cmdargs->argv);
127 printf_arglist_function1(void putresult, cmd_t, result, const char *, format)
131 arglist_start(argp, format);
132 dbprintf(_("putresult: %d %s\n"), result, cmdstr[result]);
133 g_printf("%s ", cmdstr[result]);
134 g_vprintf(format, argp);
140 amhost_get_security_conf(
144 if(!string || !*string)
147 if(strcmp(string, "krb5principal")==0)
148 return(getconf_str(CNF_KRB5PRINCIPAL));
149 else if(strcmp(string, "krb5keytab")==0)
150 return(getconf_str(CNF_KRB5KEYTAB));
152 if(!arg || !((am_host_t *)arg)->disks) return(NULL);
154 if(strcmp(string, "amandad_path")==0)
155 return ((am_host_t *)arg)->disks->amandad_path;
156 else if(strcmp(string, "client_username")==0)
157 return ((am_host_t *)arg)->disks->client_username;
158 else if(strcmp(string, "client_port")==0)
159 return ((am_host_t *)arg)->disks->client_port;
160 else if(strcmp(string, "ssh_keys")==0)
161 return ((am_host_t *)arg)->disks->ssh_keys;
172 char *hostinfodir, *old_hostinfodir, *Xhostinfodir;
173 char *diskdir, *old_diskdir, *Xdiskdir;
174 char *infofile, *old_infofile, *Xinfofile;
178 if (stat(infodir, &statbuf) != 0) {
182 for (dp = dl->head; dp != NULL; dp = dp->next) {
183 hostinfodir = sanitise_filename(dp->host->hostname);
184 diskdir = sanitise_filename(dp->name);
185 infofile = vstralloc(infodir, "/", hostinfodir, "/", diskdir,
187 if (stat(infofile, &statbuf) == -1 && errno == ENOENT) {
188 old_hostinfodir = old_sanitise_filename(dp->host->hostname);
189 old_diskdir = old_sanitise_filename(dp->name);
190 old_infofile = vstralloc(infodir, old_hostinfodir, "/",
191 old_diskdir, "/info", NULL);
192 if (stat(old_infofile, &statbuf) == 0) {
195 while (diskp != NULL) {
196 Xhostinfodir = sanitise_filename(diskp->host->hostname);
197 Xdiskdir = sanitise_filename(diskp->name);
198 Xinfofile = vstralloc(infodir, "/", Xhostinfodir, "/",
199 Xdiskdir, "/info", NULL);
200 if (strcmp(old_infofile, Xinfofile) == 0) {
208 if (other_dle_match == 0) {
209 if(mkpdir(infofile, (mode_t)0755, (uid_t)-1,
211 *errmsg = vstralloc("Can't create directory for ",
215 if(copy_file(infofile, old_infofile, errmsg) == -1)
219 amfree(old_hostinfodir);
221 amfree(old_infofile);
232 pp_script_t *pp_script,
233 execute_on_t execute_on,
239 int scriptin, scriptout, scripterr;
241 char *command = NULL;
242 GPtrArray *argv_ptr = g_ptr_array_new();
246 char level_number[NUM_STR_SIZE];
248 if ((pp_script_get_execute_on(pp_script) & execute_on) == 0)
250 if (pp_script_get_execute_where(pp_script) != ES_SERVER)
253 plugin = pp_script_get_plugin(pp_script);
254 cmd = vstralloc(APPLICATION_DIR, "/", plugin, NULL);
255 g_ptr_array_add(argv_ptr, stralloc(plugin));
257 switch (execute_on) {
258 case EXECUTE_ON_PRE_DLE_AMCHECK:
259 command = "PRE-DLE-AMCHECK";
261 case EXECUTE_ON_PRE_HOST_AMCHECK:
262 command = "PRE-HOST-AMCHECK";
264 case EXECUTE_ON_POST_DLE_AMCHECK:
265 command = "POST-DLE-AMCHECK";
267 case EXECUTE_ON_POST_HOST_AMCHECK:
268 command = "POST-HOST-AMCHECK";
270 case EXECUTE_ON_PRE_DLE_ESTIMATE:
271 command = "PRE-DLE-ESTIMATE";
273 case EXECUTE_ON_PRE_HOST_ESTIMATE:
274 command = "PRE-HOST-ESTIMATE";
276 case EXECUTE_ON_POST_DLE_ESTIMATE:
277 command = "POST-DLE-ESTIMATE";
279 case EXECUTE_ON_POST_HOST_ESTIMATE:
280 command = "POST-HOST-ESTIMATE";
282 case EXECUTE_ON_PRE_DLE_BACKUP:
283 command = "PRE-DLE-BACKUP";
285 case EXECUTE_ON_PRE_HOST_BACKUP:
286 command = "PRE-HOST-BACKUP";
288 case EXECUTE_ON_POST_DLE_BACKUP:
289 command = "POST-DLE-BACKUP";
291 case EXECUTE_ON_POST_HOST_BACKUP:
292 command = "POST-HOST-BACKUP";
294 case EXECUTE_ON_PRE_RECOVER:
295 case EXECUTE_ON_POST_RECOVER:
296 case EXECUTE_ON_PRE_LEVEL_RECOVER:
297 case EXECUTE_ON_POST_LEVEL_RECOVER:
298 case EXECUTE_ON_INTER_LEVEL_RECOVER:
300 // ERROR these script can't be executed on server.
305 g_ptr_array_add(argv_ptr, stralloc(command));
306 g_ptr_array_add(argv_ptr, stralloc("--execute-where"));
307 g_ptr_array_add(argv_ptr, stralloc("server"));
310 g_ptr_array_add(argv_ptr, stralloc("--config"));
311 g_ptr_array_add(argv_ptr, stralloc(config));
313 if (dp->host->hostname) {
314 g_ptr_array_add(argv_ptr, stralloc("--host"));
315 g_ptr_array_add(argv_ptr, stralloc(dp->host->hostname));
318 g_ptr_array_add(argv_ptr, stralloc("--disk"));
319 g_ptr_array_add(argv_ptr, stralloc(dp->name));
322 g_ptr_array_add(argv_ptr, stralloc("--device"));
323 g_ptr_array_add(argv_ptr, stralloc(dp->device));
326 g_snprintf(level_number, SIZEOF(level_number), "%d", level);
327 g_ptr_array_add(argv_ptr, stralloc("--level"));
328 g_ptr_array_add(argv_ptr, stralloc(level_number));
331 property_add_to_argv(argv_ptr, pp_script_get_property(pp_script));
332 g_ptr_array_add(argv_ptr, NULL);
334 scripterr = fileno(stderr);
335 scriptpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE, 0, &scriptin,
336 &scriptout, &scripterr,
337 (char **)argv_ptr->pdata);
340 streamout = fdopen(scriptout, "r");
342 while((line = agets(streamout)) != NULL) {
343 dbprintf("script: %s\n", line);
348 waitpid(scriptpid, NULL, 0);
349 g_ptr_array_free_full(argv_ptr);
356 execute_on_t execute_on,
361 identlist_t pp_scriptlist;
363 for (pp_scriptlist = dp->pp_scriptlist; pp_scriptlist != NULL;
364 pp_scriptlist = pp_scriptlist->next) {
365 pp_script_t *pp_script = lookup_pp_script((char *)pp_scriptlist->data);
366 g_assert(pp_script != NULL);
367 run_server_script(pp_script, execute_on, config, dp, level);
376 char *amcleanup_program;
377 char *amcleanup_options[4];
379 switch(amcleanup_pid = fork()) {
383 case 0: /* child process */
384 amcleanup_program = vstralloc(sbindir, "/", "amcleanup", NULL);
385 amcleanup_options[0] = amcleanup_program;
386 amcleanup_options[1] = "-p";
387 amcleanup_options[2] = config_name;
388 amcleanup_options[3] = NULL;
389 execve(amcleanup_program, amcleanup_options, safe_env());
390 error("exec %s: %s", amcleanup_program, strerror(errno));
395 waitpid(amcleanup_pid, NULL, 0);
407 log = fopen(logfile, "r");
409 return stralloc("UNKNOWN");
411 while(fgets(line, 1024, log)) {
412 if (strncmp_const(line, "INFO ") == 0) {
416 skip_non_whitespace(s, ch);
418 skip_whitespace(s, ch);
419 skip_non_whitespace(s, ch);
421 skip_whitespace(s, ch);
422 if (strncmp_const(s-1, "pid ") == 0) {
423 process_name = stralloc(process_name);
430 return stralloc("UNKNOWN");
435 internal_server_estimate(
446 if (level == 0) { /* use latest level 0, should do extrapolation */
447 gint64 est_size = (gint64)0;
450 for (j=NB_HISTORY-2; j>=0; j--) {
451 if (info->history[j].level == 0) {
452 if (info->history[j].size < (gint64)0) continue;
453 est_size = info->history[j].size;
460 } else if (info->inf[level].size > (gint64)1000) { /* stats */
461 size = info->inf[level].size;
464 char *conf_tapetype = getconf_str(CNF_TAPETYPE);
465 tapetype_t *tape = lookup_tapetype(conf_tapetype);
466 size = (gint64)1000000;
467 if (size > tapetype_get_length(tape)/2)
468 size = tapetype_get_length(tape)/2;
471 } else if (level == info->last_level) {
472 /* means of all X day at the same level */
475 gint64 est_size_day[NB_DAY];
476 int nb_est_day[NB_DAY];
478 for (j=0; j<NB_DAY; j++) {
479 est_size_day[j] = (gint64)0;
483 for (j=NB_HISTORY-2; j>=0; j--) {
484 if (info->history[j].level <= 0) continue;
485 if (info->history[j].size < (gint64)0) continue;
486 if (info->history[j].level == info->history[j+1].level) {
487 if (nb_day <NB_DAY-1) nb_day++;
488 est_size_day[nb_day] += info->history[j].size;
489 nb_est_day[nb_day]++;
494 nb_day = info->consecutive_runs + 1;
495 if (nb_day > NB_DAY-1) nb_day = NB_DAY-1;
497 while (nb_day > 0 && nb_est_day[nb_day] == 0) nb_day--;
499 if (nb_est_day[nb_day] > 0) {
500 size = est_size_day[nb_day] / (gint64)nb_est_day[nb_day];
503 else if (info->inf[level].size > (gint64)1000) { /* stats */
504 size = info->inf[level].size;
510 char *conf_tapetype = getconf_str(CNF_TAPETYPE);
511 tapetype_t *tape = lookup_tapetype(conf_tapetype);
513 level0_size = internal_server_estimate(dp, info, 0, &level0_stat);
514 size = (gint64)10000;
515 if (size > tapetype_get_length(tape)/2)
516 size = tapetype_get_length(tape)/2;
517 if (level0_size > 0 && dp->strategy != DS_NOFULL) {
518 if (size > level0_size/2)
519 size = level0_size/2;
524 else if (level == info->last_level + 1) {
525 /* means of all first day at a new level */
526 gint64 est_size = (gint64)0;
529 for (j=NB_HISTORY-2; j>=0; j--) {
530 if (info->history[j].level <= 0) continue;
531 if (info->history[j].size < (gint64)0) continue;
532 if (info->history[j].level == info->history[j+1].level + 1 ) {
533 est_size += info->history[j].size;
538 size = est_size / (gint64)nb_est;
540 } else if (info->inf[level].size > (gint64)1000) { /* stats */
541 size = info->inf[level].size;
546 char *conf_tapetype = getconf_str(CNF_TAPETYPE);
547 tapetype_t *tape = lookup_tapetype(conf_tapetype);
549 level0_size = internal_server_estimate(dp, info, 0, &level0_stat);
550 size = (gint64)100000;
551 if (size > tapetype_get_length(tape)/2)
552 size = tapetype_get_length(tape)/2;
553 if (level0_size > 0 && dp->strategy != DS_NOFULL) {
554 if (size > level0_size/2)
555 size = level0_size/2;
560 char *conf_tapetype = getconf_str(CNF_TAPETYPE);
561 tapetype_t *tape = lookup_tapetype(conf_tapetype);
562 size = (gint64)100000;
563 if (size > tapetype_get_length(tape)/2)
564 size = tapetype_get_length(tape)/2;
571 server_can_do_estimate(
579 size = internal_server_estimate(dp, info, level, &stats);