d168b6f1c3143a7956f24c347baf01bcb23a1232
[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.13 2007/01/24 18:33:29 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: %s\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             } else if (*str == '\\') {
502                 *(s++) = '\\';
503                 *(s++) = '\\';
504                 str++;
505                 continue;
506             }
507             if (*str == '"')
508                 *(s++) = '\\';
509             *(s++) = *(str++);
510         }
511         *(s++) = '"';
512         *s = '\0';
513     }
514     return (ret);
515 }
516
517
518 char *
519 unquote_string(
520     const char *str)
521 {
522     char * ret;
523
524     if ((str == NULL) || (*str == '\0')) {
525         ret = stralloc("");
526     } else {
527         char * in;
528         char * out;
529
530         ret = in = out = stralloc(str);
531         while (*in != '\0') {
532             if (*in == '"') {
533                 in++;
534                 continue;
535             }
536
537             if (*in == '\\') {
538                 in++;
539                 if (*in == 'n') {
540                     in++;
541                     *(out++) = '\n';
542                     continue;
543                 } else if (*in == 't') {
544                     in++;
545                     *(out++) = '\t';
546                     continue;
547                 } else if (*in == 'r') {
548                     in++;
549                     *(out++) = '\r';
550                     continue;
551                 } else if (*in == 'f') {
552                     in++;
553                     *(out++) = '\f';
554                     continue;
555                 }
556             }
557             *(out++) = *(in++);
558         }
559         *out = '\0';
560     }
561     return (ret);
562 }
563
564 char *
565 sanitize_string(
566     const char *str)
567 {
568     char * s;
569     char * ret;
570
571     if ((str == NULL) || (*str == '\0')) {
572         ret = stralloc("");
573     } else {
574         ret = stralloc(str);
575         for (s = ret; *s != '\0'; s++) {
576             if (iscntrl(*s))
577                 *s = '?';
578         }
579     }
580     return (ret);
581 }
582
583 char *
584 strquotedstr(void)
585 {
586     char *  tok = strtok(NULL, " ");
587
588     if ((tok != NULL) && (tok[0] == '"')) {
589         char *  t;
590         size_t  len;
591
592         len = strlen(tok);
593         do {
594             t = strtok(NULL, " ");
595             tok[len] = ' ';
596             len = strlen(tok);
597         } while ((t != NULL) &&
598                  (tok[len - 1] != '"') && (tok[len - 2] != '\\'));
599     }
600     return tok;
601 }
602
603 ssize_t
604 hexdump(
605     const char *buffer,
606     size_t      len)
607 {
608     ssize_t rc = -1;
609
610     FILE *stream = popen("od -w10 -c -x -", "w");
611         
612     if (stream != NULL) {
613         fflush(stdout);
614         rc = (ssize_t)fwrite(buffer, len, 1, stream);
615         if (ferror(stream))
616             rc = -1;
617         fclose(stream);
618     }
619     return rc;
620 }
621
622 /*
623    Return 0 if the following characters are present
624    * ( ) < > [ ] , ; : ! $ \ / "
625    else returns 1
626 */
627
628 int
629 validate_mailto(
630     const char *mailto)
631 {
632     return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto);
633 }
634
635
636 t_conf_var *
637 get_np(
638     t_conf_var  *get_var,
639     int         parm)
640 {
641     t_conf_var *np;
642
643     for(np = get_var; np->token != CONF_UNKNOWN; np++) {
644         if(np->parm == parm)
645             break;
646     }
647
648     if(np->token == CONF_UNKNOWN) {
649         error("error [unknown getconf_np parm: %d]", parm);
650         /* NOTREACHED */
651     }
652     return np;
653 }
654
655 void
656 get_simple(
657     val_t  *var,
658     tok_t  type)
659 {
660     ckseen(&var->seen);
661
662     switch(type) {
663     case CONF_STRING:
664     case CONF_IDENT:
665         get_conftoken(type);
666         var->v.s = newstralloc(var->v.s, tokenval.v.s);
667         malloc_mark(var->v.s);
668         break;
669
670     case CONF_INT:
671         var->v.i = get_int();
672         break;
673
674     case CONF_LONG:
675         var->v.l = get_long();
676         break;
677
678     case CONF_SIZE:
679         var->v.size = get_size();
680         break;
681
682     case CONF_AM64:
683         var->v.am64 = get_am64_t();
684         break;
685
686     case CONF_BOOL:
687         var->v.i = get_bool();
688         break;
689
690     case CONF_REAL:
691         get_conftoken(CONF_REAL);
692         var->v.r = tokenval.v.r;
693         break;
694
695     case CONF_TIME:
696         var->v.t = get_time();
697         break;
698
699     default:
700         error("error [unknown get_simple type: %d]", type);
701         /* NOTREACHED */
702     }
703     return;
704 }
705
706 time_t
707 get_time(void)
708 {
709     time_t hhmm;
710
711     get_conftoken(CONF_ANY);
712     switch(tok) {
713     case CONF_INT:
714 #if SIZEOF_TIME_T < SIZEOF_INT
715         if ((off_t)tokenval.v.i >= (off_t)TIME_MAX)
716             conf_parserror("value too large");
717 #endif
718         hhmm = (time_t)tokenval.v.i;
719         break;
720
721     case CONF_LONG:
722 #if SIZEOF_TIME_T < SIZEOF_LONG
723         if ((off_t)tokenval.v.l >= (off_t)TIME_MAX)
724             conf_parserror("value too large");
725 #endif
726         hhmm = (time_t)tokenval.v.l;
727         break;
728
729     case CONF_SIZE:
730 #if SIZEOF_TIME_T < SIZEOF_SSIZE_T
731         if ((off_t)tokenval.v.size >= (off_t)TIME_MAX)
732             conf_parserror("value too large");
733 #endif
734         hhmm = (time_t)tokenval.v.size;
735         break;
736
737     case CONF_AM64:
738 #if SIZEOF_TIME_T < SIZEOF_LONG_LONG
739         if ((off_t)tokenval.v.am64 >= (off_t)TIME_MAX)
740             conf_parserror("value too large");
741 #endif
742         hhmm = (time_t)tokenval.v.am64;
743         break;
744
745     case CONF_AMINFINITY:
746         hhmm = TIME_MAX;
747         break;
748
749     default:
750         conf_parserror("a time is expected");
751         hhmm = 0;
752         break;
753     }
754     return hhmm;
755 }
756
757 keytab_t numb_keytable[] = {
758     { "B", CONF_MULT1 },
759     { "BPS", CONF_MULT1 },
760     { "BYTE", CONF_MULT1 },
761     { "BYTES", CONF_MULT1 },
762     { "DAY", CONF_MULT1 },
763     { "DAYS", CONF_MULT1 },
764     { "INF", CONF_AMINFINITY },
765     { "K", CONF_MULT1K },
766     { "KB", CONF_MULT1K },
767     { "KBPS", CONF_MULT1K },
768     { "KBYTE", CONF_MULT1K },
769     { "KBYTES", CONF_MULT1K },
770     { "KILOBYTE", CONF_MULT1K },
771     { "KILOBYTES", CONF_MULT1K },
772     { "KPS", CONF_MULT1K },
773     { "M", CONF_MULT1M },
774     { "MB", CONF_MULT1M },
775     { "MBPS", CONF_MULT1M },
776     { "MBYTE", CONF_MULT1M },
777     { "MBYTES", CONF_MULT1M },
778     { "MEG", CONF_MULT1M },
779     { "MEGABYTE", CONF_MULT1M },
780     { "MEGABYTES", CONF_MULT1M },
781     { "G", CONF_MULT1G },
782     { "GB", CONF_MULT1G },
783     { "GBPS", CONF_MULT1G },
784     { "GBYTE", CONF_MULT1G },
785     { "GBYTES", CONF_MULT1G },
786     { "GIG", CONF_MULT1G },
787     { "GIGABYTE", CONF_MULT1G },
788     { "GIGABYTES", CONF_MULT1G },
789     { "MPS", CONF_MULT1M },
790     { "TAPE", CONF_MULT1 },
791     { "TAPES", CONF_MULT1 },
792     { "WEEK", CONF_MULT7 },
793     { "WEEKS", CONF_MULT7 },
794     { NULL, CONF_IDENT }
795 };
796
797 int
798 get_int(void)
799 {
800     int val;
801     keytab_t *save_kt;
802
803     save_kt = keytable;
804     keytable = numb_keytable;
805
806     get_conftoken(CONF_ANY);
807     switch(tok) {
808     case CONF_INT:
809         val = tokenval.v.i;
810         break;
811
812     case CONF_LONG:
813 #if SIZEOF_INT < SIZEOF_LONG
814         if ((off_t)tokenval.v.l > (off_t)INT_MAX)
815             conf_parserror("value too large");
816         if ((off_t)tokenval.v.l < (off_t)INT_MIN)
817             conf_parserror("value too small");
818 #endif
819         val = (int)tokenval.v.l;
820         break;
821
822     case CONF_SIZE:
823 #if SIZEOF_INT < SIZEOF_SSIZE_T
824         if ((off_t)tokenval.v.size > (off_t)INT_MAX)
825             conf_parserror("value too large");
826         if ((off_t)tokenval.v.size < (off_t)INT_MIN)
827             conf_parserror("value too small");
828 #endif
829         val = (int)tokenval.v.size;
830         break;
831
832     case CONF_AM64:
833 #if SIZEOF_INT < SIZEOF_LONG_LONG
834         if (tokenval.v.am64 > (off_t)INT_MAX)
835             conf_parserror("value too large");
836         if (tokenval.v.am64 < (off_t)INT_MIN)
837             conf_parserror("value too small");
838 #endif
839         val = (int)tokenval.v.am64;
840         break;
841
842     case CONF_AMINFINITY:
843         val = INT_MAX;
844         break;
845
846     default:
847         conf_parserror("an int is expected");
848         val = 0;
849         break;
850     }
851
852     /* get multiplier, if any */
853     get_conftoken(CONF_ANY);
854     switch(tok) {
855     case CONF_NL:                       /* multiply by one */
856     case CONF_END:
857     case CONF_MULT1:
858     case CONF_MULT1K:
859         break;
860
861     case CONF_MULT7:
862         if (val > (INT_MAX / 7))
863             conf_parserror("value too large");
864         if (val < (INT_MIN / 7))
865             conf_parserror("value too small");
866         val *= 7;
867         break;
868
869     case CONF_MULT1M:
870         if (val > (INT_MAX / 1024))
871             conf_parserror("value too large");
872         if (val < (INT_MIN / 1024))
873             conf_parserror("value too small");
874         val *= 1024;
875         break;
876
877     case CONF_MULT1G:
878         if (val > (INT_MAX / (1024 * 1024)))
879             conf_parserror("value too large");
880         if (val < (INT_MIN / (1024 * 1024)))
881             conf_parserror("value too small");
882         val *= 1024 * 1024;
883         break;
884
885     default:    /* it was not a multiplier */
886         unget_conftoken();
887         break;
888     }
889
890     keytable = save_kt;
891     return val;
892 }
893
894 long
895 get_long(void)
896 {
897     long val;
898     keytab_t *save_kt;
899
900     save_kt = keytable;
901     keytable = numb_keytable;
902
903     get_conftoken(CONF_ANY);
904
905     switch(tok) {
906     case CONF_LONG:
907         val = tokenval.v.l;
908         break;
909
910     case CONF_INT:
911 #if SIZEOF_LONG < SIZEOF_INT
912         if ((off_t)tokenval.v.i > (off_t)LONG_MAX)
913             conf_parserror("value too large");
914         if ((off_t)tokenval.v.i < (off_t)LONG_MIN)
915             conf_parserror("value too small");
916 #endif
917         val = (long)tokenval.v.i;
918         break;
919
920     case CONF_SIZE:
921 #if SIZEOF_LONG < SIZEOF_SSIZE_T
922         if ((off_t)tokenval.v.size > (off_t)LONG_MAX)
923             conf_parserror("value too large");
924         if ((off_t)tokenval.v.size < (off_t)LONG_MIN)
925             conf_parserror("value too small");
926 #endif
927         val = (long)tokenval.v.size;
928         break;
929
930     case CONF_AM64:
931 #if SIZEOF_LONG < SIZEOF_LONG_LONG
932         if (tokenval.v.am64 > (off_t)LONG_MAX)
933             conf_parserror("value too large");
934         if (tokenval.v.am64 < (off_t)LONG_MIN)
935             conf_parserror("value too small");
936 #endif
937         val = (long)tokenval.v.am64;
938         break;
939
940     case CONF_AMINFINITY:
941         val = (long)LONG_MAX;
942         break;
943
944     default:
945         conf_parserror("a long is expected");
946         val = 0;
947         break;
948     }
949
950     /* get multiplier, if any */
951     get_conftoken(CONF_ANY);
952
953     switch(tok) {
954     case CONF_NL:                       /* multiply by one */
955     case CONF_MULT1:
956     case CONF_MULT1K:
957         break;
958
959     case CONF_MULT7:
960         if (val > (LONG_MAX / 7L))
961             conf_parserror("value too large");
962         if (val < (LONG_MIN / 7L))
963             conf_parserror("value too small");
964         val *= 7L;
965         break;
966
967     case CONF_MULT1M:
968         if (val > (LONG_MAX / 1024L))
969             conf_parserror("value too large");
970         if (val < (LONG_MIN / 1024L))
971             conf_parserror("value too small");
972         val *= 1024L;
973         break;
974
975     case CONF_MULT1G:
976         if (val > (LONG_MAX / (1024L * 1024L)))
977             conf_parserror("value too large");
978         if (val < (LONG_MIN / (1024L * 1024L)))
979             conf_parserror("value too small");
980         val *= 1024L * 1024L;
981         break;
982
983     default:    /* it was not a multiplier */
984         unget_conftoken();
985         break;
986     }
987
988     keytable = save_kt;
989     return val;
990 }
991
992 ssize_t
993 get_size(void)
994 {
995     ssize_t val;
996     keytab_t *save_kt;
997
998     save_kt = keytable;
999     keytable = numb_keytable;
1000
1001     get_conftoken(CONF_ANY);
1002
1003     switch(tok) {
1004     case CONF_SIZE:
1005         val = tokenval.v.size;
1006         break;
1007
1008     case CONF_INT:
1009 #if SIZEOF_SIZE_T < SIZEOF_INT
1010         if ((off_t)tokenval.v.i > (off_t)SSIZE_MAX)
1011             conf_parserror("value too large");
1012         if ((off_t)tokenval.v.i < (off_t)SSIZE_MIN)
1013             conf_parserror("value too small");
1014 #endif
1015         val = (ssize_t)tokenval.v.i;
1016         break;
1017
1018     case CONF_LONG:
1019 #if SIZEOF_SIZE_T < SIZEOF_LONG
1020         if ((off_t)tokenval.v.l > (off_t)SSIZE_MAX)
1021             conf_parserror("value too large");
1022         if ((off_t)tokenval.v.l < (off_t)SSIZE_MIN)
1023             conf_parserror("value too small");
1024 #endif
1025         val = (ssize_t)tokenval.v.l;
1026         break;
1027
1028     case CONF_AM64:
1029 #if SIZEOF_SIZE_T < SIZEOF_LONG_LONG
1030         if (tokenval.v.am64 > (off_t)SSIZE_MAX)
1031             conf_parserror("value too large");
1032         if (tokenval.v.am64 < (off_t)SSIZE_MIN)
1033             conf_parserror("value too small");
1034 #endif
1035         val = (ssize_t)tokenval.v.am64;
1036         break;
1037
1038     case CONF_AMINFINITY:
1039         val = (ssize_t)SSIZE_MAX;
1040         break;
1041
1042     default:
1043         conf_parserror("an integer is expected");
1044         val = 0;
1045         break;
1046     }
1047
1048     /* get multiplier, if any */
1049     get_conftoken(CONF_ANY);
1050
1051     switch(tok) {
1052     case CONF_NL:                       /* multiply by one */
1053     case CONF_MULT1:
1054     case CONF_MULT1K:
1055         break;
1056
1057     case CONF_MULT7:
1058         if (val > (ssize_t)(SSIZE_MAX / 7))
1059             conf_parserror("value too large");
1060         if (val < (ssize_t)(SSIZE_MIN / 7))
1061             conf_parserror("value too small");
1062         val *= (ssize_t)7;
1063         break;
1064
1065     case CONF_MULT1M:
1066         if (val > (ssize_t)(SSIZE_MAX / (ssize_t)1024))
1067             conf_parserror("value too large");
1068         if (val < (ssize_t)(SSIZE_MIN / (ssize_t)1024))
1069             conf_parserror("value too small");
1070         val *= (ssize_t)1024;
1071         break;
1072
1073     case CONF_MULT1G:
1074         if (val > (ssize_t)(SSIZE_MAX / (1024 * 1024)))
1075             conf_parserror("value too large");
1076         if (val < (ssize_t)(SSIZE_MIN / (1024 * 1024)))
1077             conf_parserror("value too small");
1078         val *= (ssize_t)(1024 * 1024);
1079         break;
1080
1081     default:    /* it was not a multiplier */
1082         unget_conftoken();
1083         break;
1084     }
1085
1086     keytable = save_kt;
1087     return val;
1088 }
1089
1090 off_t
1091 get_am64_t(void)
1092 {
1093     off_t val;
1094     keytab_t *save_kt;
1095
1096     save_kt = keytable;
1097     keytable = numb_keytable;
1098
1099     get_conftoken(CONF_ANY);
1100
1101     switch(tok) {
1102     case CONF_INT:
1103         val = (off_t)tokenval.v.i;
1104         break;
1105
1106     case CONF_LONG:
1107         val = (off_t)tokenval.v.l;
1108         break;
1109
1110     case CONF_SIZE:
1111         val = (off_t)tokenval.v.size;
1112         break;
1113
1114     case CONF_AM64:
1115         val = tokenval.v.am64;
1116         break;
1117
1118     case CONF_AMINFINITY:
1119         val = AM64_MAX;
1120         break;
1121
1122     default:
1123         conf_parserror("an am64 is expected %d", tok);
1124         val = 0;
1125         break;
1126     }
1127
1128     /* get multiplier, if any */
1129     get_conftoken(CONF_ANY);
1130
1131     switch(tok) {
1132     case CONF_NL:                       /* multiply by one */
1133     case CONF_MULT1:
1134     case CONF_MULT1K:
1135         break;
1136
1137     case CONF_MULT7:
1138         if (val > AM64_MAX/7 || val < AM64_MIN/7)
1139             conf_parserror("value too large");
1140         val *= 7;
1141         break;
1142
1143     case CONF_MULT1M:
1144         if (val > AM64_MAX/1024 || val < AM64_MIN/1024)
1145             conf_parserror("value too large");
1146         val *= 1024;
1147         break;
1148
1149     case CONF_MULT1G:
1150         if (val > AM64_MAX/(1024*1024) || val < AM64_MIN/(1024*1024))
1151             conf_parserror("value too large");
1152         val *= 1024*1024;
1153         break;
1154
1155     default:    /* it was not a multiplier */
1156         unget_conftoken();
1157         break;
1158     }
1159
1160     keytable = save_kt;
1161
1162     return val;
1163 }
1164
1165 keytab_t bool_keytable[] = {
1166     { "Y", CONF_ATRUE },
1167     { "YES", CONF_ATRUE },
1168     { "T", CONF_ATRUE },
1169     { "TRUE", CONF_ATRUE },
1170     { "ON", CONF_ATRUE },
1171     { "N", CONF_AFALSE },
1172     { "NO", CONF_AFALSE },
1173     { "F", CONF_AFALSE },
1174     { "FALSE", CONF_AFALSE },
1175     { "OFF", CONF_AFALSE },
1176     { NULL, CONF_IDENT }
1177 };
1178
1179 int
1180 get_bool(void)
1181 {
1182     int val;
1183     keytab_t *save_kt;
1184
1185     save_kt = keytable;
1186     keytable = bool_keytable;
1187
1188     get_conftoken(CONF_ANY);
1189
1190     switch(tok) {
1191     case CONF_INT:
1192         if (tokenval.v.i != 0)
1193             val = 1;
1194         else
1195             val = 0;
1196         break;
1197
1198     case CONF_LONG:
1199         if (tokenval.v.l != 0L)
1200             val = 1;
1201         else
1202             val = 0;
1203         break;
1204
1205     case CONF_SIZE:
1206         if (tokenval.v.size != (size_t)0)
1207             val = 1;
1208         else
1209             val = 0;
1210         break;
1211
1212     case CONF_AM64:
1213         if (tokenval.v.am64 != (off_t)0)
1214             val = 1;
1215         else
1216             val = 0;
1217         break;
1218
1219     case CONF_ATRUE:
1220         val = 1;
1221         break;
1222
1223     case CONF_AFALSE:
1224         val = 0;
1225         break;
1226
1227     case CONF_NL:
1228         unget_conftoken();
1229         val = 2; /* no argument - most likely TRUE */
1230         break;
1231     default:
1232         unget_conftoken();
1233         val = 3; /* a bad argument - most likely TRUE */
1234         conf_parserror("YES, NO, TRUE, FALSE, ON, OFF expected");
1235         break;
1236     }
1237
1238     keytable = save_kt;
1239     return val;
1240 }
1241
1242 void
1243 ckseen(
1244     int *seen)
1245 {
1246     if (*seen && !allow_overwrites && conf_line_num != -2) {
1247         conf_parserror("duplicate parameter, prev def on line %d", *seen);
1248     }
1249     *seen = conf_line_num;
1250 }
1251
1252 printf_arglist_function(void conf_parserror, const char *, format)
1253 {
1254     va_list argp;
1255
1256     /* print error message */
1257
1258     if(conf_line)
1259         fprintf(stderr, "argument \"%s\": ", conf_line);
1260     else
1261         fprintf(stderr, "\"%s\", line %d: ", conf_confname, conf_line_num);
1262     arglist_start(argp, format);
1263     vfprintf(stderr, format, argp);
1264     arglist_end(argp);
1265     fputc('\n', stderr);
1266
1267     got_parserror = 1;
1268 }
1269
1270 tok_t
1271 lookup_keyword(
1272     char *      str)
1273 {
1274     keytab_t *kwp;
1275
1276     /* switch to binary search if performance warrants */
1277
1278     for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1279         if (strcasecmp(kwp->keyword, str) == 0) break;
1280     }
1281     return kwp->token;
1282 }
1283
1284 char tkbuf[4096];
1285
1286 /* push the last token back (can only unget ANY tokens) */
1287 void
1288 unget_conftoken(void)
1289 {
1290     token_pushed = 1;
1291     pushed_tok = tok;
1292     tok = CONF_UNKNOWN;
1293     return;
1294 }
1295
1296 int
1297 conftoken_getc(void)
1298 {
1299     if(conf_line == NULL)
1300         return getc(conf_conf);
1301     if(*conf_char == '\0')
1302         return -1;
1303     return(*conf_char++);
1304 }
1305
1306 int
1307 conftoken_ungetc(
1308     int c)
1309 {
1310     if(conf_line == NULL)
1311         return ungetc(c, conf_conf);
1312     else if(conf_char > conf_line) {
1313         if(c == -1)
1314             return c;
1315         conf_char--;
1316         if(*conf_char != c) {
1317             error("*conf_char != c   : %c %c", *conf_char, c);
1318             /* NOTREACHED */
1319         }
1320     } else {
1321         error("conf_char == conf_line");
1322         /* NOTREACHED */
1323     }
1324     return c;
1325 }
1326
1327 void
1328 get_conftoken(
1329     tok_t       exp)
1330 {
1331     int ch, d;
1332     off_t am64;
1333     char *buf;
1334     char *tmps;
1335     int token_overflow;
1336     int inquote = 0;
1337     int escape = 0;
1338     int sign;
1339
1340     if (token_pushed) {
1341         token_pushed = 0;
1342         tok = pushed_tok;
1343
1344         /*
1345         ** If it looked like a key word before then look it
1346         ** up again in the current keyword table.
1347         */
1348         switch(tok) {
1349         case CONF_LONG:    case CONF_AM64:    case CONF_SIZE:
1350         case CONF_INT:     case CONF_REAL:    case CONF_STRING:
1351         case CONF_LBRACE:  case CONF_RBRACE:  case CONF_COMMA:
1352         case CONF_NL:      case CONF_END:     case CONF_UNKNOWN:
1353         case CONF_TIME:
1354             break;
1355
1356         default:
1357             if (exp == CONF_IDENT)
1358                 tok = CONF_IDENT;
1359             else
1360                 tok = lookup_keyword(tokenval.v.s);
1361             break;
1362         }
1363     }
1364     else {
1365         ch = conftoken_getc();
1366
1367         while(ch != EOF && ch != '\n' && isspace(ch))
1368             ch = conftoken_getc();
1369         if (ch == '#') {        /* comment - eat everything but eol/eof */
1370             while((ch = conftoken_getc()) != EOF && ch != '\n') {
1371                 (void)ch; /* Quiet empty loop complaints */     
1372             }
1373         }
1374
1375         if (isalpha(ch)) {              /* identifier */
1376             buf = tkbuf;
1377             token_overflow = 0;
1378             do {
1379                 if (buf < tkbuf+sizeof(tkbuf)-1) {
1380                     *buf++ = (char)ch;
1381                 } else {
1382                     *buf = '\0';
1383                     if (!token_overflow) {
1384                         conf_parserror("token too long: %.20s...", tkbuf);
1385                     }
1386                     token_overflow = 1;
1387                 }
1388                 ch = conftoken_getc();
1389             } while(isalnum(ch) || ch == '_' || ch == '-');
1390
1391             if (ch != EOF && conftoken_ungetc(ch) == EOF) {
1392                 if (ferror(conf_conf)) {
1393                     conf_parserror("Pushback of '%c' failed: %s",
1394                                    ch, strerror(ferror(conf_conf)));
1395                 } else {
1396                     conf_parserror("Pushback of '%c' failed: EOF", ch);
1397                 }
1398             }
1399             *buf = '\0';
1400
1401             tokenval.v.s = tkbuf;
1402
1403             if (token_overflow) tok = CONF_UNKNOWN;
1404             else if (exp == CONF_IDENT) tok = CONF_IDENT;
1405             else tok = lookup_keyword(tokenval.v.s);
1406         }
1407         else if (isdigit(ch)) { /* integer */
1408             sign = 1;
1409
1410 negative_number: /* look for goto negative_number below sign is set there */
1411             am64 = 0;
1412             do {
1413                 am64 = am64 * 10 + (ch - '0');
1414                 ch = conftoken_getc();
1415             } while (isdigit(ch));
1416
1417             if (ch != '.') {
1418                 if (exp == CONF_INT) {
1419                     tok = CONF_INT;
1420                     tokenval.v.i = sign * (int)am64;
1421                 } else if (exp == CONF_LONG) {
1422                     tok = CONF_LONG;
1423                     tokenval.v.l = (long)sign * (long)am64;
1424                 } else if (exp != CONF_REAL) {
1425                     tok = CONF_AM64;
1426                     tokenval.v.am64 = (off_t)sign * am64;
1427                 } else {
1428                     /* automatically convert to real when expected */
1429                     tokenval.v.r = (double)sign * (double)am64;
1430                     tok = CONF_REAL;
1431                 }
1432             } else {
1433                 /* got a real number, not an int */
1434                 tokenval.v.r = sign * (double) am64;
1435                 am64 = 0;
1436                 d = 1;
1437                 ch = conftoken_getc();
1438                 while (isdigit(ch)) {
1439                     am64 = am64 * 10 + (ch - '0');
1440                     d = d * 10;
1441                     ch = conftoken_getc();
1442                 }
1443                 tokenval.v.r += sign * ((double)am64) / d;
1444                 tok = CONF_REAL;
1445             }
1446
1447             if (ch != EOF &&  conftoken_ungetc(ch) == EOF) {
1448                 if (ferror(conf_conf)) {
1449                     conf_parserror("Pushback of '%c' failed: %s",
1450                                    ch, strerror(ferror(conf_conf)));
1451                 } else {
1452                     conf_parserror("Pushback of '%c' failed: EOF", ch);
1453                 }
1454             }
1455         } else switch(ch) {
1456         case '"':                       /* string */
1457             buf = tkbuf;
1458             token_overflow = 0;
1459             inquote = 1;
1460             *buf++ = (char)ch;
1461             while (inquote && ((ch = conftoken_getc()) != EOF)) {
1462                 if (ch == '\n') {
1463                     if (!escape)
1464                         break;
1465                     escape = 0;
1466                     buf--; /* Consume escape in buffer */
1467                 } else if (ch == '\\') {
1468                     escape = 1;
1469                 } else {
1470                     if (ch == '"') {
1471                         if (!escape)
1472                             inquote = 0;
1473                     }
1474                     escape = 0;
1475                 }
1476
1477                 if(buf >= &tkbuf[sizeof(tkbuf) - 1]) {
1478                     if (!token_overflow) {
1479                         conf_parserror("string too long: %.20s...", tkbuf);
1480                     }
1481                     token_overflow = 1;
1482                     break;
1483                 }
1484                 *buf++ = (char)ch;
1485             }
1486             *buf = '\0';
1487
1488             /*
1489              * A little manuver to leave a fully unquoted, unallocated  string
1490              * in tokenval.v.s
1491              */
1492             tmps = unquote_string(tkbuf);
1493             strncpy(tkbuf, tmps, sizeof(tkbuf));
1494             amfree(tmps);
1495             tokenval.v.s = tkbuf;
1496
1497             tok = (token_overflow) ? CONF_UNKNOWN :
1498                         (exp == CONF_IDENT) ? CONF_IDENT : CONF_STRING;
1499             break;
1500
1501         case '-':
1502             ch = conftoken_getc();
1503             if (isdigit(ch)) {
1504                 sign = -1;
1505                 goto negative_number;
1506             }
1507             else {
1508                 if (ch != EOF && conftoken_ungetc(ch) == EOF) {
1509                     if (ferror(conf_conf)) {
1510                         conf_parserror("Pushback of '%c' failed: %s",
1511                                        ch, strerror(ferror(conf_conf)));
1512                     } else {
1513                         conf_parserror("Pushback of '%c' failed: EOF", ch);
1514                     }
1515                 }
1516                 tok = CONF_UNKNOWN;
1517             }
1518             break;
1519
1520         case ',':
1521             tok = CONF_COMMA;
1522             break;
1523
1524         case '{':
1525             tok = CONF_LBRACE;
1526             break;
1527
1528         case '}':
1529             tok = CONF_RBRACE;
1530             break;
1531
1532         case '\n':
1533             tok = CONF_NL;
1534             break;
1535
1536         case EOF:
1537             tok = CONF_END;
1538             break;
1539
1540         default:
1541             tok = CONF_UNKNOWN;
1542             break;
1543         }
1544     }
1545
1546     if (exp != CONF_ANY && tok != exp) {
1547         char *str;
1548         keytab_t *kwp;
1549
1550         switch(exp) {
1551         case CONF_LBRACE:
1552             str = "\"{\"";
1553             break;
1554
1555         case CONF_RBRACE:
1556             str = "\"}\"";
1557             break;
1558
1559         case CONF_COMMA:
1560             str = "\",\"";
1561             break;
1562
1563         case CONF_NL:
1564             str = "end of line";
1565             break;
1566
1567         case CONF_END:
1568             str = "end of file";
1569             break;
1570
1571         case CONF_INT:
1572             str = "an integer";
1573             break;
1574
1575         case CONF_REAL:
1576             str = "a real number";
1577             break;
1578
1579         case CONF_STRING:
1580             str = "a quoted string";
1581             break;
1582
1583         case CONF_IDENT:
1584             str = "an identifier";
1585             break;
1586
1587         default:
1588             for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1589                 if (exp == kwp->token)
1590                     break;
1591             }
1592             if (kwp->keyword == NULL)
1593                 str = "token not";
1594             else
1595                 str = kwp->keyword;
1596             break;
1597         }
1598         conf_parserror("%s is expected", str);
1599         tok = exp;
1600         if (tok == CONF_INT)
1601             tokenval.v.i = 0;
1602         else
1603             tokenval.v.s = "";
1604     }
1605 }
1606
1607
1608 void
1609 read_string(
1610     t_conf_var *np,
1611     val_t *val)
1612 {
1613     np = np;
1614     ckseen(&val->seen);
1615     get_conftoken(CONF_STRING);
1616     val->v.s = newstralloc(val->v.s, tokenval.v.s);
1617 }
1618
1619 void
1620 read_ident(
1621     t_conf_var *np,
1622     val_t *val)
1623 {
1624     np = np;
1625     ckseen(&val->seen);
1626     get_conftoken(CONF_IDENT);
1627     val->v.s = newstralloc(val->v.s, tokenval.v.s);
1628 }
1629
1630 void
1631 read_int(
1632     t_conf_var *np,
1633     val_t *val)
1634 {
1635     np = np;
1636     ckseen(&val->seen);
1637     val->v.i = get_int();
1638 }
1639
1640 void
1641 read_long(
1642     t_conf_var *np,
1643     val_t *val)
1644 {
1645     np = np;
1646     ckseen(&val->seen);
1647     val->v.l = get_long();
1648 }
1649
1650 void
1651 read_size(
1652     t_conf_var *np,
1653     val_t *val)
1654 {
1655     np = np;
1656     ckseen(&val->seen);
1657     val->v.size = get_size();
1658 }
1659
1660 void
1661 read_am64(
1662     t_conf_var *np,
1663     val_t *val)
1664 {
1665     np = np;
1666     ckseen(&val->seen);
1667     val->v.am64 = get_am64_t();
1668 }
1669
1670 void
1671 read_bool(
1672     t_conf_var *np,
1673     val_t *val)
1674 {
1675     np = np;
1676     ckseen(&val->seen);
1677     val->v.i = get_bool();
1678 }
1679
1680 void
1681 read_real(
1682     t_conf_var *np,
1683     val_t *val)
1684 {
1685     np = np;
1686     ckseen(&val->seen);
1687     get_conftoken(CONF_REAL);
1688     val->v.r = tokenval.v.r;
1689 }
1690
1691 void
1692 read_time(
1693     t_conf_var *np,
1694     val_t *val)
1695 {
1696     np = np;
1697     ckseen(&val->seen);
1698     val->v.t = get_time();
1699 }
1700
1701 void
1702 copy_val_t(
1703     val_t *valdst,
1704     val_t *valsrc)
1705 {
1706     if(valsrc->seen) {
1707         valdst->type = valsrc->type;
1708         valdst->seen = valsrc->seen;
1709         switch(valsrc->type) {
1710         case CONFTYPE_INT:
1711         case CONFTYPE_BOOL:
1712         case CONFTYPE_COMPRESS:
1713         case CONFTYPE_ENCRYPT:
1714         case CONFTYPE_HOLDING:
1715         case CONFTYPE_ESTIMATE:
1716         case CONFTYPE_STRATEGY:
1717         case CONFTYPE_TAPERALGO:
1718         case CONFTYPE_PRIORITY:
1719             valdst->v.i = valsrc->v.i;
1720             break;
1721
1722         case CONFTYPE_LONG:
1723             valdst->v.l = valsrc->v.l;
1724             break;
1725
1726         case CONFTYPE_SIZE:
1727             valdst->v.size = valsrc->v.size;
1728             break;
1729
1730         case CONFTYPE_AM64:
1731             valdst->v.am64 = valsrc->v.am64;
1732             break;
1733
1734         case CONFTYPE_REAL:
1735             valdst->v.r = valsrc->v.r;
1736             break;
1737
1738         case CONFTYPE_RATE:
1739             valdst->v.rate[0] = valsrc->v.rate[0];
1740             valdst->v.rate[1] = valsrc->v.rate[1];
1741             break;
1742
1743         case CONFTYPE_IDENT:
1744         case CONFTYPE_STRING:
1745             valdst->v.s = stralloc(valsrc->v.s);
1746             break;
1747
1748         case CONFTYPE_TIME:
1749             valdst->v.t = valsrc->v.t;
1750             break;
1751
1752         case CONFTYPE_SL:
1753             valdst->v.sl = duplicate_sl(valsrc->v.sl);
1754             break;
1755
1756         case CONFTYPE_EXINCLUDE:
1757             valdst->v.exinclude.optional = valsrc->v.exinclude.optional;
1758             valdst->v.exinclude.sl_list = duplicate_sl(valsrc->v.exinclude.sl_list);
1759             valdst->v.exinclude.sl_file = duplicate_sl(valsrc->v.exinclude.sl_file);
1760             break;
1761         }
1762     }
1763 }
1764
1765 void
1766 free_val_t(
1767     val_t *val)
1768 {
1769     switch(val->type) {
1770         case CONFTYPE_INT:
1771         case CONFTYPE_BOOL:
1772         case CONFTYPE_COMPRESS:
1773         case CONFTYPE_ENCRYPT:
1774         case CONFTYPE_HOLDING:
1775         case CONFTYPE_ESTIMATE:
1776         case CONFTYPE_STRATEGY:
1777         case CONFTYPE_SIZE:
1778         case CONFTYPE_TAPERALGO:
1779         case CONFTYPE_PRIORITY:
1780         case CONFTYPE_LONG:
1781         case CONFTYPE_AM64:
1782         case CONFTYPE_REAL:
1783         case CONFTYPE_RATE:
1784             break;
1785
1786         case CONFTYPE_IDENT:
1787         case CONFTYPE_STRING:
1788             amfree(val->v.s);
1789             break;
1790
1791         case CONFTYPE_TIME:
1792             break;
1793
1794         case CONFTYPE_SL:
1795             free_sl(val->v.sl);
1796             break;
1797
1798         case CONFTYPE_EXINCLUDE:
1799             free_sl(val->v.exinclude.sl_list);
1800             free_sl(val->v.exinclude.sl_file);
1801             break;
1802     }
1803     val->seen = 0;
1804 }
1805
1806 char *
1807 taperalgo2str(
1808     int taperalgo)
1809 {
1810     if(taperalgo == ALGO_FIRST) return "FIRST";
1811     if(taperalgo == ALGO_FIRSTFIT) return "FIRSTFIT";
1812     if(taperalgo == ALGO_LARGEST) return "LARGEST";
1813     if(taperalgo == ALGO_LARGESTFIT) return "LARGESTFIT";
1814     if(taperalgo == ALGO_SMALLEST) return "SMALLEST";
1815     if(taperalgo == ALGO_LAST) return "LAST";
1816     return "UNKNOWN";
1817 }
1818
1819 static char buffer_conf_print[1025];
1820
1821 char *
1822 conf_print(
1823     val_t *val,
1824     int    str_need_quote)
1825 {
1826     buffer_conf_print[0] = '\0';
1827     switch(val->type) {
1828     case CONFTYPE_INT:
1829         snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%d", val->v.i);
1830         break;
1831
1832     case CONFTYPE_LONG:
1833         snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%ld", val->v.l);
1834         break;
1835
1836     case CONFTYPE_SIZE:
1837         snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), SSIZE_T_FMT,
1838                 (SSIZE_T_FMT_TYPE)val->v.size);
1839         break;
1840
1841     case CONFTYPE_AM64:
1842         snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), OFF_T_FMT ,
1843                  (OFF_T_FMT_TYPE)val->v.am64);
1844         break;
1845
1846     case CONFTYPE_REAL:
1847         snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%0.5f" , val->v.r);
1848         break;
1849
1850     case CONFTYPE_RATE:
1851         snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%0.5f %0.5f" , val->v.rate[0], val->v.rate[1]);
1852         break;
1853
1854     case CONFTYPE_IDENT:
1855         if(val->v.s) {
1856             strncpy(buffer_conf_print, val->v.s, SIZEOF(buffer_conf_print));
1857             buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0';
1858         } else
1859             buffer_conf_print[0] = '\0';
1860         break;
1861
1862     case CONFTYPE_STRING:
1863         if(str_need_quote) {
1864             buffer_conf_print[0] = '"';
1865             if(val->v.s) {
1866                 strncpy(&buffer_conf_print[1], val->v.s,
1867                         SIZEOF(buffer_conf_print) - 1);
1868                 buffer_conf_print[SIZEOF(buffer_conf_print) - 2] = '\0';
1869                 buffer_conf_print[strlen(buffer_conf_print)] = '"';
1870             } else {
1871                 buffer_conf_print[1] = '"';
1872                 buffer_conf_print[2] = '\0';
1873             }
1874         } else {
1875             if(val->v.s) {
1876                 strncpy(&buffer_conf_print[0], val->v.s,
1877                         SIZEOF(buffer_conf_print));
1878                 buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0';
1879             } else {
1880                 buffer_conf_print[0] = '\0';
1881             }
1882         }
1883         break;
1884
1885     case CONFTYPE_TIME:
1886         snprintf(buffer_conf_print, SIZEOF(buffer_conf_print),
1887                  "%2d%02d", (int)val->v.t/100, (int)val->v.t % 100);
1888         break;
1889
1890     case CONFTYPE_SL:
1891         buffer_conf_print[0] = '\0';
1892         break;
1893
1894     case CONFTYPE_EXINCLUDE:
1895         strcpy(buffer_conf_print, "ERROR: use print_conf_exinclude");
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 char *
2038 conf_print_exinclude(
2039     val_t *val,
2040     int    str_need_quote,
2041     int    file)
2042 {
2043     int    pos;
2044     sl_t  *sl;
2045     sle_t *excl;
2046
2047     (void)str_need_quote;
2048     buffer_conf_print[0] = '\0';
2049     if (val->type != CONFTYPE_EXINCLUDE) {
2050         strcpy(buffer_conf_print, "ERROR: conf_print_exinclude called for type != CONFTYPE_EXINCLUDE");
2051         return buffer_conf_print;
2052     }
2053
2054     if (file == 0) {
2055         sl = val->v.exinclude.sl_list;
2056         strncpy(buffer_conf_print, "LIST ", SIZEOF(buffer_conf_print));
2057         pos = 5;
2058     } else {
2059         sl = val->v.exinclude.sl_file;
2060         strncpy(buffer_conf_print, "FILE ", SIZEOF(buffer_conf_print));
2061         pos = 5;
2062     }
2063
2064     if(val->v.exinclude.optional == 1) {
2065         strncpy(&buffer_conf_print[pos], "OPTIONAL ", SIZEOF(buffer_conf_print)-pos);
2066         pos += 9;
2067     }
2068
2069     if( sl != NULL) {
2070         for(excl = sl->first; excl != NULL; excl = excl->next) {
2071             if (pos + 3 + strlen(excl->name) < SIZEOF(buffer_conf_print)) {
2072                 buffer_conf_print[pos++] = ' ';
2073                 buffer_conf_print[pos++] = '"';
2074                 strcpy(&buffer_conf_print[pos], excl->name);
2075                 pos += strlen(excl->name);
2076                 buffer_conf_print[pos++] = '"';
2077             }
2078         }
2079     }
2080
2081     buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0';
2082     return buffer_conf_print;
2083 }
2084
2085 void
2086 conf_init_string(
2087     val_t *val,
2088     char  *s)
2089 {
2090     val->seen = 0;
2091     val->type = CONFTYPE_STRING;
2092     if(s)
2093         val->v.s = stralloc(s);
2094     else
2095         val->v.s = NULL;
2096 }
2097
2098 void
2099 conf_init_ident(
2100     val_t *val,
2101     char  *s)
2102 {
2103     val->seen = 0;
2104     val->type = CONFTYPE_IDENT;
2105     if(s)
2106         val->v.s = stralloc(s);
2107     else
2108         val->v.s = NULL;
2109 }
2110
2111 void
2112 conf_init_int(
2113     val_t *val,
2114     int    i)
2115 {
2116     val->seen = 0;
2117     val->type = CONFTYPE_INT;
2118     val->v.i = i;
2119 }
2120
2121 void
2122 conf_init_bool(
2123     val_t *val,
2124     int    i)
2125 {
2126     val->seen = 0;
2127     val->type = CONFTYPE_BOOL;
2128     val->v.i = i;
2129 }
2130
2131 void
2132 conf_init_strategy(
2133     val_t *val,
2134     int    i)
2135 {
2136     val->seen = 0;
2137     val->type = CONFTYPE_STRATEGY;
2138     val->v.i = i;
2139 }
2140
2141 void
2142 conf_init_estimate(
2143     val_t *val,
2144     int    i)
2145 {
2146     val->seen = 0;
2147     val->type = CONFTYPE_ESTIMATE;
2148     val->v.i = i;
2149 }
2150
2151 void
2152 conf_init_taperalgo(
2153     val_t *val,
2154     int    i)
2155 {
2156     val->seen = 0;
2157     val->type = CONFTYPE_TAPERALGO;
2158     val->v.i = i;
2159 }
2160
2161 void
2162 conf_init_priority(
2163     val_t *val,
2164     int    i)
2165 {
2166     val->seen = 0;
2167     val->type = CONFTYPE_PRIORITY;
2168     val->v.i = i;
2169 }
2170
2171 void
2172 conf_init_compress(
2173     val_t *val,
2174     comp_t    i)
2175 {
2176     val->seen = 0;
2177     val->type = CONFTYPE_COMPRESS;
2178     val->v.i = (int)i;
2179 }
2180
2181 void
2182 conf_init_encrypt(
2183     val_t *val,
2184     encrypt_t    i)
2185 {
2186     val->seen = 0;
2187     val->type = CONFTYPE_ENCRYPT;
2188     val->v.i = (int)i;
2189 }
2190
2191 void
2192 conf_init_holding(
2193     val_t              *val,
2194     dump_holdingdisk_t  i)
2195 {
2196     val->seen = 0;
2197     val->type = CONFTYPE_HOLDING;
2198     val->v.i = (int)i;
2199 }
2200
2201 void
2202 conf_init_long(
2203     val_t *val,
2204     long   l)
2205 {
2206     val->seen = 0;
2207     val->type = CONFTYPE_LONG;
2208     val->v.l = l;
2209 }
2210
2211 void
2212 conf_init_size(
2213     val_t *val,
2214     ssize_t   sz)
2215 {
2216     val->seen = 0;
2217     val->type = CONFTYPE_SIZE;
2218     val->v.size = sz;
2219 }
2220
2221 void
2222 conf_init_am64(
2223     val_t *val,
2224     off_t   l)
2225 {
2226     val->seen = 0;
2227     val->type = CONFTYPE_AM64;
2228     val->v.am64 = l;
2229 }
2230
2231 void
2232 conf_init_real(
2233     val_t  *val,
2234     double r)
2235 {
2236     val->seen = 0;
2237     val->type = CONFTYPE_REAL;
2238     val->v.r = r;
2239 }
2240
2241 void
2242 conf_init_rate(
2243     val_t  *val,
2244     double r1,
2245     double r2)
2246 {
2247     val->seen = 0;
2248     val->type = CONFTYPE_RATE;
2249     val->v.rate[0] = r1;
2250     val->v.rate[1] = r2;
2251 }
2252
2253 void
2254 conf_init_time(
2255     val_t *val,
2256     time_t   t)
2257 {
2258     val->seen = 0;
2259     val->type = CONFTYPE_TIME;
2260     val->v.t = t;
2261 }
2262
2263 void
2264 conf_init_sl(
2265     val_t *val,
2266     sl_t  *sl)
2267 {
2268     val->seen = 0;
2269     val->type = CONFTYPE_AM64;
2270     val->v.sl = sl;
2271 }
2272
2273 void
2274 conf_init_exinclude(
2275     val_t *val)
2276 {
2277     val->seen = 0;
2278     val->type = CONFTYPE_EXINCLUDE;
2279     val->v.exinclude.optional = 0;
2280     val->v.exinclude.sl_list = NULL;
2281     val->v.exinclude.sl_file = NULL;
2282 }
2283
2284 void
2285 conf_set_string(
2286     val_t *val,
2287     char *s)
2288 {
2289     val->seen = -1;
2290     val->type = CONFTYPE_STRING;
2291     amfree(val->v.s);
2292     val->v.s = stralloc(s);
2293 }
2294
2295 void
2296 conf_set_int(
2297     val_t *val,
2298     int    i)
2299 {
2300     val->seen = -1;
2301     val->type = CONFTYPE_INT;
2302     val->v.i = i;
2303 }
2304
2305 void
2306 conf_set_bool(
2307     val_t *val,
2308     int    i)
2309 {
2310     val->seen = -1;
2311     val->type = CONFTYPE_BOOL;
2312     val->v.i = i;
2313 }
2314
2315 void
2316 conf_set_compress(
2317     val_t *val,
2318     comp_t    i)
2319 {
2320     val->seen = -1;
2321     val->type = CONFTYPE_COMPRESS;
2322     val->v.i = (int)i;
2323 }
2324
2325 void
2326 conf_set_encrypt(
2327     val_t *val,
2328     encrypt_t    i)
2329 {
2330     val->seen = -1;
2331     val->type = CONFTYPE_COMPRESS;
2332     val->v.i = (int)i;
2333 }
2334
2335 void
2336 conf_set_holding(
2337     val_t              *val,
2338     dump_holdingdisk_t  i)
2339 {
2340     val->seen = -1;
2341     val->type = CONFTYPE_HOLDING;
2342     val->v.i = (int)i;
2343 }
2344
2345 void
2346 conf_set_strategy(
2347     val_t *val,
2348     int    i)
2349 {
2350     val->seen = -1;
2351     val->type = CONFTYPE_STRATEGY;
2352     val->v.i = i;
2353 }
2354
2355
2356 int
2357 get_conftype_int(
2358     val_t *val)
2359 {
2360     if (val->type != CONFTYPE_INT) {
2361         error("get_conftype_int: val.type is not CONFTYPE_INT");
2362         /*NOTREACHED*/
2363     }
2364     return val->v.i;
2365 }
2366
2367 long
2368 get_conftype_long(
2369     val_t *val)
2370 {
2371     if (val->type != CONFTYPE_LONG) {
2372         error("get_conftype_long: val.type is not CONFTYPE_LONG");
2373         /*NOTREACHED*/
2374     }
2375     return val->v.l;
2376 }
2377
2378 off_t
2379 get_conftype_am64(
2380     val_t *val)
2381 {
2382     if (val->type != CONFTYPE_AM64) {
2383         error("get_conftype_am64: val.type is not CONFTYPE_AM64");
2384         /*NOTREACHED*/
2385     }
2386     return val->v.am64;
2387 }
2388
2389 double
2390 get_conftype_real(
2391     val_t *val)
2392 {
2393     if (val->type != CONFTYPE_REAL) {
2394         error("get_conftype_real: val.type is not CONFTYPE_REAL");
2395         /*NOTREACHED*/
2396     }
2397     return val->v.r;
2398 }
2399
2400 char *
2401 get_conftype_string(
2402     val_t *val)
2403 {
2404     if (val->type != CONFTYPE_STRING) {
2405         error("get_conftype_string: val.type is not CONFTYPE_STRING");
2406         /*NOTREACHED*/
2407     }
2408     return val->v.s;
2409 }
2410
2411 char *
2412 get_conftype_ident(
2413     val_t *val)
2414 {
2415     if (val->type != CONFTYPE_IDENT) {
2416         error("get_conftype_ident: val.type is not CONFTYPE_IDENT");
2417         /*NOTREACHED*/
2418     }
2419     return val->v.s;
2420 }
2421
2422 time_t
2423 get_conftype_time(
2424     val_t *val)
2425 {
2426     if (val->type != CONFTYPE_TIME) {
2427         error("get_conftype_time: val.type is not CONFTYPE_TIME");
2428         /*NOTREACHED*/
2429     }
2430     return val->v.t;
2431 }
2432
2433 ssize_t
2434 get_conftype_size(
2435     val_t *val)
2436 {
2437     if (val->type != CONFTYPE_SIZE) {
2438         error("get_conftype_size: val.type is not CONFTYPE_SIZE");
2439         /*NOTREACHED*/
2440     }
2441     return val->v.size;
2442 }
2443
2444 sl_t *
2445 get_conftype_sl(
2446     val_t *val)
2447 {
2448     if (val->type != CONFTYPE_SL) {
2449         error("get_conftype_size: val.type is not CONFTYPE_SL");
2450         /*NOTREACHED*/
2451     }
2452     return val->v.sl;
2453 }
2454
2455 int
2456 get_conftype_bool(
2457     val_t *val)
2458 {
2459     if (val->type != CONFTYPE_BOOL) {
2460         error("get_conftype_bool: val.type is not CONFTYPE_BOOL");
2461         /*NOTREACHED*/
2462     }
2463     return val->v.i;
2464 }
2465
2466 int
2467 get_conftype_hold(
2468     val_t *val)
2469 {
2470     if (val->type != CONFTYPE_HOLDING) {
2471         error("get_conftype_hold: val.type is not CONFTYPE_HOLDING");
2472         /*NOTREACHED*/
2473     }
2474     return val->v.i;
2475 }
2476
2477 int
2478 get_conftype_compress(
2479     val_t *val)
2480 {
2481     if (val->type != CONFTYPE_COMPRESS) {
2482         error("get_conftype_compress: val.type is not CONFTYPE_COMPRESS");
2483         /*NOTREACHED*/
2484     }
2485     return val->v.i;
2486 }
2487
2488 int
2489 get_conftype_encrypt(
2490     val_t *val)
2491 {
2492     if (val->type != CONFTYPE_ENCRYPT) {
2493         error("get_conftype_encrypt: val.type is not CONFTYPE_ENCRYPT");
2494         /*NOTREACHED*/
2495     }
2496     return val->v.i;
2497 }
2498
2499 int
2500 get_conftype_estimate(
2501     val_t *val)
2502 {
2503     if (val->type != CONFTYPE_ESTIMATE) {
2504         error("get_conftype_extimate: val.type is not CONFTYPE_ESTIMATE");
2505         /*NOTREACHED*/
2506     }
2507     return val->v.i;
2508 }
2509
2510 int
2511 get_conftype_strategy(
2512     val_t *val)
2513 {
2514     if (val->type != CONFTYPE_STRATEGY) {
2515         error("get_conftype_strategy: val.type is not CONFTYPE_STRATEGY");
2516         /*NOTREACHED*/
2517     }
2518     return val->v.i;
2519 }
2520
2521 int
2522 get_conftype_taperalgo(
2523     val_t *val)
2524 {
2525     if (val->type != CONFTYPE_TAPERALGO) {
2526         error("get_conftype_taperalgo: val.type is not CONFTYPE_TAPERALGO");
2527         /*NOTREACHED*/
2528     }
2529     return val->v.i;
2530 }
2531
2532 int
2533 get_conftype_priority(
2534     val_t *val)
2535 {
2536     if (val->type != CONFTYPE_PRIORITY) {
2537         error("get_conftype_priority: val.type is not CONFTYPE_PRIORITY");
2538         /*NOTREACHED*/
2539     }
2540     return val->v.i;
2541 }
2542
2543 exinclude_t
2544 get_conftype_exinclude(
2545     val_t *val)
2546 {
2547     if (val->type != CONFTYPE_EXINCLUDE) {
2548         error("get_conftype_exinclude: val.type is not CONFTYPE_EXINCLUDE");
2549         /*NOTREACHED*/
2550     }
2551     return val->v.exinclude;
2552 }
2553
2554
2555 void
2556 dump_sockaddr(
2557         struct sockaddr_in *    sa)
2558 {
2559         dbprintf(("%s: (sockaddr_in *)%p = { %d, %d, %s }\n",
2560                 debug_prefix_time(NULL), sa, sa->sin_family,
2561                 (int)ntohs(sa->sin_port),
2562                 inet_ntoa(sa->sin_addr)));
2563 }
2564
2565 void
2566 read_block(
2567     command_option_t *command_options,
2568     t_conf_var    *read_var,
2569     keytab_t *keytab,
2570     val_t    *valarray,
2571     char     *prefix,
2572     char     *errormsg,
2573     int       read_brace,
2574     void      (*copy_function)(void))
2575 {
2576     t_conf_var *np;
2577     int    saved_conf_line_num;
2578     int    done;
2579
2580     if(read_brace) {
2581         get_conftoken(CONF_LBRACE);
2582         get_conftoken(CONF_NL);
2583     }
2584
2585     done = 0;
2586     do {
2587         conf_line_num += 1;
2588         get_conftoken(CONF_ANY);
2589         switch(tok) {
2590         case CONF_RBRACE:
2591             done = 1;
2592             break;
2593         case CONF_NL:   /* empty line */
2594             break;
2595         case CONF_END:  /* end of file */
2596             done = 1;
2597             break;
2598         case CONF_IDENT:
2599         case CONF_STRING:
2600             if(copy_function) 
2601                 copy_function();
2602             else
2603                 conf_parserror("ident not expected");
2604             break;
2605         default:
2606             {
2607                 for(np = read_var; np->token != CONF_UNKNOWN; np++)
2608                     if(np->token == tok) break;
2609
2610                 if(np->token == CONF_UNKNOWN)
2611                     conf_parserror(errormsg);
2612                 else {
2613                     np->read_function(np, &valarray[np->parm]);
2614                     if(np->validate)
2615                         np->validate(np, &valarray[np->parm]);
2616                 }
2617             }
2618         }
2619         if(tok != CONF_NL && tok != CONF_END && tok != CONF_RBRACE)
2620             get_conftoken(CONF_NL);
2621     } while(!done);
2622
2623     /* overwrite with command line option */
2624     saved_conf_line_num = conf_line_num;
2625     command_overwrite(command_options, read_var, keytab, valarray, prefix);
2626     conf_line_num = saved_conf_line_num;
2627 }
2628
2629 void
2630 command_overwrite(
2631     command_option_t *command_options,
2632     t_conf_var    *overwrite_var,
2633     keytab_t *keytab,
2634     val_t    *valarray,
2635     char     *prefix)
2636 {
2637     t_conf_var       *np;
2638     keytab_t         *kt;
2639     char             *myprefix;
2640     command_option_t *command_option;
2641     int               duplicate;
2642
2643     if(!command_options) return;
2644
2645     for(np = overwrite_var; np->token != CONF_UNKNOWN; np++) {
2646         for(kt = keytab; kt->token != CONF_UNKNOWN; kt++)
2647             if(kt->token == np->token) break;
2648
2649         if(kt->token == CONF_UNKNOWN) {
2650             error("read_conf: invalid token");
2651             /* NOTREACHED */
2652         }
2653
2654         for(command_option = command_options; command_option->name != NULL;
2655                                                             command_option++) {
2656             myprefix = stralloc2(prefix, kt->keyword);
2657             if(strcasecmp(myprefix, command_option->name) == 0) {
2658                 duplicate = 0;
2659                 if (command_option->used == 0 &&
2660                     valarray[np->parm].seen == -2) {
2661                     duplicate = 1;
2662                 }
2663                 command_option->used = 1;
2664                 valarray[np->parm].seen = -2;
2665                 if(np->type == CONFTYPE_STRING &&
2666                    command_option->value[0] != '"') {
2667                     conf_line = vstralloc("\"", command_option->value, "\"",
2668                                           NULL);
2669                 }
2670                 else {
2671                     conf_line = stralloc(command_option->value);
2672                 }
2673                 conf_char = conf_line;
2674                 token_pushed = 0;
2675                 conf_line_num = -2;
2676                 np->read_function(np, &valarray[np->parm]);
2677                 amfree(conf_line);
2678                 conf_line = conf_char = NULL;
2679
2680                 if (np->validate)
2681                     np->validate(np, &valarray[np->parm]);
2682                 if (duplicate == 1) {
2683                     fprintf(stderr,"Duplicate %s option, using %s\n",
2684                             command_option->name, command_option->value);
2685                 }
2686             }
2687             amfree(myprefix);
2688         }
2689     }
2690 }
2691
2692 void
2693 free_new_argv(
2694     int new_argc,
2695     char **new_argv)
2696 {
2697     int i;
2698     for(i=0; i<new_argc; i++)
2699         amfree(new_argv[i]);
2700     amfree(new_argv);
2701 }
2702
2703
2704 int copy_file(
2705     char  *dst,
2706     char  *src,
2707     char **errmsg)
2708 {
2709     int     infd, outfd;
2710     int     save_errno;
2711     ssize_t nb;
2712     char    buf[32768];
2713     char   *quoted;
2714
2715     if ((infd = open(src, O_RDONLY)) == -1) {
2716         save_errno = errno;
2717         quoted = quote_string(src);
2718         *errmsg = vstralloc("Can't open file ", quoted, " for reading: %s",
2719                             strerror(save_errno));
2720         amfree(quoted);
2721         return -1;
2722     }
2723
2724     if ((outfd = open(dst, O_WRONLY|O_CREAT, 0600)) == -1) {
2725         save_errno = errno;
2726         quoted = quote_string(dst);
2727         *errmsg = vstralloc("Can't open file ", quoted, " for writting: %s",
2728                             strerror(save_errno));
2729         amfree(quoted);
2730         close(infd);
2731         return -1;
2732     }
2733
2734     while((nb=read(infd, &buf, SIZEOF(buf))) > 0) {
2735         if(fullwrite(outfd,&buf,(size_t)nb) < nb) {
2736             save_errno = errno;
2737             quoted = quote_string(dst);
2738             *errmsg = vstralloc("Error writing to \"", quoted, "\":",
2739                                 strerror(save_errno));
2740             amfree(quoted);
2741             close(infd);
2742             close(outfd);
2743             return -1;
2744         }
2745     }
2746
2747     if (nb < 0) {
2748         save_errno = errno;
2749         quoted = quote_string(src);
2750         *errmsg = vstralloc("Error reading from \"", quoted, "\":",
2751                             strerror(save_errno));
2752         amfree(quoted);
2753         close(infd);
2754         close(outfd);
2755         return -1;
2756     }
2757
2758     close(infd);
2759     close(outfd);
2760     return 0;
2761 }
2762 #ifndef HAVE_LIBREADLINE
2763 /*
2764  * simple readline() replacements
2765  */
2766
2767 char *
2768 readline(
2769     const char *prompt)
2770 {
2771     printf("%s", prompt);
2772     fflush(stdout);
2773     fflush(stderr);
2774     return agets(stdin);
2775 }
2776
2777 void 
2778 add_history(
2779     const char *line)
2780 {
2781     (void)line;         /* Quite unused parameter warning */
2782 }
2783 #endif