Imported Upstream version 2.5.1p1
[debian/amanda] / common-src / util.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1999 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  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /*
27  * $Id: util.c,v 1.42.2.4 2006/09/21 11:12:21 martinea Exp $
28  */
29
30 #include "amanda.h"
31 #include "util.h"
32 #include "arglist.h"
33 #include "clock.h"
34
35 int allow_overwrites;
36 int token_pushed;
37
38 tok_t tok, pushed_tok;
39 val_t tokenval;
40 keytab_t *keytable;
41
42 int conf_line_num, got_parserror;
43 FILE *conf_conf = (FILE *)NULL;
44 char *conf_confname = NULL;
45 char *conf_line = NULL;
46 char *conf_char = NULL;
47
48 /*#define NET_READ_DEBUG*/
49
50 #ifdef NET_READ_DEBUG
51 #define netprintf(x)    dbprintf(x)
52 #else
53 #define netprintf(x)
54 #endif
55
56 static int make_socket(void);
57 static int connect_port(struct sockaddr_in *addrp, in_port_t port, char *proto,
58                         struct sockaddr_in *svaddr, int nonblock);
59
60 int conftoken_getc(void);
61 int conftoken_ungetc(int c);
62
63 /*
64  * Keep calling read() until we've read buflen's worth of data, or EOF,
65  * or we get an error.
66  *
67  * Returns the number of bytes read, 0 on EOF, or negative on error.
68  */
69 ssize_t
70 fullread(
71     int         fd,
72     void *      vbuf,
73     size_t      buflen)
74 {
75     ssize_t nread, tot = 0;
76     char *buf = vbuf;   /* cast to char so we can ++ it */
77
78     while (buflen > 0) {
79         nread = read(fd, buf, buflen);
80         if (nread < 0) {
81             if ((errno == EINTR) || (errno == EAGAIN))
82                 continue;
83             return ((tot > 0) ? tot : -1);
84         }
85
86         if (nread == 0)
87             break;
88
89         tot += nread;
90         buf += nread;
91         buflen -= nread;
92     }
93     return (tot);
94 }
95
96 /*
97  * Keep calling write() until we've written buflen's worth of data,
98  * or we get an error.
99  *
100  * Returns the number of bytes written, or negative on error.
101  */
102 ssize_t
103 fullwrite(
104     int         fd,
105     const void *vbuf,
106     size_t      buflen)
107 {
108     ssize_t nwritten, tot = 0;
109     const char *buf = vbuf;     /* cast to char so we can ++ it */
110
111     while (buflen > 0) {
112         nwritten = write(fd, buf, buflen);
113         if (nwritten < 0) {
114             if ((errno == EINTR) || (errno == EAGAIN))
115                 continue;
116             return ((tot > 0) ? tot : -1);
117         }
118         tot += nwritten;
119         buf += nwritten;
120         buflen -= nwritten;
121     }
122     return (tot);
123 }
124
125 static int
126 make_socket(void)
127 {
128     int s;
129     int save_errno;
130 #if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR)
131     int on=1;
132     int r;
133 #endif
134
135     if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
136         save_errno = errno;
137         dbprintf(("%s: make_socket: socket() failed: %s\n",
138                   debug_prefix(NULL),
139                   strerror(save_errno)));
140         errno = save_errno;
141         return -1;
142     }
143     if (s < 0 || s >= (int)FD_SETSIZE) {
144         aclose(s);
145         errno = EMFILE;                         /* out of range */
146         return -1;
147     }
148
149 #ifdef USE_REUSEADDR
150     r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
151     if (r < 0) {
152         save_errno = errno;
153         dbprintf(("%s: stream_server: setsockopt(SO_REUSEADDR) failed: %s\n",
154                   debug_prefix(NULL),
155                   strerror(errno)));
156         errno = save_errno;
157     }
158 #endif
159
160 #ifdef SO_KEEPALIVE
161     r = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
162                    (void *)&on, SIZEOF(on));
163     if (r == -1) {
164         save_errno = errno;
165         dbprintf(("%s: make_socket: setsockopt() failed: %s\n",
166                   debug_prefix(NULL),
167                   strerror(save_errno)));
168         aclose(s);
169         errno = save_errno;
170         return -1;
171     }
172 #endif
173
174     return s;
175 }
176
177 /* addrp is my address */
178 /* svaddr is the address of the remote machine */
179 /* return socket on success */
180 /* return -1     on failure */
181 int
182 connect_portrange(
183     struct sockaddr_in *addrp,
184     in_port_t           first_port,
185     in_port_t           last_port,
186     char *              proto,
187     struct sockaddr_in *svaddr,
188     int                 nonblock)
189 {
190     int                 s;
191     in_port_t           port;
192     static in_port_t    port_in_use[1024];
193     static int          nb_port_in_use = 0;
194     int                 i;
195
196     assert(first_port <= last_port);
197
198     /* Try a port already used */
199     for(i=0; i < nb_port_in_use; i++) {
200         port = port_in_use[i];
201         if(port >= first_port && port <= last_port) {
202             s = connect_port(addrp, port, proto, svaddr, nonblock);
203             if(s == -2) return -1;
204             if(s > 0) {
205                 return s;
206             }
207         }
208     }
209
210     /* Try a port in the range */
211     for (port = first_port; port <= last_port; port++) {
212         s = connect_port(addrp, port, proto, svaddr, nonblock);
213         if(s == -2) return -1;
214         if(s > 0) {
215             port_in_use[nb_port_in_use++] = port;
216             return s;
217         }
218     }
219
220     dbprintf(("%s: connect_portrange: all ports between %d and %d busy\n",
221               debug_prefix_time(NULL),
222               first_port,
223               last_port));
224     errno = EAGAIN;
225     return -1;
226 }
227
228 /* addrp is my address */
229 /* svaddr is the address of the remote machine */
230 /* return -2: Don't try again */
231 /* return -1: Try with another port */
232 /* return >0: this is the connected socket */
233 int
234 connect_port(
235     struct sockaddr_in *addrp,
236     in_port_t           port,
237     char *              proto,
238     struct sockaddr_in *svaddr,
239     int                 nonblock)
240 {
241     int                 save_errno;
242     struct servent *    servPort;
243     socklen_t           len;
244     int                 s;
245
246     servPort = getservbyport((int)htons(port), proto);
247     if (servPort != NULL && !strstr(servPort->s_name, "amanda")) {
248         dbprintf(("%s: connect_port: Skip port %d: Owned by %s.\n",
249                   debug_prefix_time(NULL), port, servPort->s_name));
250         return -1;
251     }
252
253     if(servPort == NULL)
254         dbprintf(("%s: connect_port: Try  port %d: Available   - \n",
255                   debug_prefix_time(NULL), port));
256     else {
257         dbprintf(("%s: connect_port: Try  port %d: Owned by %s - \n",
258                   debug_prefix_time(NULL), port, servPort->s_name));
259     }
260
261     if ((s = make_socket()) == -1) return -2;
262
263     addrp->sin_port = (in_port_t)htons(port);
264
265     if (bind(s, (struct sockaddr *)addrp, sizeof(*addrp)) != 0) {
266         save_errno = errno;
267         aclose(s);
268         if (save_errno != EADDRINUSE) {
269             dbprintf(("errno %d strerror %s\n",
270                       errno, strerror(errno)));
271             errno = save_errno;
272             return -2;
273         }
274         errno = save_errno;
275         return -1;
276     }
277
278     /* find out what port was actually used */
279
280     len = sizeof(*addrp);
281     if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) {
282         save_errno = errno;
283         dbprintf(("%s: connect_port: getsockname() failed: %s\n",
284                   debug_prefix(NULL),
285                   strerror(save_errno)));
286         aclose(s);
287         errno = save_errno;
288         return -1;
289     }
290
291     if (nonblock)
292         fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0)|O_NONBLOCK);
293     if (connect(s, (struct sockaddr *)svaddr,
294                 (socklen_t)sizeof(*svaddr)) == -1 && !nonblock) {
295         save_errno = errno;
296         dbprintf(("%s: connect_portrange: connect from %s.%d failed\n",
297                   debug_prefix_time(NULL),
298                   inet_ntoa(addrp->sin_addr),
299                   ntohs(addrp->sin_port),
300                   strerror(save_errno)));
301         dbprintf(("%s: connect_portrange: connect to %s.%d failed: %s\n",
302                   debug_prefix_time(NULL),
303                   inet_ntoa(svaddr->sin_addr),
304                   ntohs(svaddr->sin_port),
305                   strerror(save_errno)));
306         aclose(s);
307         errno = save_errno;
308         if (save_errno == ECONNREFUSED ||
309             save_errno == EHOSTUNREACH ||
310             save_errno == ENETUNREACH ||
311             save_errno == ETIMEDOUT)  {
312             return -2   ;
313         }
314         return -1;
315     }
316
317     dbprintf(("%s: connected to %s.%d\n",
318               debug_prefix_time(NULL),
319               inet_ntoa(svaddr->sin_addr),
320               ntohs(svaddr->sin_port)));
321     dbprintf(("%s: our side is %s.%d\n",
322               debug_prefix(NULL),
323               inet_ntoa(addrp->sin_addr),
324               ntohs(addrp->sin_port)));
325     return s;
326 }
327
328
329 /*
330  * Bind to a port in the given range.  Takes a begin,end pair of port numbers.
331  *
332  * Returns negative on error (EGAIN if all ports are in use).  Returns 0
333  * on success.
334  */
335 int
336 bind_portrange(
337     int                 s,
338     struct sockaddr_in *addrp,
339     in_port_t           first_port,
340     in_port_t           last_port,
341     char *              proto)
342 {
343     in_port_t port;
344     in_port_t cnt;
345     struct servent *servPort;
346     const in_port_t num_ports = (in_port_t)(last_port - first_port + 1);
347
348     assert(first_port <= last_port);
349
350     /*
351      * We pick a different starting port based on our pid and the current
352      * time to avoid always picking the same reserved port twice.
353      */
354     port = (in_port_t)(((getpid() + time(0)) % num_ports) + first_port);
355
356     /*
357      * Scan through the range, trying all available ports that are either 
358      * not taken in /etc/services or registered for *amanda*.  Wrap around
359      * if we don't happen to start at the beginning.
360      */
361     for (cnt = 0; cnt < num_ports; cnt++) {
362         servPort = getservbyport((int)htons(port), proto);
363         if ((servPort == NULL) || strstr(servPort->s_name, "amanda")) {
364             if (servPort == NULL) {
365                 dbprintf(("%s: bind_portrange2: Try  port %d: Available   - ",
366                       debug_prefix_time(NULL), port));
367             } else {
368                 dbprintf(("%s: bind_portrange2: Try  port %d: Owned by %s - ",
369                       debug_prefix_time(NULL), port, servPort->s_name));
370             }
371             addrp->sin_port = (in_port_t)htons(port);
372             if (bind(s, (struct sockaddr *)addrp, (socklen_t)sizeof(*addrp)) >= 0) {
373                 dbprintf(("Success\n"));
374                 return 0;
375             }
376             dbprintf(("%s\n", strerror(errno)));
377         } else {
378                 dbprintf(("%s: bind_portrange2: Skip port %d: Owned by %s.\n",
379                       debug_prefix_time(NULL), port, servPort->s_name));
380         }
381         if (++port > last_port)
382             port = first_port;
383     }
384     dbprintf(("%s: bind_portrange: all ports between %d and %d busy\n",
385                   debug_prefix_time(NULL),
386                   first_port,
387                   last_port));
388     errno = EAGAIN;
389     return -1;
390 }
391
392 /*
393  * Construct a datestamp (YYYYMMDD) from a time_t.
394  */
395 char *
396 construct_datestamp(
397     time_t *t)
398 {
399     struct tm *tm;
400     char datestamp[3 * NUM_STR_SIZE];
401     time_t when;
402
403     if (t == NULL) {
404         when = time((time_t *)NULL);
405     } else {
406         when = *t;
407     }
408     tm = localtime(&when);
409     if (!tm)
410         return stralloc("19000101");
411
412     snprintf(datestamp, SIZEOF(datestamp),
413              "%04d%02d%02d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
414     return stralloc(datestamp);
415 }
416
417 /*
418  * Construct a timestamp (YYYYMMDDHHMMSS) from a time_t.
419  */
420 char *
421 construct_timestamp(
422     time_t *t)
423 {
424     struct tm *tm;
425     char timestamp[6 * NUM_STR_SIZE];
426     time_t when;
427
428     if (t == NULL) {
429         when = time((time_t *)NULL);
430     } else {
431         when = *t;
432     }
433     tm = localtime(&when);
434     if (!tm)
435         return stralloc("19000101000000");
436
437     snprintf(timestamp, SIZEOF(timestamp),
438              "%04d%02d%02d%02d%02d%02d",
439              tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
440              tm->tm_hour, tm->tm_min, tm->tm_sec);
441     return stralloc(timestamp);
442 }
443
444
445 int
446 needs_quotes(
447     const char * str)
448 {
449     return (match("[ \t\f\r\n\"]", str) != 0);
450 }
451
452
453 /*
454  * For backward compatibility we are trying for minimal quoting.
455  * We only quote a string if it contains whitespace or is misquoted...
456  */
457
458 char *
459 quote_string(
460     const char *str)
461 {
462     char *  s;
463     char *  ret;
464
465     if ((str == NULL) || (*str == '\0')) {
466         ret = stralloc("\"\"");
467     } else if ((match("[\\\"[:space:][:cntrl:]]", str)) == 0) {
468         /*
469          * String does not need to be quoted since it contains
470          * neither whitespace, control or quote characters.
471          */
472         ret = stralloc(str);
473     } else {
474         /*
475          * Allocate maximum possible string length.
476          * (a string of all quotes plus room for leading ", trailing " and NULL)
477          */
478         ret = s = alloc((strlen(str) * 2) + 2 + 1);
479         *(s++) = '"';
480         while (*str != '\0') {
481             if (*str == '\t') {
482                 *(s++) = '\\';
483                 *(s++) = 't';
484                 str++;
485                 continue;
486             } else if (*str == '\n') {
487                 *(s++) = '\\';
488                 *(s++) = 'n';
489                 str++;
490                 continue;
491             } else if (*str == '\r') {
492                 *(s++) = '\\';
493                 *(s++) = 'r';
494                 str++;
495                 continue;
496             } else if (*str == '\f') {
497                 *(s++) = '\\';
498                 *(s++) = 'f';
499                 str++;
500                 continue;
501             }
502             if (*str == '"')
503                 *(s++) = '\\';
504             *(s++) = *(str++);
505         }
506         *(s++) = '"';
507         *s = '\0';
508     }
509     return (ret);
510 }
511
512
513 char *
514 unquote_string(
515     const char *str)
516 {
517     char * ret;
518
519     if ((str == NULL) || (*str == '\0')) {
520         ret = stralloc("");
521     } else {
522         char * in;
523         char * out;
524
525         ret = in = out = stralloc(str);
526         while (*in != '\0') {
527             if (*in == '"') {
528                 in++;
529                 continue;
530             }
531
532             if (*in == '\\') {
533                 in++;
534                 if (*in == 'n') {
535                     in++;
536                     *(out++) = '\n';
537                     continue;
538                 } else if (*in == 't') {
539                     in++;
540                     *(out++) = '\t';
541                     continue;
542                 } else if (*in == 'r') {
543                     in++;
544                     *(out++) = '\r';
545                     continue;
546                 } else if (*in == 'f') {
547                     in++;
548                     *(out++) = '\f';
549                     continue;
550                 }
551             }
552             *(out++) = *(in++);
553         }
554         *out = '\0';
555     }
556     return (ret);
557 }
558
559 char *
560 sanitize_string(
561     const char *str)
562 {
563     char * s;
564     char * ret;
565
566     if ((str == NULL) || (*str == '\0')) {
567         ret = stralloc("");
568     } else {
569         ret = stralloc(str);
570         for (s = ret; *s != '\0'; s++) {
571             if (iscntrl(*s))
572                 *s = '?';
573         }
574     }
575     return (ret);
576 }
577
578 char *
579 strquotedstr(void)
580 {
581     char *  tok = strtok(NULL, " ");
582
583     if ((tok != NULL) && (tok[0] == '"')) {
584         char *  t;
585         size_t  len;
586
587         len = strlen(tok);
588         do {
589             t = strtok(NULL, " ");
590             tok[len] = ' ';
591             len = strlen(tok);
592         } while ((t != NULL) &&
593                  (tok[len - 1] != '"') && (tok[len - 2] != '\\'));
594     }
595     return tok;
596 }
597
598 ssize_t
599 hexdump(
600     const char *buffer,
601     size_t      len)
602 {
603     ssize_t rc = -1;
604
605     FILE *stream = popen("od -w10 -c -x -", "w");
606         
607     if (stream != NULL) {
608         fflush(stdout);
609         rc = (ssize_t)fwrite(buffer, len, 1, stream);
610         if (ferror(stream))
611             rc = -1;
612         fclose(stream);
613     }
614     return rc;
615 }
616
617 /*
618    Return 0 if the following characters are present
619    * ( ) < > [ ] , ; : ! $ \ / "
620    else returns 1
621 */
622
623 int
624 validate_mailto(
625     const char *mailto)
626 {
627     return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto);
628 }
629
630
631 t_conf_var *
632 get_np(
633     t_conf_var  *get_var,
634     int         parm)
635 {
636     t_conf_var *np;
637
638     for(np = get_var; np->token != CONF_UNKNOWN; np++) {
639         if(np->parm == parm)
640             break;
641     }
642
643     if(np->token == CONF_UNKNOWN) {
644         error("error [unknown getconf_np parm: %d]", parm);
645         /* NOTREACHED */
646     }
647     return np;
648 }
649
650 void
651 get_simple(
652     val_t  *var,
653     tok_t  type)
654 {
655     ckseen(&var->seen);
656
657     switch(type) {
658     case CONF_STRING:
659     case CONF_IDENT:
660         get_conftoken(type);
661         var->v.s = newstralloc(var->v.s, tokenval.v.s);
662         malloc_mark(var->v.s);
663         break;
664
665     case CONF_INT:
666         var->v.i = get_int();
667         break;
668
669     case CONF_LONG:
670         var->v.l = get_long();
671         break;
672
673     case CONF_SIZE:
674         var->v.size = get_size();
675         break;
676
677     case CONF_AM64:
678         var->v.am64 = get_am64_t();
679         break;
680
681     case CONF_BOOL:
682         var->v.i = get_bool();
683         break;
684
685     case CONF_REAL:
686         get_conftoken(CONF_REAL);
687         var->v.r = tokenval.v.r;
688         break;
689
690     case CONF_TIME:
691         var->v.t = get_time();
692         break;
693
694     default:
695         error("error [unknown get_simple type: %d]", type);
696         /* NOTREACHED */
697     }
698     return;
699 }
700
701 time_t
702 get_time(void)
703 {
704     time_t hhmm;
705
706     get_conftoken(CONF_ANY);
707     switch(tok) {
708     case CONF_INT:
709 #if SIZEOF_TIME_T < SIZEOF_INT
710         if ((off_t)tokenval.v.i >= (off_t)TIME_MAX)
711             conf_parserror("value too large");
712 #endif
713         hhmm = (time_t)tokenval.v.i;
714         break;
715
716     case CONF_LONG:
717 #if SIZEOF_TIME_T < SIZEOF_LONG
718         if ((off_t)tokenval.v.l >= (off_t)TIME_MAX)
719             conf_parserror("value too large");
720 #endif
721         hhmm = (time_t)tokenval.v.l;
722         break;
723
724     case CONF_SIZE:
725 #if SIZEOF_TIME_T < SIZEOF_SSIZE_T
726         if ((off_t)tokenval.v.size >= (off_t)TIME_MAX)
727             conf_parserror("value too large");
728 #endif
729         hhmm = (time_t)tokenval.v.size;
730         break;
731
732     case CONF_AM64:
733 #if SIZEOF_TIME_T < SIZEOF_LONG_LONG
734         if ((off_t)tokenval.v.am64 >= (off_t)TIME_MAX)
735             conf_parserror("value too large");
736 #endif
737         hhmm = (time_t)tokenval.v.am64;
738         break;
739
740     case CONF_AMINFINITY:
741         hhmm = TIME_MAX;
742         break;
743
744     default:
745         conf_parserror("a time is expected");
746         hhmm = 0;
747         break;
748     }
749     return hhmm;
750 }
751
752 keytab_t numb_keytable[] = {
753     { "B", CONF_MULT1 },
754     { "BPS", CONF_MULT1 },
755     { "BYTE", CONF_MULT1 },
756     { "BYTES", CONF_MULT1 },
757     { "DAY", CONF_MULT1 },
758     { "DAYS", CONF_MULT1 },
759     { "INF", CONF_AMINFINITY },
760     { "K", CONF_MULT1K },
761     { "KB", CONF_MULT1K },
762     { "KBPS", CONF_MULT1K },
763     { "KBYTE", CONF_MULT1K },
764     { "KBYTES", CONF_MULT1K },
765     { "KILOBYTE", CONF_MULT1K },
766     { "KILOBYTES", CONF_MULT1K },
767     { "KPS", CONF_MULT1K },
768     { "M", CONF_MULT1M },
769     { "MB", CONF_MULT1M },
770     { "MBPS", CONF_MULT1M },
771     { "MBYTE", CONF_MULT1M },
772     { "MBYTES", CONF_MULT1M },
773     { "MEG", CONF_MULT1M },
774     { "MEGABYTE", CONF_MULT1M },
775     { "MEGABYTES", CONF_MULT1M },
776     { "G", CONF_MULT1G },
777     { "GB", CONF_MULT1G },
778     { "GBPS", CONF_MULT1G },
779     { "GBYTE", CONF_MULT1G },
780     { "GBYTES", CONF_MULT1G },
781     { "GIG", CONF_MULT1G },
782     { "GIGABYTE", CONF_MULT1G },
783     { "GIGABYTES", CONF_MULT1G },
784     { "MPS", CONF_MULT1M },
785     { "TAPE", CONF_MULT1 },
786     { "TAPES", CONF_MULT1 },
787     { "WEEK", CONF_MULT7 },
788     { "WEEKS", CONF_MULT7 },
789     { NULL, CONF_IDENT }
790 };
791
792 int
793 get_int(void)
794 {
795     int val;
796     keytab_t *save_kt;
797
798     save_kt = keytable;
799     keytable = numb_keytable;
800
801     get_conftoken(CONF_ANY);
802     switch(tok) {
803     case CONF_INT:
804         val = tokenval.v.i;
805         break;
806
807     case CONF_LONG:
808 #if SIZEOF_INT < SIZEOF_LONG
809         if ((off_t)tokenval.v.l > (off_t)INT_MAX)
810             conf_parserror("value too large");
811         if ((off_t)tokenval.v.l < (off_t)INT_MIN)
812             conf_parserror("value too small");
813 #endif
814         val = (int)tokenval.v.l;
815         break;
816
817     case CONF_SIZE:
818 #if SIZEOF_INT < SIZEOF_SSIZE_T
819         if ((off_t)tokenval.v.size > (off_t)INT_MAX)
820             conf_parserror("value too large");
821         if ((off_t)tokenval.v.size < (off_t)INT_MIN)
822             conf_parserror("value too small");
823 #endif
824         val = (int)tokenval.v.size;
825         break;
826
827     case CONF_AM64:
828 #if SIZEOF_INT < SIZEOF_LONG_LONG
829         if (tokenval.v.am64 > (off_t)INT_MAX)
830             conf_parserror("value too large");
831         if (tokenval.v.am64 < (off_t)INT_MIN)
832             conf_parserror("value too small");
833 #endif
834         val = (int)tokenval.v.am64;
835         break;
836
837     case CONF_AMINFINITY:
838         val = INT_MAX;
839         break;
840
841     default:
842         conf_parserror("an int is expected");
843         val = 0;
844         break;
845     }
846
847     /* get multiplier, if any */
848     get_conftoken(CONF_ANY);
849     switch(tok) {
850     case CONF_NL:                       /* multiply by one */
851     case CONF_END:
852     case CONF_MULT1:
853     case CONF_MULT1K:
854         break;
855
856     case CONF_MULT7:
857         if (val > (INT_MAX / 7))
858             conf_parserror("value too large");
859         if (val < (INT_MIN / 7))
860             conf_parserror("value too small");
861         val *= 7;
862         break;
863
864     case CONF_MULT1M:
865         if (val > (INT_MAX / 1024))
866             conf_parserror("value too large");
867         if (val < (INT_MIN / 1024))
868             conf_parserror("value too small");
869         val *= 1024;
870         break;
871
872     case CONF_MULT1G:
873         if (val > (INT_MAX / (1024 * 1024)))
874             conf_parserror("value too large");
875         if (val < (INT_MIN / (1024 * 1024)))
876             conf_parserror("value too small");
877         val *= 1024 * 1024;
878         break;
879
880     default:    /* it was not a multiplier */
881         unget_conftoken();
882         break;
883     }
884
885     keytable = save_kt;
886     return val;
887 }
888
889 long
890 get_long(void)
891 {
892     long val;
893     keytab_t *save_kt;
894
895     save_kt = keytable;
896     keytable = numb_keytable;
897
898     get_conftoken(CONF_ANY);
899
900     switch(tok) {
901     case CONF_LONG:
902         val = tokenval.v.l;
903         break;
904
905     case CONF_INT:
906 #if SIZEOF_LONG < SIZEOF_INT
907         if ((off_t)tokenval.v.i > (off_t)LONG_MAX)
908             conf_parserror("value too large");
909         if ((off_t)tokenval.v.i < (off_t)LONG_MIN)
910             conf_parserror("value too small");
911 #endif
912         val = (long)tokenval.v.i;
913         break;
914
915     case CONF_SIZE:
916 #if SIZEOF_LONG < SIZEOF_SSIZE_T
917         if ((off_t)tokenval.v.size > (off_t)LONG_MAX)
918             conf_parserror("value too large");
919         if ((off_t)tokenval.v.size < (off_t)LONG_MIN)
920             conf_parserror("value too small");
921 #endif
922         val = (long)tokenval.v.size;
923         break;
924
925     case CONF_AM64:
926 #if SIZEOF_LONG < SIZEOF_LONG_LONG
927         if (tokenval.v.am64 > (off_t)LONG_MAX)
928             conf_parserror("value too large");
929         if (tokenval.v.am64 < (off_t)LONG_MIN)
930             conf_parserror("value too small");
931 #endif
932         val = (long)tokenval.v.am64;
933         break;
934
935     case CONF_AMINFINITY:
936         val = (long)LONG_MAX;
937         break;
938
939     default:
940         conf_parserror("a long is expected");
941         val = 0;
942         break;
943     }
944
945     /* get multiplier, if any */
946     get_conftoken(CONF_ANY);
947
948     switch(tok) {
949     case CONF_NL:                       /* multiply by one */
950     case CONF_MULT1:
951     case CONF_MULT1K:
952         break;
953
954     case CONF_MULT7:
955         if (val > (LONG_MAX / 7L))
956             conf_parserror("value too large");
957         if (val < (LONG_MIN / 7L))
958             conf_parserror("value too small");
959         val *= 7L;
960         break;
961
962     case CONF_MULT1M:
963         if (val > (LONG_MAX / 1024L))
964             conf_parserror("value too large");
965         if (val < (LONG_MIN / 1024L))
966             conf_parserror("value too small");
967         val *= 1024L;
968         break;
969
970     case CONF_MULT1G:
971         if (val > (LONG_MAX / (1024L * 1024L)))
972             conf_parserror("value too large");
973         if (val < (LONG_MIN / (1024L * 1024L)))
974             conf_parserror("value too small");
975         val *= 1024L * 1024L;
976         break;
977
978     default:    /* it was not a multiplier */
979         unget_conftoken();
980         break;
981     }
982
983     keytable = save_kt;
984     return val;
985 }
986
987 ssize_t
988 get_size(void)
989 {
990     ssize_t val;
991     keytab_t *save_kt;
992
993     save_kt = keytable;
994     keytable = numb_keytable;
995
996     get_conftoken(CONF_ANY);
997
998     switch(tok) {
999     case CONF_SIZE:
1000         val = tokenval.v.size;
1001         break;
1002
1003     case CONF_INT:
1004 #if SIZEOF_SIZE_T < SIZEOF_INT
1005         if ((off_t)tokenval.v.i > (off_t)SSIZE_MAX)
1006             conf_parserror("value too large");
1007         if ((off_t)tokenval.v.i < (off_t)SSIZE_MIN)
1008             conf_parserror("value too small");
1009 #endif
1010         val = (ssize_t)tokenval.v.i;
1011         break;
1012
1013     case CONF_LONG:
1014 #if SIZEOF_SIZE_T < SIZEOF_LONG
1015         if ((off_t)tokenval.v.l > (off_t)SSIZE_MAX)
1016             conf_parserror("value too large");
1017         if ((off_t)tokenval.v.l < (off_t)SSIZE_MIN)
1018             conf_parserror("value too small");
1019 #endif
1020         val = (ssize_t)tokenval.v.l;
1021         break;
1022
1023     case CONF_AM64:
1024 #if SIZEOF_SIZE_T < SIZEOF_LONG_LONG
1025         if (tokenval.v.am64 > (off_t)SSIZE_MAX)
1026             conf_parserror("value too large");
1027         if (tokenval.v.am64 < (off_t)SSIZE_MIN)
1028             conf_parserror("value too small");
1029 #endif
1030         val = (ssize_t)tokenval.v.am64;
1031         break;
1032
1033     case CONF_AMINFINITY:
1034         val = (ssize_t)SSIZE_MAX;
1035         break;
1036
1037     default:
1038         conf_parserror("an integer is expected");
1039         val = 0;
1040         break;
1041     }
1042
1043     /* get multiplier, if any */
1044     get_conftoken(CONF_ANY);
1045
1046     switch(tok) {
1047     case CONF_NL:                       /* multiply by one */
1048     case CONF_MULT1:
1049     case CONF_MULT1K:
1050         break;
1051
1052     case CONF_MULT7:
1053         if (val > (ssize_t)(SSIZE_MAX / 7))
1054             conf_parserror("value too large");
1055         if (val < (ssize_t)(SSIZE_MIN / 7))
1056             conf_parserror("value too small");
1057         val *= (ssize_t)7;
1058         break;
1059
1060     case CONF_MULT1M:
1061         if (val > (ssize_t)(SSIZE_MAX / (ssize_t)1024))
1062             conf_parserror("value too large");
1063         if (val < (ssize_t)(SSIZE_MIN / (ssize_t)1024))
1064             conf_parserror("value too small");
1065         val *= (ssize_t)1024;
1066         break;
1067
1068     case CONF_MULT1G:
1069         if (val > (ssize_t)(SSIZE_MAX / (1024 * 1024)))
1070             conf_parserror("value too large");
1071         if (val < (ssize_t)(SSIZE_MIN / (1024 * 1024)))
1072             conf_parserror("value too small");
1073         val *= (ssize_t)(1024 * 1024);
1074         break;
1075
1076     default:    /* it was not a multiplier */
1077         unget_conftoken();
1078         break;
1079     }
1080
1081     keytable = save_kt;
1082     return val;
1083 }
1084
1085 off_t
1086 get_am64_t(void)
1087 {
1088     off_t val;
1089     keytab_t *save_kt;
1090
1091     save_kt = keytable;
1092     keytable = numb_keytable;
1093
1094     get_conftoken(CONF_ANY);
1095
1096     switch(tok) {
1097     case CONF_INT:
1098         val = (off_t)tokenval.v.i;
1099         break;
1100
1101     case CONF_LONG:
1102         val = (off_t)tokenval.v.l;
1103         break;
1104
1105     case CONF_SIZE:
1106         val = (off_t)tokenval.v.size;
1107         break;
1108
1109     case CONF_AM64:
1110         val = tokenval.v.am64;
1111         break;
1112
1113     case CONF_AMINFINITY:
1114         val = AM64_MAX;
1115         break;
1116
1117     default:
1118         conf_parserror("an am64 is expected %d", tok);
1119         val = 0;
1120         break;
1121     }
1122
1123     /* get multiplier, if any */
1124     get_conftoken(CONF_ANY);
1125
1126     switch(tok) {
1127     case CONF_NL:                       /* multiply by one */
1128     case CONF_MULT1:
1129     case CONF_MULT1K:
1130         break;
1131
1132     case CONF_MULT7:
1133         if (val > AM64_MAX/7 || val < AM64_MIN/7)
1134             conf_parserror("value too large");
1135         val *= 7;
1136         break;
1137
1138     case CONF_MULT1M:
1139         if (val > AM64_MAX/1024 || val < AM64_MIN/1024)
1140             conf_parserror("value too large");
1141         val *= 1024;
1142         break;
1143
1144     case CONF_MULT1G:
1145         if (val > AM64_MAX/(1024*1024) || val < AM64_MIN/(1024*1024))
1146             conf_parserror("value too large");
1147         val *= 1024*1024;
1148         break;
1149
1150     default:    /* it was not a multiplier */
1151         unget_conftoken();
1152         break;
1153     }
1154
1155     keytable = save_kt;
1156
1157     return val;
1158 }
1159
1160 keytab_t bool_keytable[] = {
1161     { "Y", CONF_ATRUE },
1162     { "YES", CONF_ATRUE },
1163     { "T", CONF_ATRUE },
1164     { "TRUE", CONF_ATRUE },
1165     { "ON", CONF_ATRUE },
1166     { "N", CONF_AFALSE },
1167     { "NO", CONF_AFALSE },
1168     { "F", CONF_AFALSE },
1169     { "FALSE", CONF_AFALSE },
1170     { "OFF", CONF_AFALSE },
1171     { NULL, CONF_IDENT }
1172 };
1173
1174 int
1175 get_bool(void)
1176 {
1177     int val;
1178     keytab_t *save_kt;
1179
1180     save_kt = keytable;
1181     keytable = bool_keytable;
1182
1183     get_conftoken(CONF_ANY);
1184
1185     switch(tok) {
1186     case CONF_INT:
1187         if (tokenval.v.i != 0)
1188             val = 1;
1189         else
1190             val = 0;
1191         break;
1192
1193     case CONF_LONG:
1194         if (tokenval.v.l != 0L)
1195             val = 1;
1196         else
1197             val = 0;
1198         break;
1199
1200     case CONF_SIZE:
1201         if (tokenval.v.size != (size_t)0)
1202             val = 1;
1203         else
1204             val = 0;
1205         break;
1206
1207     case CONF_AM64:
1208         if (tokenval.v.am64 != (off_t)0)
1209             val = 1;
1210         else
1211             val = 0;
1212         break;
1213
1214     case CONF_ATRUE:
1215         val = 1;
1216         break;
1217
1218     case CONF_AFALSE:
1219         val = 0;
1220         break;
1221
1222     case CONF_NL:
1223         unget_conftoken();
1224         val = 2; /* no argument - most likely TRUE */
1225         break;
1226     default:
1227         unget_conftoken();
1228         val = 3; /* a bad argument - most likely TRUE */
1229         conf_parserror("YES, NO, TRUE, FALSE, ON, OFF expected");
1230         break;
1231     }
1232
1233     keytable = save_kt;
1234     return val;
1235 }
1236
1237 void
1238 ckseen(
1239     int *seen)
1240 {
1241     if (*seen && !allow_overwrites && conf_line_num != -2) {
1242         conf_parserror("duplicate parameter, prev def on line %d", *seen);
1243     }
1244     *seen = conf_line_num;
1245 }
1246
1247 printf_arglist_function(void conf_parserror, const char *, format)
1248 {
1249     va_list argp;
1250
1251     /* print error message */
1252
1253     if(conf_line)
1254         fprintf(stderr, "argument \"%s\": ", conf_line);
1255     else
1256         fprintf(stderr, "\"%s\", line %d: ", conf_confname, conf_line_num);
1257     arglist_start(argp, format);
1258     vfprintf(stderr, format, argp);
1259     arglist_end(argp);
1260     fputc('\n', stderr);
1261
1262     got_parserror = 1;
1263 }
1264
1265 tok_t
1266 lookup_keyword(
1267     char *      str)
1268 {
1269     keytab_t *kwp;
1270
1271     /* switch to binary search if performance warrants */
1272
1273     for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1274         if (strcmp(kwp->keyword, str) == 0) break;
1275     }
1276     return kwp->token;
1277 }
1278
1279 char tkbuf[4096];
1280
1281 /* push the last token back (can only unget ANY tokens) */
1282 void
1283 unget_conftoken(void)
1284 {
1285     token_pushed = 1;
1286     pushed_tok = tok;
1287     tok = CONF_UNKNOWN;
1288     return;
1289 }
1290
1291 int
1292 conftoken_getc(void)
1293 {
1294     if(conf_line == NULL)
1295         return getc(conf_conf);
1296     if(*conf_char == '\0')
1297         return -1;
1298     return(*conf_char++);
1299 }
1300
1301 int
1302 conftoken_ungetc(
1303     int c)
1304 {
1305     if(conf_line == NULL)
1306         return ungetc(c, conf_conf);
1307     else if(conf_char > conf_line) {
1308         if(c == -1)
1309             return c;
1310         conf_char--;
1311         if(*conf_char != c) {
1312             error("*conf_char != c   : %c %c", *conf_char, c);
1313             /* NOTREACHED */
1314         }
1315     } else {
1316         error("conf_char == conf_line");
1317         /* NOTREACHED */
1318     }
1319     return c;
1320 }
1321
1322 void
1323 get_conftoken(
1324     tok_t       exp)
1325 {
1326     int ch, d;
1327     off_t am64;
1328     char *buf;
1329     char *tmps;
1330     int token_overflow;
1331     int inquote = 0;
1332     int escape = 0;
1333     int sign;
1334
1335     if (token_pushed) {
1336         token_pushed = 0;
1337         tok = pushed_tok;
1338
1339         /*
1340         ** If it looked like a key word before then look it
1341         ** up again in the current keyword table.
1342         */
1343         switch(tok) {
1344         case CONF_LONG:    case CONF_AM64:    case CONF_SIZE:
1345         case CONF_INT:     case CONF_REAL:    case CONF_STRING:
1346         case CONF_LBRACE:  case CONF_RBRACE:  case CONF_COMMA:
1347         case CONF_NL:      case CONF_END:     case CONF_UNKNOWN:
1348         case CONF_TIME:
1349             break;
1350
1351         default:
1352             if (exp == CONF_IDENT)
1353                 tok = CONF_IDENT;
1354             else
1355                 tok = lookup_keyword(tokenval.v.s);
1356             break;
1357         }
1358     }
1359     else {
1360         ch = conftoken_getc();
1361
1362         while(ch != EOF && ch != '\n' && isspace(ch))
1363             ch = conftoken_getc();
1364         if (ch == '#') {        /* comment - eat everything but eol/eof */
1365             while((ch = conftoken_getc()) != EOF && ch != '\n') {
1366                 (void)ch; /* Quiet empty loop complaints */     
1367             }
1368         }
1369
1370         if (isalpha(ch)) {              /* identifier */
1371             buf = tkbuf;
1372             token_overflow = 0;
1373             do {
1374                 if (islower(ch)) ch = toupper(ch);
1375                 if (buf < tkbuf+sizeof(tkbuf)-1) {
1376                     *buf++ = (char)ch;
1377                 } else {
1378                     *buf = '\0';
1379                     if (!token_overflow) {
1380                         conf_parserror("token too long: %.20s...", tkbuf);
1381                     }
1382                     token_overflow = 1;
1383                 }
1384                 ch = conftoken_getc();
1385             } while(isalnum(ch) || ch == '_' || ch == '-');
1386
1387             if (ch != EOF && conftoken_ungetc(ch) == EOF) {
1388                 if (ferror(conf_conf)) {
1389                     conf_parserror("Pushback of '%c' failed: %s",
1390                                    ch, strerror(ferror(conf_conf)));
1391                 } else {
1392                     conf_parserror("Pushback of '%c' failed: EOF", ch);
1393                 }
1394             }
1395             *buf = '\0';
1396
1397             tokenval.v.s = tkbuf;
1398
1399             if (token_overflow) tok = CONF_UNKNOWN;
1400             else if (exp == CONF_IDENT) tok = CONF_IDENT;
1401             else tok = lookup_keyword(tokenval.v.s);
1402         }
1403         else if (isdigit(ch)) { /* integer */
1404             sign = 1;
1405
1406 negative_number: /* look for goto negative_number below sign is set there */
1407             am64 = 0;
1408             do {
1409                 am64 = am64 * 10 + (ch - '0');
1410                 ch = conftoken_getc();
1411             } while (isdigit(ch));
1412
1413             if (ch != '.') {
1414                 if (exp == CONF_INT) {
1415                     tok = CONF_INT;
1416                     tokenval.v.i = sign * (int)am64;
1417                 } else if (exp == CONF_LONG) {
1418                     tok = CONF_LONG;
1419                     tokenval.v.l = (long)sign * (long)am64;
1420                 } else if (exp != CONF_REAL) {
1421                     tok = CONF_AM64;
1422                     tokenval.v.am64 = (off_t)sign * am64;
1423                 } else {
1424                     /* automatically convert to real when expected */
1425                     tokenval.v.r = (double)sign * (double)am64;
1426                     tok = CONF_REAL;
1427                 }
1428             } else {
1429                 /* got a real number, not an int */
1430                 tokenval.v.r = sign * (double) am64;
1431                 am64 = 0;
1432                 d = 1;
1433                 ch = conftoken_getc();
1434                 while (isdigit(ch)) {
1435                     am64 = am64 * 10 + (ch - '0');
1436                     d = d * 10;
1437                     ch = conftoken_getc();
1438                 }
1439                 tokenval.v.r += sign * ((double)am64) / d;
1440                 tok = CONF_REAL;
1441             }
1442
1443             if (ch != EOF &&  conftoken_ungetc(ch) == EOF) {
1444                 if (ferror(conf_conf)) {
1445                     conf_parserror("Pushback of '%c' failed: %s",
1446                                    ch, strerror(ferror(conf_conf)));
1447                 } else {
1448                     conf_parserror("Pushback of '%c' failed: EOF", ch);
1449                 }
1450             }
1451         } else switch(ch) {
1452         case '"':                       /* string */
1453             buf = tkbuf;
1454             token_overflow = 0;
1455             inquote = 1;
1456             *buf++ = (char)ch;
1457             while (inquote && ((ch = conftoken_getc()) != EOF)) {
1458                 if (ch == '\n') {
1459                     if (!escape)
1460                         break;
1461                     escape = 0;
1462                     buf--; /* Consume escape in buffer */
1463                 } else if (ch == '\\') {
1464                     escape = 1;
1465                 } else {
1466                     if (ch == '"') {
1467                         if (!escape)
1468                             inquote = 0;
1469                     }
1470                     escape = 0;
1471                 }
1472
1473                 if(buf >= &tkbuf[sizeof(tkbuf) - 1]) {
1474                     if (!token_overflow) {
1475                         conf_parserror("string too long: %.20s...", tkbuf);
1476                     }
1477                     token_overflow = 1;
1478                     break;
1479                 }
1480                 *buf++ = (char)ch;
1481             }
1482             *buf = '\0';
1483
1484             /*
1485              * A little manuver to leave a fully unquoted, unallocated  string
1486              * in tokenval.v.s
1487              */
1488             tmps = unquote_string(tkbuf);
1489             strncpy(tkbuf, tmps, sizeof(tkbuf));
1490             amfree(tmps);
1491             tokenval.v.s = tkbuf;
1492
1493             tok = (token_overflow) ? CONF_UNKNOWN :
1494                         (exp == CONF_IDENT) ? CONF_IDENT : CONF_STRING;
1495             break;
1496
1497         case '-':
1498             ch = conftoken_getc();
1499             if (isdigit(ch)) {
1500                 sign = -1;
1501                 goto negative_number;
1502             }
1503             else {
1504                 if (ch != EOF && conftoken_ungetc(ch) == EOF) {
1505                     if (ferror(conf_conf)) {
1506                         conf_parserror("Pushback of '%c' failed: %s",
1507                                        ch, strerror(ferror(conf_conf)));
1508                     } else {
1509                         conf_parserror("Pushback of '%c' failed: EOF", ch);
1510                     }
1511                 }
1512                 tok = CONF_UNKNOWN;
1513             }
1514             break;
1515
1516         case ',':
1517             tok = CONF_COMMA;
1518             break;
1519
1520         case '{':
1521             tok = CONF_LBRACE;
1522             break;
1523
1524         case '}':
1525             tok = CONF_RBRACE;
1526             break;
1527
1528         case '\n':
1529             tok = CONF_NL;
1530             break;
1531
1532         case EOF:
1533             tok = CONF_END;
1534             break;
1535
1536         default:
1537             tok = CONF_UNKNOWN;
1538             break;
1539         }
1540     }
1541
1542     if (exp != CONF_ANY && tok != exp) {
1543         char *str;
1544         keytab_t *kwp;
1545
1546         switch(exp) {
1547         case CONF_LBRACE:
1548             str = "\"{\"";
1549             break;
1550
1551         case CONF_RBRACE:
1552             str = "\"}\"";
1553             break;
1554
1555         case CONF_COMMA:
1556             str = "\",\"";
1557             break;
1558
1559         case CONF_NL:
1560             str = "end of line";
1561             break;
1562
1563         case CONF_END:
1564             str = "end of file";
1565             break;
1566
1567         case CONF_INT:
1568             str = "an integer";
1569             break;
1570
1571         case CONF_REAL:
1572             str = "a real number";
1573             break;
1574
1575         case CONF_STRING:
1576             str = "a quoted string";
1577             break;
1578
1579         case CONF_IDENT:
1580             str = "an identifier";
1581             break;
1582
1583         default:
1584             for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1585                 if (exp == kwp->token)
1586                     break;
1587             }
1588             if (kwp->keyword == NULL)
1589                 str = "token not";
1590             else
1591                 str = kwp->keyword;
1592             break;
1593         }
1594         conf_parserror("%s is expected", str);
1595         tok = exp;
1596         if (tok == CONF_INT)
1597             tokenval.v.i = 0;
1598         else
1599             tokenval.v.s = "";
1600     }
1601 }
1602
1603
1604 void
1605 read_string(
1606     t_conf_var *np,
1607     val_t *val)
1608 {
1609     np = np;
1610     ckseen(&val->seen);
1611     get_conftoken(CONF_STRING);
1612     val->v.s = newstralloc(val->v.s, tokenval.v.s);
1613 }
1614
1615 void
1616 read_ident(
1617     t_conf_var *np,
1618     val_t *val)
1619 {
1620     np = np;
1621     ckseen(&val->seen);
1622     get_conftoken(CONF_IDENT);
1623     val->v.s = newstralloc(val->v.s, tokenval.v.s);
1624 }
1625
1626 void
1627 read_int(
1628     t_conf_var *np,
1629     val_t *val)
1630 {
1631     np = np;
1632     ckseen(&val->seen);
1633     val->v.i = get_int();
1634 }
1635
1636 void
1637 read_long(
1638     t_conf_var *np,
1639     val_t *val)
1640 {
1641     np = np;
1642     ckseen(&val->seen);
1643     val->v.l = get_long();
1644 }
1645
1646 void
1647 read_size(
1648     t_conf_var *np,
1649     val_t *val)
1650 {
1651     np = np;
1652     ckseen(&val->seen);
1653     val->v.size = get_size();
1654 }
1655
1656 void
1657 read_am64(
1658     t_conf_var *np,
1659     val_t *val)
1660 {
1661     np = np;
1662     ckseen(&val->seen);
1663     val->v.am64 = get_am64_t();
1664 }
1665
1666 void
1667 read_bool(
1668     t_conf_var *np,
1669     val_t *val)
1670 {
1671     np = np;
1672     ckseen(&val->seen);
1673     val->v.i = get_bool();
1674 }
1675
1676 void
1677 read_real(
1678     t_conf_var *np,
1679     val_t *val)
1680 {
1681     np = np;
1682     ckseen(&val->seen);
1683     get_conftoken(CONF_REAL);
1684     val->v.r = tokenval.v.r;
1685 }
1686
1687 void
1688 read_time(
1689     t_conf_var *np,
1690     val_t *val)
1691 {
1692     np = np;
1693     ckseen(&val->seen);
1694     val->v.t = get_time();
1695 }
1696
1697 void
1698 copy_val_t(
1699     val_t *valdst,
1700     val_t *valsrc)
1701 {
1702     if(valsrc->seen) {
1703         valdst->type = valsrc->type;
1704         valdst->seen = valsrc->seen;
1705         switch(valsrc->type) {
1706         case CONFTYPE_INT:
1707         case CONFTYPE_BOOL:
1708         case CONFTYPE_COMPRESS:
1709         case CONFTYPE_ENCRYPT:
1710         case CONFTYPE_HOLDING:
1711         case CONFTYPE_ESTIMATE:
1712         case CONFTYPE_STRATEGY:
1713         case CONFTYPE_TAPERALGO:
1714         case CONFTYPE_PRIORITY:
1715             valdst->v.i = valsrc->v.i;
1716             break;
1717
1718         case CONFTYPE_LONG:
1719             valdst->v.l = valsrc->v.l;
1720             break;
1721
1722         case CONFTYPE_SIZE:
1723             valdst->v.size = valsrc->v.size;
1724             break;
1725
1726         case CONFTYPE_AM64:
1727             valdst->v.am64 = valsrc->v.am64;
1728             break;
1729
1730         case CONFTYPE_REAL:
1731             valdst->v.r = valsrc->v.r;
1732             break;
1733
1734         case CONFTYPE_RATE:
1735             valdst->v.rate[0] = valsrc->v.rate[0];
1736             valdst->v.rate[1] = valsrc->v.rate[1];
1737             break;
1738
1739         case CONFTYPE_IDENT:
1740         case CONFTYPE_STRING:
1741             valdst->v.s = stralloc(valsrc->v.s);
1742             break;
1743
1744         case CONFTYPE_TIME:
1745             valdst->v.t = valsrc->v.t;
1746             break;
1747
1748         case CONFTYPE_SL:
1749             valdst->v.sl = duplicate_sl(valsrc->v.sl);
1750             break;
1751
1752         case CONFTYPE_EXINCLUDE:
1753             valdst->v.exinclude.type = valsrc->v.exinclude.type;
1754             valdst->v.exinclude.optional = valsrc->v.exinclude.optional;
1755             valdst->v.exinclude.sl = duplicate_sl(valsrc->v.exinclude.sl);
1756             break;
1757         }
1758     }
1759 }
1760
1761 void
1762 free_val_t(
1763     val_t *val)
1764 {
1765     switch(val->type) {
1766         case CONFTYPE_INT:
1767         case CONFTYPE_BOOL:
1768         case CONFTYPE_COMPRESS:
1769         case CONFTYPE_ENCRYPT:
1770         case CONFTYPE_HOLDING:
1771         case CONFTYPE_ESTIMATE:
1772         case CONFTYPE_STRATEGY:
1773         case CONFTYPE_SIZE:
1774         case CONFTYPE_TAPERALGO:
1775         case CONFTYPE_PRIORITY:
1776         case CONFTYPE_LONG:
1777         case CONFTYPE_AM64:
1778         case CONFTYPE_REAL:
1779         case CONFTYPE_RATE:
1780             break;
1781
1782         case CONFTYPE_IDENT:
1783         case CONFTYPE_STRING:
1784             amfree(val->v.s);
1785             break;
1786
1787         case CONFTYPE_TIME:
1788             break;
1789
1790         case CONFTYPE_SL:
1791             free_sl(val->v.sl);
1792             break;
1793
1794         case CONFTYPE_EXINCLUDE:
1795             free_sl(val->v.exinclude.sl);
1796             break;
1797     }
1798     val->seen = 0;
1799 }
1800
1801 char *
1802 taperalgo2str(
1803     int taperalgo)
1804 {
1805     if(taperalgo == ALGO_FIRST) return "FIRST";
1806     if(taperalgo == ALGO_FIRSTFIT) return "FIRSTFIT";
1807     if(taperalgo == ALGO_LARGEST) return "LARGEST";
1808     if(taperalgo == ALGO_LARGESTFIT) return "LARGESTFIT";
1809     if(taperalgo == ALGO_SMALLEST) return "SMALLEST";
1810     if(taperalgo == ALGO_LAST) return "LAST";
1811     return "UNKNOWN";
1812 }
1813
1814 static char buffer_conf_print[1025];
1815
1816 char *
1817 conf_print(
1818     val_t *val)
1819 {
1820     struct tm *stm;
1821     int pos;
1822
1823     buffer_conf_print[0] = '\0';
1824     switch(val->type) {
1825     case CONFTYPE_INT:
1826         snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%d", val->v.i);
1827         break;
1828
1829     case CONFTYPE_LONG:
1830         snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%ld", val->v.l);
1831         break;
1832
1833     case CONFTYPE_SIZE:
1834         snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), SSIZE_T_FMT,
1835                 (SSIZE_T_FMT_TYPE)val->v.size);
1836         break;
1837
1838     case CONFTYPE_AM64:
1839         snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), OFF_T_FMT ,
1840                  (OFF_T_FMT_TYPE)val->v.am64);
1841         break;
1842
1843     case CONFTYPE_REAL:
1844         snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%0.5f" , val->v.r);
1845         break;
1846
1847     case CONFTYPE_RATE:
1848         snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%0.5f %0.5f" , val->v.rate[0], val->v.rate[1]);
1849         break;
1850
1851     case CONFTYPE_IDENT:
1852         if(val->v.s) {
1853             strncpy(buffer_conf_print, val->v.s, SIZEOF(buffer_conf_print));
1854             buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0';
1855         } else
1856             buffer_conf_print[0] = '\0';
1857         break;
1858
1859     case CONFTYPE_STRING:
1860         buffer_conf_print[0] = '"';
1861         if(val->v.s) {
1862             strncpy(&buffer_conf_print[1], val->v.s,
1863                         SIZEOF(buffer_conf_print) - 1);
1864             buffer_conf_print[SIZEOF(buffer_conf_print) - 2] = '\0';
1865             buffer_conf_print[strlen(buffer_conf_print)] = '"';
1866         } else {
1867             buffer_conf_print[1] = '"';
1868             buffer_conf_print[2] = '\0';
1869         }
1870         break;
1871
1872     case CONFTYPE_TIME:
1873         stm = localtime(&val->v.t);
1874         if (stm) {
1875             snprintf(buffer_conf_print, SIZEOF(buffer_conf_print),
1876                      "%d%02d%02d", stm->tm_hour, stm->tm_min, stm->tm_sec);
1877         } else {
1878             strcpy(buffer_conf_print, "00000");
1879         }
1880         break;
1881
1882     case CONFTYPE_SL:
1883         buffer_conf_print[0] = '\0';
1884         break;
1885
1886     case CONFTYPE_EXINCLUDE:
1887         buffer_conf_print[0] = '\0';
1888         if(val->v.exinclude.type == 0)
1889             strncpy(buffer_conf_print, "LIST ", SIZEOF(buffer_conf_print));
1890         else
1891             strncpy(buffer_conf_print, "FILE ", SIZEOF(buffer_conf_print));
1892         pos = 5;
1893         if(val->v.exinclude.optional == 1)
1894             strncpy(&buffer_conf_print[pos], "OPTIONAL ", SIZEOF(buffer_conf_print));
1895         pos += 9;
1896         break;
1897
1898     case CONFTYPE_BOOL:
1899         if(val->v.i)
1900             strncpy(buffer_conf_print, "yes", SIZEOF(buffer_conf_print));
1901         else
1902             strncpy(buffer_conf_print, "no", SIZEOF(buffer_conf_print));
1903         break;
1904
1905     case CONFTYPE_STRATEGY:
1906         switch(val->v.i) {
1907         case DS_SKIP:
1908             strncpy(buffer_conf_print, "SKIP", SIZEOF(buffer_conf_print));
1909             break;
1910
1911         case DS_STANDARD:
1912             strncpy(buffer_conf_print, "STANDARD", SIZEOF(buffer_conf_print));
1913             break;
1914
1915         case DS_NOFULL:
1916             strncpy(buffer_conf_print, "NOFULL", SIZEOF(buffer_conf_print));
1917             break;
1918
1919         case DS_NOINC:
1920             strncpy(buffer_conf_print, "NOINC", SIZEOF(buffer_conf_print));
1921             break;
1922
1923         case DS_HANOI:
1924             strncpy(buffer_conf_print, "HANOI", SIZEOF(buffer_conf_print));
1925             break;
1926
1927         case DS_INCRONLY:
1928             strncpy(buffer_conf_print, "INCRONLY", SIZEOF(buffer_conf_print));
1929             break;
1930         }
1931         break;
1932
1933     case CONFTYPE_COMPRESS:
1934         switch(val->v.i) {
1935         case COMP_NONE:
1936             strncpy(buffer_conf_print, "NONE", SIZEOF(buffer_conf_print));
1937             break;
1938
1939         case COMP_FAST:
1940             strncpy(buffer_conf_print, "CLIENT FAST", SIZEOF(buffer_conf_print));
1941             break;
1942
1943         case COMP_BEST:
1944             strncpy(buffer_conf_print, "CLIENT BEST", SIZEOF(buffer_conf_print));
1945             break;
1946
1947         case COMP_CUST:
1948             strncpy(buffer_conf_print, "CLIENT CUSTOM", SIZEOF(buffer_conf_print));
1949             break;
1950
1951         case COMP_SERV_FAST:
1952             strncpy(buffer_conf_print, "SERVER FAST", SIZEOF(buffer_conf_print));
1953             break;
1954
1955         case COMP_SERV_BEST:
1956             strncpy(buffer_conf_print, "SERVER FAST", SIZEOF(buffer_conf_print));
1957             break;
1958
1959         case COMP_SERV_CUST:
1960             strncpy(buffer_conf_print, "SERVER CUSTOM", SIZEOF(buffer_conf_print));
1961             break;
1962         }
1963         break;
1964
1965     case CONFTYPE_ESTIMATE:
1966         switch(val->v.i) {
1967         case ES_CLIENT:
1968             strncpy(buffer_conf_print, "CLIENT", SIZEOF(buffer_conf_print));
1969             break;
1970
1971         case ES_SERVER:
1972             strncpy(buffer_conf_print, "SERVER", SIZEOF(buffer_conf_print));
1973             break;
1974
1975         case ES_CALCSIZE:
1976             strncpy(buffer_conf_print, "CALCSIZE", SIZEOF(buffer_conf_print));
1977             break;
1978         }
1979         break;
1980
1981      case CONFTYPE_ENCRYPT:
1982         switch(val->v.i) {
1983         case ENCRYPT_NONE:
1984             strncpy(buffer_conf_print, "NONE", SIZEOF(buffer_conf_print));
1985             break;
1986
1987         case ENCRYPT_CUST:
1988             strncpy(buffer_conf_print, "CLIENT", SIZEOF(buffer_conf_print));
1989             break;
1990
1991         case ENCRYPT_SERV_CUST:
1992             strncpy(buffer_conf_print, "SERVER", SIZEOF(buffer_conf_print));
1993             break;
1994         }
1995         break;
1996
1997      case CONFTYPE_HOLDING:
1998         switch(val->v.i) {
1999         case HOLD_NEVER:
2000             strncpy(buffer_conf_print, "NEVER", SIZEOF(buffer_conf_print));
2001             break;
2002
2003         case HOLD_AUTO:
2004             strncpy(buffer_conf_print, "AUTO", SIZEOF(buffer_conf_print));
2005             break;
2006
2007         case HOLD_REQUIRED:
2008             strncpy(buffer_conf_print, "REQUIRED", SIZEOF(buffer_conf_print));
2009             break;
2010         }
2011         break;
2012
2013      case CONFTYPE_TAPERALGO:
2014         strncpy(buffer_conf_print, taperalgo2str(val->v.i), SIZEOF(buffer_conf_print));
2015         break;
2016
2017      case CONFTYPE_PRIORITY:
2018         switch(val->v.i) {
2019         case 0:
2020             strncpy(buffer_conf_print, "LOW", SIZEOF(buffer_conf_print));
2021             break;
2022
2023         case 1:
2024             strncpy(buffer_conf_print, "MEDIUM", SIZEOF(buffer_conf_print));
2025             break;
2026
2027         case 2:
2028             strncpy(buffer_conf_print, "HIGH", SIZEOF(buffer_conf_print));
2029             break;
2030         }
2031         break;
2032     }
2033     buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0';
2034     return buffer_conf_print;
2035 }
2036
2037 void
2038 conf_init_string(
2039     val_t *val,
2040     char  *s)
2041 {
2042     val->seen = 0;
2043     val->type = CONFTYPE_STRING;
2044     if(s)
2045         val->v.s = stralloc(s);
2046     else
2047         val->v.s = NULL;
2048 }
2049
2050 void
2051 conf_init_ident(
2052     val_t *val,
2053     char  *s)
2054 {
2055     val->seen = 0;
2056     val->type = CONFTYPE_IDENT;
2057     if(s)
2058         val->v.s = stralloc(s);
2059     else
2060         val->v.s = NULL;
2061 }
2062
2063 void
2064 conf_init_int(
2065     val_t *val,
2066     int    i)
2067 {
2068     val->seen = 0;
2069     val->type = CONFTYPE_INT;
2070     val->v.i = i;
2071 }
2072
2073 void
2074 conf_init_bool(
2075     val_t *val,
2076     int    i)
2077 {
2078     val->seen = 0;
2079     val->type = CONFTYPE_BOOL;
2080     val->v.i = i;
2081 }
2082
2083 void
2084 conf_init_strategy(
2085     val_t *val,
2086     int    i)
2087 {
2088     val->seen = 0;
2089     val->type = CONFTYPE_STRATEGY;
2090     val->v.i = i;
2091 }
2092
2093 void
2094 conf_init_estimate(
2095     val_t *val,
2096     int    i)
2097 {
2098     val->seen = 0;
2099     val->type = CONFTYPE_ESTIMATE;
2100     val->v.i = i;
2101 }
2102
2103 void
2104 conf_init_taperalgo(
2105     val_t *val,
2106     int    i)
2107 {
2108     val->seen = 0;
2109     val->type = CONFTYPE_TAPERALGO;
2110     val->v.i = i;
2111 }
2112
2113 void
2114 conf_init_priority(
2115     val_t *val,
2116     int    i)
2117 {
2118     val->seen = 0;
2119     val->type = CONFTYPE_PRIORITY;
2120     val->v.i = i;
2121 }
2122
2123 void
2124 conf_init_compress(
2125     val_t *val,
2126     comp_t    i)
2127 {
2128     val->seen = 0;
2129     val->type = CONFTYPE_COMPRESS;
2130     val->v.i = (int)i;
2131 }
2132
2133 void
2134 conf_init_encrypt(
2135     val_t *val,
2136     encrypt_t    i)
2137 {
2138     val->seen = 0;
2139     val->type = CONFTYPE_ENCRYPT;
2140     val->v.i = (int)i;
2141 }
2142
2143 void
2144 conf_init_holding(
2145     val_t              *val,
2146     dump_holdingdisk_t  i)
2147 {
2148     val->seen = 0;
2149     val->type = CONFTYPE_HOLDING;
2150     val->v.i = (int)i;
2151 }
2152
2153 void
2154 conf_init_long(
2155     val_t *val,
2156     long   l)
2157 {
2158     val->seen = 0;
2159     val->type = CONFTYPE_LONG;
2160     val->v.l = l;
2161 }
2162
2163 void
2164 conf_init_size(
2165     val_t *val,
2166     ssize_t   sz)
2167 {
2168     val->seen = 0;
2169     val->type = CONFTYPE_SIZE;
2170     val->v.size = sz;
2171 }
2172
2173 void
2174 conf_init_am64(
2175     val_t *val,
2176     off_t   l)
2177 {
2178     val->seen = 0;
2179     val->type = CONFTYPE_AM64;
2180     val->v.am64 = l;
2181 }
2182
2183 void
2184 conf_init_real(
2185     val_t  *val,
2186     double r)
2187 {
2188     val->seen = 0;
2189     val->type = CONFTYPE_REAL;
2190     val->v.r = r;
2191 }
2192
2193 void
2194 conf_init_rate(
2195     val_t  *val,
2196     double r1,
2197     double r2)
2198 {
2199     val->seen = 0;
2200     val->type = CONFTYPE_RATE;
2201     val->v.rate[0] = r1;
2202     val->v.rate[1] = r2;
2203 }
2204
2205 void
2206 conf_init_time(
2207     val_t *val,
2208     time_t   t)
2209 {
2210     val->seen = 0;
2211     val->type = CONFTYPE_TIME;
2212     val->v.t = t;
2213 }
2214
2215 void
2216 conf_init_sl(
2217     val_t *val,
2218     sl_t  *sl)
2219 {
2220     val->seen = 0;
2221     val->type = CONFTYPE_AM64;
2222     val->v.sl = sl;
2223 }
2224
2225 void
2226 conf_init_exinclude(
2227     val_t *val)
2228 {
2229     val->seen = 0;
2230     val->type = CONFTYPE_EXINCLUDE;
2231     val->v.exinclude.type = 0;
2232     val->v.exinclude.optional = 0;
2233     val->v.exinclude.sl = NULL;
2234 }
2235
2236 void
2237 conf_set_string(
2238     val_t *val,
2239     char *s)
2240 {
2241     val->seen = -1;
2242     val->type = CONFTYPE_STRING;
2243     amfree(val->v.s);
2244     val->v.s = stralloc(s);
2245 }
2246
2247 void
2248 conf_set_int(
2249     val_t *val,
2250     int    i)
2251 {
2252     val->seen = -1;
2253     val->type = CONFTYPE_INT;
2254     val->v.i = i;
2255 }
2256
2257 void
2258 conf_set_bool(
2259     val_t *val,
2260     int    i)
2261 {
2262     val->seen = -1;
2263     val->type = CONFTYPE_BOOL;
2264     val->v.i = i;
2265 }
2266
2267 void
2268 conf_set_compress(
2269     val_t *val,
2270     comp_t    i)
2271 {
2272     val->seen = -1;
2273     val->type = CONFTYPE_COMPRESS;
2274     val->v.i = (int)i;
2275 }
2276
2277 void
2278 conf_set_encrypt(
2279     val_t *val,
2280     encrypt_t    i)
2281 {
2282     val->seen = -1;
2283     val->type = CONFTYPE_COMPRESS;
2284     val->v.i = (int)i;
2285 }
2286
2287 void
2288 conf_set_holding(
2289     val_t              *val,
2290     dump_holdingdisk_t  i)
2291 {
2292     val->seen = -1;
2293     val->type = CONFTYPE_HOLDING;
2294     val->v.i = (int)i;
2295 }
2296
2297 void
2298 conf_set_strategy(
2299     val_t *val,
2300     int    i)
2301 {
2302     val->seen = -1;
2303     val->type = CONFTYPE_STRATEGY;
2304     val->v.i = i;
2305 }
2306
2307
2308 int
2309 get_conftype_int(
2310     val_t *val)
2311 {
2312     if (val->type != CONFTYPE_INT) {
2313         error("get_conftype_int: val.type is not CONFTYPE_INT");
2314         /*NOTREACHED*/
2315     }
2316     return val->v.i;
2317 }
2318
2319 long
2320 get_conftype_long(
2321     val_t *val)
2322 {
2323     if (val->type != CONFTYPE_LONG) {
2324         error("get_conftype_long: val.type is not CONFTYPE_LONG");
2325         /*NOTREACHED*/
2326     }
2327     return val->v.l;
2328 }
2329
2330 off_t
2331 get_conftype_am64(
2332     val_t *val)
2333 {
2334     if (val->type != CONFTYPE_AM64) {
2335         error("get_conftype_am64: val.type is not CONFTYPE_AM64");
2336         /*NOTREACHED*/
2337     }
2338     return val->v.am64;
2339 }
2340
2341 double
2342 get_conftype_real(
2343     val_t *val)
2344 {
2345     if (val->type != CONFTYPE_REAL) {
2346         error("get_conftype_real: val.type is not CONFTYPE_REAL");
2347         /*NOTREACHED*/
2348     }
2349     return val->v.r;
2350 }
2351
2352 char *
2353 get_conftype_string(
2354     val_t *val)
2355 {
2356     if (val->type != CONFTYPE_STRING) {
2357         error("get_conftype_string: val.type is not CONFTYPE_STRING");
2358         /*NOTREACHED*/
2359     }
2360     return val->v.s;
2361 }
2362
2363 char *
2364 get_conftype_ident(
2365     val_t *val)
2366 {
2367     if (val->type != CONFTYPE_IDENT) {
2368         error("get_conftype_ident: val.type is not CONFTYPE_IDENT");
2369         /*NOTREACHED*/
2370     }
2371     return val->v.s;
2372 }
2373
2374 time_t
2375 get_conftype_time(
2376     val_t *val)
2377 {
2378     if (val->type != CONFTYPE_TIME) {
2379         error("get_conftype_time: val.type is not CONFTYPE_TIME");
2380         /*NOTREACHED*/
2381     }
2382     return val->v.t;
2383 }
2384
2385 ssize_t
2386 get_conftype_size(
2387     val_t *val)
2388 {
2389     if (val->type != CONFTYPE_SIZE) {
2390         error("get_conftype_size: val.type is not CONFTYPE_SIZE");
2391         /*NOTREACHED*/
2392     }
2393     return val->v.size;
2394 }
2395
2396 sl_t *
2397 get_conftype_sl(
2398     val_t *val)
2399 {
2400     if (val->type != CONFTYPE_SL) {
2401         error("get_conftype_size: val.type is not CONFTYPE_SL");
2402         /*NOTREACHED*/
2403     }
2404     return val->v.sl;
2405 }
2406
2407 int
2408 get_conftype_bool(
2409     val_t *val)
2410 {
2411     if (val->type != CONFTYPE_BOOL) {
2412         error("get_conftype_bool: val.type is not CONFTYPE_BOOL");
2413         /*NOTREACHED*/
2414     }
2415     return val->v.i;
2416 }
2417
2418 int
2419 get_conftype_hold(
2420     val_t *val)
2421 {
2422     if (val->type != CONFTYPE_HOLDING) {
2423         error("get_conftype_hold: val.type is not CONFTYPE_HOLDING");
2424         /*NOTREACHED*/
2425     }
2426     return val->v.i;
2427 }
2428
2429 int
2430 get_conftype_compress(
2431     val_t *val)
2432 {
2433     if (val->type != CONFTYPE_COMPRESS) {
2434         error("get_conftype_compress: val.type is not CONFTYPE_COMPRESS");
2435         /*NOTREACHED*/
2436     }
2437     return val->v.i;
2438 }
2439
2440 int
2441 get_conftype_encrypt(
2442     val_t *val)
2443 {
2444     if (val->type != CONFTYPE_ENCRYPT) {
2445         error("get_conftype_encrypt: val.type is not CONFTYPE_ENCRYPT");
2446         /*NOTREACHED*/
2447     }
2448     return val->v.i;
2449 }
2450
2451 int
2452 get_conftype_estimate(
2453     val_t *val)
2454 {
2455     if (val->type != CONFTYPE_ESTIMATE) {
2456         error("get_conftype_extimate: val.type is not CONFTYPE_ESTIMATE");
2457         /*NOTREACHED*/
2458     }
2459     return val->v.i;
2460 }
2461
2462 int
2463 get_conftype_strategy(
2464     val_t *val)
2465 {
2466     if (val->type != CONFTYPE_STRATEGY) {
2467         error("get_conftype_strategy: val.type is not CONFTYPE_STRATEGY");
2468         /*NOTREACHED*/
2469     }
2470     return val->v.i;
2471 }
2472
2473 int
2474 get_conftype_taperalgo(
2475     val_t *val)
2476 {
2477     if (val->type != CONFTYPE_TAPERALGO) {
2478         error("get_conftype_taperalgo: val.type is not CONFTYPE_TAPERALGO");
2479         /*NOTREACHED*/
2480     }
2481     return val->v.i;
2482 }
2483
2484 int
2485 get_conftype_priority(
2486     val_t *val)
2487 {
2488     if (val->type != CONFTYPE_PRIORITY) {
2489         error("get_conftype_priority: val.type is not CONFTYPE_PRIORITY");
2490         /*NOTREACHED*/
2491     }
2492     return val->v.i;
2493 }
2494
2495 exinclude_t
2496 get_conftype_exinclude(
2497     val_t *val)
2498 {
2499     if (val->type != CONFTYPE_EXINCLUDE) {
2500         error("get_conftype_exinclude: val.type is not CONFTYPE_EXINCLUDE");
2501         /*NOTREACHED*/
2502     }
2503     return val->v.exinclude;
2504 }
2505
2506
2507 void
2508 dump_sockaddr(
2509         struct sockaddr_in *    sa)
2510 {
2511         dbprintf(("%s: (sockaddr_in *)%p = { %d, %d, %s }\n",
2512                 debug_prefix_time(NULL), sa, sa->sin_family,
2513                 (int)ntohs(sa->sin_port),
2514                 inet_ntoa(sa->sin_addr)));
2515 }
2516
2517 void
2518 read_block(
2519     command_option_t *command_options,
2520     t_conf_var    *read_var,
2521     keytab_t *keytab,
2522     val_t    *valarray,
2523     char     *prefix,
2524     char     *errormsg,
2525     int       read_brace,
2526     void      (*copy_function)(void))
2527 {
2528     t_conf_var *np;
2529     int    saved_conf_line_num;
2530     int    done;
2531
2532     if(read_brace) {
2533         get_conftoken(CONF_LBRACE);
2534         get_conftoken(CONF_NL);
2535     }
2536
2537     done = 0;
2538     do {
2539         conf_line_num += 1;
2540         get_conftoken(CONF_ANY);
2541         switch(tok) {
2542         case CONF_RBRACE:
2543             done = 1;
2544             break;
2545         case CONF_NL:   /* empty line */
2546             break;
2547         case CONF_END:  /* end of file */
2548             done = 1;
2549             break;
2550         case CONF_IDENT:
2551         case CONF_STRING:
2552             if(copy_function) 
2553                 copy_function();
2554             else
2555                 conf_parserror("ident not expected");
2556             break;
2557         default:
2558             {
2559                 for(np = read_var; np->token != CONF_UNKNOWN; np++)
2560                     if(np->token == tok) break;
2561
2562                 if(np->token == CONF_UNKNOWN)
2563                     conf_parserror(errormsg);
2564                 else {
2565                     np->read_function(np, &valarray[np->parm]);
2566                     if(np->validate)
2567                         np->validate(np, &valarray[np->parm]);
2568                 }
2569             }
2570         }
2571         if(tok != CONF_NL && tok != CONF_END && tok != CONF_RBRACE)
2572             get_conftoken(CONF_NL);
2573     } while(!done);
2574
2575     /* overwrite with command line option */
2576     saved_conf_line_num = conf_line_num;
2577     command_overwrite(command_options, read_var, keytab, valarray, prefix);
2578     conf_line_num = saved_conf_line_num;
2579 }
2580
2581 void
2582 command_overwrite(
2583     command_option_t *command_options,
2584     t_conf_var    *overwrite_var,
2585     keytab_t *keytab,
2586     val_t    *valarray,
2587     char     *prefix)
2588 {
2589     t_conf_var       *np;
2590     keytab_t         *kt;
2591     char             *myprefix;
2592     command_option_t *command_option;
2593
2594     if(!command_options) return;
2595
2596     for(np = overwrite_var; np->token != CONF_UNKNOWN; np++) {
2597         for(kt = keytab; kt->token != CONF_UNKNOWN; kt++)
2598             if(kt->token == np->token) break;
2599
2600         if(kt->token == CONF_UNKNOWN) {
2601             error("read_conf: invalid token");
2602             /* NOTREACHED */
2603         }
2604
2605         for(command_option = command_options; command_option->name != NULL;
2606                                                             command_option++) {
2607             myprefix = stralloc2(prefix, kt->keyword);
2608             if(strcasecmp(myprefix, command_option->name) == 0) {
2609                 command_option->used = 1;
2610                 valarray[np->parm].seen = -2;
2611                 if(np->type == CONFTYPE_STRING &&
2612                    command_option->value[0] != '"') {
2613                     conf_line = vstralloc("\"", command_option->value, "\"",
2614                                           NULL);
2615                 }
2616                 else {
2617                     conf_line = stralloc(command_option->value);
2618                 }
2619                 conf_char = conf_line;
2620                 token_pushed = 0;
2621                 conf_line_num = -2;
2622                 np->read_function(np, &valarray[np->parm]);
2623                 amfree(conf_line);
2624                 conf_line = conf_char = NULL;
2625
2626                 if(np->validate)
2627                     np->validate(np, &valarray[np->parm]);
2628             }
2629             amfree(myprefix);
2630         }
2631     }
2632 }
2633
2634 void
2635 free_new_argv(
2636     int new_argc,
2637     char **new_argv)
2638 {
2639     int i;
2640     for(i=0; i<new_argc; i++)
2641         amfree(new_argv[i]);
2642     amfree(new_argv);
2643 }
2644
2645
2646 #ifndef HAVE_LIBREADLINE
2647 /*
2648  * simple readline() replacements
2649  */
2650
2651 char *
2652 readline(
2653     const char *prompt)
2654 {
2655     printf("%s", prompt);
2656     fflush(stdout);
2657     fflush(stderr);
2658     return agets(stdin);
2659 }
2660
2661 void 
2662 add_history(
2663     const char *line)
2664 {
2665     (void)line;         /* Quite unused parameter warning */
2666 }
2667 #endif