1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1999 University of Maryland at College Park
4  * Copyright (c) 2007-2013 Zmanda, Inc.  All Rights Reserved.
5  * All Rights Reserved.
6  *
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.
16  *
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.
23  *
24  * Authors: the Amanda Development Team.  Its members are listed in a
25  * file named AUTHORS, in the root directory of this distribution.
26  */
27 /*
28  * $Id: server_util.c,v 1.17 2006/05/25 01:47:20 johnfranks Exp $
29  *
30  */
31 
32 #include "amanda.h"
33 #include "server_util.h"
34 #include "arglist.h"
35 #include "logfile.h"
36 #include "util.h"
37 #include "conffile.h"
38 #include "diskfile.h"
39 #include "pipespawn.h"
40 #include "conffile.h"
41 #include "infofile.h"
42 #include "sys/wait.h"
43 
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",
50 
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", "READY", "LAST_TOK",
55     NULL
56 };
57 
58 
59 struct cmdargs *
getcmd(void)60 getcmd(void)
61 {
62     char *line;
63     cmd_t cmd_i;
64     struct cmdargs *cmdargs = g_new0(struct cmdargs, 1);
65 
66     if (isatty(0)) {
67 	g_printf("%s> ", get_pname());
68 	fflush(stdout);
69         line = agets(stdin);
70     } else {
71         line = agets(stdin);
72     }
73     if (line == NULL) {
74 	line = stralloc("QUIT");
75     }
76 
77     dbprintf(_("getcmd: %s\n"), line);
78 
79     cmdargs->argv = split_quoted_strings(line);
80     cmdargs->argc = g_strv_length(cmdargs->argv);
81     cmdargs->cmd = BOGUS;
82 
83     amfree(line);
84 
85     if (cmdargs->argc < 1) {
86 	return cmdargs;
87     }
88 
89     for(cmd_i=BOGUS; cmdstr[cmd_i] != NULL; cmd_i++)
90 	if(strcmp(cmdargs->argv[0], cmdstr[cmd_i]) == 0) {
91 	    cmdargs->cmd = cmd_i;
92 	    return cmdargs;
93 	}
94     return cmdargs;
95 }
96 
97 struct cmdargs *
get_pending_cmd(void)98 get_pending_cmd(void)
99 {
100     SELECT_ARG_TYPE ready;
101     struct timeval  to;
102     int             nfound;
103 
104     FD_ZERO(&ready);
105     FD_SET(0, &ready);
106     to.tv_sec = 0;
107     to.tv_usec = 0;
108 
109     nfound = select(1, &ready, NULL, NULL, &to);
110     if (nfound && FD_ISSET(0, &ready)) {
111         return getcmd();
112     } else {
113 	return NULL;
114     }
115 }
116 
117 void
free_cmdargs(struct cmdargs * cmdargs)118 free_cmdargs(
119     struct cmdargs *cmdargs)
120 {
121     if (!cmdargs)
122 	return;
123     if (cmdargs->argv)
124 	g_strfreev(cmdargs->argv);
125     g_free(cmdargs);
126 }
127 
printf_arglist_function1(void putresult,cmd_t,result,const char *,format)128 printf_arglist_function1(void putresult, cmd_t, result, const char *, format)
129 {
130     va_list argp;
131 
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);
136     fflush(stdout);
137     arglist_end(argp);
138 }
139 
140 char *
amhost_get_security_conf(char * string,void * arg)141 amhost_get_security_conf(
142     char *	string,
143     void *	arg)
144 {
145     if(!string || !*string)
146 	return(NULL);
147 
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));
152 
153     if(!arg || !((am_host_t *)arg)->disks) return(NULL);
154 
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;
163 
164     return(NULL);
165 }
166 
check_infofile(char * infodir,disklist_t * dl,char ** errmsg)167 int check_infofile(
168     char        *infodir,
169     disklist_t  *dl,
170     char       **errmsg)
171 {
172     disk_t      *dp, *diskp;
173     char        *hostinfodir, *old_hostinfodir, *Xhostinfodir;
174     char        *diskdir,     *old_diskdir,     *Xdiskdir;
175     char        *infofile,    *old_infofile,    *Xinfofile;
176     struct stat  statbuf;
177     int other_dle_match;
178 
179     if (stat(infodir, &statbuf) != 0) {
180 	return 0;
181     }
182 
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,
187 			     "/info", NULL);
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) {
194 		other_dle_match = 0;
195 		diskp = dl->head;
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) {
202 			other_dle_match = 1;
203 			diskp = NULL;
204 		    }
205 		    else {
206 			diskp = diskp->next;
207 		    }
208 		}
209 		if (other_dle_match == 0) {
210 		    if(mkpdir(infofile, (mode_t)0755, (uid_t)-1,
211 			      (gid_t)-1) == -1) {
212 			*errmsg = vstralloc("Can't create directory for ",
213 					    infofile, NULL);
214 			return -1;
215 		    }
216 		    if(copy_file(infofile, old_infofile, errmsg) == -1)
217 			return -1;
218 		}
219 	    }
220 	    amfree(old_hostinfodir);
221 	    amfree(old_diskdir);
222 	    amfree(old_infofile);
223 	}
224 	amfree(diskdir);
225 	amfree(hostinfodir);
226 	amfree(infofile);
227     }
228     return 0;
229 }
230 
231 void
run_server_script(pp_script_t * pp_script,execute_on_t execute_on,char * config,disk_t * dp,int level)232 run_server_script(
233     pp_script_t  *pp_script,
234     execute_on_t  execute_on,
235     char         *config,
236     disk_t	 *dp,
237     int           level)
238 {
239     pid_t      scriptpid;
240     int        scriptin, scriptout, scripterr;
241     char      *cmd;
242     char      *command = NULL;
243     GPtrArray *argv_ptr = g_ptr_array_new();
244     FILE      *streamout;
245     char      *line;
246     char      *plugin;
247     char       level_number[NUM_STR_SIZE];
248     struct stat cmd_stat;
249     int         result;
250 
251     if ((pp_script_get_execute_on(pp_script) & execute_on) == 0)
252 	return;
253     if (pp_script_get_execute_where(pp_script) != ES_SERVER)
254 	return;
255 
256     plugin = pp_script_get_plugin(pp_script);
257 
258     cmd = vstralloc(APPLICATION_DIR, "/", plugin, NULL);
259     result = stat(cmd, &cmd_stat);
260     if (result == -1) {
261 	dbprintf("Can't stat script '%s': %s\n", cmd, strerror(errno));
262 	amfree(cmd);
263 	cmd = vstralloc(get_config_dir(), "/application/", plugin, NULL);
264 	result = stat(cmd, &cmd_stat);
265 	if (result == -1) {
266 	    dbprintf("Can't stat script '%s': %s\n", cmd, strerror(errno));
267 	    amfree(cmd);
268 	    cmd = vstralloc(CONFIG_DIR, "/application/", plugin, NULL);
269 	    result = stat(cmd, &cmd_stat);
270 	    if (result == -1) {
271 		dbprintf("Can't stat script '%s': %s\n", cmd, strerror(errno));
272 		amfree(cmd);
273 		cmd = vstralloc(APPLICATION_DIR, "/", plugin, NULL);
274 	    }
275 	}
276     }
277 
278     g_ptr_array_add(argv_ptr, stralloc(plugin));
279 
280     switch (execute_on) {
281     case EXECUTE_ON_PRE_AMCHECK:
282 	command = "PRE-AMCHECK";
283 	break;
284     case EXECUTE_ON_PRE_DLE_AMCHECK:
285 	command = "PRE-DLE-AMCHECK";
286 	break;
287     case EXECUTE_ON_PRE_HOST_AMCHECK:
288 	command = "PRE-HOST-AMCHECK";
289 	break;
290     case EXECUTE_ON_POST_AMCHECK:
291 	command = "POST-AMCHECK";
292 	break;
293     case EXECUTE_ON_POST_DLE_AMCHECK:
294 	command = "POST-DLE-AMCHECK";
295 	break;
296     case EXECUTE_ON_POST_HOST_AMCHECK:
297 	command = "POST-HOST-AMCHECK";
298 	break;
299     case EXECUTE_ON_PRE_ESTIMATE:
300 	command = "PRE-ESTIMATE";
301 	break;
302     case EXECUTE_ON_PRE_DLE_ESTIMATE:
303 	command = "PRE-DLE-ESTIMATE";
304 	break;
305     case EXECUTE_ON_PRE_HOST_ESTIMATE:
306 	command = "PRE-HOST-ESTIMATE";
307 	break;
308     case EXECUTE_ON_POST_ESTIMATE:
309 	command = "POST-ESTIMATE";
310 	break;
311     case EXECUTE_ON_POST_DLE_ESTIMATE:
312 	command = "POST-DLE-ESTIMATE";
313 	break;
314     case EXECUTE_ON_POST_HOST_ESTIMATE:
315 	command = "POST-HOST-ESTIMATE";
316 	break;
317     case EXECUTE_ON_PRE_BACKUP:
318 	command = "PRE-BACKUP";
319 	break;
320     case EXECUTE_ON_PRE_DLE_BACKUP:
321 	command = "PRE-DLE-BACKUP";
322 	break;
323     case EXECUTE_ON_PRE_HOST_BACKUP:
324 	command = "PRE-HOST-BACKUP";
325 	break;
326     case EXECUTE_ON_POST_BACKUP:
327 	command = "POST-BACKUP";
328 	break;
329     case EXECUTE_ON_POST_DLE_BACKUP:
330 	command = "POST-DLE-BACKUP";
331 	break;
332     case EXECUTE_ON_POST_HOST_BACKUP:
333 	command = "POST-HOST-BACKUP";
334 	break;
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:
340 	{
341 	     // ERROR these script can't be executed on server.
342 	     return;
343 	}
344     }
345 
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"));
349 
350     if (config) {
351 	g_ptr_array_add(argv_ptr, stralloc("--config"));
352 	g_ptr_array_add(argv_ptr, stralloc(config));
353     }
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));
357     }
358     if (dp->name) {
359 	g_ptr_array_add(argv_ptr, stralloc("--disk"));
360 	g_ptr_array_add(argv_ptr, stralloc(dp->name));
361     }
362     if (dp->device) {
363 	g_ptr_array_add(argv_ptr, stralloc("--device"));
364 	g_ptr_array_add(argv_ptr, stralloc(dp->device));
365     }
366     if (level >= 0) {
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));
370     }
371 
372     property_add_to_argv(argv_ptr, pp_script_get_property(pp_script));
373     g_ptr_array_add(argv_ptr, NULL);
374 
375     scripterr = fileno(stderr);
376     scriptpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE, 0, &scriptin,
377 			   &scriptout, &scripterr,
378 			   (char **)argv_ptr->pdata);
379     close(scriptin);
380 
381     streamout = fdopen(scriptout, "r");
382     if (streamout) {
383 	while((line = agets(streamout)) != NULL) {
384 	    dbprintf("script: %s\n", line);
385 	    amfree(line);
386 	}
387     }
388     fclose(streamout);
389     waitpid(scriptpid, NULL, 0);
390     g_ptr_array_free_full(argv_ptr);
391     amfree(cmd);
392 }
393 
394 
395 void
run_server_dle_scripts(execute_on_t execute_on,char * config,disk_t * dp,int level)396 run_server_dle_scripts(
397     execute_on_t  execute_on,
398     char         *config,
399     disk_t	 *dp,
400     int           level)
401 {
402     identlist_t pp_scriptlist;
403 
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);
409     }
410 }
411 
412 void
run_server_host_scripts(execute_on_t execute_on,char * config,am_host_t * hostp)413 run_server_host_scripts(
414     execute_on_t  execute_on,
415     char         *config,
416     am_host_t	 *hostp)
417 {
418     identlist_t pp_scriptlist;
419     disk_t *dp;
420 
421     GHashTable* executed = g_hash_table_new_full(g_str_hash, g_str_equal,
422 						 NULL, NULL);
423     for (dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
424 	if (dp->todo) {
425 	    for (pp_scriptlist = dp->pp_scriptlist; pp_scriptlist != NULL;
426 		 pp_scriptlist = pp_scriptlist->next) {
427 		int todo = 1;
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))
433 			   == NULL;
434 		}
435 		if (todo) {
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),
440 					    GINT_TO_POINTER(1));
441 		    }
442 		}
443 	    }
444 	}
445     }
446 
447     g_hash_table_destroy(executed);
448 }
449 
450 void
run_server_global_scripts(execute_on_t execute_on,char * config)451 run_server_global_scripts(
452     execute_on_t  execute_on,
453     char         *config)
454 {
455     identlist_t  pp_scriptlist;
456     disk_t      *dp;
457     am_host_t   *host;
458 
459     GHashTable* executed = g_hash_table_new_full(g_str_hash, g_str_equal,
460 						 NULL, NULL);
461     for (host = get_hostlist(); host != NULL; host = host->next) {
462 	for (dp = host->disks; dp != NULL; dp = dp->hostnext) {
463 	    if (dp->todo) {
464 		for (pp_scriptlist = dp->pp_scriptlist; pp_scriptlist != NULL;
465 		     pp_scriptlist = pp_scriptlist->next) {
466 		    int todo = 1;
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;
473 		    }
474 		    if (todo) {
475 			run_server_script(pp_script, execute_on, config,
476 					  dp, -1);
477 			if (pp_script_get_single_execution(pp_script)) {
478 			    g_hash_table_insert(executed,
479 					pp_script_get_plugin(pp_script),
480 					GINT_TO_POINTER(1));
481 			}
482 		    }
483 		}
484 	    }
485 	}
486     }
487     g_hash_table_destroy(executed);
488 }
489 
490 void
run_amcleanup(char * config_name)491 run_amcleanup(
492     char *config_name)
493 {
494     pid_t amcleanup_pid;
495     char *amcleanup_program;
496     char *amcleanup_options[4];
497 
498     switch(amcleanup_pid = fork()) {
499 	case -1:
500 	    return;
501 	    break;
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));
510 	    /*NOTREACHED*/
511 	default:
512 	    break;
513     }
514     waitpid(amcleanup_pid, NULL, 0);
515 }
516 
517 char *
get_master_process(char * logfile)518 get_master_process(
519     char *logfile)
520 {
521     FILE *log;
522     char line[1024];
523     char *s, ch;
524     char *process_name;
525 
526     log = fopen(logfile, "r");
527     if (!log)
528 	return stralloc("UNKNOWN");
529 
530     while(fgets(line, 1024, log)) {
531 	if (strncmp_const(line, "INFO ") == 0) {
532 	    s = line+5;
533 	    ch = *s++;
534 	    process_name = s-1;
535 	    skip_non_whitespace(s, ch);
536 	    s[-1] = '\0';
537 	    skip_whitespace(s, ch);
538 	    skip_non_whitespace(s, ch);
539 	    s[-1] = '\0';
540 	    skip_whitespace(s, ch);
541 	    if (strncmp_const(s-1, "pid ") == 0) {
542 		process_name = stralloc(process_name);
543 		fclose(log);
544 		return process_name;
545 	    }
546 	}
547     }
548     fclose(log);
549     return stralloc("UNKNOWN");
550 }
551 
552 
553 gint64
internal_server_estimate(disk_t * dp,info_t * info,int level,int * stats)554 internal_server_estimate(
555     disk_t *dp,
556     info_t *info,
557     int     level,
558     int    *stats)
559 {
560     int    j;
561     gint64 size = 0;
562 
563     *stats = 0;
564 
565     if (level == 0) { /* use latest level 0, should do extrapolation */
566 	gint64 est_size = (gint64)0;
567 	int nb_est = 0;
568 
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;
573 		nb_est++;
574 	    }
575 	}
576 	if (nb_est > 0) {
577 	    size = est_size;
578 	    *stats = 1;
579 	} else if (info->inf[level].size > (gint64)1000) { /* stats */
580 	    size = info->inf[level].size;
581 	    *stats = 1;
582 	} else {
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;
588 	    *stats = 0;
589 	}
590     } else if (level == info->last_level) {
591 	/* means of all X day at the same level */
592 	#define NB_DAY 30
593 	int nb_day = 0;
594 	gint64 est_size_day[NB_DAY];
595 	int nb_est_day[NB_DAY];
596 
597 	for (j=0; j<NB_DAY; j++) {
598 	    est_size_day[j] = (gint64)0;
599 	    nb_est_day[j] = 0;
600 	}
601 
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]++;
609 	    } else {
610 		nb_day=0;
611 	    }
612 	}
613 	nb_day = info->consecutive_runs + 1;
614 	if (nb_day > NB_DAY-1) nb_day = NB_DAY-1;
615 
616 	while (nb_day > 0 && nb_est_day[nb_day] == 0) nb_day--;
617 
618 	if (nb_est_day[nb_day] > 0) {
619 	    size = est_size_day[nb_day] / (gint64)nb_est_day[nb_day];
620 	    *stats = 1;
621 	}
622 	else if (info->inf[level].size > (gint64)1000) { /* stats */
623 	    size = info->inf[level].size;
624 	    *stats = 1;
625 	}
626 	else {
627 	    int level0_stat;
628 	    gint64 level0_size;
629 	    char *conf_tapetype = getconf_str(CNF_TAPETYPE);
630 	    tapetype_t *tape = lookup_tapetype(conf_tapetype);
631 
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;
639 	    }
640 	    *stats = 0;
641 	}
642     }
643     else if (level == info->last_level + 1) {
644 	/* means of all first day at a new level */
645 	gint64 est_size = (gint64)0;
646 	int nb_est = 0;
647 
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;
653 		nb_est++;
654 	    }
655 	}
656 	if (nb_est > 0) {
657 	    size = est_size / (gint64)nb_est;
658 	    *stats = 1;
659 	} else if (info->inf[level].size > (gint64)1000) { /* stats */
660 	    size = info->inf[level].size;
661 	    *stats = 1;
662 	} else {
663 	    int level0_stat;
664 	    gint64 level0_size;
665 	    char *conf_tapetype = getconf_str(CNF_TAPETYPE);
666 	    tapetype_t *tape = lookup_tapetype(conf_tapetype);
667 
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;
675 	    }
676 	    *stats = 0;
677 	}
678     } else {
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;
684     }
685 
686     return size;
687 }
688 
689 int
server_can_do_estimate(disk_t * dp,info_t * info,int level)690 server_can_do_estimate(
691     disk_t *dp,
692     info_t *info,
693     int     level)
694 {
695     int     stats;
696 
697     internal_server_estimate(dp, info, level, &stats);
698     return stats;
699 }
700 
701