Imported Upstream version 3.3.3
[debian/amanda] / server-src / server_util.c
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-2012 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", "LAST_TOK",
55     NULL
56 };
57
58
59 struct cmdargs *
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 *
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
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
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 *
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
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
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
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
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
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
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 *
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
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
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