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