misc.c revision 124208
176259Sgreen/* 276259Sgreen * Copyright (c) 2000 Markus Friedl. All rights reserved. 376259Sgreen * 476259Sgreen * Redistribution and use in source and binary forms, with or without 576259Sgreen * modification, are permitted provided that the following conditions 676259Sgreen * are met: 776259Sgreen * 1. Redistributions of source code must retain the above copyright 876259Sgreen * notice, this list of conditions and the following disclaimer. 976259Sgreen * 2. Redistributions in binary form must reproduce the above copyright 1076259Sgreen * notice, this list of conditions and the following disclaimer in the 1176259Sgreen * documentation and/or other materials provided with the distribution. 1276259Sgreen * 1376259Sgreen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1476259Sgreen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1576259Sgreen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1676259Sgreen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1776259Sgreen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1876259Sgreen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1976259Sgreen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2076259Sgreen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2176259Sgreen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2276259Sgreen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2376259Sgreen */ 2476259Sgreen 2576259Sgreen#include "includes.h" 26124208SdesRCSID("$OpenBSD: misc.c,v 1.22 2003/09/18 08:49:45 markus Exp $"); 2776259Sgreen 2876259Sgreen#include "misc.h" 2976259Sgreen#include "log.h" 3076259Sgreen#include "xmalloc.h" 3176259Sgreen 3292555Sdes/* remove newline at end of string */ 3376259Sgreenchar * 3476259Sgreenchop(char *s) 3576259Sgreen{ 3676259Sgreen char *t = s; 3776259Sgreen while (*t) { 3892555Sdes if (*t == '\n' || *t == '\r') { 3976259Sgreen *t = '\0'; 4076259Sgreen return s; 4176259Sgreen } 4276259Sgreen t++; 4376259Sgreen } 4476259Sgreen return s; 4576259Sgreen 4676259Sgreen} 4776259Sgreen 4892555Sdes/* set/unset filedescriptor to non-blocking */ 4976259Sgreenvoid 5076259Sgreenset_nonblock(int fd) 5176259Sgreen{ 5276259Sgreen int val; 5392555Sdes 5476259Sgreen val = fcntl(fd, F_GETFL, 0); 5576259Sgreen if (val < 0) { 5676259Sgreen error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 5776259Sgreen return; 5876259Sgreen } 5976259Sgreen if (val & O_NONBLOCK) { 6092555Sdes debug2("fd %d is O_NONBLOCK", fd); 6176259Sgreen return; 6276259Sgreen } 63124208Sdes debug2("fd %d setting O_NONBLOCK", fd); 6476259Sgreen val |= O_NONBLOCK; 6576259Sgreen if (fcntl(fd, F_SETFL, val) == -1) 6692555Sdes debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", 6792555Sdes fd, strerror(errno)); 6876259Sgreen} 6976259Sgreen 7092555Sdesvoid 7192555Sdesunset_nonblock(int fd) 7292555Sdes{ 7392555Sdes int val; 7492555Sdes 7592555Sdes val = fcntl(fd, F_GETFL, 0); 7692555Sdes if (val < 0) { 7792555Sdes error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 7892555Sdes return; 7992555Sdes } 8092555Sdes if (!(val & O_NONBLOCK)) { 8192555Sdes debug2("fd %d is not O_NONBLOCK", fd); 8292555Sdes return; 8392555Sdes } 8492555Sdes debug("fd %d clearing O_NONBLOCK", fd); 8592555Sdes val &= ~O_NONBLOCK; 8692555Sdes if (fcntl(fd, F_SETFL, val) == -1) 8792555Sdes debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", 8892555Sdes fd, strerror(errno)); 8992555Sdes} 9092555Sdes 9192555Sdes/* disable nagle on socket */ 9292555Sdesvoid 9392555Sdesset_nodelay(int fd) 9492555Sdes{ 9592555Sdes int opt; 9692555Sdes socklen_t optlen; 9792555Sdes 9892555Sdes optlen = sizeof opt; 9992555Sdes if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) { 10092555Sdes error("getsockopt TCP_NODELAY: %.100s", strerror(errno)); 10192555Sdes return; 10292555Sdes } 10392555Sdes if (opt == 1) { 10492555Sdes debug2("fd %d is TCP_NODELAY", fd); 10592555Sdes return; 10692555Sdes } 10792555Sdes opt = 1; 108113908Sdes debug2("fd %d setting TCP_NODELAY", fd); 10992555Sdes if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) 11092555Sdes error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 11192555Sdes} 11292555Sdes 11376259Sgreen/* Characters considered whitespace in strsep calls. */ 11476259Sgreen#define WHITESPACE " \t\r\n" 11576259Sgreen 11692555Sdes/* return next token in configuration line */ 11776259Sgreenchar * 11876259Sgreenstrdelim(char **s) 11976259Sgreen{ 12076259Sgreen char *old; 12176259Sgreen int wspace = 0; 12276259Sgreen 12376259Sgreen if (*s == NULL) 12476259Sgreen return NULL; 12576259Sgreen 12676259Sgreen old = *s; 12776259Sgreen 12876259Sgreen *s = strpbrk(*s, WHITESPACE "="); 12976259Sgreen if (*s == NULL) 13076259Sgreen return (old); 13176259Sgreen 13276259Sgreen /* Allow only one '=' to be skipped */ 13376259Sgreen if (*s[0] == '=') 13476259Sgreen wspace = 1; 13576259Sgreen *s[0] = '\0'; 13676259Sgreen 13776259Sgreen *s += strspn(*s + 1, WHITESPACE) + 1; 13876259Sgreen if (*s[0] == '=' && !wspace) 13976259Sgreen *s += strspn(*s + 1, WHITESPACE) + 1; 14076259Sgreen 14176259Sgreen return (old); 14276259Sgreen} 14376259Sgreen 14476259Sgreenstruct passwd * 14576259Sgreenpwcopy(struct passwd *pw) 14676259Sgreen{ 14776259Sgreen struct passwd *copy = xmalloc(sizeof(*copy)); 14876259Sgreen 14976259Sgreen memset(copy, 0, sizeof(*copy)); 15076259Sgreen copy->pw_name = xstrdup(pw->pw_name); 15176259Sgreen copy->pw_passwd = xstrdup(pw->pw_passwd); 15276259Sgreen copy->pw_gecos = xstrdup(pw->pw_gecos); 15376259Sgreen copy->pw_uid = pw->pw_uid; 15476259Sgreen copy->pw_gid = pw->pw_gid; 15598937Sdes#ifdef HAVE_PW_EXPIRE_IN_PASSWD 15692555Sdes copy->pw_expire = pw->pw_expire; 15798937Sdes#endif 15898937Sdes#ifdef HAVE_PW_CHANGE_IN_PASSWD 15992555Sdes copy->pw_change = pw->pw_change; 16098937Sdes#endif 16198937Sdes#ifdef HAVE_PW_CLASS_IN_PASSWD 16276259Sgreen copy->pw_class = xstrdup(pw->pw_class); 16398937Sdes#endif 16476259Sgreen copy->pw_dir = xstrdup(pw->pw_dir); 16576259Sgreen copy->pw_shell = xstrdup(pw->pw_shell); 16676259Sgreen return copy; 16776259Sgreen} 16876259Sgreen 16992555Sdes/* 17092555Sdes * Convert ASCII string to TCP/IP port number. 17192555Sdes * Port must be >0 and <=65535. 17292555Sdes * Return 0 if invalid. 17392555Sdes */ 17492555Sdesint 17592555Sdesa2port(const char *s) 17676259Sgreen{ 17776259Sgreen long port; 17876259Sgreen char *endp; 17976259Sgreen 18076259Sgreen errno = 0; 18176259Sgreen port = strtol(s, &endp, 0); 18276259Sgreen if (s == endp || *endp != '\0' || 18376259Sgreen (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) || 18476259Sgreen port <= 0 || port > 65535) 18576259Sgreen return 0; 18676259Sgreen 18776259Sgreen return port; 18876259Sgreen} 18992555Sdes 19092555Sdes#define SECONDS 1 19192555Sdes#define MINUTES (SECONDS * 60) 19292555Sdes#define HOURS (MINUTES * 60) 19392555Sdes#define DAYS (HOURS * 24) 19492555Sdes#define WEEKS (DAYS * 7) 19592555Sdes 19692555Sdes/* 19792555Sdes * Convert a time string into seconds; format is 19892555Sdes * a sequence of: 19992555Sdes * time[qualifier] 20092555Sdes * 20192555Sdes * Valid time qualifiers are: 20292555Sdes * <none> seconds 20392555Sdes * s|S seconds 20492555Sdes * m|M minutes 20592555Sdes * h|H hours 20692555Sdes * d|D days 20792555Sdes * w|W weeks 20892555Sdes * 20992555Sdes * Examples: 21092555Sdes * 90m 90 minutes 21192555Sdes * 1h30m 90 minutes 21292555Sdes * 2d 2 days 21392555Sdes * 1w 1 week 21492555Sdes * 21592555Sdes * Return -1 if time string is invalid. 21692555Sdes */ 21792555Sdeslong 21892555Sdesconvtime(const char *s) 21992555Sdes{ 22092555Sdes long total, secs; 22192555Sdes const char *p; 22292555Sdes char *endp; 22392555Sdes 22492555Sdes errno = 0; 22592555Sdes total = 0; 22692555Sdes p = s; 22792555Sdes 22892555Sdes if (p == NULL || *p == '\0') 22992555Sdes return -1; 23092555Sdes 23192555Sdes while (*p) { 23292555Sdes secs = strtol(p, &endp, 10); 23392555Sdes if (p == endp || 23492555Sdes (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || 23592555Sdes secs < 0) 23692555Sdes return -1; 23792555Sdes 23892555Sdes switch (*endp++) { 23992555Sdes case '\0': 24092555Sdes endp--; 24192555Sdes case 's': 24292555Sdes case 'S': 24392555Sdes break; 24492555Sdes case 'm': 24592555Sdes case 'M': 24692555Sdes secs *= MINUTES; 24792555Sdes break; 24892555Sdes case 'h': 24992555Sdes case 'H': 25092555Sdes secs *= HOURS; 25192555Sdes break; 25292555Sdes case 'd': 25392555Sdes case 'D': 25492555Sdes secs *= DAYS; 25592555Sdes break; 25692555Sdes case 'w': 25792555Sdes case 'W': 25892555Sdes secs *= WEEKS; 25992555Sdes break; 26092555Sdes default: 26192555Sdes return -1; 26292555Sdes } 26392555Sdes total += secs; 26492555Sdes if (total < 0) 26592555Sdes return -1; 26692555Sdes p = endp; 26792555Sdes } 26892555Sdes 26992555Sdes return total; 27092555Sdes} 27192555Sdes 27292555Sdeschar * 27392555Sdescleanhostname(char *host) 27492555Sdes{ 27592555Sdes if (*host == '[' && host[strlen(host) - 1] == ']') { 27692555Sdes host[strlen(host) - 1] = '\0'; 27792555Sdes return (host + 1); 27892555Sdes } else 27992555Sdes return host; 28092555Sdes} 28192555Sdes 28292555Sdeschar * 28392555Sdescolon(char *cp) 28492555Sdes{ 28592555Sdes int flag = 0; 28692555Sdes 28792555Sdes if (*cp == ':') /* Leading colon is part of file name. */ 28892555Sdes return (0); 28992555Sdes if (*cp == '[') 29092555Sdes flag = 1; 29192555Sdes 29292555Sdes for (; *cp; ++cp) { 29392555Sdes if (*cp == '@' && *(cp+1) == '[') 29492555Sdes flag = 1; 29592555Sdes if (*cp == ']' && *(cp+1) == ':' && flag) 29692555Sdes return (cp+1); 29792555Sdes if (*cp == ':' && !flag) 29892555Sdes return (cp); 29992555Sdes if (*cp == '/') 30092555Sdes return (0); 30192555Sdes } 30292555Sdes return (0); 30392555Sdes} 30492555Sdes 30592555Sdes/* function to assist building execv() arguments */ 30692555Sdesvoid 30792555Sdesaddargs(arglist *args, char *fmt, ...) 30892555Sdes{ 30992555Sdes va_list ap; 31092555Sdes char buf[1024]; 311120161Snectar int nalloc; 31292555Sdes 31392555Sdes va_start(ap, fmt); 31492555Sdes vsnprintf(buf, sizeof(buf), fmt, ap); 31592555Sdes va_end(ap); 31692555Sdes 317120161Snectar nalloc = args->nalloc; 31892555Sdes if (args->list == NULL) { 319120161Snectar nalloc = 32; 32092555Sdes args->num = 0; 321120161Snectar } else if (args->num+2 >= nalloc) 322120161Snectar nalloc *= 2; 32392555Sdes 324120161Snectar args->list = xrealloc(args->list, nalloc * sizeof(char *)); 325120161Snectar args->nalloc = nalloc; 32692555Sdes args->list[args->num++] = xstrdup(buf); 32792555Sdes args->list[args->num] = NULL; 32892555Sdes} 329