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