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",
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)
229 pp_script_t *pp_script,
230 execute_on_t execute_on,
236 int scriptin, scriptout, scripterr;
238 char *command = NULL;
239 GPtrArray *argv_ptr = g_ptr_array_new();
243 char level_number[NUM_STR_SIZE];
245 if ((pp_script_get_execute_on(pp_script) & execute_on) == 0)
247 if (pp_script_get_execute_where(pp_script) != ES_SERVER)
250 plugin = pp_script_get_plugin(pp_script);
251 cmd = vstralloc(APPLICATION_DIR, "/", plugin, NULL);
252 g_ptr_array_add(argv_ptr, stralloc(plugin));
254 switch (execute_on) {
255 case EXECUTE_ON_PRE_DLE_AMCHECK:
256 command = "PRE-DLE-AMCHECK";
258 case EXECUTE_ON_PRE_HOST_AMCHECK:
259 command = "PRE-HOST-AMCHECK";
261 case EXECUTE_ON_POST_DLE_AMCHECK:
262 command = "POST-DLE-AMCHECK";
264 case EXECUTE_ON_POST_HOST_AMCHECK:
265 command = "POST-HOST-AMCHECK";
267 case EXECUTE_ON_PRE_DLE_ESTIMATE:
268 command = "PRE-DLE-ESTIMATE";
270 case EXECUTE_ON_PRE_HOST_ESTIMATE:
271 command = "PRE-HOST-ESTIMATE";
273 case EXECUTE_ON_POST_DLE_ESTIMATE:
274 command = "POST-DLE-ESTIMATE";
276 case EXECUTE_ON_POST_HOST_ESTIMATE:
277 command = "POST-HOST-ESTIMATE";
279 case EXECUTE_ON_PRE_DLE_BACKUP:
280 command = "PRE-DLE-BACKUP";
282 case EXECUTE_ON_PRE_HOST_BACKUP:
283 command = "PRE-HOST-BACKUP";
285 case EXECUTE_ON_POST_DLE_BACKUP:
286 command = "POST-DLE-BACKUP";
288 case EXECUTE_ON_POST_HOST_BACKUP:
289 command = "POST-HOST-BACKUP";
291 case EXECUTE_ON_PRE_RECOVER:
292 case EXECUTE_ON_POST_RECOVER:
293 case EXECUTE_ON_PRE_LEVEL_RECOVER:
294 case EXECUTE_ON_POST_LEVEL_RECOVER:
295 case EXECUTE_ON_INTER_LEVEL_RECOVER:
297 // ERROR these script can't be executed on server.
302 g_ptr_array_add(argv_ptr, stralloc(command));
303 g_ptr_array_add(argv_ptr, stralloc("--execute-where"));
304 g_ptr_array_add(argv_ptr, stralloc("server"));
307 g_ptr_array_add(argv_ptr, stralloc("--config"));
308 g_ptr_array_add(argv_ptr, stralloc(config));
310 if (dp->host->hostname) {
311 g_ptr_array_add(argv_ptr, stralloc("--host"));
312 g_ptr_array_add(argv_ptr, stralloc(dp->host->hostname));
315 g_ptr_array_add(argv_ptr, stralloc("--disk"));
316 g_ptr_array_add(argv_ptr, stralloc(dp->name));
319 g_ptr_array_add(argv_ptr, stralloc("--device"));
320 g_ptr_array_add(argv_ptr, stralloc(dp->device));
323 g_snprintf(level_number, SIZEOF(level_number), "%d", level);
324 g_ptr_array_add(argv_ptr, stralloc("--level"));
325 g_ptr_array_add(argv_ptr, stralloc(level_number));
328 property_add_to_argv(argv_ptr, pp_script_get_property(pp_script));
329 g_ptr_array_add(argv_ptr, NULL);
331 scripterr = fileno(stderr);
332 scriptpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE, 0, &scriptin,
333 &scriptout, &scripterr,
334 (char **)argv_ptr->pdata);
337 streamout = fdopen(scriptout, "r");
339 while((line = agets(streamout)) != NULL) {
340 dbprintf("script: %s\n", line);
344 waitpid(scriptpid, NULL, 0);
345 g_ptr_array_free_full(argv_ptr);
351 execute_on_t execute_on,
356 identlist_t pp_scriptlist;
358 for (pp_scriptlist = dp->pp_scriptlist; pp_scriptlist != NULL;
359 pp_scriptlist = pp_scriptlist->next) {
360 pp_script_t *pp_script = lookup_pp_script((char *)pp_scriptlist->data);
361 g_assert(pp_script != NULL);
362 run_server_script(pp_script, execute_on, config, dp, level);
371 char *amcleanup_program;
372 char *amcleanup_options[4];
374 switch(amcleanup_pid = fork()) {
378 case 0: /* child process */
379 amcleanup_program = vstralloc(sbindir, "/", "amcleanup", NULL);
380 amcleanup_options[0] = amcleanup_program;
381 amcleanup_options[1] = "-p";
382 amcleanup_options[2] = config_name;
383 amcleanup_options[3] = NULL;
384 execve(amcleanup_program, amcleanup_options, safe_env());
385 error("exec %s: %s", amcleanup_program, strerror(errno));
390 waitpid(amcleanup_pid, NULL, 0);
402 log = fopen(logfile, "r");
404 return stralloc("UNKNOWN");
406 while(fgets(line, 1024, log)) {
407 if (strncmp_const(line, "INFO ") == 0) {
411 skip_non_whitespace(s, ch);
413 skip_whitespace(s, ch);
414 skip_non_whitespace(s, ch);
416 skip_whitespace(s, ch);
417 if (strncmp_const(s-1, "pid ") == 0) {
418 process_name = stralloc(process_name);
425 return stralloc("UNKNOWN");
430 internal_server_estimate(
441 if (level == 0) { /* use latest level 0, should do extrapolation */
442 gint64 est_size = (gint64)0;
445 for (j=NB_HISTORY-2; j>=0; j--) {
446 if (info->history[j].level == 0) {
447 if (info->history[j].size < (gint64)0) continue;
448 est_size = info->history[j].size;
455 } else if (info->inf[level].size > (gint64)1000) { /* stats */
456 size = info->inf[level].size;
459 char *conf_tapetype = getconf_str(CNF_TAPETYPE);
460 tapetype_t *tape = lookup_tapetype(conf_tapetype);
461 size = (gint64)1000000;
462 if (size > tapetype_get_length(tape)/2)
463 size = tapetype_get_length(tape)/2;
466 } else if (level == info->last_level) {
467 /* means of all X day at the same level */
470 gint64 est_size_day[NB_DAY];
471 int nb_est_day[NB_DAY];
473 for (j=0; j<NB_DAY; j++) {
474 est_size_day[j] = (gint64)0;
478 for (j=NB_HISTORY-2; j>=0; j--) {
479 if (info->history[j].level <= 0) continue;
480 if (info->history[j].size < (gint64)0) continue;
481 if (info->history[j].level == info->history[j+1].level) {
482 if (nb_day <NB_DAY-1) nb_day++;
483 est_size_day[nb_day] += info->history[j].size;
484 nb_est_day[nb_day]++;
489 nb_day = info->consecutive_runs + 1;
490 if (nb_day > NB_DAY-1) nb_day = NB_DAY-1;
492 while (nb_day > 0 && nb_est_day[nb_day] == 0) nb_day--;
494 if (nb_est_day[nb_day] > 0) {
495 size = est_size_day[nb_day] / (gint64)nb_est_day[nb_day];
498 else if (info->inf[level].size > (gint64)1000) { /* stats */
499 size = info->inf[level].size;
505 char *conf_tapetype = getconf_str(CNF_TAPETYPE);
506 tapetype_t *tape = lookup_tapetype(conf_tapetype);
508 level0_size = internal_server_estimate(dp, info, 0, &level0_stat);
509 size = (gint64)10000;
510 if (size > tapetype_get_length(tape)/2)
511 size = tapetype_get_length(tape)/2;
512 if (size > level0_size/2)
513 size = level0_size/2;
517 else if (level == info->last_level + 1) {
518 /* means of all first day at a new level */
519 gint64 est_size = (gint64)0;
522 for (j=NB_HISTORY-2; j>=0; j--) {
523 if (info->history[j].level <= 0) continue;
524 if (info->history[j].size < (gint64)0) continue;
525 if (info->history[j].level == info->history[j+1].level + 1 ) {
526 est_size += info->history[j].size;
531 size = est_size / (gint64)nb_est;
533 } else if (info->inf[level].size > (gint64)1000) { /* stats */
534 size = info->inf[level].size;
539 char *conf_tapetype = getconf_str(CNF_TAPETYPE);
540 tapetype_t *tape = lookup_tapetype(conf_tapetype);
542 level0_size = internal_server_estimate(dp, info, 0, &level0_stat);
543 size = (gint64)100000;
544 if (size > tapetype_get_length(tape)/2)
545 size = tapetype_get_length(tape)/2;
546 if (size > level0_size/2)
547 size = level0_size/2;
556 server_can_do_estimate(
564 size = internal_server_estimate(dp, info, level, &stats);