xref: /dragonfly/sbin/rconfig/subs.c (revision 063db479)
186ed60a6SMatthew Dillon /*
286ed60a6SMatthew Dillon  * RCONFIG/SUBS.C
386ed60a6SMatthew Dillon  *
47a25b4e0SMatthew Dillon  * Copyright (c) 2003,2004 The DragonFly Project.  All rights reserved.
57a25b4e0SMatthew Dillon  *
67a25b4e0SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
77a25b4e0SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
87a25b4e0SMatthew Dillon  *
97a25b4e0SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
107a25b4e0SMatthew Dillon  * modification, are permitted provided that the following conditions
117a25b4e0SMatthew Dillon  * are met:
127a25b4e0SMatthew Dillon  *
137a25b4e0SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
147a25b4e0SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
157a25b4e0SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
167a25b4e0SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
177a25b4e0SMatthew Dillon  *    the documentation and/or other materials provided with the
187a25b4e0SMatthew Dillon  *    distribution.
197a25b4e0SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
207a25b4e0SMatthew Dillon  *    contributors may be used to endorse or promote products derived
217a25b4e0SMatthew Dillon  *    from this software without specific, prior written permission.
227a25b4e0SMatthew Dillon  *
237a25b4e0SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
247a25b4e0SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
257a25b4e0SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
267a25b4e0SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
277a25b4e0SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
287a25b4e0SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
297a25b4e0SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
307a25b4e0SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
317a25b4e0SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
327a25b4e0SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
337a25b4e0SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
347a25b4e0SMatthew Dillon  * SUCH DAMAGE.
3586ed60a6SMatthew Dillon  */
3686ed60a6SMatthew Dillon 
3786ed60a6SMatthew Dillon #include "defs.h"
3886ed60a6SMatthew Dillon 
3986ed60a6SMatthew Dillon static void udp_alarm(int signo);
4086ed60a6SMatthew Dillon 
4186ed60a6SMatthew Dillon static __inline
4286ed60a6SMatthew Dillon int
iswhite(char c)4386ed60a6SMatthew Dillon iswhite(char c)
4486ed60a6SMatthew Dillon {
4586ed60a6SMatthew Dillon     return(c == ' ' || c == '\t' || c == '\r' || c == '\n');
4686ed60a6SMatthew Dillon }
4786ed60a6SMatthew Dillon 
4886ed60a6SMatthew Dillon const char *
parse_str(char ** scanp,int flags)4986ed60a6SMatthew Dillon parse_str(char **scanp, int flags)
5086ed60a6SMatthew Dillon {
5186ed60a6SMatthew Dillon     char *base;
5286ed60a6SMatthew Dillon     char *ptr;
5386ed60a6SMatthew Dillon 
5486ed60a6SMatthew Dillon     for (base = *scanp; *base && iswhite(*base); ++base)
5586ed60a6SMatthew Dillon 	;
5686ed60a6SMatthew Dillon     for (ptr = base; *ptr && !iswhite(*ptr); ++ptr) {
5786ed60a6SMatthew Dillon 	if (flags & PAS_ALPHA) {
58*063db479SAaron LI 	    if ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z'))
5986ed60a6SMatthew Dillon 		continue;
6086ed60a6SMatthew Dillon 	}
61*063db479SAaron LI 	if (flags & PAS_SYMBOL) {
62*063db479SAaron LI 	    if (*ptr == '_' || *ptr == '.' || *ptr == '-' || *ptr == '+')
63*063db479SAaron LI 		continue;
6486ed60a6SMatthew Dillon 	}
6586ed60a6SMatthew Dillon 	if (flags & PAS_NUMERIC) {
6686ed60a6SMatthew Dillon 	    if (*ptr >= '0' && *ptr <= '9')
6786ed60a6SMatthew Dillon 		continue;
6886ed60a6SMatthew Dillon 	}
6986ed60a6SMatthew Dillon 	if ((flags & PAS_ANY) == 0)
7086ed60a6SMatthew Dillon 	    return(NULL);
7186ed60a6SMatthew Dillon     }
7286ed60a6SMatthew Dillon     if (*ptr)
7386ed60a6SMatthew Dillon 	*ptr++ = 0;
7486ed60a6SMatthew Dillon     *scanp = ptr;
7586ed60a6SMatthew Dillon     return(base);
7686ed60a6SMatthew Dillon }
7786ed60a6SMatthew Dillon 
7886ed60a6SMatthew Dillon int
udp_transact(struct sockaddr_in * sain,struct sockaddr_in * rsin,int * pfd,char ** bufp,int * lenp,const char * ctl,...)7986ed60a6SMatthew Dillon udp_transact(struct sockaddr_in *sain, struct sockaddr_in *rsin, int *pfd,
8086ed60a6SMatthew Dillon 		char **bufp, int *lenp, const char *ctl, ...)
8186ed60a6SMatthew Dillon {
8286ed60a6SMatthew Dillon     va_list va;
8386ed60a6SMatthew Dillon     int fd;
8486ed60a6SMatthew Dillon     int n;
85d70f9514SSascha Wildner     socklen_t rsin_len = sizeof(*rsin);
8686ed60a6SMatthew Dillon     int rc;
8786ed60a6SMatthew Dillon     int nretry = 3;
8886ed60a6SMatthew Dillon     int timeout = 1;
8986ed60a6SMatthew Dillon     int on = 1;
9086ed60a6SMatthew Dillon     char buf[2048];
9186ed60a6SMatthew Dillon 
9286ed60a6SMatthew Dillon     if (*bufp) {
9386ed60a6SMatthew Dillon 	free(*bufp);
9486ed60a6SMatthew Dillon 	*bufp = NULL;
9586ed60a6SMatthew Dillon 	*lenp = 0;
9686ed60a6SMatthew Dillon     }
9786ed60a6SMatthew Dillon     if ((fd = *pfd) < 0) {
9886ed60a6SMatthew Dillon 	struct sockaddr_in lsin;
9986ed60a6SMatthew Dillon 
10086ed60a6SMatthew Dillon 	lsin.sin_addr.s_addr = INADDR_ANY;
10186ed60a6SMatthew Dillon 	lsin.sin_port = 0;
10286ed60a6SMatthew Dillon 	lsin.sin_family = AF_INET;
10386ed60a6SMatthew Dillon 	if ((fd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC)) < 0) {
10486ed60a6SMatthew Dillon 	    asprintf(bufp, "udp_transaction: socket: %s", strerror(errno));
10586ed60a6SMatthew Dillon 	    *lenp = strlen(*bufp);
10686ed60a6SMatthew Dillon 	    return(509);
10786ed60a6SMatthew Dillon 	}
10886ed60a6SMatthew Dillon 	setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
10986ed60a6SMatthew Dillon 	if (bind(fd, (void *)&lsin, sizeof(lsin)) < 0) {
11086ed60a6SMatthew Dillon 	    asprintf(bufp, "udp_transaction: bind: %s", strerror(errno));
11186ed60a6SMatthew Dillon 	    *lenp = strlen(*bufp);
11286ed60a6SMatthew Dillon 	    close(fd);
11386ed60a6SMatthew Dillon 	    return(509);
11486ed60a6SMatthew Dillon 	}
11586ed60a6SMatthew Dillon 	*pfd = fd;
11686ed60a6SMatthew Dillon     }
117be853a16SMatthew Dillon retry:
11886ed60a6SMatthew Dillon     va_start(va, ctl);
11986ed60a6SMatthew Dillon     vsnprintf(buf, sizeof(buf), ctl, va);
12086ed60a6SMatthew Dillon     va_end(va);
12186ed60a6SMatthew Dillon     if (sendto(fd, buf, strlen(buf), 0, (void *)sain, sizeof(*sain)) >= 0) {
12286ed60a6SMatthew Dillon 	struct sigaction nact;
12386ed60a6SMatthew Dillon 	struct sigaction oact;
12486ed60a6SMatthew Dillon 
12586ed60a6SMatthew Dillon 	bzero(&nact, sizeof(nact));
12686ed60a6SMatthew Dillon 	nact.sa_handler = udp_alarm;
12786ed60a6SMatthew Dillon 	nact.sa_flags = 0;
12886ed60a6SMatthew Dillon 	sigaction(SIGALRM, &nact, &oact);
12986ed60a6SMatthew Dillon 	alarm(timeout);
13086ed60a6SMatthew Dillon 	n = recvfrom(fd, buf, sizeof(buf) - 1, 0, (void *)rsin, &rsin_len);
13186ed60a6SMatthew Dillon 	alarm(0);
13286ed60a6SMatthew Dillon 	sigaction(SIGALRM, &oact, NULL);
133be853a16SMatthew Dillon 	if (n < 0) {
134be853a16SMatthew Dillon 	    if (errno == EINTR && --nretry > 0)
13586ed60a6SMatthew Dillon 		goto retry;
13686ed60a6SMatthew Dillon 	    asprintf(bufp, "udp_transaction: recvfrom: timeout");
13786ed60a6SMatthew Dillon 	    *lenp = strlen(*bufp);
13886ed60a6SMatthew Dillon 	    return(508);
13986ed60a6SMatthew Dillon 	}
14086ed60a6SMatthew Dillon 	while (n > 0 && (buf[n - 1] == '\r' || buf[n - 1] == '\n'))
14186ed60a6SMatthew Dillon 		--n;
14286ed60a6SMatthew Dillon 	buf[n] = 0;
143be853a16SMatthew Dillon 	rc = strtol(buf, NULL, 10);
14486ed60a6SMatthew Dillon 	*bufp = strdup(buf);
14586ed60a6SMatthew Dillon 	*lenp = strlen(buf);
14686ed60a6SMatthew Dillon     } else {
14786ed60a6SMatthew Dillon 	rc = 508;
14886ed60a6SMatthew Dillon 	asprintf(bufp, "udp_transaction: sendto: %s", strerror(errno));
14986ed60a6SMatthew Dillon 	*lenp = strlen(*bufp);
15086ed60a6SMatthew Dillon     }
15186ed60a6SMatthew Dillon     return(rc);
15286ed60a6SMatthew Dillon }
15386ed60a6SMatthew Dillon 
15486ed60a6SMatthew Dillon int
tcp_transact(struct sockaddr_in * sain,FILE ** pfi,FILE ** pfo,char ** bufp,int * lenp,const char * ctl,...)15586ed60a6SMatthew Dillon tcp_transact(struct sockaddr_in *sain, FILE **pfi, FILE **pfo, char **bufp,
15686ed60a6SMatthew Dillon 		int *lenp, const char *ctl, ...)
15786ed60a6SMatthew Dillon {
15886ed60a6SMatthew Dillon     char buf[2048];
15986ed60a6SMatthew Dillon     va_list va;
16086ed60a6SMatthew Dillon     int rc;
16186ed60a6SMatthew Dillon     int n;
16286ed60a6SMatthew Dillon 
16386ed60a6SMatthew Dillon     if (*bufp) {
16486ed60a6SMatthew Dillon 	free(*bufp);
16586ed60a6SMatthew Dillon 	*bufp = NULL;
16686ed60a6SMatthew Dillon     }
16786ed60a6SMatthew Dillon     if (*pfi == NULL) {
16886ed60a6SMatthew Dillon 	int fd;
16986ed60a6SMatthew Dillon 
17086ed60a6SMatthew Dillon 	if ((fd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
17186ed60a6SMatthew Dillon 	    asprintf(bufp, "tcp_transaction: socket: %s", strerror(errno));
17286ed60a6SMatthew Dillon 	    *lenp = strlen(*bufp);
17386ed60a6SMatthew Dillon 	    return(509);
17486ed60a6SMatthew Dillon 	}
17586ed60a6SMatthew Dillon 	if (connect(fd, (void *)sain, sizeof(*sain)) < 0) {
17686ed60a6SMatthew Dillon 	    asprintf(bufp, "tcp_transaction: connect: %s", strerror(errno));
17786ed60a6SMatthew Dillon 	    *lenp = strlen(*bufp);
17886ed60a6SMatthew Dillon 	    close(fd);
17986ed60a6SMatthew Dillon 	    return(509);
18086ed60a6SMatthew Dillon 	}
18186ed60a6SMatthew Dillon 	*pfi = fdopen(fd, "r");
18286ed60a6SMatthew Dillon 	*pfo = fdopen(dup(fd), "w");
18386ed60a6SMatthew Dillon 	if (tcp_transact(sain, pfi, pfo, bufp, lenp, NULL) != 108) {
18486ed60a6SMatthew Dillon 	    fclose(*pfi);
18586ed60a6SMatthew Dillon 	    fclose(*pfo);
18686ed60a6SMatthew Dillon 	    *pfi = *pfo = NULL;
18786ed60a6SMatthew Dillon 	    if (*bufp)
18886ed60a6SMatthew Dillon 		free(*bufp);
18986ed60a6SMatthew Dillon 	    asprintf(bufp, "tcp_transaction: did not get HELLO from server\n");
19086ed60a6SMatthew Dillon 	    *lenp = strlen(*bufp);
19186ed60a6SMatthew Dillon 	    return(509);
19286ed60a6SMatthew Dillon 	}
19386ed60a6SMatthew Dillon 	if (*bufp) {
19486ed60a6SMatthew Dillon 	    printf("%s\n", *bufp);
19586ed60a6SMatthew Dillon 	    free(*bufp);
19686ed60a6SMatthew Dillon 	    *bufp = NULL;
19786ed60a6SMatthew Dillon 	}
19886ed60a6SMatthew Dillon     }
19986ed60a6SMatthew Dillon     if (ctl) {
20086ed60a6SMatthew Dillon 	va_start(va, ctl);
20186ed60a6SMatthew Dillon 	vfprintf(*pfo, ctl, va);
20286ed60a6SMatthew Dillon 	va_end(va);
20386ed60a6SMatthew Dillon 	fflush(*pfo);
20486ed60a6SMatthew Dillon     }
20586ed60a6SMatthew Dillon     if (fgets(buf, sizeof(buf), *pfi) != NULL) {
20686ed60a6SMatthew Dillon 	rc = strtol(buf, NULL, 10);
20786ed60a6SMatthew Dillon 	n = strlen(buf);
20886ed60a6SMatthew Dillon 	if (rc == 201 && strstr(buf, "SIZE=") != NULL) {
20986ed60a6SMatthew Dillon 	    *lenp = strtol(strstr(buf, "SIZE=") + 5, NULL, 0);
21086ed60a6SMatthew Dillon 	    if (*lenp > 0)
21186ed60a6SMatthew Dillon 		*bufp = malloc(*lenp);
21286ed60a6SMatthew Dillon 	    for (rc = 0; *bufp && rc < *lenp; rc += n) {
2131213fdc4SMatthew Dillon 		if ((n = *lenp - rc) > (int)sizeof(buf))
21486ed60a6SMatthew Dillon 		    n = sizeof(buf);
21586ed60a6SMatthew Dillon 		n = fread(*bufp + rc, 1, n, *pfi);
21686ed60a6SMatthew Dillon 		if (n <= 0)
21786ed60a6SMatthew Dillon 		    break;
21886ed60a6SMatthew Dillon 	    }
21986ed60a6SMatthew Dillon 	    if (rc == *lenp && fgets(buf, sizeof(buf), *pfi)) {
22086ed60a6SMatthew Dillon 		if (strstr(buf, "ERROR=")) {
22186ed60a6SMatthew Dillon 		    rc = strtol(strstr(buf, "ERROR=") + 6, NULL, 0);
22286ed60a6SMatthew Dillon 		    if (rc == 0)
22386ed60a6SMatthew Dillon 			rc = 201;
22486ed60a6SMatthew Dillon 		    else
22586ed60a6SMatthew Dillon 			rc = 509;
22686ed60a6SMatthew Dillon 		} else {
22786ed60a6SMatthew Dillon 		    rc = 509;
22886ed60a6SMatthew Dillon 		}
22986ed60a6SMatthew Dillon 	    } else {
23086ed60a6SMatthew Dillon 		rc = 509;
23186ed60a6SMatthew Dillon 	    }
23286ed60a6SMatthew Dillon 	    if (rc != 201) {
23386ed60a6SMatthew Dillon 		free(*bufp);
23486ed60a6SMatthew Dillon 		asprintf(bufp, "tcp_transaction: download failed\n");
23586ed60a6SMatthew Dillon 		*lenp = strlen(*bufp);
23686ed60a6SMatthew Dillon 	    }
23786ed60a6SMatthew Dillon 	} else {
23886ed60a6SMatthew Dillon 	    while (n > 0 && (buf[n-1] == '\r' || buf[n-1] == '\n'))
23986ed60a6SMatthew Dillon 		--n;
24086ed60a6SMatthew Dillon 	    buf[n] = 0;
24186ed60a6SMatthew Dillon 	    *bufp = strdup(buf);
24286ed60a6SMatthew Dillon 	    *lenp = n;
24386ed60a6SMatthew Dillon 	}
24486ed60a6SMatthew Dillon     } else {
24586ed60a6SMatthew Dillon 	asprintf(bufp, "tcp_transaction: read: %s", strerror(errno));
24686ed60a6SMatthew Dillon 	*lenp = strlen(*bufp);
24786ed60a6SMatthew Dillon 	fclose(*pfi);
24886ed60a6SMatthew Dillon 	fclose(*pfo);
24986ed60a6SMatthew Dillon 	*pfi = *pfo = NULL;
25086ed60a6SMatthew Dillon 	rc = 509;
25186ed60a6SMatthew Dillon     }
25286ed60a6SMatthew Dillon     return(rc);
25386ed60a6SMatthew Dillon }
25486ed60a6SMatthew Dillon 
25586ed60a6SMatthew Dillon static
25686ed60a6SMatthew Dillon void
udp_alarm(int signo __unused)2571213fdc4SMatthew Dillon udp_alarm(int signo __unused)
25886ed60a6SMatthew Dillon {
25986ed60a6SMatthew Dillon     /* do nothing */
26086ed60a6SMatthew Dillon }
26186ed60a6SMatthew Dillon 
262