Merge branch 'master' of ssh://crater.dragonflybsd.org/repository/git/dragonfly
[dragonfly.git] / sbin / rconfig / subs.c
blob9915c7b2862f080bd85f57eb0b52b08ae48c7f3b
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:
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.
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.
36 * $DragonFly: src/sbin/rconfig/subs.c,v 1.4 2005/04/02 22:15:20 dillon Exp $
39 #include "defs.h"
41 static void udp_alarm(int signo);
43 static __inline
44 int
45 iswhite(char c)
47 return(c == ' ' || c == '\t' || c == '\r' || c == '\n');
50 const char *
51 parse_str(char **scanp, int flags)
53 char *base;
54 char *ptr;
56 for (base = *scanp; *base && iswhite(*base); ++base)
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;
67 if (flags & PAS_NUMERIC) {
68 if (*ptr >= '0' && *ptr <= '9')
69 continue;
71 if ((flags & PAS_ANY) == 0)
72 return(NULL);
74 if (*ptr)
75 *ptr++ = 0;
76 *scanp = ptr;
77 return(base);
80 int
81 udp_transact(struct sockaddr_in *sain, struct sockaddr_in *rsin, int *pfd,
82 char **bufp, int *lenp, const char *ctl, ...)
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];
94 if (*bufp) {
95 free(*bufp);
96 *bufp = NULL;
97 *lenp = 0;
99 if ((fd = *pfd) < 0) {
100 struct sockaddr_in lsin;
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);
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);
117 *pfd = fd;
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;
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);
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);
153 return(rc);
157 tcp_transact(struct sockaddr_in *sain, FILE **pfi, FILE **pfo, char **bufp,
158 int *lenp, const char *ctl, ...)
160 char buf[2048];
161 va_list va;
162 int rc;
163 int n;
165 if (*bufp) {
166 free(*bufp);
167 *bufp = NULL;
169 if (*pfi == NULL) {
170 int fd;
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);
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);
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);
195 if (*bufp) {
196 printf("%s\n", *bufp);
197 free(*bufp);
198 *bufp = NULL;
201 if (ctl) {
202 va_start(va, ctl);
203 vfprintf(*pfo, ctl, va);
204 va_end(va);
205 fflush(*pfo);
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;
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;
231 } else {
232 rc = 509;
234 if (rc != 201) {
235 free(*bufp);
236 asprintf(bufp, "tcp_transaction: download failed\n");
237 *lenp = strlen(*bufp);
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;
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;
254 return(rc);
257 static
258 void
259 udp_alarm(int signo __unused)
261 /* do nothing */