Add the standard DragonFly copyright with attribution to the author (which is
[dragonfly.git] / sbin / rconfig / subs.c
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.3 2004/08/19 23:57:02 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) > 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)
260 {
261     /* do nothing */
262 }
263