xref: /dragonfly/sbin/rconfig/subs.c (revision c03f08f3)
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  * $DragonFly: src/sbin/rconfig/subs.c,v 1.4 2005/04/02 22:15:20 dillon Exp $
37  */
38 
39 #include "defs.h"
40 
41 static void udp_alarm(int signo);
42 
43 static __inline
44 int
45 iswhite(char c)
46 {
47     return(c == ' ' || c == '\t' || c == '\r' || c == '\n');
48 }
49 
50 const char *
51 parse_str(char **scanp, int flags)
52 {
53     char *base;
54     char *ptr;
55 
56     for (base = *scanp; *base && iswhite(*base); ++base)
57 	;
58     for (ptr = base; *ptr && !iswhite(*ptr); ++ptr) {
59 	if (flags & PAS_ALPHA) {
60 	    if ((*ptr >= 'a' && *ptr <= 'z') ||
61 		(*ptr >= 'A' && *ptr <= 'Z') ||
62 		*ptr == '_'
63 	    ) {
64 		continue;
65 	    }
66 	}
67 	if (flags & PAS_NUMERIC) {
68 	    if (*ptr >= '0' && *ptr <= '9')
69 		continue;
70 	}
71 	if ((flags & PAS_ANY) == 0)
72 	    return(NULL);
73     }
74     if (*ptr)
75 	*ptr++ = 0;
76     *scanp = ptr;
77     return(base);
78 }
79 
80 int
81 udp_transact(struct sockaddr_in *sain, struct sockaddr_in *rsin, int *pfd,
82 		char **bufp, int *lenp, const char *ctl, ...)
83 {
84     va_list va;
85     int fd;
86     int n;
87     int rsin_len = sizeof(*rsin);
88     int rc;
89     int nretry = 3;
90     int timeout = 1;
91     int on = 1;
92     char buf[2048];
93 
94     if (*bufp) {
95 	free(*bufp);
96 	*bufp = NULL;
97 	*lenp = 0;
98     }
99     if ((fd = *pfd) < 0) {
100 	struct sockaddr_in lsin;
101 
102 	lsin.sin_addr.s_addr = INADDR_ANY;
103 	lsin.sin_port = 0;
104 	lsin.sin_family = AF_INET;
105 	if ((fd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC)) < 0) {
106 	    asprintf(bufp, "udp_transaction: socket: %s", strerror(errno));
107 	    *lenp = strlen(*bufp);
108 	    return(509);
109 	}
110 	setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
111 	if (bind(fd, (void *)&lsin, sizeof(lsin)) < 0) {
112 	    asprintf(bufp, "udp_transaction: bind: %s", strerror(errno));
113 	    *lenp = strlen(*bufp);
114 	    close(fd);
115 	    return(509);
116 	}
117 	*pfd = fd;
118     }
119 retry:
120     va_start(va, ctl);
121     vsnprintf(buf, sizeof(buf), ctl, va);
122     va_end(va);
123     if (sendto(fd, buf, strlen(buf), 0, (void *)sain, sizeof(*sain)) >= 0) {
124 	struct sigaction nact;
125 	struct sigaction oact;
126 
127 	bzero(&nact, sizeof(nact));
128 	nact.sa_handler = udp_alarm;
129 	nact.sa_flags = 0;
130 	sigaction(SIGALRM, &nact, &oact);
131 	alarm(timeout);
132 	n = recvfrom(fd, buf, sizeof(buf) - 1, 0, (void *)rsin, &rsin_len);
133 	alarm(0);
134 	sigaction(SIGALRM, &oact, NULL);
135 	if (n < 0) {
136 	    if (errno == EINTR && --nretry > 0)
137 		goto retry;
138 	    asprintf(bufp, "udp_transaction: recvfrom: timeout");
139 	    *lenp = strlen(*bufp);
140 	    return(508);
141 	}
142 	while (n > 0 && (buf[n - 1] == '\r' || buf[n - 1] == '\n'))
143 		--n;
144 	buf[n] = 0;
145 	rc = strtol(buf, NULL, 10);
146 	*bufp = strdup(buf);
147 	*lenp = strlen(buf);
148     } else {
149 	rc = 508;
150 	asprintf(bufp, "udp_transaction: sendto: %s", strerror(errno));
151 	*lenp = strlen(*bufp);
152     }
153     return(rc);
154 }
155 
156 int
157 tcp_transact(struct sockaddr_in *sain, FILE **pfi, FILE **pfo, char **bufp,
158 		int *lenp, const char *ctl, ...)
159 {
160     char buf[2048];
161     va_list va;
162     int rc;
163     int n;
164 
165     if (*bufp) {
166 	free(*bufp);
167 	*bufp = NULL;
168     }
169     if (*pfi == NULL) {
170 	int fd;
171 
172 	if ((fd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
173 	    asprintf(bufp, "tcp_transaction: socket: %s", strerror(errno));
174 	    *lenp = strlen(*bufp);
175 	    return(509);
176 	}
177 	if (connect(fd, (void *)sain, sizeof(*sain)) < 0) {
178 	    asprintf(bufp, "tcp_transaction: connect: %s", strerror(errno));
179 	    *lenp = strlen(*bufp);
180 	    close(fd);
181 	    return(509);
182 	}
183 	*pfi = fdopen(fd, "r");
184 	*pfo = fdopen(dup(fd), "w");
185 	if (tcp_transact(sain, pfi, pfo, bufp, lenp, NULL) != 108) {
186 	    fclose(*pfi);
187 	    fclose(*pfo);
188 	    *pfi = *pfo = NULL;
189 	    if (*bufp)
190 		free(*bufp);
191 	    asprintf(bufp, "tcp_transaction: did not get HELLO from server\n");
192 	    *lenp = strlen(*bufp);
193 	    return(509);
194 	}
195 	if (*bufp) {
196 	    printf("%s\n", *bufp);
197 	    free(*bufp);
198 	    *bufp = NULL;
199 	}
200     }
201     if (ctl) {
202 	va_start(va, ctl);
203 	vfprintf(*pfo, ctl, va);
204 	va_end(va);
205 	fflush(*pfo);
206     }
207     if (fgets(buf, sizeof(buf), *pfi) != NULL) {
208 	rc = strtol(buf, NULL, 10);
209 	n = strlen(buf);
210 	if (rc == 201 && strstr(buf, "SIZE=") != NULL) {
211 	    *lenp = strtol(strstr(buf, "SIZE=") + 5, NULL, 0);
212 	    if (*lenp > 0)
213 		*bufp = malloc(*lenp);
214 	    for (rc = 0; *bufp && rc < *lenp; rc += n) {
215 		if ((n = *lenp - rc) > (int)sizeof(buf))
216 		    n = sizeof(buf);
217 		n = fread(*bufp + rc, 1, n, *pfi);
218 		if (n <= 0)
219 		    break;
220 	    }
221 	    if (rc == *lenp && fgets(buf, sizeof(buf), *pfi)) {
222 		if (strstr(buf, "ERROR=")) {
223 		    rc = strtol(strstr(buf, "ERROR=") + 6, NULL, 0);
224 		    if (rc == 0)
225 			rc = 201;
226 		    else
227 			rc = 509;
228 		} else {
229 		    rc = 509;
230 		}
231 	    } else {
232 		rc = 509;
233 	    }
234 	    if (rc != 201) {
235 		free(*bufp);
236 		asprintf(bufp, "tcp_transaction: download failed\n");
237 		*lenp = strlen(*bufp);
238 	    }
239 	} else {
240 	    while (n > 0 && (buf[n-1] == '\r' || buf[n-1] == '\n'))
241 		--n;
242 	    buf[n] = 0;
243 	    *bufp = strdup(buf);
244 	    *lenp = n;
245 	}
246     } else {
247 	asprintf(bufp, "tcp_transaction: read: %s", strerror(errno));
248 	*lenp = strlen(*bufp);
249 	fclose(*pfi);
250 	fclose(*pfo);
251 	*pfi = *pfo = NULL;
252 	rc = 509;
253     }
254     return(rc);
255 }
256 
257 static
258 void
259 udp_alarm(int signo __unused)
260 {
261     /* do nothing */
262 }
263 
264