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.2.4 2006/09/21 11:12:21 martinea Exp $
38 tok_t tok, pushed_tok;
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;
48 /*#define NET_READ_DEBUG*/
51 #define netprintf(x) dbprintf(x)
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);
60 int conftoken_getc(void);
61 int conftoken_ungetc(int c);
64 * Keep calling read() until we've read buflen's worth of data, or EOF,
67 * Returns the number of bytes read, 0 on EOF, or negative on error.
75 ssize_t nread, tot = 0;
76 char *buf = vbuf; /* cast to char so we can ++ it */
79 nread = read(fd, buf, buflen);
81 if ((errno == EINTR) || (errno == EAGAIN))
83 return ((tot > 0) ? tot : -1);
97 * Keep calling write() until we've written buflen's worth of data,
100 * Returns the number of bytes written, or negative on error.
108 ssize_t nwritten, tot = 0;
109 const char *buf = vbuf; /* cast to char so we can ++ it */
112 nwritten = write(fd, buf, buflen);
114 if ((errno == EINTR) || (errno == EAGAIN))
116 return ((tot > 0) ? tot : -1);
130 #if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR)
135 if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
137 dbprintf(("%s: make_socket: socket() failed: %s\n",
139 strerror(save_errno)));
143 if (s < 0 || s >= (int)FD_SETSIZE) {
145 errno = EMFILE; /* out of range */
150 r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
153 dbprintf(("%s: stream_server: setsockopt(SO_REUSEADDR) failed: %s\n",
161 r = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
162 (void *)&on, SIZEOF(on));
165 dbprintf(("%s: make_socket: setsockopt() failed: %s\n",
167 strerror(save_errno)));
177 /* addrp is my address */
178 /* svaddr is the address of the remote machine */
179 /* return socket on success */
180 /* return -1 on failure */
183 struct sockaddr_in *addrp,
184 in_port_t first_port,
187 struct sockaddr_in *svaddr,
192 static in_port_t port_in_use[1024];
193 static int nb_port_in_use = 0;
196 assert(first_port <= last_port);
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;
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;
215 port_in_use[nb_port_in_use++] = port;
220 dbprintf(("%s: connect_portrange: all ports between %d and %d busy\n",
221 debug_prefix_time(NULL),
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 */
235 struct sockaddr_in *addrp,
238 struct sockaddr_in *svaddr,
242 struct servent * servPort;
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));
254 dbprintf(("%s: connect_port: Try port %d: Available - \n",
255 debug_prefix_time(NULL), port));
257 dbprintf(("%s: connect_port: Try port %d: Owned by %s - \n",
258 debug_prefix_time(NULL), port, servPort->s_name));
261 if ((s = make_socket()) == -1) return -2;
263 addrp->sin_port = (in_port_t)htons(port);
265 if (bind(s, (struct sockaddr *)addrp, sizeof(*addrp)) != 0) {
268 if (save_errno != EADDRINUSE) {
269 dbprintf(("errno %d strerror %s\n",
270 errno, strerror(errno)));
278 /* find out what port was actually used */
280 len = sizeof(*addrp);
281 if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) {
283 dbprintf(("%s: connect_port: getsockname() failed: %s\n",
285 strerror(save_errno)));
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) {
296 dbprintf(("%s: connect_portrange: connect from %s.%d failed\n",
297 debug_prefix_time(NULL),
298 inet_ntoa(addrp->sin_addr),
299 ntohs(addrp->sin_port),
300 strerror(save_errno)));
301 dbprintf(("%s: connect_portrange: connect to %s.%d failed: %s\n",
302 debug_prefix_time(NULL),
303 inet_ntoa(svaddr->sin_addr),
304 ntohs(svaddr->sin_port),
305 strerror(save_errno)));
308 if (save_errno == ECONNREFUSED ||
309 save_errno == EHOSTUNREACH ||
310 save_errno == ENETUNREACH ||
311 save_errno == ETIMEDOUT) {
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",
323 inet_ntoa(addrp->sin_addr),
324 ntohs(addrp->sin_port)));
330 * Bind to a port in the given range. Takes a begin,end pair of port numbers.
332 * Returns negative on error (EGAIN if all ports are in use). Returns 0
338 struct sockaddr_in *addrp,
339 in_port_t first_port,
345 struct servent *servPort;
346 const in_port_t num_ports = (in_port_t)(last_port - first_port + 1);
348 assert(first_port <= last_port);
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.
354 port = (in_port_t)(((getpid() + time(0)) % num_ports) + first_port);
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.
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));
368 dbprintf(("%s: bind_portrange2: Try port %d: Owned by %s - ",
369 debug_prefix_time(NULL), port, servPort->s_name));
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"));
376 dbprintf(("%s\n", strerror(errno)));
378 dbprintf(("%s: bind_portrange2: Skip port %d: Owned by %s.\n",
379 debug_prefix_time(NULL), port, servPort->s_name));
381 if (++port > last_port)
384 dbprintf(("%s: bind_portrange: all ports between %d and %d busy\n",
385 debug_prefix_time(NULL),
393 * Construct a datestamp (YYYYMMDD) from a time_t.
400 char datestamp[3 * NUM_STR_SIZE];
404 when = time((time_t *)NULL);
408 tm = localtime(&when);
410 return stralloc("19000101");
412 snprintf(datestamp, SIZEOF(datestamp),
413 "%04d%02d%02d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
414 return stralloc(datestamp);
418 * Construct a timestamp (YYYYMMDDHHMMSS) from a time_t.
425 char timestamp[6 * NUM_STR_SIZE];
429 when = time((time_t *)NULL);
433 tm = localtime(&when);
435 return stralloc("19000101000000");
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);
449 return (match("[ \t\f\r\n\"]", str) != 0);
454 * For backward compatibility we are trying for minimal quoting.
455 * We only quote a string if it contains whitespace or is misquoted...
465 if ((str == NULL) || (*str == '\0')) {
466 ret = stralloc("\"\"");
467 } else if ((match("[\\\"[:space:][:cntrl:]]", str)) == 0) {
469 * String does not need to be quoted since it contains
470 * neither whitespace, control or quote characters.
475 * Allocate maximum possible string length.
476 * (a string of all quotes plus room for leading ", trailing " and NULL)
478 ret = s = alloc((strlen(str) * 2) + 2 + 1);
480 while (*str != '\0') {
486 } else if (*str == '\n') {
491 } else if (*str == '\r') {
496 } else if (*str == '\f') {
519 if ((str == NULL) || (*str == '\0')) {
525 ret = in = out = stralloc(str);
526 while (*in != '\0') {
538 } else if (*in == 't') {
542 } else if (*in == 'r') {
546 } else if (*in == 'f') {
566 if ((str == NULL) || (*str == '\0')) {
570 for (s = ret; *s != '\0'; s++) {
581 char * tok = strtok(NULL, " ");
583 if ((tok != NULL) && (tok[0] == '"')) {
589 t = strtok(NULL, " ");
592 } while ((t != NULL) &&
593 (tok[len - 1] != '"') && (tok[len - 2] != '\\'));
605 FILE *stream = popen("od -w10 -c -x -", "w");
607 if (stream != NULL) {
609 rc = (ssize_t)fwrite(buffer, len, 1, stream);
618 Return 0 if the following characters are present
619 * ( ) < > [ ] , ; : ! $ \ / "
627 return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto);
638 for(np = get_var; np->token != CONF_UNKNOWN; np++) {
643 if(np->token == CONF_UNKNOWN) {
644 error("error [unknown getconf_np parm: %d]", parm);
661 var->v.s = newstralloc(var->v.s, tokenval.v.s);
662 malloc_mark(var->v.s);
666 var->v.i = get_int();
670 var->v.l = get_long();
674 var->v.size = get_size();
678 var->v.am64 = get_am64_t();
682 var->v.i = get_bool();
686 get_conftoken(CONF_REAL);
687 var->v.r = tokenval.v.r;
691 var->v.t = get_time();
695 error("error [unknown get_simple type: %d]", type);
706 get_conftoken(CONF_ANY);
709 #if SIZEOF_TIME_T < SIZEOF_INT
710 if ((off_t)tokenval.v.i >= (off_t)TIME_MAX)
711 conf_parserror("value too large");
713 hhmm = (time_t)tokenval.v.i;
717 #if SIZEOF_TIME_T < SIZEOF_LONG
718 if ((off_t)tokenval.v.l >= (off_t)TIME_MAX)
719 conf_parserror("value too large");
721 hhmm = (time_t)tokenval.v.l;
725 #if SIZEOF_TIME_T < SIZEOF_SSIZE_T
726 if ((off_t)tokenval.v.size >= (off_t)TIME_MAX)
727 conf_parserror("value too large");
729 hhmm = (time_t)tokenval.v.size;
733 #if SIZEOF_TIME_T < SIZEOF_LONG_LONG
734 if ((off_t)tokenval.v.am64 >= (off_t)TIME_MAX)
735 conf_parserror("value too large");
737 hhmm = (time_t)tokenval.v.am64;
740 case CONF_AMINFINITY:
745 conf_parserror("a time is expected");
752 keytab_t numb_keytable[] = {
754 { "BPS", CONF_MULT1 },
755 { "BYTE", CONF_MULT1 },
756 { "BYTES", CONF_MULT1 },
757 { "DAY", CONF_MULT1 },
758 { "DAYS", CONF_MULT1 },
759 { "INF", CONF_AMINFINITY },
760 { "K", CONF_MULT1K },
761 { "KB", CONF_MULT1K },
762 { "KBPS", CONF_MULT1K },
763 { "KBYTE", CONF_MULT1K },
764 { "KBYTES", CONF_MULT1K },
765 { "KILOBYTE", CONF_MULT1K },
766 { "KILOBYTES", CONF_MULT1K },
767 { "KPS", CONF_MULT1K },
768 { "M", CONF_MULT1M },
769 { "MB", CONF_MULT1M },
770 { "MBPS", CONF_MULT1M },
771 { "MBYTE", CONF_MULT1M },
772 { "MBYTES", CONF_MULT1M },
773 { "MEG", CONF_MULT1M },
774 { "MEGABYTE", CONF_MULT1M },
775 { "MEGABYTES", CONF_MULT1M },
776 { "G", CONF_MULT1G },
777 { "GB", CONF_MULT1G },
778 { "GBPS", CONF_MULT1G },
779 { "GBYTE", CONF_MULT1G },
780 { "GBYTES", CONF_MULT1G },
781 { "GIG", CONF_MULT1G },
782 { "GIGABYTE", CONF_MULT1G },
783 { "GIGABYTES", CONF_MULT1G },
784 { "MPS", CONF_MULT1M },
785 { "TAPE", CONF_MULT1 },
786 { "TAPES", CONF_MULT1 },
787 { "WEEK", CONF_MULT7 },
788 { "WEEKS", CONF_MULT7 },
799 keytable = numb_keytable;
801 get_conftoken(CONF_ANY);
808 #if SIZEOF_INT < SIZEOF_LONG
809 if ((off_t)tokenval.v.l > (off_t)INT_MAX)
810 conf_parserror("value too large");
811 if ((off_t)tokenval.v.l < (off_t)INT_MIN)
812 conf_parserror("value too small");
814 val = (int)tokenval.v.l;
818 #if SIZEOF_INT < SIZEOF_SSIZE_T
819 if ((off_t)tokenval.v.size > (off_t)INT_MAX)
820 conf_parserror("value too large");
821 if ((off_t)tokenval.v.size < (off_t)INT_MIN)
822 conf_parserror("value too small");
824 val = (int)tokenval.v.size;
828 #if SIZEOF_INT < SIZEOF_LONG_LONG
829 if (tokenval.v.am64 > (off_t)INT_MAX)
830 conf_parserror("value too large");
831 if (tokenval.v.am64 < (off_t)INT_MIN)
832 conf_parserror("value too small");
834 val = (int)tokenval.v.am64;
837 case CONF_AMINFINITY:
842 conf_parserror("an int is expected");
847 /* get multiplier, if any */
848 get_conftoken(CONF_ANY);
850 case CONF_NL: /* multiply by one */
857 if (val > (INT_MAX / 7))
858 conf_parserror("value too large");
859 if (val < (INT_MIN / 7))
860 conf_parserror("value too small");
865 if (val > (INT_MAX / 1024))
866 conf_parserror("value too large");
867 if (val < (INT_MIN / 1024))
868 conf_parserror("value too small");
873 if (val > (INT_MAX / (1024 * 1024)))
874 conf_parserror("value too large");
875 if (val < (INT_MIN / (1024 * 1024)))
876 conf_parserror("value too small");
880 default: /* it was not a multiplier */
896 keytable = numb_keytable;
898 get_conftoken(CONF_ANY);
906 #if SIZEOF_LONG < SIZEOF_INT
907 if ((off_t)tokenval.v.i > (off_t)LONG_MAX)
908 conf_parserror("value too large");
909 if ((off_t)tokenval.v.i < (off_t)LONG_MIN)
910 conf_parserror("value too small");
912 val = (long)tokenval.v.i;
916 #if SIZEOF_LONG < SIZEOF_SSIZE_T
917 if ((off_t)tokenval.v.size > (off_t)LONG_MAX)
918 conf_parserror("value too large");
919 if ((off_t)tokenval.v.size < (off_t)LONG_MIN)
920 conf_parserror("value too small");
922 val = (long)tokenval.v.size;
926 #if SIZEOF_LONG < SIZEOF_LONG_LONG
927 if (tokenval.v.am64 > (off_t)LONG_MAX)
928 conf_parserror("value too large");
929 if (tokenval.v.am64 < (off_t)LONG_MIN)
930 conf_parserror("value too small");
932 val = (long)tokenval.v.am64;
935 case CONF_AMINFINITY:
936 val = (long)LONG_MAX;
940 conf_parserror("a long is expected");
945 /* get multiplier, if any */
946 get_conftoken(CONF_ANY);
949 case CONF_NL: /* multiply by one */
955 if (val > (LONG_MAX / 7L))
956 conf_parserror("value too large");
957 if (val < (LONG_MIN / 7L))
958 conf_parserror("value too small");
963 if (val > (LONG_MAX / 1024L))
964 conf_parserror("value too large");
965 if (val < (LONG_MIN / 1024L))
966 conf_parserror("value too small");
971 if (val > (LONG_MAX / (1024L * 1024L)))
972 conf_parserror("value too large");
973 if (val < (LONG_MIN / (1024L * 1024L)))
974 conf_parserror("value too small");
975 val *= 1024L * 1024L;
978 default: /* it was not a multiplier */
994 keytable = numb_keytable;
996 get_conftoken(CONF_ANY);
1000 val = tokenval.v.size;
1004 #if SIZEOF_SIZE_T < SIZEOF_INT
1005 if ((off_t)tokenval.v.i > (off_t)SSIZE_MAX)
1006 conf_parserror("value too large");
1007 if ((off_t)tokenval.v.i < (off_t)SSIZE_MIN)
1008 conf_parserror("value too small");
1010 val = (ssize_t)tokenval.v.i;
1014 #if SIZEOF_SIZE_T < SIZEOF_LONG
1015 if ((off_t)tokenval.v.l > (off_t)SSIZE_MAX)
1016 conf_parserror("value too large");
1017 if ((off_t)tokenval.v.l < (off_t)SSIZE_MIN)
1018 conf_parserror("value too small");
1020 val = (ssize_t)tokenval.v.l;
1024 #if SIZEOF_SIZE_T < SIZEOF_LONG_LONG
1025 if (tokenval.v.am64 > (off_t)SSIZE_MAX)
1026 conf_parserror("value too large");
1027 if (tokenval.v.am64 < (off_t)SSIZE_MIN)
1028 conf_parserror("value too small");
1030 val = (ssize_t)tokenval.v.am64;
1033 case CONF_AMINFINITY:
1034 val = (ssize_t)SSIZE_MAX;
1038 conf_parserror("an integer is expected");
1043 /* get multiplier, if any */
1044 get_conftoken(CONF_ANY);
1047 case CONF_NL: /* multiply by one */
1053 if (val > (ssize_t)(SSIZE_MAX / 7))
1054 conf_parserror("value too large");
1055 if (val < (ssize_t)(SSIZE_MIN / 7))
1056 conf_parserror("value too small");
1061 if (val > (ssize_t)(SSIZE_MAX / (ssize_t)1024))
1062 conf_parserror("value too large");
1063 if (val < (ssize_t)(SSIZE_MIN / (ssize_t)1024))
1064 conf_parserror("value too small");
1065 val *= (ssize_t)1024;
1069 if (val > (ssize_t)(SSIZE_MAX / (1024 * 1024)))
1070 conf_parserror("value too large");
1071 if (val < (ssize_t)(SSIZE_MIN / (1024 * 1024)))
1072 conf_parserror("value too small");
1073 val *= (ssize_t)(1024 * 1024);
1076 default: /* it was not a multiplier */
1092 keytable = numb_keytable;
1094 get_conftoken(CONF_ANY);
1098 val = (off_t)tokenval.v.i;
1102 val = (off_t)tokenval.v.l;
1106 val = (off_t)tokenval.v.size;
1110 val = tokenval.v.am64;
1113 case CONF_AMINFINITY:
1118 conf_parserror("an am64 is expected %d", tok);
1123 /* get multiplier, if any */
1124 get_conftoken(CONF_ANY);
1127 case CONF_NL: /* multiply by one */
1133 if (val > AM64_MAX/7 || val < AM64_MIN/7)
1134 conf_parserror("value too large");
1139 if (val > AM64_MAX/1024 || val < AM64_MIN/1024)
1140 conf_parserror("value too large");
1145 if (val > AM64_MAX/(1024*1024) || val < AM64_MIN/(1024*1024))
1146 conf_parserror("value too large");
1150 default: /* it was not a multiplier */
1160 keytab_t bool_keytable[] = {
1161 { "Y", CONF_ATRUE },
1162 { "YES", CONF_ATRUE },
1163 { "T", CONF_ATRUE },
1164 { "TRUE", CONF_ATRUE },
1165 { "ON", CONF_ATRUE },
1166 { "N", CONF_AFALSE },
1167 { "NO", CONF_AFALSE },
1168 { "F", CONF_AFALSE },
1169 { "FALSE", CONF_AFALSE },
1170 { "OFF", CONF_AFALSE },
1171 { NULL, CONF_IDENT }
1181 keytable = bool_keytable;
1183 get_conftoken(CONF_ANY);
1187 if (tokenval.v.i != 0)
1194 if (tokenval.v.l != 0L)
1201 if (tokenval.v.size != (size_t)0)
1208 if (tokenval.v.am64 != (off_t)0)
1224 val = 2; /* no argument - most likely TRUE */
1228 val = 3; /* a bad argument - most likely TRUE */
1229 conf_parserror("YES, NO, TRUE, FALSE, ON, OFF expected");
1241 if (*seen && !allow_overwrites && conf_line_num != -2) {
1242 conf_parserror("duplicate parameter, prev def on line %d", *seen);
1244 *seen = conf_line_num;
1247 printf_arglist_function(void conf_parserror, const char *, format)
1251 /* print error message */
1254 fprintf(stderr, "argument \"%s\": ", conf_line);
1256 fprintf(stderr, "\"%s\", line %d: ", conf_confname, conf_line_num);
1257 arglist_start(argp, format);
1258 vfprintf(stderr, format, argp);
1260 fputc('\n', stderr);
1271 /* switch to binary search if performance warrants */
1273 for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1274 if (strcmp(kwp->keyword, str) == 0) break;
1281 /* push the last token back (can only unget ANY tokens) */
1283 unget_conftoken(void)
1292 conftoken_getc(void)
1294 if(conf_line == NULL)
1295 return getc(conf_conf);
1296 if(*conf_char == '\0')
1298 return(*conf_char++);
1305 if(conf_line == NULL)
1306 return ungetc(c, conf_conf);
1307 else if(conf_char > conf_line) {
1311 if(*conf_char != c) {
1312 error("*conf_char != c : %c %c", *conf_char, c);
1316 error("conf_char == conf_line");
1340 ** If it looked like a key word before then look it
1341 ** up again in the current keyword table.
1344 case CONF_LONG: case CONF_AM64: case CONF_SIZE:
1345 case CONF_INT: case CONF_REAL: case CONF_STRING:
1346 case CONF_LBRACE: case CONF_RBRACE: case CONF_COMMA:
1347 case CONF_NL: case CONF_END: case CONF_UNKNOWN:
1352 if (exp == CONF_IDENT)
1355 tok = lookup_keyword(tokenval.v.s);
1360 ch = conftoken_getc();
1362 while(ch != EOF && ch != '\n' && isspace(ch))
1363 ch = conftoken_getc();
1364 if (ch == '#') { /* comment - eat everything but eol/eof */
1365 while((ch = conftoken_getc()) != EOF && ch != '\n') {
1366 (void)ch; /* Quiet empty loop complaints */
1370 if (isalpha(ch)) { /* identifier */
1374 if (islower(ch)) ch = toupper(ch);
1375 if (buf < tkbuf+sizeof(tkbuf)-1) {
1379 if (!token_overflow) {
1380 conf_parserror("token too long: %.20s...", tkbuf);
1384 ch = conftoken_getc();
1385 } while(isalnum(ch) || ch == '_' || ch == '-');
1387 if (ch != EOF && conftoken_ungetc(ch) == EOF) {
1388 if (ferror(conf_conf)) {
1389 conf_parserror("Pushback of '%c' failed: %s",
1390 ch, strerror(ferror(conf_conf)));
1392 conf_parserror("Pushback of '%c' failed: EOF", ch);
1397 tokenval.v.s = tkbuf;
1399 if (token_overflow) tok = CONF_UNKNOWN;
1400 else if (exp == CONF_IDENT) tok = CONF_IDENT;
1401 else tok = lookup_keyword(tokenval.v.s);
1403 else if (isdigit(ch)) { /* integer */
1406 negative_number: /* look for goto negative_number below sign is set there */
1409 am64 = am64 * 10 + (ch - '0');
1410 ch = conftoken_getc();
1411 } while (isdigit(ch));
1414 if (exp == CONF_INT) {
1416 tokenval.v.i = sign * (int)am64;
1417 } else if (exp == CONF_LONG) {
1419 tokenval.v.l = (long)sign * (long)am64;
1420 } else if (exp != CONF_REAL) {
1422 tokenval.v.am64 = (off_t)sign * am64;
1424 /* automatically convert to real when expected */
1425 tokenval.v.r = (double)sign * (double)am64;
1429 /* got a real number, not an int */
1430 tokenval.v.r = sign * (double) am64;
1433 ch = conftoken_getc();
1434 while (isdigit(ch)) {
1435 am64 = am64 * 10 + (ch - '0');
1437 ch = conftoken_getc();
1439 tokenval.v.r += sign * ((double)am64) / d;
1443 if (ch != EOF && conftoken_ungetc(ch) == EOF) {
1444 if (ferror(conf_conf)) {
1445 conf_parserror("Pushback of '%c' failed: %s",
1446 ch, strerror(ferror(conf_conf)));
1448 conf_parserror("Pushback of '%c' failed: EOF", ch);
1452 case '"': /* string */
1457 while (inquote && ((ch = conftoken_getc()) != EOF)) {
1462 buf--; /* Consume escape in buffer */
1463 } else if (ch == '\\') {
1473 if(buf >= &tkbuf[sizeof(tkbuf) - 1]) {
1474 if (!token_overflow) {
1475 conf_parserror("string too long: %.20s...", tkbuf);
1485 * A little manuver to leave a fully unquoted, unallocated string
1488 tmps = unquote_string(tkbuf);
1489 strncpy(tkbuf, tmps, sizeof(tkbuf));
1491 tokenval.v.s = tkbuf;
1493 tok = (token_overflow) ? CONF_UNKNOWN :
1494 (exp == CONF_IDENT) ? CONF_IDENT : CONF_STRING;
1498 ch = conftoken_getc();
1501 goto negative_number;
1504 if (ch != EOF && conftoken_ungetc(ch) == EOF) {
1505 if (ferror(conf_conf)) {
1506 conf_parserror("Pushback of '%c' failed: %s",
1507 ch, strerror(ferror(conf_conf)));
1509 conf_parserror("Pushback of '%c' failed: EOF", ch);
1542 if (exp != CONF_ANY && tok != exp) {
1560 str = "end of line";
1564 str = "end of file";
1572 str = "a real number";
1576 str = "a quoted string";
1580 str = "an identifier";
1584 for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1585 if (exp == kwp->token)
1588 if (kwp->keyword == NULL)
1594 conf_parserror("%s is expected", str);
1596 if (tok == CONF_INT)
1611 get_conftoken(CONF_STRING);
1612 val->v.s = newstralloc(val->v.s, tokenval.v.s);
1622 get_conftoken(CONF_IDENT);
1623 val->v.s = newstralloc(val->v.s, tokenval.v.s);
1633 val->v.i = get_int();
1643 val->v.l = get_long();
1653 val->v.size = get_size();
1663 val->v.am64 = get_am64_t();
1673 val->v.i = get_bool();
1683 get_conftoken(CONF_REAL);
1684 val->v.r = tokenval.v.r;
1694 val->v.t = get_time();
1703 valdst->type = valsrc->type;
1704 valdst->seen = valsrc->seen;
1705 switch(valsrc->type) {
1708 case CONFTYPE_COMPRESS:
1709 case CONFTYPE_ENCRYPT:
1710 case CONFTYPE_HOLDING:
1711 case CONFTYPE_ESTIMATE:
1712 case CONFTYPE_STRATEGY:
1713 case CONFTYPE_TAPERALGO:
1714 case CONFTYPE_PRIORITY:
1715 valdst->v.i = valsrc->v.i;
1719 valdst->v.l = valsrc->v.l;
1723 valdst->v.size = valsrc->v.size;
1727 valdst->v.am64 = valsrc->v.am64;
1731 valdst->v.r = valsrc->v.r;
1735 valdst->v.rate[0] = valsrc->v.rate[0];
1736 valdst->v.rate[1] = valsrc->v.rate[1];
1739 case CONFTYPE_IDENT:
1740 case CONFTYPE_STRING:
1741 valdst->v.s = stralloc(valsrc->v.s);
1745 valdst->v.t = valsrc->v.t;
1749 valdst->v.sl = duplicate_sl(valsrc->v.sl);
1752 case CONFTYPE_EXINCLUDE:
1753 valdst->v.exinclude.type = valsrc->v.exinclude.type;
1754 valdst->v.exinclude.optional = valsrc->v.exinclude.optional;
1755 valdst->v.exinclude.sl = duplicate_sl(valsrc->v.exinclude.sl);
1768 case CONFTYPE_COMPRESS:
1769 case CONFTYPE_ENCRYPT:
1770 case CONFTYPE_HOLDING:
1771 case CONFTYPE_ESTIMATE:
1772 case CONFTYPE_STRATEGY:
1774 case CONFTYPE_TAPERALGO:
1775 case CONFTYPE_PRIORITY:
1782 case CONFTYPE_IDENT:
1783 case CONFTYPE_STRING:
1794 case CONFTYPE_EXINCLUDE:
1795 free_sl(val->v.exinclude.sl);
1805 if(taperalgo == ALGO_FIRST) return "FIRST";
1806 if(taperalgo == ALGO_FIRSTFIT) return "FIRSTFIT";
1807 if(taperalgo == ALGO_LARGEST) return "LARGEST";
1808 if(taperalgo == ALGO_LARGESTFIT) return "LARGESTFIT";
1809 if(taperalgo == ALGO_SMALLEST) return "SMALLEST";
1810 if(taperalgo == ALGO_LAST) return "LAST";
1814 static char buffer_conf_print[1025];
1823 buffer_conf_print[0] = '\0';
1826 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%d", val->v.i);
1830 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%ld", val->v.l);
1834 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), SSIZE_T_FMT,
1835 (SSIZE_T_FMT_TYPE)val->v.size);
1839 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), OFF_T_FMT ,
1840 (OFF_T_FMT_TYPE)val->v.am64);
1844 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%0.5f" , val->v.r);
1848 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%0.5f %0.5f" , val->v.rate[0], val->v.rate[1]);
1851 case CONFTYPE_IDENT:
1853 strncpy(buffer_conf_print, val->v.s, SIZEOF(buffer_conf_print));
1854 buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0';
1856 buffer_conf_print[0] = '\0';
1859 case CONFTYPE_STRING:
1860 buffer_conf_print[0] = '"';
1862 strncpy(&buffer_conf_print[1], val->v.s,
1863 SIZEOF(buffer_conf_print) - 1);
1864 buffer_conf_print[SIZEOF(buffer_conf_print) - 2] = '\0';
1865 buffer_conf_print[strlen(buffer_conf_print)] = '"';
1867 buffer_conf_print[1] = '"';
1868 buffer_conf_print[2] = '\0';
1873 stm = localtime(&val->v.t);
1875 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print),
1876 "%d%02d%02d", stm->tm_hour, stm->tm_min, stm->tm_sec);
1878 strcpy(buffer_conf_print, "00000");
1883 buffer_conf_print[0] = '\0';
1886 case CONFTYPE_EXINCLUDE:
1887 buffer_conf_print[0] = '\0';
1888 if(val->v.exinclude.type == 0)
1889 strncpy(buffer_conf_print, "LIST ", SIZEOF(buffer_conf_print));
1891 strncpy(buffer_conf_print, "FILE ", SIZEOF(buffer_conf_print));
1893 if(val->v.exinclude.optional == 1)
1894 strncpy(&buffer_conf_print[pos], "OPTIONAL ", SIZEOF(buffer_conf_print));
1900 strncpy(buffer_conf_print, "yes", SIZEOF(buffer_conf_print));
1902 strncpy(buffer_conf_print, "no", SIZEOF(buffer_conf_print));
1905 case CONFTYPE_STRATEGY:
1908 strncpy(buffer_conf_print, "SKIP", SIZEOF(buffer_conf_print));
1912 strncpy(buffer_conf_print, "STANDARD", SIZEOF(buffer_conf_print));
1916 strncpy(buffer_conf_print, "NOFULL", SIZEOF(buffer_conf_print));
1920 strncpy(buffer_conf_print, "NOINC", SIZEOF(buffer_conf_print));
1924 strncpy(buffer_conf_print, "HANOI", SIZEOF(buffer_conf_print));
1928 strncpy(buffer_conf_print, "INCRONLY", SIZEOF(buffer_conf_print));
1933 case CONFTYPE_COMPRESS:
1936 strncpy(buffer_conf_print, "NONE", SIZEOF(buffer_conf_print));
1940 strncpy(buffer_conf_print, "CLIENT FAST", SIZEOF(buffer_conf_print));
1944 strncpy(buffer_conf_print, "CLIENT BEST", SIZEOF(buffer_conf_print));
1948 strncpy(buffer_conf_print, "CLIENT CUSTOM", SIZEOF(buffer_conf_print));
1951 case COMP_SERV_FAST:
1952 strncpy(buffer_conf_print, "SERVER FAST", SIZEOF(buffer_conf_print));
1955 case COMP_SERV_BEST:
1956 strncpy(buffer_conf_print, "SERVER FAST", SIZEOF(buffer_conf_print));
1959 case COMP_SERV_CUST:
1960 strncpy(buffer_conf_print, "SERVER CUSTOM", SIZEOF(buffer_conf_print));
1965 case CONFTYPE_ESTIMATE:
1968 strncpy(buffer_conf_print, "CLIENT", SIZEOF(buffer_conf_print));
1972 strncpy(buffer_conf_print, "SERVER", SIZEOF(buffer_conf_print));
1976 strncpy(buffer_conf_print, "CALCSIZE", SIZEOF(buffer_conf_print));
1981 case CONFTYPE_ENCRYPT:
1984 strncpy(buffer_conf_print, "NONE", SIZEOF(buffer_conf_print));
1988 strncpy(buffer_conf_print, "CLIENT", SIZEOF(buffer_conf_print));
1991 case ENCRYPT_SERV_CUST:
1992 strncpy(buffer_conf_print, "SERVER", SIZEOF(buffer_conf_print));
1997 case CONFTYPE_HOLDING:
2000 strncpy(buffer_conf_print, "NEVER", SIZEOF(buffer_conf_print));
2004 strncpy(buffer_conf_print, "AUTO", SIZEOF(buffer_conf_print));
2008 strncpy(buffer_conf_print, "REQUIRED", SIZEOF(buffer_conf_print));
2013 case CONFTYPE_TAPERALGO:
2014 strncpy(buffer_conf_print, taperalgo2str(val->v.i), SIZEOF(buffer_conf_print));
2017 case CONFTYPE_PRIORITY:
2020 strncpy(buffer_conf_print, "LOW", SIZEOF(buffer_conf_print));
2024 strncpy(buffer_conf_print, "MEDIUM", SIZEOF(buffer_conf_print));
2028 strncpy(buffer_conf_print, "HIGH", SIZEOF(buffer_conf_print));
2033 buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0';
2034 return buffer_conf_print;
2043 val->type = CONFTYPE_STRING;
2045 val->v.s = stralloc(s);
2056 val->type = CONFTYPE_IDENT;
2058 val->v.s = stralloc(s);
2069 val->type = CONFTYPE_INT;
2079 val->type = CONFTYPE_BOOL;
2089 val->type = CONFTYPE_STRATEGY;
2099 val->type = CONFTYPE_ESTIMATE;
2104 conf_init_taperalgo(
2109 val->type = CONFTYPE_TAPERALGO;
2119 val->type = CONFTYPE_PRIORITY;
2129 val->type = CONFTYPE_COMPRESS;
2139 val->type = CONFTYPE_ENCRYPT;
2146 dump_holdingdisk_t i)
2149 val->type = CONFTYPE_HOLDING;
2159 val->type = CONFTYPE_LONG;
2169 val->type = CONFTYPE_SIZE;
2179 val->type = CONFTYPE_AM64;
2189 val->type = CONFTYPE_REAL;
2200 val->type = CONFTYPE_RATE;
2201 val->v.rate[0] = r1;
2202 val->v.rate[1] = r2;
2211 val->type = CONFTYPE_TIME;
2221 val->type = CONFTYPE_AM64;
2226 conf_init_exinclude(
2230 val->type = CONFTYPE_EXINCLUDE;
2231 val->v.exinclude.type = 0;
2232 val->v.exinclude.optional = 0;
2233 val->v.exinclude.sl = NULL;
2242 val->type = CONFTYPE_STRING;
2244 val->v.s = stralloc(s);
2253 val->type = CONFTYPE_INT;
2263 val->type = CONFTYPE_BOOL;
2273 val->type = CONFTYPE_COMPRESS;
2283 val->type = CONFTYPE_COMPRESS;
2290 dump_holdingdisk_t i)
2293 val->type = CONFTYPE_HOLDING;
2303 val->type = CONFTYPE_STRATEGY;
2312 if (val->type != CONFTYPE_INT) {
2313 error("get_conftype_int: val.type is not CONFTYPE_INT");
2323 if (val->type != CONFTYPE_LONG) {
2324 error("get_conftype_long: val.type is not CONFTYPE_LONG");
2334 if (val->type != CONFTYPE_AM64) {
2335 error("get_conftype_am64: val.type is not CONFTYPE_AM64");
2345 if (val->type != CONFTYPE_REAL) {
2346 error("get_conftype_real: val.type is not CONFTYPE_REAL");
2353 get_conftype_string(
2356 if (val->type != CONFTYPE_STRING) {
2357 error("get_conftype_string: val.type is not CONFTYPE_STRING");
2367 if (val->type != CONFTYPE_IDENT) {
2368 error("get_conftype_ident: val.type is not CONFTYPE_IDENT");
2378 if (val->type != CONFTYPE_TIME) {
2379 error("get_conftype_time: val.type is not CONFTYPE_TIME");
2389 if (val->type != CONFTYPE_SIZE) {
2390 error("get_conftype_size: val.type is not CONFTYPE_SIZE");
2400 if (val->type != CONFTYPE_SL) {
2401 error("get_conftype_size: val.type is not CONFTYPE_SL");
2411 if (val->type != CONFTYPE_BOOL) {
2412 error("get_conftype_bool: val.type is not CONFTYPE_BOOL");
2422 if (val->type != CONFTYPE_HOLDING) {
2423 error("get_conftype_hold: val.type is not CONFTYPE_HOLDING");
2430 get_conftype_compress(
2433 if (val->type != CONFTYPE_COMPRESS) {
2434 error("get_conftype_compress: val.type is not CONFTYPE_COMPRESS");
2441 get_conftype_encrypt(
2444 if (val->type != CONFTYPE_ENCRYPT) {
2445 error("get_conftype_encrypt: val.type is not CONFTYPE_ENCRYPT");
2452 get_conftype_estimate(
2455 if (val->type != CONFTYPE_ESTIMATE) {
2456 error("get_conftype_extimate: val.type is not CONFTYPE_ESTIMATE");
2463 get_conftype_strategy(
2466 if (val->type != CONFTYPE_STRATEGY) {
2467 error("get_conftype_strategy: val.type is not CONFTYPE_STRATEGY");
2474 get_conftype_taperalgo(
2477 if (val->type != CONFTYPE_TAPERALGO) {
2478 error("get_conftype_taperalgo: val.type is not CONFTYPE_TAPERALGO");
2485 get_conftype_priority(
2488 if (val->type != CONFTYPE_PRIORITY) {
2489 error("get_conftype_priority: val.type is not CONFTYPE_PRIORITY");
2496 get_conftype_exinclude(
2499 if (val->type != CONFTYPE_EXINCLUDE) {
2500 error("get_conftype_exinclude: val.type is not CONFTYPE_EXINCLUDE");
2503 return val->v.exinclude;
2509 struct sockaddr_in * sa)
2511 dbprintf(("%s: (sockaddr_in *)%p = { %d, %d, %s }\n",
2512 debug_prefix_time(NULL), sa, sa->sin_family,
2513 (int)ntohs(sa->sin_port),
2514 inet_ntoa(sa->sin_addr)));
2519 command_option_t *command_options,
2520 t_conf_var *read_var,
2526 void (*copy_function)(void))
2529 int saved_conf_line_num;
2533 get_conftoken(CONF_LBRACE);
2534 get_conftoken(CONF_NL);
2540 get_conftoken(CONF_ANY);
2545 case CONF_NL: /* empty line */
2547 case CONF_END: /* end of file */
2555 conf_parserror("ident not expected");
2559 for(np = read_var; np->token != CONF_UNKNOWN; np++)
2560 if(np->token == tok) break;
2562 if(np->token == CONF_UNKNOWN)
2563 conf_parserror(errormsg);
2565 np->read_function(np, &valarray[np->parm]);
2567 np->validate(np, &valarray[np->parm]);
2571 if(tok != CONF_NL && tok != CONF_END && tok != CONF_RBRACE)
2572 get_conftoken(CONF_NL);
2575 /* overwrite with command line option */
2576 saved_conf_line_num = conf_line_num;
2577 command_overwrite(command_options, read_var, keytab, valarray, prefix);
2578 conf_line_num = saved_conf_line_num;
2583 command_option_t *command_options,
2584 t_conf_var *overwrite_var,
2592 command_option_t *command_option;
2594 if(!command_options) return;
2596 for(np = overwrite_var; np->token != CONF_UNKNOWN; np++) {
2597 for(kt = keytab; kt->token != CONF_UNKNOWN; kt++)
2598 if(kt->token == np->token) break;
2600 if(kt->token == CONF_UNKNOWN) {
2601 error("read_conf: invalid token");
2605 for(command_option = command_options; command_option->name != NULL;
2607 myprefix = stralloc2(prefix, kt->keyword);
2608 if(strcasecmp(myprefix, command_option->name) == 0) {
2609 command_option->used = 1;
2610 valarray[np->parm].seen = -2;
2611 if(np->type == CONFTYPE_STRING &&
2612 command_option->value[0] != '"') {
2613 conf_line = vstralloc("\"", command_option->value, "\"",
2617 conf_line = stralloc(command_option->value);
2619 conf_char = conf_line;
2622 np->read_function(np, &valarray[np->parm]);
2624 conf_line = conf_char = NULL;
2627 np->validate(np, &valarray[np->parm]);
2640 for(i=0; i<new_argc; i++)
2641 amfree(new_argv[i]);
2646 #ifndef HAVE_LIBREADLINE
2648 * simple readline() replacements
2655 printf("%s", prompt);
2658 return agets(stdin);
2665 (void)line; /* Quite unused parameter warning */