1 /* $OpenBSD: misc.c,v 1.12 2001/06/26 17:27:24 markus 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.12 2001/06/26 17:27:24 markus 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 /* Characters considered whitespace in strsep calls. */ 96 #define WHITESPACE " \t\r\n" 97 98 /* return next token in configuration line */ 99 char * 100 strdelim(char **s) 101 { 102 char *old; 103 int wspace = 0; 104 105 if (*s == NULL) 106 return NULL; 107 108 old = *s; 109 110 *s = strpbrk(*s, WHITESPACE "="); 111 if (*s == NULL) 112 return (old); 113 114 /* Allow only one '=' to be skipped */ 115 if (*s[0] == '=') 116 wspace = 1; 117 *s[0] = '\0'; 118 119 *s += strspn(*s + 1, WHITESPACE) + 1; 120 if (*s[0] == '=' && !wspace) 121 *s += strspn(*s + 1, WHITESPACE) + 1; 122 123 return (old); 124 } 125 126 struct passwd * 127 pwcopy(struct passwd *pw) 128 { 129 struct passwd *copy = xmalloc(sizeof(*copy)); 130 131 memset(copy, 0, sizeof(*copy)); 132 copy->pw_name = xstrdup(pw->pw_name); 133 copy->pw_passwd = xstrdup(pw->pw_passwd); 134 copy->pw_gecos = xstrdup(pw->pw_gecos); 135 copy->pw_uid = pw->pw_uid; 136 copy->pw_gid = pw->pw_gid; 137 copy->pw_expire = pw->pw_expire; 138 copy->pw_change = pw->pw_change; 139 copy->pw_class = xstrdup(pw->pw_class); 140 copy->pw_dir = xstrdup(pw->pw_dir); 141 copy->pw_shell = xstrdup(pw->pw_shell); 142 return copy; 143 } 144 145 /* 146 * Convert ASCII string to TCP/IP port number. 147 * Port must be >0 and <=65535. 148 * Return 0 if invalid. 149 */ 150 int 151 a2port(const char *s) 152 { 153 long port; 154 char *endp; 155 156 errno = 0; 157 port = strtol(s, &endp, 0); 158 if (s == endp || *endp != '\0' || 159 (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) || 160 port <= 0 || port > 65535) 161 return 0; 162 163 return port; 164 } 165 166 #define SECONDS 1 167 #define MINUTES (SECONDS * 60) 168 #define HOURS (MINUTES * 60) 169 #define DAYS (HOURS * 24) 170 #define WEEKS (DAYS * 7) 171 172 /* 173 * Convert a time string into seconds; format is 174 * a sequence of: 175 * time[qualifier] 176 * 177 * Valid time qualifiers are: 178 * <none> seconds 179 * s|S seconds 180 * m|M minutes 181 * h|H hours 182 * d|D days 183 * w|W weeks 184 * 185 * Examples: 186 * 90m 90 minutes 187 * 1h30m 90 minutes 188 * 2d 2 days 189 * 1w 1 week 190 * 191 * Return -1 if time string is invalid. 192 */ 193 long 194 convtime(const char *s) 195 { 196 long total, secs; 197 const char *p; 198 char *endp; 199 200 errno = 0; 201 total = 0; 202 p = s; 203 204 if (p == NULL || *p == '\0') 205 return -1; 206 207 while (*p) { 208 secs = strtol(p, &endp, 10); 209 if (p == endp || 210 (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || 211 secs < 0) 212 return -1; 213 214 switch (*endp++) { 215 case '\0': 216 endp--; 217 case 's': 218 case 'S': 219 break; 220 case 'm': 221 case 'M': 222 secs *= MINUTES; 223 break; 224 case 'h': 225 case 'H': 226 secs *= HOURS; 227 break; 228 case 'd': 229 case 'D': 230 secs *= DAYS; 231 break; 232 case 'w': 233 case 'W': 234 secs *= WEEKS; 235 break; 236 default: 237 return -1; 238 } 239 total += secs; 240 if (total < 0) 241 return -1; 242 p = endp; 243 } 244 245 return total; 246 } 247 248 char * 249 cleanhostname(char *host) 250 { 251 if (*host == '[' && host[strlen(host) - 1] == ']') { 252 host[strlen(host) - 1] = '\0'; 253 return (host + 1); 254 } else 255 return host; 256 } 257 258 char * 259 colon(char *cp) 260 { 261 int flag = 0; 262 263 if (*cp == ':') /* Leading colon is part of file name. */ 264 return (0); 265 if (*cp == '[') 266 flag = 1; 267 268 for (; *cp; ++cp) { 269 if (*cp == '@' && *(cp+1) == '[') 270 flag = 1; 271 if (*cp == ']' && *(cp+1) == ':' && flag) 272 return (cp+1); 273 if (*cp == ':' && !flag) 274 return (cp); 275 if (*cp == '/') 276 return (0); 277 } 278 return (0); 279 } 280 281 /* function to assist building execv() arguments */ 282 void 283 addargs(arglist *args, char *fmt, ...) 284 { 285 va_list ap; 286 char buf[1024]; 287 288 va_start(ap, fmt); 289 vsnprintf(buf, sizeof(buf), fmt, ap); 290 va_end(ap); 291 292 if (args->list == NULL) { 293 args->nalloc = 32; 294 args->num = 0; 295 } else if (args->num+2 >= args->nalloc) 296 args->nalloc *= 2; 297 298 args->list = xrealloc(args->list, args->nalloc * sizeof(char *)); 299 args->list[args->num++] = xstrdup(buf); 300 args->list[args->num] = NULL; 301 } 302