xref: /dragonfly/sbin/rconfig/subs.c (revision 0db87cb7)
1 /*
2  * RCONFIG/SUBS.C
3  *
4  * Copyright (c) 2003,2004 The DragonFly Project.  All rights reserved.
5  *
6  * This code is derived from software contributed to The DragonFly Project
7  * by Matthew Dillon <dillon@backplane.com>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  * 3. Neither the name of The DragonFly Project nor the names of its
20  *    contributors may be used to endorse or promote products derived
21  *    from this software without specific, prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
27  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #include "defs.h"
38 
39 static void udp_alarm(int signo);
40 
41 static __inline
42 int
43 iswhite(char c)
44 {
45     return(c == ' ' || c == '\t' || c == '\r' || c == '\n');
46 }
47 
48 const char *
49 parse_str(char **scanp, int flags)
50 {
51     char *base;
52     char *ptr;
53 
54     for (base = *scanp; *base && iswhite(*base); ++base)
55 	;
56     for (ptr = base; *ptr && !iswhite(*ptr); ++ptr) {
57 	if (flags & PAS_ALPHA) {
58 	    if ((*ptr >= 'a' && *ptr <= 'z') ||
59 		(*ptr >= 'A' && *ptr <= 'Z') ||
60 		*ptr == '_'
61 	    ) {
62 		continue;
63 	    }
64 	}
65 	if (flags & PAS_NUMERIC) {
66 	    if (*ptr >= '0' && *ptr <= '9')
67 		continue;
68 	}
69 	if ((flags & PAS_ANY) == 0)
70 	    return(NULL);
71     }
72     if (*ptr)
73 	*ptr++ = 0;
74     *scanp = ptr;
75     return(base);
76 }
77 
78 int
79 udp_transact(struct sockaddr_in *sain, struct sockaddr_in *rsin, int *pfd,
80 		char **bufp, int *lenp, const char *ctl, ...)
81 {
82     va_list va;
83     int fd;
84     int n;
85     socklen_t rsin_len = sizeof(*rsin);
86     int rc;
87     int nretry = 3;
88     int timeout = 1;
89     int on = 1;
90     char buf[2048];
91 
92     if (*bufp) {
93 	free(*bufp);
94 	*bufp = NULL;
95 	*lenp = 0;
96     }
97     if ((fd = *pfd) < 0) {
98 	struct sockaddr_in lsin;
99 
100 	lsin.sin_addr.s_addr = INADDR_ANY;
101 	lsin.sin_port = 0;
102 	lsin.sin_family = AF_INET;
103 	if ((fd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC)) < 0) {
104 	    asprintf(bufp, "udp_transaction: socket: %s", strerror(errno));
105 	    *lenp = strlen(*bufp);
106 	    return(509);
107 	}
108 	setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
109 	if (bind(fd, (void *)&lsin, sizeof(lsin)) < 0) {
110 	    asprintf(bufp, "udp_transaction: bind: %s", strerror(errno));
111 	    *lenp = strlen(*bufp);
112 	    close(fd);
113 	    return(509);
114 	}
115 	*pfd = fd;
116     }
117 retry:
118     va_start(va, ctl);
119     vsnprintf(buf, sizeof(buf), ctl, va);
120     va_end(va);
121     if (sendto(fd, buf, strlen(buf), 0, (void *)sain, sizeof(*sain)) >= 0) {
122 	struct sigaction nact;
123 	struct sigaction oact;
124 
125 	bzero(&nact, sizeof(nact));
126 	nact.sa_handler = udp_alarm;
127 	nact.sa_flags = 0;
128 	sigaction(SIGALRM, &nact, &oact);
129 	alarm(timeout);
130 	n = recvfrom(fd, buf, sizeof(buf) - 1, 0, (void *)rsin, &rsin_len);
131 	alarm(0);
132 	sigaction(SIGALRM, &oact, NULL);
133 	if (n < 0) {
134 	    if (errno == EINTR && --nretry > 0)
135 		goto retry;
136 	    asprintf(bufp, "udp_transaction: recvfrom: timeout");
137 	    *lenp = strlen(*bufp);
138 	    return(508);
139 	}
140 	while (n > 0 && (buf[n - 1] == '\r' || buf[n - 1] == '\n'))
141 		--n;
142 	buf[n] = 0;
143 	rc = strtol(buf, NULL, 10);
144 	*bufp = strdup(buf);
145 	*lenp = strlen(buf);
146     } else {
147 	rc = 508;
148 	asprintf(bufp, "udp_transaction: sendto: %s", strerror(errno));
149 	*lenp = strlen(*bufp);
150     }
151     return(rc);
152 }
153 
154 int
155 tcp_transact(struct sockaddr_in *sain, FILE **pfi, FILE **pfo, char **bufp,
156 		int *lenp, const char *ctl, ...)
157 {
158     char buf[2048];
159     va_list va;
160     int rc;
161     int n;
162 
163     if (*bufp) {
164 	free(*bufp);
165 	*bufp = NULL;
166     }
167     if (*pfi == NULL) {
168 	int fd;
169 
170 	if ((fd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
171 	    asprintf(bufp, "tcp_transaction: socket: %s", strerror(errno));
172 	    *lenp = strlen(*bufp);
173 	    return(509);
174 	}
175 	if (connect(fd, (void *)sain, sizeof(*sain)) < 0) {
176 	    asprintf(bufp, "tcp_transaction: connect: %s", strerror(errno));
177 	    *lenp = strlen(*bufp);
178 	    close(fd);
179 	    return(509);
180 	}
181 	*pfi = fdopen(fd, "r");
182 	*pfo = fdopen(dup(fd), "w");
183 	if (tcp_transact(sain, pfi, pfo, bufp, lenp, NULL) != 108) {
184 	    fclose(*pfi);
185 	    fclose(*pfo);
186 	    *pfi = *pfo = NULL;
187 	    if (*bufp)
188 		free(*bufp);
189 	    asprintf(bufp, "tcp_transaction: did not get HELLO from server\n");
190 	    *lenp = strlen(*bufp);
191 	    return(509);
192 	}
193 	if (*bufp) {
194 	    printf("%s\n", *bufp);
195 	    free(*bufp);
196 	    *bufp = NULL;
197 	}
198     }
199     if (ctl) {
200 	va_start(va, ctl);
201 	vfprintf(*pfo, ctl, va);
202 	va_end(va);
203 	fflush(*pfo);
204     }
205     if (fgets(buf, sizeof(buf), *pfi) != NULL) {
206 	rc = strtol(buf, NULL, 10);
207 	n = strlen(buf);
208 	if (rc == 201 && strstr(buf, "SIZE=") != NULL) {
209 	    *lenp = strtol(strstr(buf, "SIZE=") + 5, NULL, 0);
210 	    if (*lenp > 0)
211 		*bufp = malloc(*lenp);
212 	    for (rc = 0; *bufp && rc < *lenp; rc += n) {
213 		if ((n = *lenp - rc) > (int)sizeof(buf))
214 		    n = sizeof(buf);
215 		n = fread(*bufp + rc, 1, n, *pfi);
216 		if (n <= 0)
217 		    break;
218 	    }
219 	    if (rc == *lenp && fgets(buf, sizeof(buf), *pfi)) {
220 		if (strstr(buf, "ERROR=")) {
221 		    rc = strtol(strstr(buf, "ERROR=") + 6, NULL, 0);
222 		    if (rc == 0)
223 			rc = 201;
224 		    else
225 			rc = 509;
226 		} else {
227 		    rc = 509;
228 		}
229 	    } else {
230 		rc = 509;
231 	    }
232 	    if (rc != 201) {
233 		free(*bufp);
234 		asprintf(bufp, "tcp_transaction: download failed\n");
235 		*lenp = strlen(*bufp);
236 	    }
237 	} else {
238 	    while (n > 0 && (buf[n-1] == '\r' || buf[n-1] == '\n'))
239 		--n;
240 	    buf[n] = 0;
241 	    *bufp = strdup(buf);
242 	    *lenp = n;
243 	}
244     } else {
245 	asprintf(bufp, "tcp_transaction: read: %s", strerror(errno));
246 	*lenp = strlen(*bufp);
247 	fclose(*pfi);
248 	fclose(*pfo);
249 	*pfi = *pfo = NULL;
250 	rc = 509;
251     }
252     return(rc);
253 }
254 
255 static
256 void
257 udp_alarm(int signo __unused)
258 {
259     /* do nothing */
260 }
261 
262