5be24f2085886162d30963f09ed6dbdc1ee0bf37
[debian/amanda] / server-src / conffile.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-2000 University of Maryland at College Park
4  * All Rights Reserved.
5  *
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.
15  *
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.
22  *
23  * Author: James da Silva, Systems Design and Analysis Group
24  *                         Computer Science Department
25  *                         University of Maryland at College Park
26  */
27 /*
28  * $Id: conffile.c,v 1.156.2.9 2007/01/11 13:06:10 martinea Exp $
29  *
30  * read configuration file
31  */
32
33 #include "amanda.h"
34 #include "arglist.h"
35 #include "util.h"
36 #include "conffile.h"
37 #include "diskfile.h"
38 #include "driverio.h"
39 #include "clock.h"
40
41 #ifdef HAVE_LIMITS_H
42 #include <limits.h>
43 #endif
44
45 #ifndef INT_MAX
46 #define INT_MAX 2147483647
47 #endif
48
49 /* this corresponds to the normal output of amanda, but may
50  * be adapted to any spacing as you like.
51  */
52 ColumnInfo ColumnData[] = {
53     { "HostName",   0, 12, 12, 0, "%-*.*s", "HOSTNAME" },
54     { "Disk",       1, 11, 11, 0, "%-*.*s", "DISK" },
55     { "Level",      1, 1,  1,  0, "%*.*d",  "L" },
56     { "OrigKB",     1, 7,  0,  0, "%*.*lf", "ORIG-KB" },
57     { "OutKB",      1, 7,  0,  0, "%*.*lf", "OUT-KB" },
58     { "Compress",   1, 6,  1,  0, "%*.*lf", "COMP%" },
59     { "DumpTime",   1, 7,  7,  0, "%*.*s",  "MMM:SS" },
60     { "DumpRate",   1, 6,  1,  0, "%*.*lf", "KB/s" },
61     { "TapeTime",   1, 6,  6,  0, "%*.*s",  "MMM:SS" },
62     { "TapeRate",   1, 6,  1,  0, "%*.*lf", "KB/s" },
63     { NULL,         0, 0,  0,  0, NULL,     NULL }
64 };
65
66 char *config_name = NULL;
67 char *config_dir = NULL;
68
69 /* visible holding disk variables */
70
71 holdingdisk_t *holdingdisks;
72 int num_holdingdisks;
73
74 long int unit_divisor = 1;
75
76 /* configuration parameters */
77
78 val_t server_conf[CNF_CNF];
79
80 command_option_t *server_options = NULL;
81
82 /* other internal variables */
83 static holdingdisk_t hdcur;
84
85 static tapetype_t tpcur;
86
87 static dumptype_t dpcur;
88
89 static interface_t ifcur;
90
91 static dumptype_t *dumplist = NULL;
92 static tapetype_t *tapelist = NULL;
93 static interface_t *interface_list = NULL;
94
95 /* predeclare local functions */
96
97 char *get_token_name(tok_t);
98
99
100 void validate_positive0   (t_conf_var *, val_t *);
101 void validate_positive1   (t_conf_var *, val_t *);
102 void validate_runspercycle(t_conf_var *, val_t *);
103 void validate_bumppercent (t_conf_var *, val_t *);
104 void validate_bumpmult    (t_conf_var *, val_t *);
105 void validate_inparallel  (t_conf_var *, val_t *);
106 void validate_displayunit (t_conf_var *, val_t *);
107 void validate_reserve     (t_conf_var *, val_t *);
108 void validate_use         (t_conf_var *, val_t *);
109 void validate_chunksize   (t_conf_var *, val_t *);
110 void validate_blocksize   (t_conf_var *, val_t *);
111
112 static void init_defaults(void);
113 static void read_conffile_recursively(char *filename);
114
115 static int read_confline(void);
116 static void get_holdingdisk(void);
117 static void init_holdingdisk_defaults(void);
118 static void save_holdingdisk(void);
119 static void get_dumptype(void);
120 static void init_dumptype_defaults(void);
121 static void save_dumptype(void);
122 static void copy_dumptype(void);
123 static void get_tapetype(void);
124 static void init_tapetype_defaults(void);
125 static void save_tapetype(void);
126 static void copy_tapetype(void);
127 static void get_interface(void);
128 static void init_interface_defaults(void);
129 static void save_interface(void);
130 static void copy_interface(void);
131 static void get_comprate(t_conf_var *, val_t *);
132 static void get_compress(t_conf_var *, val_t *);
133 static void get_encrypt (t_conf_var *, val_t *);
134 static void get_holding (t_conf_var *, val_t *);
135 static void get_priority(t_conf_var *, val_t *);
136 static void get_strategy(t_conf_var *, val_t *);
137 static void get_estimate(t_conf_var *, val_t *);
138 static void get_exclude (t_conf_var *, val_t *);
139 /*static void get_include(t_conf_var *, val_t *);*/
140 static void get_taperalgo(t_conf_var *, val_t *);
141
142 keytab_t server_keytab[] = {
143     { "AMANDAD_PATH", CONF_AMANDAD_PATH },
144     { "AMRECOVER_CHANGER", CONF_AMRECOVER_CHANGER },
145     { "AMRECOVER_CHECK_LABEL", CONF_AMRECOVER_CHECK_LABEL },
146     { "AMRECOVER_DO_FSF", CONF_AMRECOVER_DO_FSF },
147     { "APPEND", CONF_APPEND },
148     { "AUTH", CONF_AUTH },
149     { "AUTO", CONF_AUTO },
150     { "AUTOFLUSH", CONF_AUTOFLUSH },
151     { "BEST", CONF_BEST },
152     { "BLOCKSIZE", CONF_BLOCKSIZE },
153     { "BUMPDAYS", CONF_BUMPDAYS },
154     { "BUMPMULT", CONF_BUMPMULT },
155     { "BUMPPERCENT", CONF_BUMPPERCENT },
156     { "BUMPSIZE", CONF_BUMPSIZE },
157     { "CALCSIZE", CONF_CALCSIZE },
158     { "CHANGERDEV", CONF_CHNGRDEV },
159     { "CHANGERFILE", CONF_CHNGRFILE },
160     { "CHUNKSIZE", CONF_CHUNKSIZE },
161     { "CLIENT", CONF_CLIENT },
162     { "CLIENT_CUSTOM_COMPRESS", CONF_CLNTCOMPPROG },
163     { "CLIENT_DECRYPT_OPTION", CONF_CLNT_DECRYPT_OPT },
164     { "CLIENT_ENCRYPT", CONF_CLNT_ENCRYPT },
165     { "CLIENT_USERNAME", CONF_CLIENT_USERNAME },
166     { "COLUMNSPEC", CONF_COLUMNSPEC },
167     { "COMMENT", CONF_COMMENT },
168     { "COMPRATE", CONF_COMPRATE },
169     { "COMPRESS", CONF_COMPRESS },
170     { "CTIMEOUT", CONF_CTIMEOUT },
171     { "CUSTOM", CONF_CUSTOM },
172     { "DEFINE", CONF_DEFINE },
173     { "DIRECTORY", CONF_DIRECTORY },
174     { "DISKFILE", CONF_DISKFILE },
175     { "DISPLAYUNIT", CONF_DISPLAYUNIT },
176     { "DTIMEOUT", CONF_DTIMEOUT },
177     { "DUMPCYCLE", CONF_DUMPCYCLE },
178     { "DUMPORDER", CONF_DUMPORDER },
179     { "DUMPTYPE", CONF_DUMPTYPE },
180     { "DUMPUSER", CONF_DUMPUSER },
181     { "ENCRYPT", CONF_ENCRYPT },
182     { "ESTIMATE", CONF_ESTIMATE },
183     { "ETIMEOUT", CONF_ETIMEOUT },
184     { "EXCLUDE", CONF_EXCLUDE },
185     { "EXCLUDE-FILE", CONF_EXCLUDE_FILE },
186     { "EXCLUDE-LIST", CONF_EXCLUDE_LIST },
187     { "FALLBACK_SPLITSIZE", CONF_FALLBACK_SPLITSIZE },
188     { "FAST", CONF_FAST },
189     { "FILE", CONF_EFILE },
190     { "FILE-PAD", CONF_FILE_PAD },
191     { "FILEMARK", CONF_FILEMARK },
192     { "FIRST", CONF_FIRST },
193     { "FIRSTFIT", CONF_FIRSTFIT },
194     { "HANOI", CONF_HANOI },
195     { "HIGH", CONF_HIGH },
196     { "HOLDINGDISK", CONF_HOLDING },
197     { "IGNORE", CONF_IGNORE },
198     { "INCLUDE", CONF_INCLUDE },
199     { "INCLUDEFILE", CONF_INCLUDEFILE },
200     { "INCRONLY", CONF_INCRONLY },
201     { "INDEX", CONF_INDEX },
202     { "INDEXDIR", CONF_INDEXDIR },
203     { "INFOFILE", CONF_INFOFILE },
204     { "INPARALLEL", CONF_INPARALLEL },
205     { "INTERFACE", CONF_INTERFACE },
206     { "KENCRYPT", CONF_KENCRYPT },
207     { "KRB5KEYTAB", CONF_KRB5KEYTAB },
208     { "KRB5PRINCIPAL", CONF_KRB5PRINCIPAL },
209     { "LABELSTR", CONF_LABELSTR },
210     { "LABEL_NEW_TAPES", CONF_LABEL_NEW_TAPES },
211     { "LARGEST", CONF_LARGEST },
212     { "LARGESTFIT", CONF_LARGESTFIT },
213     { "LAST", CONF_LAST },
214     { "LBL-TEMPL", CONF_LBL_TEMPL },
215     { "LENGTH", CONF_LENGTH },
216     { "LIST", CONF_LIST },
217     { "LOGDIR", CONF_LOGDIR },
218     { "LOW", CONF_LOW },
219     { "MAILTO", CONF_MAILTO },
220     { "MAXDUMPS", CONF_MAXDUMPS },
221     { "MAXDUMPSIZE", CONF_MAXDUMPSIZE },
222     { "MAXPROMOTEDAY", CONF_MAXPROMOTEDAY },
223     { "MEDIUM", CONF_MEDIUM },
224     { "NETUSAGE", CONF_NETUSAGE },      /* XXX - historical */
225     { "NEVER", CONF_NEVER },
226     { "NOFULL", CONF_NOFULL },
227     { "NOINC", CONF_NOINC },
228     { "NONE", CONF_NONE },
229     { "OPTIONAL", CONF_OPTIONAL },
230     { "ORG", CONF_ORG },
231     { "PRINTER", CONF_PRINTER },
232     { "PRIORITY", CONF_PRIORITY },
233     { "PROGRAM", CONF_PROGRAM },
234     { "RAWTAPEDEV", CONF_RAWTAPEDEV },
235     { "RECORD", CONF_RECORD },
236     { "REQUIRED", CONF_REQUIRED },
237     { "RESERVE", CONF_RESERVE },
238     { "RUNSPERCYCLE", CONF_RUNSPERCYCLE },
239     { "RUNTAPES", CONF_RUNTAPES },
240     { "SERVER", CONF_SERVER },
241     { "SERVER_CUSTOM_COMPRESS", CONF_SRVCOMPPROG },
242     { "SERVER_DECRYPT_OPTION", CONF_SRV_DECRYPT_OPT },
243     { "SERVER_ENCRYPT", CONF_SRV_ENCRYPT },
244     { "SKIP", CONF_SKIP },
245     { "SKIP-FULL", CONF_SKIP_FULL },
246     { "SKIP-INCR", CONF_SKIP_INCR },
247     { "SMALLEST", CONF_SMALLEST },
248     { "SPEED", CONF_SPEED },
249     { "SPLIT_DISKBUFFER", CONF_SPLIT_DISKBUFFER },
250     { "SSH_KEYS", CONF_SSH_KEYS },
251     { "STANDARD", CONF_STANDARD },
252     { "STARTTIME", CONF_STARTTIME },
253     { "STRATEGY", CONF_STRATEGY },
254     { "TAPEBUFS", CONF_TAPEBUFS },
255     { "TAPECYCLE", CONF_TAPECYCLE },
256     { "TAPEDEV", CONF_TAPEDEV },
257     { "TAPELIST", CONF_TAPELIST },
258     { "TAPERALGO", CONF_TAPERALGO },
259     { "TAPETYPE", CONF_TAPETYPE },
260     { "TAPE_SPLITSIZE", CONF_TAPE_SPLITSIZE },
261     { "TPCHANGER", CONF_TPCHANGER },
262     { "USE", CONF_USE },
263     { "USETIMESTAMPS", CONF_USETIMESTAMPS },
264     { NULL, CONF_IDENT },
265     { NULL, CONF_UNKNOWN }
266 };
267
268 t_conf_var server_var [] = {
269    { CONF_ORG                  , CONFTYPE_STRING   , read_string  , CNF_ORG                  , NULL },
270    { CONF_MAILTO               , CONFTYPE_STRING   , read_string  , CNF_MAILTO               , NULL },
271    { CONF_DUMPUSER             , CONFTYPE_STRING   , read_string  , CNF_DUMPUSER             , NULL },
272    { CONF_PRINTER              , CONFTYPE_STRING   , read_string  , CNF_PRINTER              , NULL },
273    { CONF_TAPEDEV              , CONFTYPE_STRING   , read_string  , CNF_TAPEDEV              , NULL },
274    { CONF_TPCHANGER            , CONFTYPE_STRING   , read_string  , CNF_TPCHANGER            , NULL },
275    { CONF_CHNGRDEV             , CONFTYPE_STRING   , read_string  , CNF_CHNGRDEV             , NULL },
276    { CONF_CHNGRFILE            , CONFTYPE_STRING   , read_string  , CNF_CHNGRFILE            , NULL },
277    { CONF_LABELSTR             , CONFTYPE_STRING   , read_string  , CNF_LABELSTR             , NULL },
278    { CONF_TAPELIST             , CONFTYPE_STRING   , read_string  , CNF_TAPELIST             , NULL },
279    { CONF_DISKFILE             , CONFTYPE_STRING   , read_string  , CNF_DISKFILE             , NULL },
280    { CONF_INFOFILE             , CONFTYPE_STRING   , read_string  , CNF_INFOFILE             , NULL },
281    { CONF_LOGDIR               , CONFTYPE_STRING   , read_string  , CNF_LOGDIR               , NULL },
282    { CONF_INDEXDIR             , CONFTYPE_STRING   , read_string  , CNF_INDEXDIR             , NULL },
283    { CONF_TAPETYPE             , CONFTYPE_IDENT    , read_ident   , CNF_TAPETYPE             , NULL },
284    { CONF_DUMPCYCLE            , CONFTYPE_INT      , read_int     , CNF_DUMPCYCLE            , validate_positive0 },
285    { CONF_RUNSPERCYCLE         , CONFTYPE_INT      , read_int     , CNF_RUNSPERCYCLE         , validate_runspercycle },
286    { CONF_RUNTAPES             , CONFTYPE_INT      , read_int     , CNF_RUNTAPES             , validate_positive0 },
287    { CONF_TAPECYCLE            , CONFTYPE_INT      , read_int     , CNF_TAPECYCLE            , validate_positive1 },
288    { CONF_BUMPDAYS             , CONFTYPE_INT      , read_int     , CNF_BUMPDAYS             , validate_positive1 },
289    { CONF_BUMPSIZE             , CONFTYPE_AM64     , read_am64    , CNF_BUMPSIZE             , validate_positive1 },
290    { CONF_BUMPPERCENT          , CONFTYPE_INT      , read_int     , CNF_BUMPPERCENT          , validate_bumppercent },
291    { CONF_BUMPMULT             , CONFTYPE_REAL     , read_real    , CNF_BUMPMULT             , validate_bumpmult },
292    { CONF_NETUSAGE             , CONFTYPE_INT      , read_int     , CNF_NETUSAGE             , validate_positive1 },
293    { CONF_INPARALLEL           , CONFTYPE_INT      , read_int     , CNF_INPARALLEL           , validate_inparallel },
294    { CONF_DUMPORDER            , CONFTYPE_STRING   , read_string  , CNF_DUMPORDER            , NULL },
295    { CONF_MAXDUMPS             , CONFTYPE_INT      , read_int     , CNF_MAXDUMPS             , validate_positive1 },
296    { CONF_ETIMEOUT             , CONFTYPE_INT      , read_int     , CNF_ETIMEOUT             , NULL },
297    { CONF_DTIMEOUT             , CONFTYPE_INT      , read_int     , CNF_DTIMEOUT             , validate_positive1 },
298    { CONF_CTIMEOUT             , CONFTYPE_INT      , read_int     , CNF_CTIMEOUT             , validate_positive1 },
299    { CONF_TAPEBUFS             , CONFTYPE_INT      , read_int     , CNF_TAPEBUFS             , validate_positive1 },
300    { CONF_RAWTAPEDEV           , CONFTYPE_STRING   , read_string  , CNF_RAWTAPEDEV           , NULL },
301    { CONF_COLUMNSPEC           , CONFTYPE_STRING   , read_string  , CNF_COLUMNSPEC           , NULL },
302    { CONF_TAPERALGO            , CONFTYPE_TAPERALGO, get_taperalgo, CNF_TAPERALGO            , NULL },
303    { CONF_DISPLAYUNIT          , CONFTYPE_STRING   , read_string  , CNF_DISPLAYUNIT          , validate_displayunit },
304    { CONF_AUTOFLUSH            , CONFTYPE_BOOL     , read_bool    , CNF_AUTOFLUSH            , NULL },
305    { CONF_RESERVE              , CONFTYPE_INT      , read_int     , CNF_RESERVE              , validate_reserve },
306    { CONF_MAXDUMPSIZE          , CONFTYPE_AM64     , read_am64    , CNF_MAXDUMPSIZE          , NULL },
307    { CONF_KRB5KEYTAB           , CONFTYPE_STRING   , read_string  , CNF_KRB5KEYTAB           , NULL },
308    { CONF_KRB5PRINCIPAL        , CONFTYPE_STRING   , read_string  , CNF_KRB5PRINCIPAL        , NULL },
309    { CONF_LABEL_NEW_TAPES      , CONFTYPE_STRING   , read_string  , CNF_LABEL_NEW_TAPES      , NULL },
310    { CONF_USETIMESTAMPS        , CONFTYPE_BOOL     , read_bool    , CNF_USETIMESTAMPS        , NULL },
311    { CONF_AMRECOVER_DO_FSF     , CONFTYPE_BOOL     , read_bool    , CNF_AMRECOVER_DO_FSF     , NULL },
312    { CONF_AMRECOVER_CHANGER    , CONFTYPE_STRING   , read_string  , CNF_AMRECOVER_CHANGER    , NULL },
313    { CONF_AMRECOVER_CHECK_LABEL, CONFTYPE_BOOL     , read_bool    , CNF_AMRECOVER_CHECK_LABEL, NULL },
314    { CONF_UNKNOWN              , CONFTYPE_INT      , NULL         , CNF_CNF                  , NULL }
315 };
316
317 t_conf_var tapetype_var [] = {
318    { CONF_COMMENT  , CONFTYPE_STRING, read_string, TAPETYPE_COMMENT  , NULL },
319    { CONF_LBL_TEMPL, CONFTYPE_STRING, read_string, TAPETYPE_LBL_TEMPL, NULL },
320    { CONF_BLOCKSIZE, CONFTYPE_SIZE  , read_size  , TAPETYPE_BLOCKSIZE, validate_blocksize },
321    { CONF_LENGTH   , CONFTYPE_AM64  , read_am64  , TAPETYPE_LENGTH   , validate_positive0 },
322    { CONF_FILEMARK , CONFTYPE_AM64  , read_am64  , TAPETYPE_FILEMARK , NULL },
323    { CONF_SPEED    , CONFTYPE_INT   , read_int   , TAPETYPE_SPEED    , validate_positive0 },
324    { CONF_FILE_PAD , CONFTYPE_BOOL  , read_bool  , TAPETYPE_FILE_PAD , NULL },
325    { CONF_UNKNOWN  , CONFTYPE_INT   , NULL       , TAPETYPE_TAPETYPE , NULL }
326 };
327
328 t_conf_var dumptype_var [] = {
329    { CONF_COMMENT           , CONFTYPE_STRING   , read_string , DUMPTYPE_COMMENT           , NULL },
330    { CONF_AUTH              , CONFTYPE_STRING   , read_string , DUMPTYPE_SECURITY_DRIVER   , NULL },
331    { CONF_BUMPDAYS          , CONFTYPE_INT      , read_int    , DUMPTYPE_BUMPDAYS          , NULL },
332    { CONF_BUMPMULT          , CONFTYPE_REAL     , read_real   , DUMPTYPE_BUMPMULT          , NULL },
333    { CONF_BUMPSIZE          , CONFTYPE_AM64     , read_am64   , DUMPTYPE_BUMPSIZE          , NULL },
334    { CONF_BUMPPERCENT       , CONFTYPE_INT      , read_int    , DUMPTYPE_BUMPPERCENT       , NULL },
335    { CONF_COMPRATE          , CONFTYPE_REAL     , get_comprate, DUMPTYPE_COMPRATE          , NULL },
336    { CONF_COMPRESS          , CONFTYPE_INT      , get_compress, DUMPTYPE_COMPRESS          , NULL },
337    { CONF_ENCRYPT           , CONFTYPE_INT      , get_encrypt , DUMPTYPE_ENCRYPT           , NULL },
338    { CONF_DUMPCYCLE         , CONFTYPE_INT      , read_int    , DUMPTYPE_DUMPCYCLE         , validate_positive0 },
339    { CONF_EXCLUDE           , CONFTYPE_EXINCLUDE, get_exclude , DUMPTYPE_EXCLUDE           , NULL },
340    { CONF_INCLUDE           , CONFTYPE_EXINCLUDE, get_exclude , DUMPTYPE_INCLUDE           , NULL },
341    { CONF_IGNORE            , CONFTYPE_BOOL     , read_bool   , DUMPTYPE_IGNORE            , NULL },
342    { CONF_HOLDING           , CONFTYPE_HOLDING  , get_holding , DUMPTYPE_HOLDINGDISK       , NULL },
343    { CONF_INDEX             , CONFTYPE_BOOL     , read_bool   , DUMPTYPE_INDEX             , NULL },
344    { CONF_KENCRYPT          , CONFTYPE_BOOL     , read_bool   , DUMPTYPE_KENCRYPT          , NULL },
345    { CONF_MAXDUMPS          , CONFTYPE_INT      , read_int    , DUMPTYPE_MAXDUMPS          , validate_positive1 },
346    { CONF_MAXPROMOTEDAY     , CONFTYPE_INT      , read_int    , DUMPTYPE_MAXPROMOTEDAY     , validate_positive0 },
347    { CONF_PRIORITY          , CONFTYPE_PRIORITY , get_priority, DUMPTYPE_PRIORITY          , NULL },
348    { CONF_PROGRAM           , CONFTYPE_STRING   , read_string , DUMPTYPE_PROGRAM           , NULL },
349    { CONF_RECORD            , CONFTYPE_BOOL     , read_bool   , DUMPTYPE_RECORD            , NULL },
350    { CONF_SKIP_FULL         , CONFTYPE_BOOL     , read_bool   , DUMPTYPE_SKIP_FULL         , NULL },
351    { CONF_SKIP_INCR         , CONFTYPE_BOOL     , read_bool   , DUMPTYPE_SKIP_INCR         , NULL },
352    { CONF_STARTTIME         , CONFTYPE_TIME     , read_time   , DUMPTYPE_STARTTIME         , NULL },
353    { CONF_STRATEGY          , CONFTYPE_INT      , get_strategy, DUMPTYPE_STRATEGY          , NULL },
354    { CONF_TAPE_SPLITSIZE    , CONFTYPE_AM64     , read_am64   , DUMPTYPE_TAPE_SPLITSIZE    , validate_positive0 },
355    { CONF_SPLIT_DISKBUFFER  , CONFTYPE_STRING   , read_string , DUMPTYPE_SPLIT_DISKBUFFER  , NULL },
356    { CONF_ESTIMATE          , CONFTYPE_INT      , get_estimate, DUMPTYPE_ESTIMATE          , NULL },
357    { CONF_SRV_ENCRYPT       , CONFTYPE_STRING   , read_string , DUMPTYPE_SRV_ENCRYPT       , NULL },
358    { CONF_CLNT_ENCRYPT      , CONFTYPE_STRING   , read_string , DUMPTYPE_CLNT_ENCRYPT      , NULL },
359    { CONF_AMANDAD_PATH      , CONFTYPE_STRING   , read_string , DUMPTYPE_AMANDAD_PATH      , NULL },
360    { CONF_CLIENT_USERNAME   , CONFTYPE_STRING   , read_string , DUMPTYPE_CLIENT_USERNAME   , NULL },
361    { CONF_SSH_KEYS          , CONFTYPE_STRING   , read_string , DUMPTYPE_SSH_KEYS          , NULL },
362    { CONF_SRVCOMPPROG       , CONFTYPE_STRING   , read_string , DUMPTYPE_SRVCOMPPROG       , NULL },
363    { CONF_CLNTCOMPPROG      , CONFTYPE_STRING   , read_string , DUMPTYPE_CLNTCOMPPROG      , NULL },
364    { CONF_FALLBACK_SPLITSIZE, CONFTYPE_AM64     , read_am64   , DUMPTYPE_FALLBACK_SPLITSIZE, NULL },
365    { CONF_SRV_DECRYPT_OPT   , CONFTYPE_STRING   , read_string , DUMPTYPE_SRV_DECRYPT_OPT   , NULL },
366    { CONF_CLNT_DECRYPT_OPT  , CONFTYPE_STRING   , read_string , DUMPTYPE_CLNT_DECRYPT_OPT  , NULL },
367    { CONF_UNKNOWN           , CONFTYPE_INT      , NULL        , DUMPTYPE_DUMPTYPE          , NULL }
368 };
369
370 t_conf_var holding_var [] = {
371    { CONF_DIRECTORY, CONFTYPE_STRING, read_string, HOLDING_DISKDIR  , NULL },
372    { CONF_COMMENT  , CONFTYPE_STRING, read_string, HOLDING_COMMENT  , NULL },
373    { CONF_USE      , CONFTYPE_AM64  , read_am64  , HOLDING_DISKSIZE , validate_use },
374    { CONF_CHUNKSIZE, CONFTYPE_AM64  , read_am64  , HOLDING_CHUNKSIZE, validate_chunksize },
375    { CONF_UNKNOWN  , CONFTYPE_INT   , NULL       , HOLDING_HOLDING  , NULL }
376 };
377
378 /*
379 ** ------------------------
380 **  External entry points
381 ** ------------------------
382 */
383
384 int
385 read_conffile(
386     char *filename)
387 {
388     interface_t *ip;
389
390     init_defaults();
391
392     /* We assume that conf_confname & conf are initialized to NULL above */
393     read_conffile_recursively(filename);
394
395     /* overwrite with command line option */
396     command_overwrite(server_options, server_var, server_keytab, server_conf,
397                       "");
398
399     if(got_parserror != -1 ) {
400         if(lookup_tapetype(server_conf[CNF_TAPETYPE].v.s) == NULL) {
401             char *save_confname = conf_confname;
402
403             conf_confname = filename;
404             if(!server_conf[CNF_TAPETYPE].seen)
405                 conf_parserror("default tapetype %s not defined", server_conf[CNF_TAPETYPE].v.s);
406             else {
407                 conf_line_num = server_conf[CNF_TAPETYPE].seen;
408                 conf_parserror("tapetype %s not defined", server_conf[CNF_TAPETYPE].v.s);
409             }
410             conf_confname = save_confname;
411         }
412     }
413
414     ip = alloc(SIZEOF(interface_t));
415     ip->name = stralloc("default");
416     ip->seen = server_conf[CNF_NETUSAGE].seen;
417     conf_init_string(&ip->value[INTER_COMMENT], "implicit from NETUSAGE");
418     conf_init_int(&ip->value[INTER_MAXUSAGE], server_conf[CNF_NETUSAGE].v.i);
419     ip->curusage = 0;
420     ip->next = interface_list;
421     interface_list = ip;
422
423     return got_parserror;
424 }
425
426 void
427 validate_positive0(
428     struct s_conf_var *np,
429     val_t        *val)
430 {
431     switch(val->type) {
432     case CONFTYPE_INT:
433         if(val->v.i < 0)
434             conf_parserror("%s must be positive", get_token_name(np->token));
435         break;
436     case CONFTYPE_LONG:
437         if(val->v.l < 0)
438             conf_parserror("%s must be positive", get_token_name(np->token));
439         break;
440     case CONFTYPE_AM64:
441         if(val->v.am64 < 0)
442             conf_parserror("%s must be positive", get_token_name(np->token));
443         break;
444     default:
445         conf_parserror("validate_positive0 invalid type %d\n", val->type);
446     }
447 }
448
449 void
450 validate_positive1(
451     struct s_conf_var *np,
452     val_t        *val)
453 {
454     switch(val->type) {
455     case CONFTYPE_INT:
456         if(val->v.i < 1)
457             conf_parserror("%s must be positive", get_token_name(np->token));
458         break;
459     case CONFTYPE_LONG:
460         if(val->v.l < 1)
461             conf_parserror("%s must be positive", get_token_name(np->token));
462         break;
463     case CONFTYPE_AM64:
464         if(val->v.am64 < 1)
465             conf_parserror("%s must be positive", get_token_name(np->token));
466         break;
467     case CONFTYPE_TIME:
468         if(val->v.t < 1)
469             conf_parserror("%s must be positive", get_token_name(np->token));
470         break;
471     default:
472         conf_parserror("validate_positive1 invalid type %d\n", val->type);
473     }
474 }
475
476 void
477 validate_runspercycle(
478     struct s_conf_var *np,
479     val_t        *val)
480 {
481     np = np;
482     if(val->v.i < -1)
483         conf_parserror("runspercycle must be >= -1");
484 }
485
486 void
487 validate_bumppercent(
488     struct s_conf_var *np,
489     val_t        *val)
490 {
491     np = np;
492     if(val->v.i < 0 || val->v.i > 100)
493         conf_parserror("bumppercent must be between 0 and 100");
494 }
495
496 void
497 validate_inparallel(
498     struct s_conf_var *np,
499     val_t        *val)
500 {
501     np = np;
502     if(val->v.i < 1 || val->v.i >MAX_DUMPERS)
503         conf_parserror("inparallel must be between 1 and MAX_DUMPERS (%d)",
504                        MAX_DUMPERS);
505 }
506
507 void
508 validate_bumpmult(
509     struct s_conf_var *np,
510     val_t        *val)
511 {
512     np = np;
513     if(val->v.r < 0.999) {
514         conf_parserror("bumpmult must be positive");
515     }
516 }
517
518 void
519 validate_displayunit(
520     struct s_conf_var *np,
521     val_t        *val)
522 {
523     np = np;
524     if(strcmp(val->v.s, "k") == 0 ||
525        strcmp(val->v.s, "K") == 0) {
526         val->v.s[0] = (char)toupper(val->v.s[0]);
527         unit_divisor=1;
528     }
529     else if(strcmp(val->v.s, "m") == 0 ||
530        strcmp(val->v.s, "M") == 0) {
531         val->v.s[0] = (char)toupper(val->v.s[0]);
532         unit_divisor=1024;
533     }
534     else if(strcmp(val->v.s, "g") == 0 ||
535        strcmp(val->v.s, "G") == 0) {
536         val->v.s[0] = (char)toupper(val->v.s[0]);
537         unit_divisor=1024*1024;
538     }
539     else if(strcmp(val->v.s, "t") == 0 ||
540        strcmp(val->v.s, "T") == 0) {
541         val->v.s[0] = (char)toupper(val->v.s[0]);
542         unit_divisor=1024*1024*1024;
543     }
544     else {
545         conf_parserror("displayunit must be k,m,g or t.");
546     }
547 }
548
549 void
550 validate_reserve(
551     struct s_conf_var *np,
552     val_t        *val)
553 {
554     np = np;
555     if(val->v.i < 0 || val->v.i > 100)
556         conf_parserror("reserve must be between 0 and 100");
557 }
558
559 void
560 validate_use(
561     struct s_conf_var *np,
562     val_t        *val)
563 {
564     np = np;
565     val->v.am64 = am_floor(val->v.am64, DISK_BLOCK_KB);
566 }
567
568 void
569 validate_chunksize(
570     struct s_conf_var *np,
571     val_t        *val)
572 {
573     np = np;
574     if(val->v.am64 == 0) {
575         val->v.am64 = ((AM64_MAX / 1024) - (2 * DISK_BLOCK_KB));
576     }
577     else if(val->v.am64 < 0) {
578         conf_parserror("Negative chunksize ("OFF_T_FMT") is no longer supported",
579                        val->v.am64);
580     }
581     val->v.am64 = am_floor(val->v.am64, (off_t)DISK_BLOCK_KB);
582     if (val->v.am64 < 2*DISK_BLOCK_KB) {
583         conf_parserror("chunksize must be at least %dkb", 2*DISK_BLOCK_KB);
584     }
585 }
586
587 void
588 validate_blocksize(
589     struct s_conf_var *np,
590     val_t        *val)
591 {
592     np = np;
593     if(val->v.l < DISK_BLOCK_KB) {
594         conf_parserror("Tape blocksize must be at least %d KBytes",
595                   DISK_BLOCK_KB);
596     } else if(val->v.l > MAX_TAPE_BLOCK_KB) {
597         conf_parserror("Tape blocksize must not be larger than %d KBytes",
598                   MAX_TAPE_BLOCK_KB);
599     }
600 }
601
602 char *
603 getconf_byname(
604     char *str)
605 {
606     static char *tmpstr;
607     t_conf_var *np;
608     keytab_t *kt;
609     char *s;
610     char ch;
611     char *first_delim;
612     char *second_delim;
613     tapetype_t *tp;
614     dumptype_t *dp;
615     interface_t *ip;
616     holdingdisk_t *hp;
617
618     tmpstr = stralloc(str);
619     s = tmpstr;
620     while((ch = *s++) != '\0') {
621         if(islower((int)ch))
622             s[-1] = (char)toupper(ch);
623     }
624
625     first_delim = strchr(tmpstr, ':');
626     if (first_delim) {
627         *first_delim = '\0';
628         first_delim++;
629         second_delim = strchr(first_delim,':');
630         if(!second_delim) {
631             amfree(tmpstr);
632             return(NULL);
633         }
634         *second_delim = '\0';
635         second_delim++;
636
637         for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) {
638             if(kt->keyword && strcmp(kt->keyword, second_delim) == 0)
639                 break;
640         }
641
642         if(kt->token == CONF_UNKNOWN)
643             return NULL;
644
645         if (strcmp(tmpstr, "TAPETYPE") == 0) {
646             tp = lookup_tapetype(first_delim);
647             if (!tp) {
648                 amfree(tmpstr);
649                 return(NULL);
650             }
651             for(np = tapetype_var; np->token != CONF_UNKNOWN; np++) {
652                 if(np->token == kt->token)
653                    break;
654             }
655             if (np->token == CONF_UNKNOWN) return NULL;
656             tmpstr = stralloc(conf_print(&tp->value[np->parm], 0));
657         } else if (strcmp(tmpstr, "DUMPTYPE") == 0) {
658             dp = lookup_dumptype(first_delim);
659             if (!dp) {
660                 amfree(tmpstr);
661                 return(NULL);
662             }
663             for(np = dumptype_var; np->token != CONF_UNKNOWN; np++) {
664                 if(np->token == kt->token)
665                    break;
666             }
667             if (np->token == CONF_UNKNOWN) return NULL;
668             tmpstr = stralloc(conf_print(&dp->value[np->parm], 0));
669         } else if (strcmp(tmpstr, "HOLDINGDISK") == 0) {
670             hp = lookup_holdingdisk(first_delim);
671             if (!hp) {
672                 amfree(tmpstr);
673                 return(NULL);
674             }
675             for(np = holding_var; np->token != CONF_UNKNOWN; np++) {
676                 if(np->token == kt->token)
677                    break;
678             }
679             if (np->token == CONF_UNKNOWN) return NULL;
680             tmpstr = stralloc(conf_print(&hp->value[np->parm], 0));
681         } else if (strcmp(tmpstr, "INTERFACE") == 0) {
682             ip = lookup_interface(first_delim);
683             if (!ip) {
684                 amfree(tmpstr);
685                 return(NULL);
686             }
687             for(np = holding_var; np->token != CONF_UNKNOWN; np++) {
688                 if(np->token == kt->token)
689                    break;
690             }
691             if (np->token == CONF_UNKNOWN) return NULL;
692             tmpstr = stralloc(conf_print(&ip->value[np->parm], 0));
693         } else {
694             amfree(tmpstr);
695             return(NULL);
696         }
697     } else {
698         for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) {
699             if(kt->keyword && strcmp(kt->keyword, tmpstr) == 0)
700                 break;
701         }
702
703         if(kt->token == CONF_UNKNOWN)
704             return NULL;
705
706         for(np = server_var; np->token != CONF_UNKNOWN; np++) {
707             if(np->token == kt->token)
708                 break;
709         }
710
711         if(np->token == CONF_UNKNOWN) return NULL;
712
713         tmpstr = stralloc(conf_print(&server_conf[np->parm], 0));
714     }
715
716     return tmpstr;
717 }
718
719
720 char *
721 getconf_list(
722     char *listname)
723 {
724     char *result = NULL;
725     tapetype_t *tp;
726     dumptype_t *dp;
727     interface_t *ip;
728     holdingdisk_t *hp;
729
730     if (strcasecmp(listname,"tapetype") == 0) {
731         result = stralloc("");
732         for(tp = tapelist; tp != NULL; tp=tp->next) {
733             result = vstrextend(&result, tp->name, "\n", NULL);
734         }
735     } else if (strcasecmp(listname,"dumptype") == 0) {
736         result = stralloc("");
737         for(dp = dumplist; dp != NULL; dp=dp->next) {
738             result = vstrextend(&result, dp->name, "\n", NULL);
739         }
740     } else if (strcasecmp(listname,"holdingdisk") == 0) {
741         result = stralloc("");
742         for(hp = holdingdisks; hp != NULL; hp=hp->next) {
743             result = vstrextend(&result, hp->name, "\n", NULL);
744         }
745     } else if (strcasecmp(listname,"interface") == 0) {
746         result = stralloc("");
747         for(ip = interface_list; ip != NULL; ip=ip->next) {
748             result = vstrextend(&result, ip->name, "\n", NULL);
749         }
750     }
751     return result;
752 }
753
754
755 int
756 getconf_seen(
757     confparm_t parm)
758 {
759     t_conf_var *np;
760     np = get_np(server_var, parm);
761     return(server_conf[np->parm].seen);
762 }
763
764 int
765 getconf_boolean(
766     confparm_t parm)
767 {
768     t_conf_var *np;
769     np = get_np(server_var, parm);
770     if (np->type != CONFTYPE_BOOL) {
771         error("getconf_boolean: np is not a CONFTYPE_BOOL");
772         /*NOTREACHED*/
773     }
774     return(server_conf[np->parm].v.i != 0);
775 }
776
777 int
778 getconf_int(
779     confparm_t parm)
780 {
781     t_conf_var *np;
782     np = get_np(server_var, parm);
783     if (np->type != CONFTYPE_INT) {
784         error("getconf_int: np is not a CONFTYPE_INT");
785         /*NOTREACHED*/
786     }
787     return(server_conf[np->parm].v.i);
788 }
789
790 long
791 getconf_long(
792     confparm_t parm)
793 {
794     t_conf_var *np;
795     np = get_np(server_var, parm);
796     if (np->type != CONFTYPE_LONG) {
797         error("getconf_long: np is not a CONFTYPE_LONG");
798         /*NOTREACHED*/
799     }
800     return(server_conf[np->parm].v.l);
801 }
802
803 time_t
804 getconf_time(
805     confparm_t parm)
806 {
807     t_conf_var *np;
808     np = get_np(server_var, parm);
809     if (np->type != CONFTYPE_TIME) {
810         error("getconf_time: np is not a CONFTYPE_TIME");
811         /*NOTREACHED*/
812     }
813     return(server_conf[np->parm].v.t);
814 }
815
816 ssize_t
817 getconf_size(
818     confparm_t parm)
819 {
820     t_conf_var *np;
821     np = get_np(server_var, parm);
822     if (np->type != CONFTYPE_SIZE) {
823         error("getconf_size: np is not a CONFTYPE_SIZE");
824         /*NOTREACHED*/
825     }
826     return(server_conf[np->parm].v.size);
827 }
828
829 off_t
830 getconf_am64(
831     confparm_t parm)
832 {
833     t_conf_var *np;
834     np = get_np(server_var, parm);
835     if (np->type != CONFTYPE_AM64) {
836         error("getconf_am64: np is not a CONFTYPE_AM64");
837         /*NOTREACHED*/
838     }
839     return(server_conf[np->parm].v.am64);
840 }
841
842 double
843 getconf_real(
844     confparm_t parm)
845 {
846     t_conf_var *np;
847     np = get_np(server_var, parm);
848     if (np->type != CONFTYPE_REAL) {
849         error("getconf_real: np is not a CONFTYPE_REAL");
850         /*NOTREACHED*/
851     }
852     return(server_conf[np->parm].v.r);
853 }
854
855 char *
856 getconf_str(
857     confparm_t parm)
858 {
859     t_conf_var *np;
860     np = get_np(server_var, parm);
861     if (np->type != CONFTYPE_STRING && np->type != CONFTYPE_IDENT) {
862         error("getconf_str: np is not a CONFTYPE_STRING|CONFTYPE_IDENT: %d", parm);
863         /*NOTREACHED*/
864     }
865     return(server_conf[np->parm].v.s);
866 }
867
868 int
869 getconf_taperalgo(
870     confparm_t parm)
871 {
872     t_conf_var *np;
873     np = get_np(server_var, parm);
874     if (np->type != CONFTYPE_TAPERALGO) {
875         error("getconf_taperalgo: np is not a CONFTYPE_TAPERALGO");
876         /*NOTREACHED*/
877     }
878     return(server_conf[np->parm].v.i);
879 }
880
881 holdingdisk_t *
882 getconf_holdingdisks(
883     void)
884 {
885     return holdingdisks;
886 }
887
888 dumptype_t *
889 lookup_dumptype(
890     char *str)
891 {
892     dumptype_t *p;
893
894     for(p = dumplist; p != NULL; p = p->next) {
895         if(strcasecmp(p->name, str) == 0) return p;
896     }
897     return NULL;
898 }
899
900 tapetype_t *
901 lookup_tapetype(
902     char *str)
903 {
904     tapetype_t *p;
905
906     for(p = tapelist; p != NULL; p = p->next) {
907         if(strcasecmp(p->name, str) == 0) return p;
908     }
909     return NULL;
910 }
911
912 holdingdisk_t *
913 lookup_holdingdisk(
914     char *str)
915 {
916     holdingdisk_t *p;
917
918     for(p = holdingdisks; p != NULL; p = p->next) {
919         if(strcasecmp(p->name, str) == 0) return p;
920     }
921     return NULL;
922 }
923
924 interface_t *
925 lookup_interface(
926     char *str)
927 {
928 #ifndef __lint
929     interface_t *p;
930 #endif
931
932     if (str == NULL)
933         return interface_list;
934
935 #ifndef __lint
936     for (p = interface_list; p != NULL; p = p->next) {
937         if (strcasecmp(p->name, str) == 0)
938             return p;
939     }
940 #endif
941     return NULL;
942 }
943
944
945 /*
946 ** ------------------------
947 **  Internal routines
948 ** ------------------------
949 */
950
951
952 static void
953 init_defaults(
954     void)
955 {
956     char *s;
957
958     /* defaults for exported variables */
959
960 #ifdef DEFAULT_CONFIG
961     s = DEFAULT_CONFIG;
962 #else
963     s = "YOUR ORG";
964 #endif
965     conf_init_string(&server_conf[CNF_ORG], s);
966     conf_init_string(&server_conf[CNF_MAILTO], "operators");
967     conf_init_string(&server_conf[CNF_DUMPUSER], CLIENT_LOGIN);
968 #ifdef DEFAULT_TAPE_DEVICE
969     s = DEFAULT_TAPE_DEVICE;
970 #else
971     s = NULL;
972 #endif
973     conf_init_string(&server_conf[CNF_TAPEDEV], s);
974 #ifdef DEFAULT_CHANGER_DEVICE
975     s = DEFAULT_CHANGER_DEVICE;
976 #else
977     s = "/dev/null";
978 #endif
979     conf_init_string(&server_conf[CNF_CHNGRDEV], s);
980     conf_init_string(&server_conf[CNF_CHNGRFILE], "/usr/adm/amanda/changer-status");
981 #ifdef DEFAULT_RAW_TAPE_DEVICE
982     s = DEFAULT_RAW_TAPE_DEVICE;
983 #else
984     s = "/dev/rawft0";
985 #endif
986     conf_init_string   (&server_conf[CNF_LABELSTR]             , ".*");
987     conf_init_string   (&server_conf[CNF_TAPELIST]             , "tapelist");
988     conf_init_string   (&server_conf[CNF_DISKFILE]             , "disklist");
989     conf_init_string   (&server_conf[CNF_INFOFILE]             , "/usr/adm/amanda/curinfo");
990     conf_init_string   (&server_conf[CNF_LOGDIR]               , "/usr/adm/amanda");
991     conf_init_string   (&server_conf[CNF_INDEXDIR]             , "/usr/adm/amanda/index");
992     conf_init_ident    (&server_conf[CNF_TAPETYPE]             , "EXABYTE");
993     conf_init_int      (&server_conf[CNF_DUMPCYCLE]            , 10);
994     conf_init_int      (&server_conf[CNF_RUNSPERCYCLE]         , 0);
995     conf_init_int      (&server_conf[CNF_TAPECYCLE]            , 15);
996     conf_init_int      (&server_conf[CNF_NETUSAGE]             , 300);
997     conf_init_int      (&server_conf[CNF_INPARALLEL]           , 10);
998     conf_init_string   (&server_conf[CNF_DUMPORDER]            , "ttt");
999     conf_init_int      (&server_conf[CNF_BUMPPERCENT]          , 0);
1000     conf_init_am64     (&server_conf[CNF_BUMPSIZE]             , (off_t)10*1024);
1001     conf_init_real     (&server_conf[CNF_BUMPMULT]             , 1.5);
1002     conf_init_int      (&server_conf[CNF_BUMPDAYS]             , 2);
1003     conf_init_string   (&server_conf[CNF_TPCHANGER]            , "");
1004     conf_init_int      (&server_conf[CNF_RUNTAPES]             , 1);
1005     conf_init_int      (&server_conf[CNF_MAXDUMPS]             , 1);
1006     conf_init_int      (&server_conf[CNF_ETIMEOUT]             , 300);
1007     conf_init_int      (&server_conf[CNF_DTIMEOUT]             , 1800);
1008     conf_init_int      (&server_conf[CNF_CTIMEOUT]             , 30);
1009     conf_init_int      (&server_conf[CNF_TAPEBUFS]             , 20);
1010     conf_init_string   (&server_conf[CNF_RAWTAPEDEV]           , s);
1011     conf_init_string   (&server_conf[CNF_PRINTER]              , "");
1012     conf_init_bool     (&server_conf[CNF_AUTOFLUSH]            , 0);
1013     conf_init_int      (&server_conf[CNF_RESERVE]              , 100);
1014     conf_init_am64     (&server_conf[CNF_MAXDUMPSIZE]          , (off_t)-1);
1015     conf_init_string   (&server_conf[CNF_COLUMNSPEC]           , "");
1016     conf_init_bool     (&server_conf[CNF_AMRECOVER_DO_FSF]     , 1);
1017     conf_init_string   (&server_conf[CNF_AMRECOVER_CHANGER]    , "");
1018     conf_init_bool     (&server_conf[CNF_AMRECOVER_CHECK_LABEL], 1);
1019     conf_init_taperalgo(&server_conf[CNF_TAPERALGO]            , 0);
1020     conf_init_string   (&server_conf[CNF_DISPLAYUNIT]          , "k");
1021     conf_init_string   (&server_conf[CNF_KRB5KEYTAB]           , "/.amanda-v5-keytab");
1022     conf_init_string   (&server_conf[CNF_KRB5PRINCIPAL]        , "service/amanda");
1023     conf_init_string   (&server_conf[CNF_LABEL_NEW_TAPES]      , "");
1024     conf_init_bool     (&server_conf[CNF_USETIMESTAMPS]        , 0);
1025
1026     /* defaults for internal variables */
1027
1028     conf_line_num = got_parserror = 0;
1029     allow_overwrites = 0;
1030     token_pushed = 0;
1031
1032     while(holdingdisks != NULL) {
1033         holdingdisk_t *hp;
1034
1035         hp = holdingdisks;
1036         holdingdisks = holdingdisks->next;
1037         amfree(hp);
1038     }
1039     num_holdingdisks = 0;
1040
1041     /* free any previously declared dump, tape and interface types */
1042
1043     while(dumplist != NULL) {
1044         dumptype_t *dp;
1045
1046         dp = dumplist;
1047         dumplist = dumplist->next;
1048         amfree(dp);
1049     }
1050     while(tapelist != NULL) {
1051         tapetype_t *tp;
1052
1053         tp = tapelist;
1054         tapelist = tapelist->next;
1055         amfree(tp);
1056     }
1057     while(interface_list != NULL) {
1058         interface_t *ip;
1059
1060         ip = interface_list;
1061         interface_list = interface_list->next;
1062         amfree(ip);
1063     }
1064
1065     /* create some predefined dumptypes for backwards compatability */
1066     init_dumptype_defaults();
1067     dpcur.name = stralloc("NO-COMPRESS");
1068     dpcur.seen = -1;
1069     conf_set_compress(&dpcur.value[DUMPTYPE_COMPRESS], COMP_NONE);
1070     save_dumptype();
1071
1072     init_dumptype_defaults();
1073     dpcur.name = stralloc("COMPRESS-FAST");
1074     dpcur.seen = -1;
1075     conf_set_compress(&dpcur.value[DUMPTYPE_COMPRESS], COMP_FAST);
1076     save_dumptype();
1077
1078     init_dumptype_defaults();
1079     dpcur.name = stralloc("COMPRESS-BEST");
1080     dpcur.seen = -1;
1081     conf_set_compress(&dpcur.value[DUMPTYPE_COMPRESS], COMP_BEST);
1082     save_dumptype();
1083
1084     init_dumptype_defaults();
1085     dpcur.name = stralloc("COMPRESS-CUST");
1086     dpcur.seen = -1;
1087     conf_set_compress(&dpcur.value[DUMPTYPE_COMPRESS], COMP_CUST);
1088     save_dumptype();
1089
1090     init_dumptype_defaults();
1091     dpcur.name = stralloc("SRVCOMPRESS");
1092     dpcur.seen = -1;
1093     conf_set_compress(&dpcur.value[DUMPTYPE_COMPRESS], COMP_SERV_FAST);
1094     save_dumptype();
1095
1096     init_dumptype_defaults();
1097     dpcur.name = stralloc("BSD-AUTH");
1098     dpcur.seen = -1;
1099     conf_set_string(&dpcur.value[DUMPTYPE_SECURITY_DRIVER], "BSD");
1100     save_dumptype();
1101
1102     init_dumptype_defaults();
1103     dpcur.name = stralloc("KRB4-AUTH");
1104     dpcur.seen = -1;
1105     conf_set_string(&dpcur.value[DUMPTYPE_SECURITY_DRIVER], "KRB4");
1106     save_dumptype();
1107
1108     init_dumptype_defaults();
1109     dpcur.name = stralloc("NO-RECORD");
1110     dpcur.seen = -1;
1111     conf_set_bool(&dpcur.value[DUMPTYPE_RECORD], 0);
1112     save_dumptype();
1113
1114     init_dumptype_defaults();
1115     dpcur.name = stralloc("NO-HOLD");
1116     dpcur.seen = -1;
1117     conf_set_holding(&dpcur.value[DUMPTYPE_HOLDINGDISK], HOLD_NEVER);
1118     save_dumptype();
1119
1120     init_dumptype_defaults();
1121     dpcur.name = stralloc("NO-FULL");
1122     dpcur.seen = -1;
1123     conf_set_strategy(&dpcur.value[DUMPTYPE_STRATEGY], DS_NOFULL);
1124     save_dumptype();
1125 }
1126
1127 static void
1128 read_conffile_recursively(
1129     char *filename)
1130 {
1131     /* Save globals used in read_confline(), elsewhere. */
1132     int  save_line_num  = conf_line_num;
1133     FILE *save_conf     = conf_conf;
1134     char *save_confname = conf_confname;
1135     int rc;
1136
1137     if (*filename == '/' || config_dir == NULL) {
1138         conf_confname = stralloc(filename);
1139     } else {
1140         conf_confname = stralloc2(config_dir, filename);
1141     }
1142
1143     if((conf_conf = fopen(conf_confname, "r")) == NULL) {
1144         fprintf(stderr, "could not open conf file \"%s\": %s\n", conf_confname,
1145                 strerror(errno));
1146         amfree(conf_confname);
1147         got_parserror = -1;
1148         return;
1149     }
1150
1151     conf_line_num = 0;
1152
1153     /* read_confline() can invoke us recursively via "includefile" */
1154     do {
1155         rc = read_confline();
1156     } while (rc != 0);
1157     afclose(conf_conf);
1158
1159     amfree(conf_confname);
1160
1161     /* Restore servers */
1162     conf_line_num = save_line_num;
1163     conf_conf     = save_conf;
1164     conf_confname = save_confname;
1165 }
1166
1167
1168 /* ------------------------ */
1169
1170
1171 static int
1172 read_confline(
1173     void)
1174 {
1175     t_conf_var *np;
1176
1177     keytable = server_keytab;
1178
1179     conf_line_num += 1;
1180     get_conftoken(CONF_ANY);
1181     switch(tok) {
1182     case CONF_INCLUDEFILE:
1183         {
1184             char *fn;
1185             char *cname;
1186
1187             get_conftoken(CONF_STRING);
1188             fn = tokenval.v.s;
1189             if (*fn == '/' || config_dir == NULL) {
1190                 cname = stralloc(fn);
1191             } else {
1192                 cname = stralloc2(config_dir, fn);
1193             }
1194             if ( cname != NULL &&  (access(cname, R_OK) == 0)) {
1195                 read_conffile_recursively(cname);
1196                 amfree(cname);
1197             } else {
1198                 conf_parserror("cannot open %s: %s\n", fn, strerror(errno));
1199             }
1200             amfree(cname);
1201             
1202         }
1203         break;
1204
1205     case CONF_HOLDING:
1206         get_holdingdisk();
1207         break;
1208
1209     case CONF_DEFINE:
1210         get_conftoken(CONF_ANY);
1211         if(tok == CONF_DUMPTYPE) get_dumptype();
1212         else if(tok == CONF_TAPETYPE) get_tapetype();
1213         else if(tok == CONF_INTERFACE) get_interface();
1214         else conf_parserror("DUMPTYPE, INTERFACE or TAPETYPE expected");
1215         break;
1216
1217     case CONF_NL:       /* empty line */
1218         break;
1219
1220     case CONF_END:      /* end of file */
1221         return 0;
1222
1223     default:
1224         {
1225             for(np = server_var; np->token != CONF_UNKNOWN; np++) 
1226                 if(np->token == tok) break;
1227
1228             if(np->token == CONF_UNKNOWN) {
1229                 conf_parserror("configuration keyword expected");
1230             } else {
1231                 np->read_function(np, &server_conf[np->parm]);
1232                 if(np->validate)
1233                     np->validate(np, &server_conf[np->parm]);
1234             }
1235         }
1236     }
1237     if(tok != CONF_NL)
1238         get_conftoken(CONF_NL);
1239     return 1;
1240 }
1241
1242 static void
1243 get_holdingdisk(
1244     void)
1245 {
1246     char *prefix;
1247     int save_overwrites;
1248
1249     save_overwrites = allow_overwrites;
1250     allow_overwrites = 1;
1251
1252     init_holdingdisk_defaults();
1253
1254     get_conftoken(CONF_IDENT);
1255     hdcur.name = stralloc(tokenval.v.s);
1256     hdcur.seen = conf_line_num;
1257
1258     prefix = vstralloc( "HOLDINGDISK:", hdcur.name, ":", NULL);
1259     read_block(server_options, holding_var, server_keytab, hdcur.value, prefix,
1260                "holding disk parameter expected", 1, NULL);
1261     amfree(prefix);
1262     get_conftoken(CONF_NL);
1263
1264     hdcur.disksize = holdingdisk_get_disksize(&hdcur);
1265     save_holdingdisk();
1266
1267     allow_overwrites = save_overwrites;
1268 }
1269
1270 static void
1271 init_holdingdisk_defaults(
1272     void)
1273 {
1274     conf_init_string(&hdcur.value[HOLDING_COMMENT]  , "");
1275     conf_init_string(&hdcur.value[HOLDING_DISKDIR]  , "");
1276     conf_init_am64(&hdcur.value[HOLDING_DISKSIZE] , (off_t)0);
1277                     /* 1 Gb = 1M counted in 1Kb blocks */
1278     conf_init_am64(&hdcur.value[HOLDING_CHUNKSIZE], (off_t)1024*1024);
1279
1280     hdcur.up = (void *)0;
1281     hdcur.disksize = 0LL;
1282 }
1283
1284 static void
1285 save_holdingdisk(
1286     void)
1287 {
1288     holdingdisk_t *hp;
1289
1290     hp = alloc(sizeof(holdingdisk_t));
1291     *hp = hdcur;
1292     hp->next = holdingdisks;
1293     holdingdisks = hp;
1294
1295     num_holdingdisks++;
1296 }
1297
1298
1299 dumptype_t *
1300 read_dumptype(
1301     char *name,
1302     FILE *from,
1303     char *fname,
1304     int *linenum)
1305 {
1306     int save_overwrites;
1307     FILE *saved_conf = NULL;
1308     char *saved_fname = NULL;
1309     char *prefix;
1310
1311     if (from) {
1312         saved_conf = conf_conf;
1313         conf_conf = from;
1314     }
1315
1316     if (fname) {
1317         saved_fname = conf_confname;
1318         conf_confname = fname;
1319     }
1320
1321     if (linenum)
1322         conf_line_num = *linenum;
1323
1324     save_overwrites = allow_overwrites;
1325     allow_overwrites = 1;
1326
1327     init_dumptype_defaults();
1328     if (name) {
1329         dpcur.name = name;
1330     } else {
1331         get_conftoken(CONF_IDENT);
1332         dpcur.name = stralloc(tokenval.v.s);
1333     }
1334     dpcur.seen = conf_line_num;
1335
1336     prefix = vstralloc( "DUMPTYPE:", dpcur.name, ":", NULL);
1337     read_block(server_options, dumptype_var, server_keytab, dpcur.value,
1338                prefix, "dumptype parameter expected",
1339                (name == NULL), *copy_dumptype);
1340     amfree(prefix);
1341     if(!name)
1342         get_conftoken(CONF_NL);
1343
1344     /* XXX - there was a stupidity check in here for skip-incr and
1345     ** skip-full.  This check should probably be somewhere else. */
1346
1347     save_dumptype();
1348
1349     allow_overwrites = save_overwrites;
1350
1351     if (linenum)
1352         *linenum = conf_line_num;
1353
1354     if (fname)
1355         conf_confname = saved_fname;
1356
1357     if (from)
1358         conf_conf = saved_conf;
1359
1360     return lookup_dumptype(dpcur.name);
1361 }
1362
1363 static void
1364 get_dumptype(void)
1365 {
1366     read_dumptype(NULL, NULL, NULL, NULL);
1367 }
1368
1369 static void
1370 init_dumptype_defaults(void)
1371 {
1372     dpcur.name = NULL;
1373     conf_init_string   (&dpcur.value[DUMPTYPE_COMMENT]           , "");
1374     conf_init_string   (&dpcur.value[DUMPTYPE_PROGRAM]           , "DUMP");
1375     conf_init_string   (&dpcur.value[DUMPTYPE_SRVCOMPPROG]       , "");
1376     conf_init_string   (&dpcur.value[DUMPTYPE_CLNTCOMPPROG]      , "");
1377     conf_init_string   (&dpcur.value[DUMPTYPE_SRV_ENCRYPT]       , "");
1378     conf_init_string   (&dpcur.value[DUMPTYPE_CLNT_ENCRYPT]      , "");
1379     conf_init_string   (&dpcur.value[DUMPTYPE_AMANDAD_PATH]      , "X");
1380     conf_init_string   (&dpcur.value[DUMPTYPE_CLIENT_USERNAME]   , "X");
1381     conf_init_string   (&dpcur.value[DUMPTYPE_SSH_KEYS]          , "X");
1382     conf_init_string   (&dpcur.value[DUMPTYPE_SECURITY_DRIVER]   , "BSD");
1383     conf_init_exinclude(&dpcur.value[DUMPTYPE_EXCLUDE]);
1384     conf_init_exinclude(&dpcur.value[DUMPTYPE_INCLUDE]);
1385     conf_init_priority (&dpcur.value[DUMPTYPE_PRIORITY]          , 1);
1386     conf_init_int      (&dpcur.value[DUMPTYPE_DUMPCYCLE]         , server_conf[CNF_DUMPCYCLE].v.i);
1387     conf_init_int      (&dpcur.value[DUMPTYPE_MAXDUMPS]          , server_conf[CNF_MAXDUMPS].v.i);
1388     conf_init_int      (&dpcur.value[DUMPTYPE_MAXPROMOTEDAY]     , 10000);
1389     conf_init_int      (&dpcur.value[DUMPTYPE_BUMPPERCENT]       , server_conf[CNF_BUMPPERCENT].v.i);
1390     conf_init_am64     (&dpcur.value[DUMPTYPE_BUMPSIZE]          , server_conf[CNF_BUMPSIZE].v.am64);
1391     conf_init_int      (&dpcur.value[DUMPTYPE_BUMPDAYS]          , server_conf[CNF_BUMPDAYS].v.i);
1392     conf_init_real     (&dpcur.value[DUMPTYPE_BUMPMULT]          , server_conf[CNF_BUMPMULT].v.r);
1393     conf_init_time     (&dpcur.value[DUMPTYPE_STARTTIME]         , (time_t)0);
1394     conf_init_strategy (&dpcur.value[DUMPTYPE_STRATEGY]          , DS_STANDARD);
1395     conf_init_estimate (&dpcur.value[DUMPTYPE_ESTIMATE]          , ES_CLIENT);
1396     conf_init_compress (&dpcur.value[DUMPTYPE_COMPRESS]          , COMP_FAST);
1397     conf_init_encrypt  (&dpcur.value[DUMPTYPE_ENCRYPT]           , ENCRYPT_NONE);
1398     conf_init_string   (&dpcur.value[DUMPTYPE_SRV_DECRYPT_OPT]   , "-d");
1399     conf_init_string   (&dpcur.value[DUMPTYPE_CLNT_DECRYPT_OPT]  , "-d");
1400     conf_init_rate     (&dpcur.value[DUMPTYPE_COMPRATE]          , 0.50, 0.50);
1401     conf_init_am64     (&dpcur.value[DUMPTYPE_TAPE_SPLITSIZE]    , (off_t)0);
1402     conf_init_am64     (&dpcur.value[DUMPTYPE_FALLBACK_SPLITSIZE], (off_t)10 * 1024);
1403     conf_init_string   (&dpcur.value[DUMPTYPE_SPLIT_DISKBUFFER]  , NULL);
1404     conf_init_bool     (&dpcur.value[DUMPTYPE_RECORD]            , 1);
1405     conf_init_bool     (&dpcur.value[DUMPTYPE_SKIP_INCR]         , 0);
1406     conf_init_bool     (&dpcur.value[DUMPTYPE_SKIP_FULL]         , 0);
1407     conf_init_holding  (&dpcur.value[DUMPTYPE_HOLDINGDISK]       , HOLD_AUTO);
1408     conf_init_bool     (&dpcur.value[DUMPTYPE_KENCRYPT]          , 0);
1409     conf_init_bool     (&dpcur.value[DUMPTYPE_IGNORE]            , 0);
1410     conf_init_bool     (&dpcur.value[DUMPTYPE_INDEX]             , 1);
1411 }
1412
1413 static void
1414 save_dumptype(void)
1415 {
1416     dumptype_t *dp, *dp1;;
1417
1418     dp = lookup_dumptype(dpcur.name);
1419
1420     if(dp != (dumptype_t *)0) {
1421         conf_parserror("dumptype %s already defined on line %d", dp->name, dp->seen);
1422         return;
1423     }
1424
1425     dp = alloc(sizeof(dumptype_t));
1426     *dp = dpcur;
1427     dp->next = NULL;
1428     /* add at end of list */
1429     if(!dumplist)
1430         dumplist = dp;
1431     else {
1432         dp1 = dumplist;
1433         while (dp1->next != NULL) {
1434              dp1 = dp1->next;
1435         }
1436         dp1->next = dp;
1437     }
1438 }
1439
1440 static void
1441 copy_dumptype(void)
1442 {
1443     dumptype_t *dt;
1444     int i;
1445
1446     dt = lookup_dumptype(tokenval.v.s);
1447
1448     if(dt == NULL) {
1449         conf_parserror("dumptype parameter expected");
1450         return;
1451     }
1452
1453     for(i=0; i < DUMPTYPE_DUMPTYPE; i++) {
1454         if(dt->value[i].seen) {
1455             free_val_t(&dpcur.value[i]);
1456             copy_val_t(&dpcur.value[i], &dt->value[i]);
1457         }
1458     }
1459 }
1460
1461 static void
1462 get_tapetype(void)
1463 {
1464     int save_overwrites;
1465     char *prefix;
1466
1467     save_overwrites = allow_overwrites;
1468     allow_overwrites = 1;
1469
1470     init_tapetype_defaults();
1471
1472     get_conftoken(CONF_IDENT);
1473     tpcur.name = stralloc(tokenval.v.s);
1474     tpcur.seen = conf_line_num;
1475
1476     prefix = vstralloc( "TAPETYPE:", tpcur.name, ":", NULL);
1477     read_block(server_options, tapetype_var, server_keytab, tpcur.value,
1478                prefix, "tapetype parameter expected", 1, &copy_tapetype);
1479     amfree(prefix);
1480     get_conftoken(CONF_NL);
1481
1482     save_tapetype();
1483
1484     allow_overwrites = save_overwrites;
1485 }
1486
1487 static void
1488 init_tapetype_defaults(void)
1489 {
1490     conf_init_string(&tpcur.value[TAPETYPE_COMMENT]  , "");
1491     conf_init_string(&tpcur.value[TAPETYPE_LBL_TEMPL], "");
1492     conf_init_size  (&tpcur.value[TAPETYPE_BLOCKSIZE], DISK_BLOCK_KB);
1493     conf_init_am64  (&tpcur.value[TAPETYPE_LENGTH]   , (off_t)2000);
1494     conf_init_am64  (&tpcur.value[TAPETYPE_FILEMARK] , (off_t)1);
1495     conf_init_int   (&tpcur.value[TAPETYPE_SPEED]    , 200);
1496     conf_init_bool  (&tpcur.value[TAPETYPE_FILE_PAD] , 1);
1497 }
1498
1499 static void
1500 save_tapetype(void)
1501 {
1502     tapetype_t *tp, *tp1;
1503
1504     tp = lookup_tapetype(tpcur.name);
1505
1506     if(tp != (tapetype_t *)0) {
1507         amfree(tpcur.name);
1508         conf_parserror("tapetype %s already defined on line %d", tp->name, tp->seen);
1509         return;
1510     }
1511
1512     tp = alloc(sizeof(tapetype_t));
1513     *tp = tpcur;
1514     /* add at end of list */
1515     if(!tapelist)
1516         tapelist = tp;
1517     else {
1518         tp1 = tapelist;
1519         while (tp1->next != NULL) {
1520             tp1 = tp1->next;
1521         }
1522         tp1->next = tp;
1523     }
1524 }
1525
1526 static void
1527 copy_tapetype(void)
1528 {
1529     tapetype_t *tp;
1530     int i;
1531
1532     tp = lookup_tapetype(tokenval.v.s);
1533
1534     if(tp == NULL) {
1535         conf_parserror("tape type parameter expected");
1536         return;
1537     }
1538
1539     for(i=0; i < TAPETYPE_TAPETYPE; i++) {
1540         if(tp->value[i].seen) {
1541             free_val_t(&tpcur.value[i]);
1542             copy_val_t(&tpcur.value[i], &tp->value[i]);
1543         }
1544     }
1545 }
1546
1547 t_conf_var interface_var [] = {
1548    { CONF_COMMENT, CONFTYPE_STRING, read_string, INTER_COMMENT , NULL },
1549    { CONF_USE    , CONFTYPE_INT   , read_int   , INTER_MAXUSAGE, validate_positive1 },
1550    { CONF_UNKNOWN, CONFTYPE_INT   , NULL       , INTER_INTER   , NULL }
1551 };
1552
1553 static void
1554 get_interface(void)
1555 {
1556     int save_overwrites;
1557     char *prefix;
1558
1559     save_overwrites = allow_overwrites;
1560     allow_overwrites = 1;
1561
1562     init_interface_defaults();
1563
1564     get_conftoken(CONF_IDENT);
1565     ifcur.name = stralloc(tokenval.v.s);
1566     ifcur.seen = conf_line_num;
1567
1568     prefix = vstralloc( "INTERFACE:", ifcur.name, ":", NULL);
1569     read_block(server_options, interface_var, server_keytab, ifcur.value,
1570                prefix, "interface parameter expected", 1, &copy_interface);
1571     amfree(prefix);
1572     get_conftoken(CONF_NL);
1573
1574     save_interface();
1575
1576     allow_overwrites = save_overwrites;
1577
1578     return;
1579 }
1580
1581 static void
1582 init_interface_defaults(void)
1583 {
1584     conf_init_string(&ifcur.value[INTER_COMMENT] , "");
1585     conf_init_int   (&ifcur.value[INTER_MAXUSAGE], 300);
1586
1587     ifcur.curusage = 0;
1588 }
1589
1590 static void
1591 save_interface(void)
1592 {
1593     interface_t *ip, *ip1;
1594
1595     ip = lookup_interface(ifcur.name);
1596
1597     if(ip != (interface_t *)0) {
1598         conf_parserror("interface %s already defined on line %d", ip->name,
1599                        ip->seen);
1600         return;
1601     }
1602
1603     ip = alloc(sizeof(interface_t));
1604     *ip = ifcur;
1605     /* add at end of list */
1606     if(!interface_list) {
1607         interface_list = ip;
1608     } else {
1609         ip1 = interface_list;
1610         while (ip1->next != NULL) {
1611             ip1 = ip1->next;
1612         }
1613         ip1->next = ip;
1614     }
1615 }
1616
1617 static void
1618 copy_interface(void)
1619 {
1620 /*
1621     int i;
1622     t_xxx *np;
1623     keytab_t *kt;
1624     
1625     val_t val;
1626 */
1627     interface_t *ip;
1628     int i;
1629
1630     ip = lookup_interface(tokenval.v.s);
1631
1632     if(ip == NULL) {
1633         conf_parserror("interface parameter expected");
1634         return;
1635     }
1636
1637     for(i=0; i < INTER_INTER; i++) {
1638         if(ip->value[i].seen) {
1639             free_val_t(&ifcur.value[i]);
1640             copy_val_t(&ifcur.value[i], &ip->value[i]);
1641         }
1642     }
1643 }
1644
1645 static void
1646 get_comprate(
1647     t_conf_var *np,
1648     val_t *val)
1649 {
1650     np = np;
1651     get_conftoken(CONF_REAL);
1652     val->v.rate[0] = tokenval.v.r;
1653     val->v.rate[1] = tokenval.v.r;
1654     val->seen = tokenval.seen;
1655     if(tokenval.v.r < 0) {
1656         conf_parserror("full compression rate must be >= 0");
1657     }
1658
1659     get_conftoken(CONF_ANY);
1660     switch(tok) {
1661     case CONF_NL:
1662         return;
1663
1664     case CONF_END:
1665         return;
1666
1667     case CONF_COMMA:
1668         break;
1669
1670     default:
1671         unget_conftoken();
1672     }
1673
1674     get_conftoken(CONF_REAL);
1675     val->v.rate[1] = tokenval.v.r;
1676     if(tokenval.v.r < 0) {
1677         conf_parserror("incremental compression rate must be >= 0");
1678     }
1679 }
1680
1681 static void
1682 get_compress(
1683     t_conf_var *np,
1684     val_t *val)
1685 {
1686     int serv, clie, none, fast, best, custom;
1687     int done;
1688     comp_t comp;
1689
1690     np = np;
1691     ckseen(&val->seen);
1692
1693     serv = clie = none = fast = best = custom  = 0;
1694
1695     done = 0;
1696     do {
1697         get_conftoken(CONF_ANY);
1698         switch(tok) {
1699         case CONF_NONE:   none = 1; break;
1700         case CONF_FAST:   fast = 1; break;
1701         case CONF_BEST:   best = 1; break;
1702         case CONF_CLIENT: clie = 1; break;
1703         case CONF_SERVER: serv = 1; break;
1704         case CONF_CUSTOM: custom=1; break;
1705         case CONF_NL:     done = 1; break;
1706         case CONF_END:    done = 1; break;
1707         default:
1708             done = 1;
1709             serv = clie = 1; /* force an error */
1710         }
1711     } while(!done);
1712
1713     if(serv + clie == 0) clie = 1;      /* default to client */
1714     if(none + fast + best + custom  == 0) fast = 1; /* default to fast */
1715
1716     comp = -1;
1717
1718     if(!serv && clie) {
1719         if(none && !fast && !best && !custom) comp = COMP_NONE;
1720         if(!none && fast && !best && !custom) comp = COMP_FAST;
1721         if(!none && !fast && best && !custom) comp = COMP_BEST;
1722         if(!none && !fast && !best && custom) comp = COMP_CUST;
1723     }
1724
1725     if(serv && !clie) {
1726         if(none && !fast && !best && !custom) comp = COMP_NONE;
1727         if(!none && fast && !best && !custom) comp = COMP_SERV_FAST;
1728         if(!none && !fast && best && !custom) comp = COMP_SERV_BEST;
1729         if(!none && !fast && !best && custom) comp = COMP_SERV_CUST;
1730     }
1731
1732     if((int)comp == -1) {
1733         conf_parserror("NONE, CLIENT FAST, CLIENT BEST, CLIENT CUSTOM, SERVER FAST, SERVER BEST or SERVER CUSTOM expected");
1734         comp = COMP_NONE;
1735     }
1736
1737     val->v.i = (int)comp;
1738 }
1739
1740 static void
1741 get_encrypt(
1742     t_conf_var *np,
1743     val_t *val)
1744 {
1745    encrypt_t encrypt;
1746
1747    np = np;
1748    ckseen(&val->seen);
1749
1750    get_conftoken(CONF_ANY);
1751    switch(tok) {
1752    case CONF_NONE:  
1753      encrypt = ENCRYPT_NONE; 
1754      break;
1755
1756    case CONF_CLIENT:  
1757      encrypt = ENCRYPT_CUST;
1758      break;
1759
1760    case CONF_SERVER: 
1761      encrypt = ENCRYPT_SERV_CUST;
1762      break;
1763
1764    default:
1765      conf_parserror("NONE, CLIENT or SERVER expected");
1766      encrypt = ENCRYPT_NONE;
1767      break;
1768    }
1769
1770    val->v.i = (int)encrypt;
1771 }
1772
1773 static void
1774 get_holding(
1775     t_conf_var *np,
1776     val_t *val)
1777 {
1778    dump_holdingdisk_t holding;
1779
1780    np = np;
1781    ckseen(&val->seen);
1782
1783    get_conftoken(CONF_ANY);
1784    switch(tok) {
1785    case CONF_NEVER:  
1786      holding = HOLD_NEVER; 
1787      break;
1788
1789    case CONF_AUTO:  
1790      holding = HOLD_AUTO;
1791      break;
1792
1793    case CONF_REQUIRED: 
1794      holding = HOLD_REQUIRED;
1795      break;
1796
1797    default: /* can be a BOOLEAN */
1798      unget_conftoken();
1799      holding =  (dump_holdingdisk_t)get_bool();
1800      if (holding == 0)
1801         holding = HOLD_NEVER;
1802      else if (holding == 1 || holding == 2)
1803         holding = HOLD_AUTO;
1804      else
1805         conf_parserror("NEVER, AUTO or REQUIRED expected");
1806      break;
1807    }
1808
1809    val->v.i = (int)holding;
1810 }
1811
1812 static void
1813 get_taperalgo(
1814     t_conf_var *np,
1815     val_t *val)
1816 {
1817     np = np;
1818     ckseen(&val->seen);
1819
1820     get_conftoken(CONF_ANY);
1821     switch(tok) {
1822     case CONF_FIRST:      val->v.i = ALGO_FIRST;      break;
1823     case CONF_FIRSTFIT:   val->v.i = ALGO_FIRSTFIT;   break;
1824     case CONF_LARGEST:    val->v.i = ALGO_LARGEST;    break;
1825     case CONF_LARGESTFIT: val->v.i = ALGO_LARGESTFIT; break;
1826     case CONF_SMALLEST:   val->v.i = ALGO_SMALLEST;   break;
1827     case CONF_LAST:       val->v.i = ALGO_LAST;       break;
1828     default:
1829         conf_parserror("FIRST, FIRSTFIT, LARGEST, LARGESTFIT, SMALLEST or LAST expected");
1830     }
1831 }
1832
1833 static void
1834 get_priority(
1835     t_conf_var *np,
1836     val_t *val)
1837 {
1838     int pri;
1839
1840     np = np;
1841     ckseen(&val->seen);
1842
1843     get_conftoken(CONF_ANY);
1844     switch(tok) {
1845     case CONF_LOW: pri = 0; break;
1846     case CONF_MEDIUM: pri = 1; break;
1847     case CONF_HIGH: pri = 2; break;
1848     case CONF_INT: pri = tokenval.v.i; break;
1849     default:
1850         conf_parserror("LOW, MEDIUM, HIGH or integer expected");
1851         pri = 0;
1852     }
1853     val->v.i = pri;
1854 }
1855
1856 static void
1857 get_strategy(
1858     t_conf_var *np,
1859     val_t *val)
1860 {
1861     int strat;
1862
1863     np = np;
1864     ckseen(&val->seen);
1865
1866     get_conftoken(CONF_ANY);
1867     switch(tok) {
1868     case CONF_SKIP:
1869         strat = DS_SKIP;
1870         break;
1871     case CONF_STANDARD:
1872         strat = DS_STANDARD;
1873         break;
1874     case CONF_NOFULL:
1875         strat = DS_NOFULL;
1876         break;
1877     case CONF_NOINC:
1878         strat = DS_NOINC;
1879         break;
1880     case CONF_HANOI:
1881         strat = DS_HANOI;
1882         break;
1883     case CONF_INCRONLY:
1884         strat = DS_INCRONLY;
1885         break;
1886     default:
1887         conf_parserror("STANDARD or NOFULL expected");
1888         strat = DS_STANDARD;
1889     }
1890     val->v.i = strat;
1891 }
1892
1893 static void
1894 get_estimate(
1895     t_conf_var *np,
1896     val_t *val)
1897 {
1898     int estime;
1899
1900     np = np;
1901     ckseen(&val->seen);
1902
1903     get_conftoken(CONF_ANY);
1904     switch(tok) {
1905     case CONF_CLIENT:
1906         estime = ES_CLIENT;
1907         break;
1908     case CONF_SERVER:
1909         estime = ES_SERVER;
1910         break;
1911     case CONF_CALCSIZE:
1912         estime = ES_CALCSIZE;
1913         break;
1914     default:
1915         conf_parserror("CLIENT, SERVER or CALCSIZE expected");
1916         estime = ES_CLIENT;
1917     }
1918     val->v.i = estime;
1919 }
1920
1921 static void
1922 get_exclude(
1923     t_conf_var *np,
1924     val_t *val)
1925 {
1926     int file, got_one = 0;
1927     sl_t *exclude;
1928     int optional = 0;
1929
1930     np = np;
1931     get_conftoken(CONF_ANY);
1932     if(tok == CONF_LIST) {
1933         file = 0;
1934         get_conftoken(CONF_ANY);
1935         exclude = val->v.exinclude.sl_list;
1936     }
1937     else {
1938         file = 1;
1939         if(tok == CONF_EFILE) get_conftoken(CONF_ANY);
1940         exclude = val->v.exinclude.sl_file;
1941     }
1942     ckseen(&val->seen);
1943
1944     if(tok == CONF_OPTIONAL) {
1945         get_conftoken(CONF_ANY);
1946         optional = 1;
1947     }
1948
1949     if(tok == CONF_APPEND) {
1950         get_conftoken(CONF_ANY);
1951     }
1952     else {
1953         free_sl(exclude);
1954         exclude = NULL;
1955     }
1956
1957     while(tok == CONF_STRING) {
1958         exclude = append_sl(exclude, tokenval.v.s);
1959         got_one = 1;
1960         get_conftoken(CONF_ANY);
1961     }
1962     unget_conftoken();
1963
1964     if(got_one == 0) { free_sl(exclude); exclude = NULL; }
1965
1966     if (file == 0)
1967         val->v.exinclude.sl_list = exclude;
1968     else
1969         val->v.exinclude.sl_file = exclude;
1970     val->v.exinclude.optional = optional;
1971 }
1972
1973 /*
1974 static void get_include(np, val)
1975     t_conf_var *np;
1976     val_t *val;
1977 {
1978     int list, got_one = 0;
1979     sl_t *include;
1980     int optional = 0;
1981     int append = 0;
1982
1983     get_conftoken(CONF_ANY);
1984     if(tok == CONF_LIST) {
1985         list = 1;
1986         include = dpcur.value[DUMPTYPE_INCLUDE_LIST].v.sl;
1987         ckseen(&dpcur.value[DUMPTYPE_INCLUDE_LIST].seen);
1988         get_conftoken(CONF_ANY);
1989     }
1990     else {
1991         list = 0;
1992         include = dpcur.value[DUMPTYPE_INCLUDE_FILE].v.sl;
1993         ckseen(&dpcur.value[DUMPTYPE_INCLUDE_FILE].seen);
1994         if(tok == CONF_EFILE) get_conftoken(CONF_ANY);
1995     }
1996
1997     if(tok == CONF_OPTIONAL) {
1998         get_conftoken(CONF_ANY);
1999         optional = 1;
2000     }
2001
2002     if(tok == CONF_APPEND) {
2003         get_conftoken(CONF_ANY);
2004         append = 1;
2005     }
2006     else {
2007         free_sl(include);
2008         include = NULL;
2009         append = 0;
2010     }
2011
2012     while(tok == CONF_STRING) {
2013         include = append_sl(include, tokenval.v.s);
2014         got_one = 1;
2015         get_conftoken(CONF_ANY);
2016     }
2017     unget_conftoken();
2018
2019     if(got_one == 0) { free_sl(include); include = NULL; }
2020
2021     if(list == 0)
2022         dpcur.value[DUMPTYPE_INCLUDE_FILE].v.sl = include;
2023     else {
2024         dpcur.value[DUMPTYPE_INCLUDE_LIST].v.sl = include;
2025         if(!append || optional)
2026             dpcur.value[DUMPTYPE_INCLUDE_OPTIONAL].v.i = optional;
2027     }
2028 }
2029 */
2030
2031 /* ------------------------ */
2032
2033 int
2034 ColumnDataCount(void )
2035 {
2036     return (int)(SIZEOF(ColumnData) / SIZEOF(ColumnData[0]));
2037 }
2038
2039 /* conversion from string to table index
2040  */
2041 int
2042 StringToColumn(
2043     char *s)
2044 {
2045     int cn;
2046
2047     for (cn=0; ColumnData[cn].Name != NULL; cn++) {
2048         if (strcasecmp(s, ColumnData[cn].Name) == 0) {
2049             break;
2050         }
2051     }
2052     return cn;
2053 }
2054
2055 char
2056 LastChar(
2057     char *s)
2058 {
2059     return s[strlen(s)-1];
2060 }
2061
2062 int
2063 SetColumDataFromString(
2064     ColumnInfo* ci,
2065     char *s,
2066     char **errstr)
2067 {
2068 #ifdef TEST
2069     char *myname= "SetColumDataFromString";
2070 #endif
2071     ci = ci;
2072
2073     /* Convert from a Columspec string to our internal format
2074      * of columspec. The purpose is to provide this string
2075      * as configuration paramter in the amanda.conf file or
2076      * (maybe) as environment variable.
2077      * 
2078      * This text should go as comment into the sample amanda.conf
2079      *
2080      * The format for such a ColumnSpec string s is a ',' seperated
2081      * list of triples. Each triple consists of
2082      *   -the name of the column (as in ColumnData.Name)
2083      *   -prefix before the column
2084      *   -the width of the column
2085      *       if set to -1 it will be recalculated
2086      *   to the maximum length of a line to print.
2087      * Example:
2088      *  "Disk=1:17,HostName=1:10,OutKB=1:7"
2089      * or
2090      *  "Disk=1:-1,HostName=1:10,OutKB=1:7"
2091      *  
2092      * You need only specify those colums that should be changed from
2093      * the default. If nothing is specified in the configfile, the
2094      * above compiled in values will be in effect, resulting in an
2095      * output as it was all the time.
2096      *                                                  ElB, 1999-02-24.
2097      */
2098
2099     while (s && *s) {
2100         int Space, Width;
2101         int cn;
2102         char *eon= strchr(s, '=');
2103
2104         if (eon == NULL) {
2105             *errstr = stralloc2("invalid columnspec: ", s);
2106 #ifdef TEST
2107             fprintf(stderr, "%s: %s\n", myname, *errstr);
2108 #endif
2109             return -1;
2110         }
2111         *eon= '\0';
2112         cn=StringToColumn(s);
2113         if (ColumnData[cn].Name == NULL) {
2114             *errstr = stralloc2("invalid column name: ", s);
2115 #ifdef TEST
2116             fprintf(stderr, "%s: %s\n", myname, *errstr);
2117 #endif
2118             return -1;
2119         }
2120         if (sscanf(eon+1, "%d:%d", &Space, &Width) != 2) {
2121             *errstr = stralloc2("invalid format: ", eon + 1);
2122 #ifdef TEST
2123             fprintf(stderr, "%s: %s\n", myname, *errstr);
2124 #endif
2125             return -1;
2126         }
2127         ColumnData[cn].Width= Width;
2128         ColumnData[cn].PrefixSpace = Space;
2129         if (LastChar(ColumnData[cn].Format) == 's') {
2130             if (Width < 0)
2131                 ColumnData[cn].MaxWidth= 1;
2132             else
2133                 if (Width > ColumnData[cn].Precision)
2134                     ColumnData[cn].Precision= Width;
2135         }
2136         else if (Width < ColumnData[cn].Precision)
2137             ColumnData[cn].Precision = Width;
2138         s= strchr(eon+1, ',');
2139         if (s != NULL)
2140             s++;
2141     }
2142     return 0;
2143 }
2144
2145
2146 long int
2147 getconf_unit_divisor(void)
2148 {
2149     return unit_divisor;
2150 }
2151
2152 /* ------------------------ */
2153
2154
2155 void
2156 dump_configuration(
2157     char *filename)
2158 {
2159     tapetype_t *tp;
2160     dumptype_t *dp;
2161     interface_t *ip;
2162     holdingdisk_t *hp;
2163     int i;
2164     t_conf_var *np;
2165     keytab_t *kt;
2166     char *prefix;
2167
2168     printf("AMANDA CONFIGURATION FROM FILE \"%s\":\n\n", filename);
2169
2170     for(i=0; i < CNF_CNF; i++) {
2171         for(np=server_var; np->token != CONF_UNKNOWN; np++) {
2172             if(np->parm == i)
2173                 break;
2174         }
2175         if(np->token == CONF_UNKNOWN)
2176             error("server bad value");
2177
2178         for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
2179             if(kt->token == np->token) break;
2180         if(kt->token == CONF_UNKNOWN)
2181             error("server bad token");
2182
2183         printf("%-21s %s\n", kt->keyword, conf_print(&server_conf[i], 1));
2184     }
2185
2186     for(hp = holdingdisks; hp != NULL; hp = hp->next) {
2187         printf("\nHOLDINGDISK %s {\n", hp->name);
2188         for(i=0; i < HOLDING_HOLDING; i++) {
2189             for(np=holding_var; np->token != CONF_UNKNOWN; np++) {
2190                 if(np->parm == i)
2191                         break;
2192             }
2193             if(np->token == CONF_UNKNOWN)
2194                 error("holding bad value");
2195
2196             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) {
2197                 if(kt->token == np->token)
2198                     break;
2199             }
2200             if(kt->token == CONF_UNKNOWN)
2201                 error("holding bad token");
2202
2203             printf("      %-9s %s\n", kt->keyword, conf_print(&hp->value[i], 1));
2204         }
2205         printf("}\n");
2206     }
2207
2208     for(tp = tapelist; tp != NULL; tp = tp->next) {
2209         printf("\nDEFINE TAPETYPE %s {\n", tp->name);
2210         for(i=0; i < TAPETYPE_TAPETYPE; i++) {
2211             for(np=tapetype_var; np->token != CONF_UNKNOWN; np++)
2212                 if(np->parm == i) break;
2213             if(np->token == CONF_UNKNOWN)
2214                 error("tapetype bad value");
2215
2216             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
2217                 if(kt->token == np->token) break;
2218             if(kt->token == CONF_UNKNOWN)
2219                 error("tapetype bad token");
2220
2221             printf("      %-9s %s\n", kt->keyword, conf_print(&tp->value[i], 1));
2222         }
2223         printf("}\n");
2224     }
2225
2226     for(dp = dumplist; dp != NULL; dp = dp->next) {
2227         if (strncmp(dp->name, "custom(", 7) != 0) {
2228             if(dp->seen == -1)
2229                 prefix = "#";
2230             else
2231                 prefix = "";
2232             printf("\n%sDEFINE DUMPTYPE %s {\n", prefix, dp->name);
2233             for(i=0; i < DUMPTYPE_DUMPTYPE; i++) {
2234                 for(np=dumptype_var; np->token != CONF_UNKNOWN; np++)
2235                     if(np->parm == i) break;
2236                 if(np->token == CONF_UNKNOWN)
2237                     error("dumptype bad value");
2238
2239                 for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
2240                     if(kt->token == np->token) break;
2241                 if(kt->token == CONF_UNKNOWN)
2242                     error("dumptype bad token");
2243
2244                 if (dp->value[i].type == CONFTYPE_EXINCLUDE) {
2245                     printf("%s      %-19s %s\n", prefix, kt->keyword,
2246                            conf_print_exinclude(&dp->value[i], 1, 0));
2247                     printf("%s      %-19s %s\n", prefix, kt->keyword,
2248                            conf_print_exinclude(&dp->value[i], 1, 1));
2249                 } else {
2250                     printf("%s      %-19s %s\n", prefix, kt->keyword,
2251                            conf_print(&dp->value[i], 1));
2252                 }
2253             }
2254             printf("%s}\n", prefix);
2255         }
2256     }
2257
2258     for(ip = interface_list; ip != NULL; ip = ip->next) {
2259         if(strcmp(ip->name,"default") == 0)
2260             prefix = "#";
2261         else
2262             prefix = "";
2263         printf("\n%sDEFINE INTERFACE %s {\n", prefix, ip->name);
2264         for(i=0; i < INTER_INTER; i++) {
2265             for(np=interface_var; np->token != CONF_UNKNOWN; np++)
2266                 if(np->parm == i) break;
2267             if(np->token == CONF_UNKNOWN)
2268                 error("interface bad value");
2269
2270             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
2271                 if(kt->token == np->token) break;
2272             if(kt->token == CONF_UNKNOWN)
2273                 error("interface bad token");
2274
2275             printf("%s      %-9s %s\n", prefix, kt->keyword, conf_print(&ip->value[i], 1));
2276         }
2277         printf("%s}\n",prefix);
2278     }
2279
2280 }
2281
2282 #ifdef TEST
2283
2284 int
2285 main(
2286     int argc,
2287     char *argv[])
2288 {
2289   char *conffile;
2290   char *diskfile;
2291   disklist_t lst;
2292   int result;
2293   unsigned long malloc_hist_1, malloc_size_1;
2294   unsigned long malloc_hist_2, malloc_size_2;
2295
2296   safe_fd(-1, 0);
2297
2298   set_pname("conffile");
2299
2300   /* Don't die when child closes pipe */
2301   signal(SIGPIPE, SIG_IGN);
2302
2303   malloc_size_1 = malloc_inuse(&malloc_hist_1);
2304
2305   startclock();
2306
2307   if (argc > 1) {
2308     if (argv[1][0] == '/') {
2309       config_dir = stralloc(argv[1]);
2310       config_name = strrchr(config_dir, '/') + 1;
2311       config_name[-1] = '\0';
2312       config_dir = newstralloc2(config_dir, config_dir, "/");
2313     } else {
2314       config_name = stralloc(argv[1]);
2315       config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
2316     }
2317   } else {
2318     char my_cwd[STR_SIZE];
2319
2320     if (getcwd(my_cwd, sizeof(my_cwd)) == NULL) {
2321       error("cannot determine current working directory");
2322     }
2323     config_dir = stralloc2(my_cwd, "/");
2324     if ((config_name = strrchr(my_cwd, '/')) != NULL) {
2325       config_name = stralloc(config_name + 1);
2326     }
2327   }
2328
2329   conffile = stralloc2(config_dir, CONFFILE_NAME);
2330   result = read_conffile(conffile);
2331   if (result == 0) {
2332       diskfile = getconf_str(CNF_DISKFILE);
2333       if (diskfile != NULL && access(diskfile, R_OK) == 0) {
2334           result = read_diskfile(diskfile, &lst);
2335       }
2336   }
2337   dump_configuration(CONFFILE_NAME);
2338   amfree(conffile);
2339
2340   malloc_size_2 = malloc_inuse(&malloc_hist_2);
2341
2342   if(malloc_size_1 != malloc_size_2) {
2343     malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
2344   }
2345
2346   return result;
2347 }
2348
2349 #endif /* TEST */
2350
2351 char *
2352 generic_get_security_conf(
2353         char *string,
2354         void *arg)
2355 {
2356         arg = arg;
2357         if(!string || !*string)
2358                 return(NULL);
2359
2360         if(strcmp(string, "krb5principal")==0) {
2361                 return(getconf_str(CNF_KRB5PRINCIPAL));
2362         } else if(strcmp(string, "krb5keytab")==0) {
2363                 return(getconf_str(CNF_KRB5KEYTAB));
2364         }
2365         return(NULL);
2366 }
2367
2368 char *
2369 get_token_name(
2370     tok_t token)
2371 {
2372     keytab_t *kt;
2373
2374     for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
2375         if(kt->token == token) break;
2376
2377     if(kt->token == CONF_UNKNOWN)
2378         return("");
2379     return(kt->keyword);
2380 }
2381
2382 void
2383 parse_server_conf(
2384     int parse_argc,
2385     char **parse_argv,
2386     int *new_argc,
2387     char ***new_argv)
2388 {
2389     int i;
2390     char **my_argv;
2391     char *myarg, *value;
2392     command_option_t *server_option;
2393
2394     server_options = alloc((size_t)(parse_argc+1) * SIZEOF(*server_options));
2395     server_option = server_options;
2396     server_option->name = NULL;
2397
2398     my_argv = alloc((size_t)parse_argc * SIZEOF(char *));
2399     *new_argv = my_argv;
2400     *new_argc = 0;
2401     i=0;
2402     while(i<parse_argc) {
2403         if(strncmp(parse_argv[i],"-o",2) == 0) {
2404             if(strlen(parse_argv[i]) > 2)
2405                 myarg = &parse_argv[i][2];
2406             else {
2407                 i++;
2408                 if(i >= parse_argc)
2409                     error("expect something after -o");
2410                 myarg = parse_argv[i];
2411             }
2412             value = index(myarg,'=');
2413             if (value == NULL) {
2414                 conf_parserror("Must specify a value for %s.\n", myarg);
2415             } else {
2416                 *value = '\0';
2417                 value++;
2418                 server_option->used = 0;
2419                 server_option->name = stralloc(myarg);
2420                 server_option->value = stralloc(value);
2421                 server_option++;
2422                 server_option->name = NULL;
2423             }
2424         }
2425         else {
2426             my_argv[*new_argc] = stralloc(parse_argv[i]);
2427             *new_argc += 1;
2428         }
2429         i++;
2430     }
2431 }
2432
2433 char **
2434 get_config_options(
2435     int first)
2436 {
2437     char             **config_options;
2438     char             **config_option;
2439     command_option_t  *command_options;
2440     int                nb_server_options = 0;
2441
2442     for(command_options = server_options; command_options->name != NULL;
2443         command_options++) {
2444         nb_server_options++;
2445     }
2446     config_options = alloc((first+nb_server_options+1)*SIZEOF(char *));
2447     for(command_options = server_options,
2448         config_option = config_options + first;
2449         command_options->name != NULL; command_options++) {
2450         *config_option = vstralloc("-o", command_options->name, "=",
2451                                    command_options->value, NULL);
2452         config_option++;
2453     }
2454     *config_option = NULL;
2455     return(config_options);
2456 }
2457
2458 void
2459 report_bad_conf_arg(void)
2460 {
2461     command_option_t *command_option;
2462
2463     for(command_option = server_options; command_option->name != NULL;
2464                                                         command_option++) {
2465         if(command_option->used == 0) {
2466             fprintf(stderr,"argument -o%s=%s not used\n",
2467                     command_option->name, command_option->value);
2468         }
2469     }
2470 }
2471
2472 void
2473 free_server_config(void)
2474 {
2475     holdingdisk_t    *hp, *hpnext;
2476     dumptype_t       *dp, *dpnext;
2477     tapetype_t       *tp, *tpnext;
2478     interface_t      *ip, *ipnext;
2479     command_option_t *server_option;
2480     int               i;
2481
2482     for(hp=holdingdisks; hp != NULL; hp = hpnext) {
2483         amfree(hp->name);
2484         for(i=0; i<HOLDING_HOLDING-1; i++) {
2485            free_val_t(&hp->value[i]);
2486         }
2487         hpnext = hp->next;
2488         amfree(hp);
2489     }
2490
2491     for(dp=dumplist; dp != NULL; dp = dpnext) {
2492         amfree(dp->name);
2493         for(i=0; i<DUMPTYPE_DUMPTYPE-1; i++) {
2494            free_val_t(&dp->value[i]);
2495         }
2496         dpnext = dp->next;
2497         amfree(dp);
2498     }
2499
2500     for(tp=tapelist; tp != NULL; tp = tpnext) {
2501         amfree(tp->name);
2502         for(i=0; i<TAPETYPE_TAPETYPE-1; i++) {
2503            free_val_t(&tp->value[i]);
2504         }
2505         tpnext = tp->next;
2506         amfree(tp);
2507     }
2508
2509     for(ip=interface_list; ip != NULL; ip = ipnext) {
2510         amfree(ip->name);
2511         for(i=0; i<INTER_INTER-1; i++) {
2512            free_val_t(&ip->value[i]);
2513         }
2514         ipnext = ip->next;
2515         amfree(ip);
2516     }
2517
2518     if(server_options) {
2519         for(server_option = server_options; server_option->name != NULL;
2520                                                 server_option++) {
2521             amfree(server_option->name);
2522             amfree(server_option->value);
2523         }
2524         amfree(server_options);
2525     }
2526
2527     for(i=0; i<CNF_CNF-1; i++)
2528         free_val_t(&server_conf[i]);
2529 }