/* * RCONFIG/SUBS.C * * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Matthew Dillon * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name of The DragonFly Project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific, prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $DragonFly: src/sbin/rconfig/subs.c,v 1.4 2005/04/02 22:15:20 dillon Exp $ */ #include "defs.h" static void udp_alarm(int signo); static __inline int iswhite(char c) { return(c == ' ' || c == '\t' || c == '\r' || c == '\n'); } const char * parse_str(char **scanp, int flags) { char *base; char *ptr; for (base = *scanp; *base && iswhite(*base); ++base) ; for (ptr = base; *ptr && !iswhite(*ptr); ++ptr) { if (flags & PAS_ALPHA) { if ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || *ptr == '_' ) { continue; } } if (flags & PAS_NUMERIC) { if (*ptr >= '0' && *ptr <= '9') continue; } if ((flags & PAS_ANY) == 0) return(NULL); } if (*ptr) *ptr++ = 0; *scanp = ptr; return(base); } int udp_transact(struct sockaddr_in *sain, struct sockaddr_in *rsin, int *pfd, char **bufp, int *lenp, const char *ctl, ...) { va_list va; int fd; int n; int rsin_len = sizeof(*rsin); int rc; int nretry = 3; int timeout = 1; int on = 1; char buf[2048]; if (*bufp) { free(*bufp); *bufp = NULL; *lenp = 0; } if ((fd = *pfd) < 0) { struct sockaddr_in lsin; lsin.sin_addr.s_addr = INADDR_ANY; lsin.sin_port = 0; lsin.sin_family = AF_INET; if ((fd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC)) < 0) { asprintf(bufp, "udp_transaction: socket: %s", strerror(errno)); *lenp = strlen(*bufp); return(509); } setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); if (bind(fd, (void *)&lsin, sizeof(lsin)) < 0) { asprintf(bufp, "udp_transaction: bind: %s", strerror(errno)); *lenp = strlen(*bufp); close(fd); return(509); } *pfd = fd; } retry: va_start(va, ctl); vsnprintf(buf, sizeof(buf), ctl, va); va_end(va); if (sendto(fd, buf, strlen(buf), 0, (void *)sain, sizeof(*sain)) >= 0) { struct sigaction nact; struct sigaction oact; bzero(&nact, sizeof(nact)); nact.sa_handler = udp_alarm; nact.sa_flags = 0; sigaction(SIGALRM, &nact, &oact); alarm(timeout); n = recvfrom(fd, buf, sizeof(buf) - 1, 0, (void *)rsin, &rsin_len); alarm(0); sigaction(SIGALRM, &oact, NULL); if (n < 0) { if (errno == EINTR && --nretry > 0) goto retry; asprintf(bufp, "udp_transaction: recvfrom: timeout"); *lenp = strlen(*bufp); return(508); } while (n > 0 && (buf[n - 1] == '\r' || buf[n - 1] == '\n')) --n; buf[n] = 0; rc = strtol(buf, NULL, 10); *bufp = strdup(buf); *lenp = strlen(buf); } else { rc = 508; asprintf(bufp, "udp_transaction: sendto: %s", strerror(errno)); *lenp = strlen(*bufp); } return(rc); } int tcp_transact(struct sockaddr_in *sain, FILE **pfi, FILE **pfo, char **bufp, int *lenp, const char *ctl, ...) { char buf[2048]; va_list va; int rc; int n; if (*bufp) { free(*bufp); *bufp = NULL; } if (*pfi == NULL) { int fd; if ((fd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { asprintf(bufp, "tcp_transaction: socket: %s", strerror(errno)); *lenp = strlen(*bufp); return(509); } if (connect(fd, (void *)sain, sizeof(*sain)) < 0) { asprintf(bufp, "tcp_transaction: connect: %s", strerror(errno)); *lenp = strlen(*bufp); close(fd); return(509); } *pfi = fdopen(fd, "r"); *pfo = fdopen(dup(fd), "w"); if (tcp_transact(sain, pfi, pfo, bufp, lenp, NULL) != 108) { fclose(*pfi); fclose(*pfo); *pfi = *pfo = NULL; if (*bufp) free(*bufp); asprintf(bufp, "tcp_transaction: did not get HELLO from server\n"); *lenp = strlen(*bufp); return(509); } if (*bufp) { printf("%s\n", *bufp); free(*bufp); *bufp = NULL; } } if (ctl) { va_start(va, ctl); vfprintf(*pfo, ctl, va); va_end(va); fflush(*pfo); } if (fgets(buf, sizeof(buf), *pfi) != NULL) { rc = strtol(buf, NULL, 10); n = strlen(buf); if (rc == 201 && strstr(buf, "SIZE=") != NULL) { *lenp = strtol(strstr(buf, "SIZE=") + 5, NULL, 0); if (*lenp > 0) *bufp = malloc(*lenp); for (rc = 0; *bufp && rc < *lenp; rc += n) { if ((n = *lenp - rc) > (int)sizeof(buf)) n = sizeof(buf); n = fread(*bufp + rc, 1, n, *pfi); if (n <= 0) break; } if (rc == *lenp && fgets(buf, sizeof(buf), *pfi)) { if (strstr(buf, "ERROR=")) { rc = strtol(strstr(buf, "ERROR=") + 6, NULL, 0); if (rc == 0) rc = 201; else rc = 509; } else { rc = 509; } } else { rc = 509; } if (rc != 201) { free(*bufp); asprintf(bufp, "tcp_transaction: download failed\n"); *lenp = strlen(*bufp); } } else { while (n > 0 && (buf[n-1] == '\r' || buf[n-1] == '\n')) --n; buf[n] = 0; *bufp = strdup(buf); *lenp = n; } } else { asprintf(bufp, "tcp_transaction: read: %s", strerror(errno)); *lenp = strlen(*bufp); fclose(*pfi); fclose(*pfo); *pfi = *pfo = NULL; rc = 509; } return(rc); } static void udp_alarm(int signo __unused) { /* do nothing */ }