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