2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1999 University of Maryland at College Park
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.
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.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: util.c,v 1.42 2006/08/24 01:57:15 paddy_s Exp $
38 tok_t tok, pushed_tok;
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;
47 /*#define NET_READ_DEBUG*/
50 #define netprintf(x) dbprintf(x)
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);
59 char conftoken_getc(void);
60 int conftoken_ungetc(int c);
63 * Keep calling read() until we've read buflen's worth of data, or EOF,
66 * Returns the number of bytes read, 0 on EOF, or negative on error.
74 ssize_t nread, tot = 0;
75 char *buf = vbuf; /* cast to char so we can ++ it */
78 nread = read(fd, buf, buflen);
80 if ((errno == EINTR) || (errno == EAGAIN))
82 return ((tot > 0) ? tot : -1);
96 * Keep calling write() until we've written buflen's worth of data,
99 * Returns the number of bytes written, or negative on error.
107 ssize_t nwritten, tot = 0;
108 const char *buf = vbuf; /* cast to char so we can ++ it */
111 nwritten = write(fd, buf, buflen);
113 if ((errno == EINTR) || (errno == EAGAIN))
115 return ((tot > 0) ? tot : -1);
129 #if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR)
134 if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
136 dbprintf(("%s: make_socket: socket() failed: %s\n",
138 strerror(save_errno)));
142 if (s < 0 || s >= (int)FD_SETSIZE) {
144 errno = EMFILE; /* out of range */
149 r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
152 dbprintf(("%s: stream_server: setsockopt(SO_REUSEADDR) failed: %s\n",
160 r = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
161 (void *)&on, SIZEOF(on));
164 dbprintf(("%s: make_socket: setsockopt() failed: %s\n",
166 strerror(save_errno)));
176 /* addrp is my address */
177 /* svaddr is the address of the remote machine */
178 /* return socket on success */
179 /* return -1 on failure */
182 struct sockaddr_in *addrp,
183 in_port_t first_port,
186 struct sockaddr_in *svaddr,
191 static in_port_t port_in_use[1024];
192 static int nb_port_in_use = 0;
195 assert(first_port <= last_port);
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;
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;
214 port_in_use[nb_port_in_use++] = port;
219 dbprintf(("%s: connect_portrange: all ports between %d and %d busy\n",
220 debug_prefix_time(NULL),
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 */
234 struct sockaddr_in *addrp,
237 struct sockaddr_in *svaddr,
241 struct servent * servPort;
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));
253 dbprintf(("%s: connect_port: Try port %d: Available - ",
254 debug_prefix_time(NULL), port));
256 dbprintf(("%s: connect_port: Try port %d: Owned by %s - ",
257 debug_prefix_time(NULL), port, servPort->s_name));
260 if ((s = make_socket()) == -1) return -2;
262 addrp->sin_port = (in_port_t)htons(port);
264 if (bind(s, (struct sockaddr *)addrp, sizeof(*addrp)) != 0) {
267 if (save_errno != EADDRINUSE) {
268 dbprintf(("errno %d strerror %s\n",
269 errno, strerror(errno)));
277 /* find out what port was actually used */
279 len = sizeof(*addrp);
280 if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) {
282 dbprintf(("%s: connect_port: getsockname() failed: %s\n",
284 strerror(save_errno)));
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) {
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)));
307 if (save_errno == ECONNREFUSED ||
308 save_errno == ETIMEDOUT) {
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",
320 inet_ntoa(addrp->sin_addr),
321 ntohs(addrp->sin_port)));
327 * Bind to a port in the given range. Takes a begin,end pair of port numbers.
329 * Returns negative on error (EGAIN if all ports are in use). Returns 0
335 struct sockaddr_in *addrp,
336 in_port_t first_port,
342 struct servent *servPort;
343 const in_port_t num_ports = (in_port_t)(last_port - first_port + 1);
345 assert(first_port <= last_port);
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.
351 port = (in_port_t)(((getpid() + time(0)) % num_ports) + first_port);
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.
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));
365 dbprintf(("%s: bind_portrange2: Try port %d: Owned by %s - ",
366 debug_prefix_time(NULL), port, servPort->s_name));
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"));
373 dbprintf(("%s\n", strerror(errno)));
375 dbprintf(("%s: bind_portrange2: Skip port %d: Owned by %s.\n",
376 debug_prefix_time(NULL), port, servPort->s_name));
378 if (++port > last_port)
381 dbprintf(("%s: bind_portrange: all ports between %d and %d busy\n",
382 debug_prefix_time(NULL),
390 * Construct a datestamp (YYYYMMDD) from a time_t.
397 char datestamp[3 * NUM_STR_SIZE];
401 when = time((time_t *)NULL);
405 tm = localtime(&when);
407 return stralloc("19000101");
409 snprintf(datestamp, SIZEOF(datestamp),
410 "%04d%02d%02d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
411 return stralloc(datestamp);
415 * Construct a timestamp (YYYYMMDDHHMMSS) from a time_t.
422 char timestamp[6 * NUM_STR_SIZE];
426 when = time((time_t *)NULL);
430 tm = localtime(&when);
432 return stralloc("19000101000000");
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);
446 return (match("[ \t\f\r\n\"]", str) != 0);
451 * For backward compatibility we are trying for minimal quoting.
452 * We only quote a string if it contains whitespace or is misquoted...
462 if ((str == NULL) || (*str == '\0')) {
463 ret = stralloc("\"\"");
464 } else if ((match("[\\\"[:space:][:cntrl:]]", str)) == 0) {
466 * String does not need to be quoted since it contains
467 * neither whitespace, control or quote characters.
472 * Allocate maximum possible string length.
473 * (a string of all quotes plus room for leading ", trailing " and NULL)
475 ret = s = alloc((strlen(str) * 2) + 2 + 1);
477 while (*str != '\0') {
483 } else if (*str == '\n') {
488 } else if (*str == '\r') {
493 } else if (*str == '\f') {
516 if ((str == NULL) || (*str == '\0')) {
522 ret = in = out = stralloc(str);
523 while (*in != '\0') {
535 } else if (*in == 't') {
539 } else if (*in == 'r') {
543 } else if (*in == 'f') {
563 if ((str == NULL) || (*str == '\0')) {
567 for (s = ret; *s != '\0'; s++) {
578 char * tok = strtok(NULL, " ");
580 if ((tok != NULL) && (tok[0] == '"')) {
586 t = strtok(NULL, " ");
589 } while ((t != NULL) &&
590 (tok[len - 1] != '"') && (tok[len - 2] != '\\'));
602 FILE *stream = popen("od -w10 -c -x -", "w");
604 if (stream != NULL) {
606 rc = (ssize_t)fwrite(buffer, len, 1, stream);
615 Return 0 if the following characters are present
616 * ( ) < > [ ] , ; : ! $ \ / "
624 return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto);
635 for(np = get_var; np->token != CONF_UNKNOWN; np++) {
640 if(np->token == CONF_UNKNOWN) {
641 error("error [unknown getconf_np parm: %d]", parm);
658 var->v.s = newstralloc(var->v.s, tokenval.v.s);
659 malloc_mark(var->v.s);
663 var->v.i = get_int();
667 var->v.l = get_long();
671 var->v.size = get_size();
675 var->v.am64 = get_am64_t();
679 var->v.i = get_bool();
683 get_conftoken(CONF_REAL);
684 var->v.r = tokenval.v.r;
688 var->v.t = get_time();
692 error("error [unknown get_simple type: %d]", type);
703 get_conftoken(CONF_ANY);
706 #if SIZEOF_TIME_T < SIZEOF_INT
707 if ((off_t)tokenval.v.i >= (off_t)TIME_MAX)
708 conf_parserror("value too large");
710 hhmm = (time_t)tokenval.v.i;
714 #if SIZEOF_TIME_T < SIZEOF_LONG
715 if ((off_t)tokenval.v.l >= (off_t)TIME_MAX)
716 conf_parserror("value too large");
718 hhmm = (time_t)tokenval.v.l;
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");
726 hhmm = (time_t)tokenval.v.size;
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");
734 hhmm = (time_t)tokenval.v.am64;
737 case CONF_AMINFINITY:
742 conf_parserror("a time is expected");
749 keytab_t numb_keytable[] = {
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 },
796 keytable = numb_keytable;
798 get_conftoken(CONF_ANY);
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");
811 val = (int)tokenval.v.l;
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");
821 val = (int)tokenval.v.size;
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");
831 val = (int)tokenval.v.am64;
834 case CONF_AMINFINITY:
839 conf_parserror("an int is expected");
844 /* get multiplier, if any */
845 get_conftoken(CONF_ANY);
847 case CONF_NL: /* multiply by one */
854 if (val > (INT_MAX / 7))
855 conf_parserror("value too large");
856 if (val < (INT_MIN / 7))
857 conf_parserror("value too small");
862 if (val > (INT_MAX / 1024))
863 conf_parserror("value too large");
864 if (val < (INT_MIN / 1024))
865 conf_parserror("value too small");
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");
877 default: /* it was not a multiplier */
893 keytable = numb_keytable;
895 get_conftoken(CONF_ANY);
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");
909 val = (long)tokenval.v.i;
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");
919 val = (long)tokenval.v.size;
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");
929 val = (long)tokenval.v.am64;
932 case CONF_AMINFINITY:
933 val = (long)LONG_MAX;
937 conf_parserror("a long is expected");
942 /* get multiplier, if any */
943 get_conftoken(CONF_ANY);
946 case CONF_NL: /* multiply by one */
952 if (val > (LONG_MAX / 7L))
953 conf_parserror("value too large");
954 if (val < (LONG_MIN / 7L))
955 conf_parserror("value too small");
960 if (val > (LONG_MAX / 1024L))
961 conf_parserror("value too large");
962 if (val < (LONG_MIN / 1024L))
963 conf_parserror("value too small");
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;
975 default: /* it was not a multiplier */
991 keytable = numb_keytable;
993 get_conftoken(CONF_ANY);
997 val = tokenval.v.size;
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");
1007 val = (ssize_t)tokenval.v.i;
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");
1017 val = (ssize_t)tokenval.v.l;
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");
1027 val = (ssize_t)tokenval.v.am64;
1030 case CONF_AMINFINITY:
1031 val = (ssize_t)SSIZE_MAX;
1035 conf_parserror("an integer is expected");
1040 /* get multiplier, if any */
1041 get_conftoken(CONF_ANY);
1044 case CONF_NL: /* multiply by one */
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");
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;
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);
1073 default: /* it was not a multiplier */
1089 keytable = numb_keytable;
1091 get_conftoken(CONF_ANY);
1095 val = (off_t)tokenval.v.i;
1099 val = (off_t)tokenval.v.l;
1103 val = (off_t)tokenval.v.size;
1107 val = tokenval.v.am64;
1110 case CONF_AMINFINITY:
1115 conf_parserror("an am64 is expected %d", tok);
1120 /* get multiplier, if any */
1121 get_conftoken(CONF_ANY);
1124 case CONF_NL: /* multiply by one */
1130 if (val > AM64_MAX/7 || val < AM64_MIN/7)
1131 conf_parserror("value too large");
1136 if (val > AM64_MAX/1024 || val < AM64_MIN/1024)
1137 conf_parserror("value too large");
1142 if (val > AM64_MAX/(1024*1024) || val < AM64_MIN/(1024*1024))
1143 conf_parserror("value too large");
1147 default: /* it was not a multiplier */
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 }
1178 keytable = bool_keytable;
1180 get_conftoken(CONF_ANY);
1184 if (tokenval.v.i != 0)
1191 if (tokenval.v.l != 0L)
1198 if (tokenval.v.size != (size_t)0)
1205 if (tokenval.v.am64 != (off_t)0)
1221 val = 2; /* no argument - most likely TRUE */
1225 val = 3; /* a bad argument - most likely TRUE */
1226 conf_parserror("YES, NO, TRUE, FALSE, ON, OFF expected");
1238 if (*seen && !allow_overwrites && conf_line_num != -2) {
1239 conf_parserror("duplicate parameter, prev def on line %d", *seen);
1241 *seen = conf_line_num;
1244 printf_arglist_function(void conf_parserror, const char *, format)
1248 /* print error message */
1251 fprintf(stderr, "argument \"%s\": ", conf_line);
1253 fprintf(stderr, "\"%s\", line %d: ", conf_confname, conf_line_num);
1254 arglist_start(argp, format);
1255 vfprintf(stderr, format, argp);
1257 fputc('\n', stderr);
1268 /* switch to binary search if performance warrants */
1270 for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1271 if (strcmp(kwp->keyword, str) == 0) break;
1278 /* push the last token back (can only unget ANY tokens) */
1280 unget_conftoken(void)
1289 conftoken_getc(void)
1291 if(conf_line == NULL)
1292 return getc(conf_conf);
1293 if(*conf_char == '\0')
1295 return(*conf_char++);
1302 if(conf_line == NULL)
1303 return ungetc(c, conf_conf);
1304 else if(conf_char > conf_line) {
1308 if(*conf_char != c) {
1309 error("*conf_char != c : %c %c", *conf_char, c);
1313 error("conf_char == conf_line");
1337 ** If it looked like a key word before then look it
1338 ** up again in the current keyword table.
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:
1349 if (exp == CONF_IDENT)
1352 tok = lookup_keyword(tokenval.v.s);
1357 ch = conftoken_getc();
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 */
1367 if (isalpha(ch)) { /* identifier */
1371 if (islower(ch)) ch = toupper(ch);
1372 if (buf < tkbuf+sizeof(tkbuf)-1) {
1376 if (!token_overflow) {
1377 conf_parserror("token too long: %.20s...", tkbuf);
1381 ch = conftoken_getc();
1382 } while(isalnum(ch) || ch == '_' || ch == '-');
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)));
1389 conf_parserror("Pushback of '%c' failed: EOF", ch);
1394 tokenval.v.s = tkbuf;
1396 if (token_overflow) tok = CONF_UNKNOWN;
1397 else if (exp == CONF_IDENT) tok = CONF_IDENT;
1398 else tok = lookup_keyword(tokenval.v.s);
1400 else if (isdigit(ch)) { /* integer */
1403 negative_number: /* look for goto negative_number below sign is set there */
1406 am64 = am64 * 10 + (ch - '0');
1407 ch = conftoken_getc();
1408 } while (isdigit(ch));
1411 if (exp == CONF_INT) {
1413 tokenval.v.i = sign * (int)am64;
1414 } else if (exp == CONF_LONG) {
1416 tokenval.v.l = (long)sign * (long)am64;
1417 } else if (exp != CONF_REAL) {
1419 tokenval.v.am64 = (off_t)sign * am64;
1421 /* automatically convert to real when expected */
1422 tokenval.v.r = (double)sign * (double)am64;
1426 /* got a real number, not an int */
1427 tokenval.v.r = sign * (double) am64;
1430 ch = conftoken_getc();
1431 while (isdigit(ch)) {
1432 am64 = am64 * 10 + (ch - '0');
1434 ch = conftoken_getc();
1436 tokenval.v.r += sign * ((double)am64) / d;
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)));
1445 conf_parserror("Pushback of '%c' failed: EOF", ch);
1449 case '"': /* string */
1454 while (inquote && ((ch = conftoken_getc()) != EOF)) {
1459 buf--; /* Consume escape in buffer */
1460 } else if (ch == '\\') {
1470 if(buf >= &tkbuf[sizeof(tkbuf) - 1]) {
1471 if (!token_overflow) {
1472 conf_parserror("string too long: %.20s...", tkbuf);
1482 * A little manuver to leave a fully unquoted, unallocated string
1485 tmps = unquote_string(tkbuf);
1486 strncpy(tkbuf, tmps, sizeof(tkbuf));
1488 tokenval.v.s = tkbuf;
1490 tok = (token_overflow) ? CONF_UNKNOWN :
1491 (exp == CONF_IDENT) ? CONF_IDENT : CONF_STRING;
1495 ch = conftoken_getc();
1498 goto negative_number;
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)));
1506 conf_parserror("Pushback of '%c' failed: EOF", ch);
1539 if (exp != CONF_ANY && tok != exp) {
1557 str = "end of line";
1561 str = "end of file";
1569 str = "a real number";
1573 str = "a quoted string";
1577 str = "an identifier";
1581 for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1582 if (exp == kwp->token)
1585 if (kwp->keyword == NULL)
1591 conf_parserror("%s is expected", str);
1593 if (tok == CONF_INT)
1608 get_conftoken(CONF_STRING);
1609 val->v.s = newstralloc(val->v.s, tokenval.v.s);
1619 get_conftoken(CONF_IDENT);
1620 val->v.s = newstralloc(val->v.s, tokenval.v.s);
1630 val->v.i = get_int();
1640 val->v.l = get_long();
1650 val->v.size = get_size();
1660 val->v.am64 = get_am64_t();
1670 val->v.i = get_bool();
1680 get_conftoken(CONF_REAL);
1681 val->v.r = tokenval.v.r;
1691 val->v.t = get_time();
1700 valdst->type = valsrc->type;
1701 valdst->seen = valsrc->seen;
1702 switch(valsrc->type) {
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;
1716 valdst->v.l = valsrc->v.l;
1720 valdst->v.size = valsrc->v.size;
1724 valdst->v.am64 = valsrc->v.am64;
1728 valdst->v.r = valsrc->v.r;
1732 valdst->v.rate[0] = valsrc->v.rate[0];
1733 valdst->v.rate[1] = valsrc->v.rate[1];
1736 case CONFTYPE_IDENT:
1737 case CONFTYPE_STRING:
1738 valdst->v.s = stralloc(valsrc->v.s);
1742 valdst->v.t = valsrc->v.t;
1746 valdst->v.sl = duplicate_sl(valsrc->v.sl);
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);
1765 case CONFTYPE_COMPRESS:
1766 case CONFTYPE_ENCRYPT:
1767 case CONFTYPE_HOLDING:
1768 case CONFTYPE_ESTIMATE:
1769 case CONFTYPE_STRATEGY:
1771 case CONFTYPE_TAPERALGO:
1772 case CONFTYPE_PRIORITY:
1779 case CONFTYPE_IDENT:
1780 case CONFTYPE_STRING:
1791 case CONFTYPE_EXINCLUDE:
1792 free_sl(val->v.exinclude.sl);
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";
1811 static char buffer_conf_print[1025];
1820 buffer_conf_print[0] = '\0';
1823 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%d", val->v.i);
1827 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%ld", val->v.l);
1831 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), SSIZE_T_FMT,
1832 (SSIZE_T_FMT_TYPE)val->v.size);
1836 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), OFF_T_FMT ,
1837 (OFF_T_FMT_TYPE)val->v.am64);
1841 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%0.5f" , val->v.r);
1845 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%0.5f %0.5f" , val->v.rate[0], val->v.rate[1]);
1848 case CONFTYPE_IDENT:
1850 strncpy(buffer_conf_print, val->v.s, SIZEOF(buffer_conf_print));
1851 buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0';
1853 buffer_conf_print[0] = '\0';
1856 case CONFTYPE_STRING:
1857 buffer_conf_print[0] = '"';
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)] = '"';
1864 buffer_conf_print[1] = '"';
1865 buffer_conf_print[2] = '\0';
1870 stm = localtime(&val->v.t);
1872 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print),
1873 "%d%02d%02d", stm->tm_hour, stm->tm_min, stm->tm_sec);
1875 strcpy(buffer_conf_print, "00000");
1880 buffer_conf_print[0] = '\0';
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));
1888 strncpy(buffer_conf_print, "FILE ", SIZEOF(buffer_conf_print));
1890 if(val->v.exinclude.optional == 1)
1891 strncpy(&buffer_conf_print[pos], "OPTIONAL ", SIZEOF(buffer_conf_print));
1897 strncpy(buffer_conf_print, "yes", SIZEOF(buffer_conf_print));
1899 strncpy(buffer_conf_print, "no", SIZEOF(buffer_conf_print));
1902 case CONFTYPE_STRATEGY:
1905 strncpy(buffer_conf_print, "SKIP", SIZEOF(buffer_conf_print));
1909 strncpy(buffer_conf_print, "STANDARD", SIZEOF(buffer_conf_print));
1913 strncpy(buffer_conf_print, "NOFULL", SIZEOF(buffer_conf_print));
1917 strncpy(buffer_conf_print, "NOINC", SIZEOF(buffer_conf_print));
1921 strncpy(buffer_conf_print, "HANOI", SIZEOF(buffer_conf_print));
1925 strncpy(buffer_conf_print, "INCRONLY", SIZEOF(buffer_conf_print));
1930 case CONFTYPE_COMPRESS:
1933 strncpy(buffer_conf_print, "NONE", SIZEOF(buffer_conf_print));
1937 strncpy(buffer_conf_print, "CLIENT FAST", SIZEOF(buffer_conf_print));
1941 strncpy(buffer_conf_print, "CLIENT BEST", SIZEOF(buffer_conf_print));
1945 strncpy(buffer_conf_print, "CLIENT CUSTOM", SIZEOF(buffer_conf_print));
1948 case COMP_SERV_FAST:
1949 strncpy(buffer_conf_print, "SERVER FAST", SIZEOF(buffer_conf_print));
1952 case COMP_SERV_BEST:
1953 strncpy(buffer_conf_print, "SERVER FAST", SIZEOF(buffer_conf_print));
1956 case COMP_SERV_CUST:
1957 strncpy(buffer_conf_print, "SERVER CUSTOM", SIZEOF(buffer_conf_print));
1962 case CONFTYPE_ESTIMATE:
1965 strncpy(buffer_conf_print, "CLIENT", SIZEOF(buffer_conf_print));
1969 strncpy(buffer_conf_print, "SERVER", SIZEOF(buffer_conf_print));
1973 strncpy(buffer_conf_print, "CALCSIZE", SIZEOF(buffer_conf_print));
1978 case CONFTYPE_ENCRYPT:
1981 strncpy(buffer_conf_print, "NONE", SIZEOF(buffer_conf_print));
1985 strncpy(buffer_conf_print, "CLIENT", SIZEOF(buffer_conf_print));
1988 case ENCRYPT_SERV_CUST:
1989 strncpy(buffer_conf_print, "SERVER", SIZEOF(buffer_conf_print));
1994 case CONFTYPE_HOLDING:
1997 strncpy(buffer_conf_print, "NEVER", SIZEOF(buffer_conf_print));
2001 strncpy(buffer_conf_print, "AUTO", SIZEOF(buffer_conf_print));
2005 strncpy(buffer_conf_print, "REQUIRED", SIZEOF(buffer_conf_print));
2010 case CONFTYPE_TAPERALGO:
2011 strncpy(buffer_conf_print, taperalgo2str(val->v.i), SIZEOF(buffer_conf_print));
2014 case CONFTYPE_PRIORITY:
2017 strncpy(buffer_conf_print, "LOW", SIZEOF(buffer_conf_print));
2021 strncpy(buffer_conf_print, "MEDIUM", SIZEOF(buffer_conf_print));
2025 strncpy(buffer_conf_print, "HIGH", SIZEOF(buffer_conf_print));
2030 buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0';
2031 return buffer_conf_print;
2040 val->type = CONFTYPE_STRING;
2042 val->v.s = stralloc(s);
2053 val->type = CONFTYPE_IDENT;
2055 val->v.s = stralloc(s);
2066 val->type = CONFTYPE_INT;
2076 val->type = CONFTYPE_BOOL;
2086 val->type = CONFTYPE_STRATEGY;
2096 val->type = CONFTYPE_ESTIMATE;
2101 conf_init_taperalgo(
2106 val->type = CONFTYPE_TAPERALGO;
2116 val->type = CONFTYPE_PRIORITY;
2126 val->type = CONFTYPE_COMPRESS;
2136 val->type = CONFTYPE_ENCRYPT;
2143 dump_holdingdisk_t i)
2146 val->type = CONFTYPE_HOLDING;
2156 val->type = CONFTYPE_LONG;
2166 val->type = CONFTYPE_SIZE;
2176 val->type = CONFTYPE_AM64;
2186 val->type = CONFTYPE_REAL;
2197 val->type = CONFTYPE_RATE;
2198 val->v.rate[0] = r1;
2199 val->v.rate[1] = r2;
2208 val->type = CONFTYPE_TIME;
2218 val->type = CONFTYPE_AM64;
2223 conf_init_exinclude(
2227 val->type = CONFTYPE_EXINCLUDE;
2228 val->v.exinclude.type = 0;
2229 val->v.exinclude.optional = 0;
2230 val->v.exinclude.sl = NULL;
2239 val->type = CONFTYPE_STRING;
2241 val->v.s = stralloc(s);
2250 val->type = CONFTYPE_INT;
2260 val->type = CONFTYPE_BOOL;
2270 val->type = CONFTYPE_COMPRESS;
2280 val->type = CONFTYPE_COMPRESS;
2287 dump_holdingdisk_t i)
2290 val->type = CONFTYPE_HOLDING;
2300 val->type = CONFTYPE_STRATEGY;
2309 if (val->type != CONFTYPE_INT) {
2310 error("get_conftype_int: val.type is not CONFTYPE_INT");
2320 if (val->type != CONFTYPE_LONG) {
2321 error("get_conftype_long: val.type is not CONFTYPE_LONG");
2331 if (val->type != CONFTYPE_AM64) {
2332 error("get_conftype_am64: val.type is not CONFTYPE_AM64");
2342 if (val->type != CONFTYPE_REAL) {
2343 error("get_conftype_real: val.type is not CONFTYPE_REAL");
2350 get_conftype_string(
2353 if (val->type != CONFTYPE_STRING) {
2354 error("get_conftype_string: val.type is not CONFTYPE_STRING");
2364 if (val->type != CONFTYPE_IDENT) {
2365 error("get_conftype_ident: val.type is not CONFTYPE_IDENT");
2375 if (val->type != CONFTYPE_TIME) {
2376 error("get_conftype_time: val.type is not CONFTYPE_TIME");
2386 if (val->type != CONFTYPE_SIZE) {
2387 error("get_conftype_size: val.type is not CONFTYPE_SIZE");
2397 if (val->type != CONFTYPE_SL) {
2398 error("get_conftype_size: val.type is not CONFTYPE_SL");
2408 if (val->type != CONFTYPE_BOOL) {
2409 error("get_conftype_bool: val.type is not CONFTYPE_BOOL");
2419 if (val->type != CONFTYPE_HOLDING) {
2420 error("get_conftype_hold: val.type is not CONFTYPE_HOLDING");
2427 get_conftype_compress(
2430 if (val->type != CONFTYPE_COMPRESS) {
2431 error("get_conftype_compress: val.type is not CONFTYPE_COMPRESS");
2438 get_conftype_encrypt(
2441 if (val->type != CONFTYPE_ENCRYPT) {
2442 error("get_conftype_encrypt: val.type is not CONFTYPE_ENCRYPT");
2449 get_conftype_estimate(
2452 if (val->type != CONFTYPE_ESTIMATE) {
2453 error("get_conftype_extimate: val.type is not CONFTYPE_ESTIMATE");
2460 get_conftype_strategy(
2463 if (val->type != CONFTYPE_STRATEGY) {
2464 error("get_conftype_strategy: val.type is not CONFTYPE_STRATEGY");
2471 get_conftype_taperalgo(
2474 if (val->type != CONFTYPE_TAPERALGO) {
2475 error("get_conftype_taperalgo: val.type is not CONFTYPE_TAPERALGO");
2482 get_conftype_priority(
2485 if (val->type != CONFTYPE_PRIORITY) {
2486 error("get_conftype_priority: val.type is not CONFTYPE_PRIORITY");
2493 get_conftype_exinclude(
2496 if (val->type != CONFTYPE_EXINCLUDE) {
2497 error("get_conftype_exinclude: val.type is not CONFTYPE_EXINCLUDE");
2500 return val->v.exinclude;
2506 struct sockaddr_in * sa)
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)));
2515 command_option_t *command_options,
2516 t_conf_var *read_var,
2522 void (*copy_function)(void))
2525 int saved_conf_line_num;
2529 get_conftoken(CONF_LBRACE);
2530 get_conftoken(CONF_NL);
2536 get_conftoken(CONF_ANY);
2541 case CONF_NL: /* empty line */
2543 case CONF_END: /* end of file */
2551 conf_parserror("ident not expected");
2555 for(np = read_var; np->token != CONF_UNKNOWN; np++)
2556 if(np->token == tok) break;
2558 if(np->token == CONF_UNKNOWN)
2559 conf_parserror(errormsg);
2561 np->read_function(np, &valarray[np->parm]);
2563 np->validate(np, &valarray[np->parm]);
2567 if(tok != CONF_NL && tok != CONF_END && tok != CONF_RBRACE)
2568 get_conftoken(CONF_NL);
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;
2579 command_option_t *command_options,
2580 t_conf_var *overwrite_var,
2588 command_option_t *command_option;
2590 if(!command_options) return;
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;
2596 if(kt->token == CONF_UNKNOWN) {
2597 error("read_conf: invalid token");
2601 for(command_option = command_options; command_option->name != NULL;
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, "\"",
2613 conf_line = stralloc(command_option->value);
2615 conf_char = conf_line;
2618 np->read_function(np, &valarray[np->parm]);
2620 conf_line = conf_char = NULL;
2623 np->validate(np, &valarray[np->parm]);
2636 for(i=0; i<new_argc; i++)
2637 amfree(new_argv[i]);
2642 #ifndef HAVE_LIBREADLINE
2644 * simple readline() replacements
2651 printf("%s", prompt);
2654 return agets(stdin);
2661 (void)line; /* Quite unused parameter warning */