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