1 /* $OpenBSD: misc.c,v 1.15 2002/01/24 21:09:25 stevesk Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Markus Friedl. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "includes.h" 28 RCSID("$OpenBSD: misc.c,v 1.15 2002/01/24 21:09:25 stevesk Exp $"); 29 30 #include "misc.h" 31 #include "log.h" 32 #include "xmalloc.h" 33 34 /* remove newline at end of string */ 35 char * 36 chop(char *s) 37 { 38 char *t = s; 39 while (*t) { 40 if (*t == '\n' || *t == '\r') { 41 *t = '\0'; 42 return s; 43 } 44 t++; 45 } 46 return s; 47 48 } 49 50 /* set/unset filedescriptor to non-blocking */ 51 void 52 set_nonblock(int fd) 53 { 54 int val; 55 56 val = fcntl(fd, F_GETFL, 0); 57 if (val < 0) { 58 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 59 return; 60 } 61 if (val & O_NONBLOCK) { 62 debug2("fd %d is O_NONBLOCK", fd); 63 return; 64 } 65 debug("fd %d setting O_NONBLOCK", fd); 66 val |= O_NONBLOCK; 67 if (fcntl(fd, F_SETFL, val) == -1) 68 if (errno != ENODEV) 69 error("fcntl(%d, F_SETFL, O_NONBLOCK): %s", 70 fd, strerror(errno)); 71 } 72 73 void 74 unset_nonblock(int fd) 75 { 76 int val; 77 78 val = fcntl(fd, F_GETFL, 0); 79 if (val < 0) { 80 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 81 return; 82 } 83 if (!(val & O_NONBLOCK)) { 84 debug2("fd %d is not O_NONBLOCK", fd); 85 return; 86 } 87 debug("fd %d clearing O_NONBLOCK", fd); 88 val &= ~O_NONBLOCK; 89 if (fcntl(fd, F_SETFL, val) == -1) 90 if (errno != ENODEV) 91 error("fcntl(%d, F_SETFL, O_NONBLOCK): %s", 92 fd, strerror(errno)); 93 } 94 95 /* disable nagle on socket */ 96 void 97 set_nodelay(int fd) 98 { 99 int on = 1; 100 101 debug("fd %d setting TCP_NODELAY", fd); 102 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on) == -1) 103 error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 104 } 105 106 /* Characters considered whitespace in strsep calls. */ 107 #define WHITESPACE " \t\r\n" 108 109 /* return next token in configuration line */ 110 char * 111 strdelim(char **s) 112 { 113 char *old; 114 int wspace = 0; 115 116 if (*s == NULL) 117 return NULL; 118 119 old = *s; 120 121 *s = strpbrk(*s, WHITESPACE "="); 122 if (*s == NULL) 123 return (old); 124 125 /* Allow only one '=' to be skipped */ 126 if (*s[0] == '=') 127 wspace = 1; 128 *s[0] = '\0'; 129 130 *s += strspn(*s + 1, WHITESPACE) + 1; 131 if (*s[0] == '=' && !wspace) 132 *s += strspn(*s + 1, WHITESPACE) + 1; 133 134 return (old); 135 } 136 137 struct passwd * 138 pwcopy(struct passwd *pw) 139 { 140 struct passwd *copy = xmalloc(sizeof(*copy)); 141 142 memset(copy, 0, sizeof(*copy)); 143 copy->pw_name = xstrdup(pw->pw_name); 144 copy->pw_passwd = xstrdup(pw->pw_passwd); 145 copy->pw_gecos = xstrdup(pw->pw_gecos); 146 copy->pw_uid = pw->pw_uid; 147 copy->pw_gid = pw->pw_gid; 148 copy->pw_expire = pw->pw_expire; 149 copy->pw_change = pw->pw_change; 150 copy->pw_class = xstrdup(pw->pw_class); 151 copy->pw_dir = xstrdup(pw->pw_dir); 152 copy->pw_shell = xstrdup(pw->pw_shell); 153 return copy; 154 } 155 156 /* 157 * Convert ASCII string to TCP/IP port number. 158 * Port must be >0 and <=65535. 159 * Return 0 if invalid. 160 */ 161 int 162 a2port(const char *s) 163 { 164 long port; 165 char *endp; 166 167 errno = 0; 168 port = strtol(s, &endp, 0); 169 if (s == endp || *endp != '\0' || 170 (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) || 171 port <= 0 || port > 65535) 172 return 0; 173 174 return port; 175 } 176 177 #define SECONDS 1 178 #define MINUTES (SECONDS * 60) 179 #define HOURS (MINUTES * 60) 180 #define DAYS (HOURS * 24) 181 #define WEEKS (DAYS * 7) 182 183 /* 184 * Convert a time string into seconds; format is 185 * a sequence of: 186 * time[qualifier] 187 * 188 * Valid time qualifiers are: 189 * <none> seconds 190 * s|S seconds 191 * m|M minutes 192 * h|H hours 193 * d|D days 194 * w|W weeks 195 * 196 * Examples: 197 * 90m 90 minutes 198 * 1h30m 90 minutes 199 * 2d 2 days 200 * 1w 1 week 201 * 202 * Return -1 if time string is invalid. 203 */ 204 long 205 convtime(const char *s) 206 { 207 long total, secs; 208 const char *p; 209 char *endp; 210 211 errno = 0; 212 total = 0; 213 p = s; 214 215 if (p == NULL || *p == '\0') 216 return -1; 217 218 while (*p) { 219 secs = strtol(p, &endp, 10); 220 if (p == endp || 221 (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || 222 secs < 0) 223 return -1; 224 225 switch (*endp++) { 226 case '\0': 227 endp--; 228 case 's': 229 case 'S': 230 break; 231 case 'm': 232 case 'M': 233 secs *= MINUTES; 234 break; 235 case 'h': 236 case 'H': 237 secs *= HOURS; 238 break; 239 case 'd': 240 case 'D': 241 secs *= DAYS; 242 break; 243 case 'w': 244 case 'W': 245 secs *= WEEKS; 246 break; 247 default: 248 return -1; 249 } 250 total += secs; 251 if (total < 0) 252 return -1; 253 p = endp; 254 } 255 256 return total; 257 } 258 259 char * 260 cleanhostname(char *host) 261 { 262 if (*host == '[' && host[strlen(host) - 1] == ']') { 263 host[strlen(host) - 1] = '\0'; 264 return (host + 1); 265 } else 266 return host; 267 } 268 269 char * 270 colon(char *cp) 271 { 272 int flag = 0; 273 274 if (*cp == ':') /* Leading colon is part of file name. */ 275 return (0); 276 if (*cp == '[') 277 flag = 1; 278 279 for (; *cp; ++cp) { 280 if (*cp == '@' && *(cp+1) == '[') 281 flag = 1; 282 if (*cp == ']' && *(cp+1) == ':' && flag) 283 return (cp+1); 284 if (*cp == ':' && !flag) 285 return (cp); 286 if (*cp == '/') 287 return (0); 288 } 289 return (0); 290 } 291 292 /* function to assist building execv() arguments */ 293 void 294 addargs(arglist *args, char *fmt, ...) 295 { 296 va_list ap; 297 char buf[1024]; 298 299 va_start(ap, fmt); 300 vsnprintf(buf, sizeof(buf), fmt, ap); 301 va_end(ap); 302 303 if (args->list == NULL) { 304 args->nalloc = 32; 305 args->num = 0; 306 } else if (args->num+2 >= args->nalloc) 307 args->nalloc *= 2; 308 309 args->list = xrealloc(args->list, args->nalloc * sizeof(char *)); 310 args->list[args->num++] = xstrdup(buf); 311 args->list[args->num] = NULL; 312 } 313