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.13 2007/01/24 18:33:29 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: %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)));
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') {
501 } else if (*str == '\\') {
524 if ((str == NULL) || (*str == '\0')) {
530 ret = in = out = stralloc(str);
531 while (*in != '\0') {
543 } else if (*in == 't') {
547 } else if (*in == 'r') {
551 } else if (*in == 'f') {
571 if ((str == NULL) || (*str == '\0')) {
575 for (s = ret; *s != '\0'; s++) {
586 char * tok = strtok(NULL, " ");
588 if ((tok != NULL) && (tok[0] == '"')) {
594 t = strtok(NULL, " ");
597 } while ((t != NULL) &&
598 (tok[len - 1] != '"') && (tok[len - 2] != '\\'));
610 FILE *stream = popen("od -w10 -c -x -", "w");
612 if (stream != NULL) {
614 rc = (ssize_t)fwrite(buffer, len, 1, stream);
623 Return 0 if the following characters are present
624 * ( ) < > [ ] , ; : ! $ \ / "
632 return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto);
643 for(np = get_var; np->token != CONF_UNKNOWN; np++) {
648 if(np->token == CONF_UNKNOWN) {
649 error("error [unknown getconf_np parm: %d]", parm);
666 var->v.s = newstralloc(var->v.s, tokenval.v.s);
667 malloc_mark(var->v.s);
671 var->v.i = get_int();
675 var->v.l = get_long();
679 var->v.size = get_size();
683 var->v.am64 = get_am64_t();
687 var->v.i = get_bool();
691 get_conftoken(CONF_REAL);
692 var->v.r = tokenval.v.r;
696 var->v.t = get_time();
700 error("error [unknown get_simple type: %d]", type);
711 get_conftoken(CONF_ANY);
714 #if SIZEOF_TIME_T < SIZEOF_INT
715 if ((off_t)tokenval.v.i >= (off_t)TIME_MAX)
716 conf_parserror("value too large");
718 hhmm = (time_t)tokenval.v.i;
722 #if SIZEOF_TIME_T < SIZEOF_LONG
723 if ((off_t)tokenval.v.l >= (off_t)TIME_MAX)
724 conf_parserror("value too large");
726 hhmm = (time_t)tokenval.v.l;
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");
734 hhmm = (time_t)tokenval.v.size;
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");
742 hhmm = (time_t)tokenval.v.am64;
745 case CONF_AMINFINITY:
750 conf_parserror("a time is expected");
757 keytab_t numb_keytable[] = {
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 },
804 keytable = numb_keytable;
806 get_conftoken(CONF_ANY);
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");
819 val = (int)tokenval.v.l;
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");
829 val = (int)tokenval.v.size;
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");
839 val = (int)tokenval.v.am64;
842 case CONF_AMINFINITY:
847 conf_parserror("an int is expected");
852 /* get multiplier, if any */
853 get_conftoken(CONF_ANY);
855 case CONF_NL: /* multiply by one */
862 if (val > (INT_MAX / 7))
863 conf_parserror("value too large");
864 if (val < (INT_MIN / 7))
865 conf_parserror("value too small");
870 if (val > (INT_MAX / 1024))
871 conf_parserror("value too large");
872 if (val < (INT_MIN / 1024))
873 conf_parserror("value too small");
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");
885 default: /* it was not a multiplier */
901 keytable = numb_keytable;
903 get_conftoken(CONF_ANY);
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");
917 val = (long)tokenval.v.i;
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");
927 val = (long)tokenval.v.size;
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");
937 val = (long)tokenval.v.am64;
940 case CONF_AMINFINITY:
941 val = (long)LONG_MAX;
945 conf_parserror("a long is expected");
950 /* get multiplier, if any */
951 get_conftoken(CONF_ANY);
954 case CONF_NL: /* multiply by one */
960 if (val > (LONG_MAX / 7L))
961 conf_parserror("value too large");
962 if (val < (LONG_MIN / 7L))
963 conf_parserror("value too small");
968 if (val > (LONG_MAX / 1024L))
969 conf_parserror("value too large");
970 if (val < (LONG_MIN / 1024L))
971 conf_parserror("value too small");
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;
983 default: /* it was not a multiplier */
999 keytable = numb_keytable;
1001 get_conftoken(CONF_ANY);
1005 val = tokenval.v.size;
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");
1015 val = (ssize_t)tokenval.v.i;
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");
1025 val = (ssize_t)tokenval.v.l;
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");
1035 val = (ssize_t)tokenval.v.am64;
1038 case CONF_AMINFINITY:
1039 val = (ssize_t)SSIZE_MAX;
1043 conf_parserror("an integer is expected");
1048 /* get multiplier, if any */
1049 get_conftoken(CONF_ANY);
1052 case CONF_NL: /* multiply by one */
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");
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;
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);
1081 default: /* it was not a multiplier */
1097 keytable = numb_keytable;
1099 get_conftoken(CONF_ANY);
1103 val = (off_t)tokenval.v.i;
1107 val = (off_t)tokenval.v.l;
1111 val = (off_t)tokenval.v.size;
1115 val = tokenval.v.am64;
1118 case CONF_AMINFINITY:
1123 conf_parserror("an am64 is expected %d", tok);
1128 /* get multiplier, if any */
1129 get_conftoken(CONF_ANY);
1132 case CONF_NL: /* multiply by one */
1138 if (val > AM64_MAX/7 || val < AM64_MIN/7)
1139 conf_parserror("value too large");
1144 if (val > AM64_MAX/1024 || val < AM64_MIN/1024)
1145 conf_parserror("value too large");
1150 if (val > AM64_MAX/(1024*1024) || val < AM64_MIN/(1024*1024))
1151 conf_parserror("value too large");
1155 default: /* it was not a multiplier */
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 }
1186 keytable = bool_keytable;
1188 get_conftoken(CONF_ANY);
1192 if (tokenval.v.i != 0)
1199 if (tokenval.v.l != 0L)
1206 if (tokenval.v.size != (size_t)0)
1213 if (tokenval.v.am64 != (off_t)0)
1229 val = 2; /* no argument - most likely TRUE */
1233 val = 3; /* a bad argument - most likely TRUE */
1234 conf_parserror("YES, NO, TRUE, FALSE, ON, OFF expected");
1246 if (*seen && !allow_overwrites && conf_line_num != -2) {
1247 conf_parserror("duplicate parameter, prev def on line %d", *seen);
1249 *seen = conf_line_num;
1252 printf_arglist_function(void conf_parserror, const char *, format)
1256 /* print error message */
1259 fprintf(stderr, "argument \"%s\": ", conf_line);
1261 fprintf(stderr, "\"%s\", line %d: ", conf_confname, conf_line_num);
1262 arglist_start(argp, format);
1263 vfprintf(stderr, format, argp);
1265 fputc('\n', stderr);
1276 /* switch to binary search if performance warrants */
1278 for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1279 if (strcasecmp(kwp->keyword, str) == 0) break;
1286 /* push the last token back (can only unget ANY tokens) */
1288 unget_conftoken(void)
1297 conftoken_getc(void)
1299 if(conf_line == NULL)
1300 return getc(conf_conf);
1301 if(*conf_char == '\0')
1303 return(*conf_char++);
1310 if(conf_line == NULL)
1311 return ungetc(c, conf_conf);
1312 else if(conf_char > conf_line) {
1316 if(*conf_char != c) {
1317 error("*conf_char != c : %c %c", *conf_char, c);
1321 error("conf_char == conf_line");
1345 ** If it looked like a key word before then look it
1346 ** up again in the current keyword table.
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:
1357 if (exp == CONF_IDENT)
1360 tok = lookup_keyword(tokenval.v.s);
1365 ch = conftoken_getc();
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 */
1375 if (isalpha(ch)) { /* identifier */
1379 if (buf < tkbuf+sizeof(tkbuf)-1) {
1383 if (!token_overflow) {
1384 conf_parserror("token too long: %.20s...", tkbuf);
1388 ch = conftoken_getc();
1389 } while(isalnum(ch) || ch == '_' || ch == '-');
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)));
1396 conf_parserror("Pushback of '%c' failed: EOF", ch);
1401 tokenval.v.s = tkbuf;
1403 if (token_overflow) tok = CONF_UNKNOWN;
1404 else if (exp == CONF_IDENT) tok = CONF_IDENT;
1405 else tok = lookup_keyword(tokenval.v.s);
1407 else if (isdigit(ch)) { /* integer */
1410 negative_number: /* look for goto negative_number below sign is set there */
1413 am64 = am64 * 10 + (ch - '0');
1414 ch = conftoken_getc();
1415 } while (isdigit(ch));
1418 if (exp == CONF_INT) {
1420 tokenval.v.i = sign * (int)am64;
1421 } else if (exp == CONF_LONG) {
1423 tokenval.v.l = (long)sign * (long)am64;
1424 } else if (exp != CONF_REAL) {
1426 tokenval.v.am64 = (off_t)sign * am64;
1428 /* automatically convert to real when expected */
1429 tokenval.v.r = (double)sign * (double)am64;
1433 /* got a real number, not an int */
1434 tokenval.v.r = sign * (double) am64;
1437 ch = conftoken_getc();
1438 while (isdigit(ch)) {
1439 am64 = am64 * 10 + (ch - '0');
1441 ch = conftoken_getc();
1443 tokenval.v.r += sign * ((double)am64) / d;
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)));
1452 conf_parserror("Pushback of '%c' failed: EOF", ch);
1456 case '"': /* string */
1461 while (inquote && ((ch = conftoken_getc()) != EOF)) {
1466 buf--; /* Consume escape in buffer */
1467 } else if (ch == '\\') {
1477 if(buf >= &tkbuf[sizeof(tkbuf) - 1]) {
1478 if (!token_overflow) {
1479 conf_parserror("string too long: %.20s...", tkbuf);
1489 * A little manuver to leave a fully unquoted, unallocated string
1492 tmps = unquote_string(tkbuf);
1493 strncpy(tkbuf, tmps, sizeof(tkbuf));
1495 tokenval.v.s = tkbuf;
1497 tok = (token_overflow) ? CONF_UNKNOWN :
1498 (exp == CONF_IDENT) ? CONF_IDENT : CONF_STRING;
1502 ch = conftoken_getc();
1505 goto negative_number;
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)));
1513 conf_parserror("Pushback of '%c' failed: EOF", ch);
1546 if (exp != CONF_ANY && tok != exp) {
1564 str = "end of line";
1568 str = "end of file";
1576 str = "a real number";
1580 str = "a quoted string";
1584 str = "an identifier";
1588 for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1589 if (exp == kwp->token)
1592 if (kwp->keyword == NULL)
1598 conf_parserror("%s is expected", str);
1600 if (tok == CONF_INT)
1615 get_conftoken(CONF_STRING);
1616 val->v.s = newstralloc(val->v.s, tokenval.v.s);
1626 get_conftoken(CONF_IDENT);
1627 val->v.s = newstralloc(val->v.s, tokenval.v.s);
1637 val->v.i = get_int();
1647 val->v.l = get_long();
1657 val->v.size = get_size();
1667 val->v.am64 = get_am64_t();
1677 val->v.i = get_bool();
1687 get_conftoken(CONF_REAL);
1688 val->v.r = tokenval.v.r;
1698 val->v.t = get_time();
1707 valdst->type = valsrc->type;
1708 valdst->seen = valsrc->seen;
1709 switch(valsrc->type) {
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;
1723 valdst->v.l = valsrc->v.l;
1727 valdst->v.size = valsrc->v.size;
1731 valdst->v.am64 = valsrc->v.am64;
1735 valdst->v.r = valsrc->v.r;
1739 valdst->v.rate[0] = valsrc->v.rate[0];
1740 valdst->v.rate[1] = valsrc->v.rate[1];
1743 case CONFTYPE_IDENT:
1744 case CONFTYPE_STRING:
1745 valdst->v.s = stralloc(valsrc->v.s);
1749 valdst->v.t = valsrc->v.t;
1753 valdst->v.sl = duplicate_sl(valsrc->v.sl);
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);
1772 case CONFTYPE_COMPRESS:
1773 case CONFTYPE_ENCRYPT:
1774 case CONFTYPE_HOLDING:
1775 case CONFTYPE_ESTIMATE:
1776 case CONFTYPE_STRATEGY:
1778 case CONFTYPE_TAPERALGO:
1779 case CONFTYPE_PRIORITY:
1786 case CONFTYPE_IDENT:
1787 case CONFTYPE_STRING:
1798 case CONFTYPE_EXINCLUDE:
1799 free_sl(val->v.exinclude.sl_list);
1800 free_sl(val->v.exinclude.sl_file);
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";
1819 static char buffer_conf_print[1025];
1826 buffer_conf_print[0] = '\0';
1829 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%d", val->v.i);
1833 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%ld", val->v.l);
1837 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), SSIZE_T_FMT,
1838 (SSIZE_T_FMT_TYPE)val->v.size);
1842 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), OFF_T_FMT ,
1843 (OFF_T_FMT_TYPE)val->v.am64);
1847 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%0.5f" , val->v.r);
1851 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), "%0.5f %0.5f" , val->v.rate[0], val->v.rate[1]);
1854 case CONFTYPE_IDENT:
1856 strncpy(buffer_conf_print, val->v.s, SIZEOF(buffer_conf_print));
1857 buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0';
1859 buffer_conf_print[0] = '\0';
1862 case CONFTYPE_STRING:
1863 if(str_need_quote) {
1864 buffer_conf_print[0] = '"';
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)] = '"';
1871 buffer_conf_print[1] = '"';
1872 buffer_conf_print[2] = '\0';
1876 strncpy(&buffer_conf_print[0], val->v.s,
1877 SIZEOF(buffer_conf_print));
1878 buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0';
1880 buffer_conf_print[0] = '\0';
1886 snprintf(buffer_conf_print, SIZEOF(buffer_conf_print),
1887 "%2d%02d", (int)val->v.t/100, (int)val->v.t % 100);
1891 buffer_conf_print[0] = '\0';
1894 case CONFTYPE_EXINCLUDE:
1895 strcpy(buffer_conf_print, "ERROR: use print_conf_exinclude");
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;
2038 conf_print_exinclude(
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;
2055 sl = val->v.exinclude.sl_list;
2056 strncpy(buffer_conf_print, "LIST ", SIZEOF(buffer_conf_print));
2059 sl = val->v.exinclude.sl_file;
2060 strncpy(buffer_conf_print, "FILE ", SIZEOF(buffer_conf_print));
2064 if(val->v.exinclude.optional == 1) {
2065 strncpy(&buffer_conf_print[pos], "OPTIONAL ", SIZEOF(buffer_conf_print)-pos);
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++] = '"';
2081 buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0';
2082 return buffer_conf_print;
2091 val->type = CONFTYPE_STRING;
2093 val->v.s = stralloc(s);
2104 val->type = CONFTYPE_IDENT;
2106 val->v.s = stralloc(s);
2117 val->type = CONFTYPE_INT;
2127 val->type = CONFTYPE_BOOL;
2137 val->type = CONFTYPE_STRATEGY;
2147 val->type = CONFTYPE_ESTIMATE;
2152 conf_init_taperalgo(
2157 val->type = CONFTYPE_TAPERALGO;
2167 val->type = CONFTYPE_PRIORITY;
2177 val->type = CONFTYPE_COMPRESS;
2187 val->type = CONFTYPE_ENCRYPT;
2194 dump_holdingdisk_t i)
2197 val->type = CONFTYPE_HOLDING;
2207 val->type = CONFTYPE_LONG;
2217 val->type = CONFTYPE_SIZE;
2227 val->type = CONFTYPE_AM64;
2237 val->type = CONFTYPE_REAL;
2248 val->type = CONFTYPE_RATE;
2249 val->v.rate[0] = r1;
2250 val->v.rate[1] = r2;
2259 val->type = CONFTYPE_TIME;
2269 val->type = CONFTYPE_AM64;
2274 conf_init_exinclude(
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;
2290 val->type = CONFTYPE_STRING;
2292 val->v.s = stralloc(s);
2301 val->type = CONFTYPE_INT;
2311 val->type = CONFTYPE_BOOL;
2321 val->type = CONFTYPE_COMPRESS;
2331 val->type = CONFTYPE_COMPRESS;
2338 dump_holdingdisk_t i)
2341 val->type = CONFTYPE_HOLDING;
2351 val->type = CONFTYPE_STRATEGY;
2360 if (val->type != CONFTYPE_INT) {
2361 error("get_conftype_int: val.type is not CONFTYPE_INT");
2371 if (val->type != CONFTYPE_LONG) {
2372 error("get_conftype_long: val.type is not CONFTYPE_LONG");
2382 if (val->type != CONFTYPE_AM64) {
2383 error("get_conftype_am64: val.type is not CONFTYPE_AM64");
2393 if (val->type != CONFTYPE_REAL) {
2394 error("get_conftype_real: val.type is not CONFTYPE_REAL");
2401 get_conftype_string(
2404 if (val->type != CONFTYPE_STRING) {
2405 error("get_conftype_string: val.type is not CONFTYPE_STRING");
2415 if (val->type != CONFTYPE_IDENT) {
2416 error("get_conftype_ident: val.type is not CONFTYPE_IDENT");
2426 if (val->type != CONFTYPE_TIME) {
2427 error("get_conftype_time: val.type is not CONFTYPE_TIME");
2437 if (val->type != CONFTYPE_SIZE) {
2438 error("get_conftype_size: val.type is not CONFTYPE_SIZE");
2448 if (val->type != CONFTYPE_SL) {
2449 error("get_conftype_size: val.type is not CONFTYPE_SL");
2459 if (val->type != CONFTYPE_BOOL) {
2460 error("get_conftype_bool: val.type is not CONFTYPE_BOOL");
2470 if (val->type != CONFTYPE_HOLDING) {
2471 error("get_conftype_hold: val.type is not CONFTYPE_HOLDING");
2478 get_conftype_compress(
2481 if (val->type != CONFTYPE_COMPRESS) {
2482 error("get_conftype_compress: val.type is not CONFTYPE_COMPRESS");
2489 get_conftype_encrypt(
2492 if (val->type != CONFTYPE_ENCRYPT) {
2493 error("get_conftype_encrypt: val.type is not CONFTYPE_ENCRYPT");
2500 get_conftype_estimate(
2503 if (val->type != CONFTYPE_ESTIMATE) {
2504 error("get_conftype_extimate: val.type is not CONFTYPE_ESTIMATE");
2511 get_conftype_strategy(
2514 if (val->type != CONFTYPE_STRATEGY) {
2515 error("get_conftype_strategy: val.type is not CONFTYPE_STRATEGY");
2522 get_conftype_taperalgo(
2525 if (val->type != CONFTYPE_TAPERALGO) {
2526 error("get_conftype_taperalgo: val.type is not CONFTYPE_TAPERALGO");
2533 get_conftype_priority(
2536 if (val->type != CONFTYPE_PRIORITY) {
2537 error("get_conftype_priority: val.type is not CONFTYPE_PRIORITY");
2544 get_conftype_exinclude(
2547 if (val->type != CONFTYPE_EXINCLUDE) {
2548 error("get_conftype_exinclude: val.type is not CONFTYPE_EXINCLUDE");
2551 return val->v.exinclude;
2557 struct sockaddr_in * sa)
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)));
2567 command_option_t *command_options,
2568 t_conf_var *read_var,
2574 void (*copy_function)(void))
2577 int saved_conf_line_num;
2581 get_conftoken(CONF_LBRACE);
2582 get_conftoken(CONF_NL);
2588 get_conftoken(CONF_ANY);
2593 case CONF_NL: /* empty line */
2595 case CONF_END: /* end of file */
2603 conf_parserror("ident not expected");
2607 for(np = read_var; np->token != CONF_UNKNOWN; np++)
2608 if(np->token == tok) break;
2610 if(np->token == CONF_UNKNOWN)
2611 conf_parserror(errormsg);
2613 np->read_function(np, &valarray[np->parm]);
2615 np->validate(np, &valarray[np->parm]);
2619 if(tok != CONF_NL && tok != CONF_END && tok != CONF_RBRACE)
2620 get_conftoken(CONF_NL);
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;
2631 command_option_t *command_options,
2632 t_conf_var *overwrite_var,
2640 command_option_t *command_option;
2643 if(!command_options) return;
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;
2649 if(kt->token == CONF_UNKNOWN) {
2650 error("read_conf: invalid token");
2654 for(command_option = command_options; command_option->name != NULL;
2656 myprefix = stralloc2(prefix, kt->keyword);
2657 if(strcasecmp(myprefix, command_option->name) == 0) {
2659 if (command_option->used == 0 &&
2660 valarray[np->parm].seen == -2) {
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, "\"",
2671 conf_line = stralloc(command_option->value);
2673 conf_char = conf_line;
2676 np->read_function(np, &valarray[np->parm]);
2678 conf_line = conf_char = NULL;
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);
2698 for(i=0; i<new_argc; i++)
2699 amfree(new_argv[i]);
2715 if ((infd = open(src, O_RDONLY)) == -1) {
2717 quoted = quote_string(src);
2718 *errmsg = vstralloc("Can't open file ", quoted, " for reading: %s",
2719 strerror(save_errno));
2724 if ((outfd = open(dst, O_WRONLY|O_CREAT, 0600)) == -1) {
2726 quoted = quote_string(dst);
2727 *errmsg = vstralloc("Can't open file ", quoted, " for writting: %s",
2728 strerror(save_errno));
2734 while((nb=read(infd, &buf, SIZEOF(buf))) > 0) {
2735 if(fullwrite(outfd,&buf,(size_t)nb) < nb) {
2737 quoted = quote_string(dst);
2738 *errmsg = vstralloc("Error writing to \"", quoted, "\":",
2739 strerror(save_errno));
2749 quoted = quote_string(src);
2750 *errmsg = vstralloc("Error reading from \"", quoted, "\":",
2751 strerror(save_errno));
2762 #ifndef HAVE_LIBREADLINE
2764 * simple readline() replacements
2771 printf("%s", prompt);
2774 return agets(stdin);
2781 (void)line; /* Quite unused parameter warning */