blob: d34423f647683e6f3e0eeb9980e7c8e0caf8f5ff [file] [log] [blame]
Ben Lindstrom1ebd7a52002-02-26 18:12:51 +00001/* $OpenBSD: misc.c,v 1.16 2002/02/24 19:59:42 stevesk Exp $ */
Damien Millere4340be2000-09-16 13:29:08 +11002
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
Damien Miller61c51502000-08-18 14:01:04 +100027#include "includes.h"
Ben Lindstrom1ebd7a52002-02-26 18:12:51 +000028RCSID("$OpenBSD: misc.c,v 1.16 2002/02/24 19:59:42 stevesk Exp $");
Damien Miller61c51502000-08-18 14:01:04 +100029
Kevin Stevesb6e773a2001-02-04 13:20:36 +000030#include "misc.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000031#include "log.h"
Ben Lindstrom06909012001-03-05 06:09:31 +000032#include "xmalloc.h"
Damien Miller61c51502000-08-18 14:01:04 +100033
Ben Lindstrom4cc240d2001-07-04 04:46:56 +000034/* remove newline at end of string */
Damien Miller61c51502000-08-18 14:01:04 +100035char *
36chop(char *s)
37{
38 char *t = s;
39 while (*t) {
Ben Lindstrom1c37c6a2001-12-06 18:00:18 +000040 if (*t == '\n' || *t == '\r') {
Damien Miller61c51502000-08-18 14:01:04 +100041 *t = '\0';
42 return s;
43 }
44 t++;
45 }
46 return s;
47
48}
49
Ben Lindstrom4cc240d2001-07-04 04:46:56 +000050/* set/unset filedescriptor to non-blocking */
Damien Miller61c51502000-08-18 14:01:04 +100051void
52set_nonblock(int fd)
53{
54 int val;
Ben Lindstromc93e84c2001-05-12 00:08:37 +000055
Damien Miller61c51502000-08-18 14:01:04 +100056 val = fcntl(fd, F_GETFL, 0);
57 if (val < 0) {
58 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
59 return;
60 }
Damien Miller69b69aa2000-10-28 14:19:58 +110061 if (val & O_NONBLOCK) {
Ben Lindstromc93e84c2001-05-12 00:08:37 +000062 debug2("fd %d is O_NONBLOCK", fd);
Damien Miller61c51502000-08-18 14:01:04 +100063 return;
Damien Miller69b69aa2000-10-28 14:19:58 +110064 }
Damien Miller61c51502000-08-18 14:01:04 +100065 debug("fd %d setting O_NONBLOCK", fd);
66 val |= O_NONBLOCK;
67 if (fcntl(fd, F_SETFL, val) == -1)
Damien Millercaf6dd62000-08-29 11:33:50 +110068 if (errno != ENODEV)
69 error("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
70 fd, strerror(errno));
Damien Miller61c51502000-08-18 14:01:04 +100071}
72
Ben Lindstromc93e84c2001-05-12 00:08:37 +000073void
74unset_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 }
Ben Lindstrom352b1c22001-06-21 03:04:37 +000087 debug("fd %d clearing O_NONBLOCK", fd);
Ben Lindstromc93e84c2001-05-12 00:08:37 +000088 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
Damien Miller398e1cf2002-02-05 11:52:13 +110095/* disable nagle on socket */
96void
97set_nodelay(int fd)
98{
Ben Lindstrom1ebd7a52002-02-26 18:12:51 +000099 int opt, optlen;
Damien Miller398e1cf2002-02-05 11:52:13 +1100100
Ben Lindstrom1ebd7a52002-02-26 18:12:51 +0000101 optlen = sizeof opt;
102 if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
103 error("getsockopt TCP_NODELAY: %.100s", strerror(errno));
104 return;
105 }
106 if (opt == 1) {
107 debug2("fd %d is TCP_NODELAY", fd);
108 return;
109 }
110 opt = 1;
Damien Miller398e1cf2002-02-05 11:52:13 +1100111 debug("fd %d setting TCP_NODELAY", fd);
Ben Lindstrom1ebd7a52002-02-26 18:12:51 +0000112 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
Damien Miller398e1cf2002-02-05 11:52:13 +1100113 error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
114}
115
Damien Miller61c51502000-08-18 14:01:04 +1000116/* Characters considered whitespace in strsep calls. */
117#define WHITESPACE " \t\r\n"
118
Ben Lindstrom4cc240d2001-07-04 04:46:56 +0000119/* return next token in configuration line */
Damien Miller61c51502000-08-18 14:01:04 +1000120char *
121strdelim(char **s)
122{
123 char *old;
124 int wspace = 0;
125
126 if (*s == NULL)
127 return NULL;
128
129 old = *s;
130
131 *s = strpbrk(*s, WHITESPACE "=");
132 if (*s == NULL)
133 return (old);
134
135 /* Allow only one '=' to be skipped */
136 if (*s[0] == '=')
137 wspace = 1;
138 *s[0] = '\0';
139
140 *s += strspn(*s + 1, WHITESPACE) + 1;
141 if (*s[0] == '=' && !wspace)
142 *s += strspn(*s + 1, WHITESPACE) + 1;
143
144 return (old);
145}
Kevin Stevesb6e773a2001-02-04 13:20:36 +0000146
Ben Lindstrom086cf212001-03-05 05:56:40 +0000147struct passwd *
148pwcopy(struct passwd *pw)
149{
150 struct passwd *copy = xmalloc(sizeof(*copy));
Ben Lindstrom40304422001-03-05 06:22:01 +0000151
Ben Lindstrom086cf212001-03-05 05:56:40 +0000152 memset(copy, 0, sizeof(*copy));
153 copy->pw_name = xstrdup(pw->pw_name);
154 copy->pw_passwd = xstrdup(pw->pw_passwd);
Ben Lindstrom40304422001-03-05 06:22:01 +0000155 copy->pw_gecos = xstrdup(pw->pw_gecos);
Ben Lindstrom086cf212001-03-05 05:56:40 +0000156 copy->pw_uid = pw->pw_uid;
157 copy->pw_gid = pw->pw_gid;
Kevin Steves82456952001-06-22 21:14:18 +0000158#ifdef HAVE_PW_EXPIRE_IN_PASSWD
Ben Lindstrom3af4d462001-06-21 03:11:27 +0000159 copy->pw_expire = pw->pw_expire;
Kevin Steves82456952001-06-22 21:14:18 +0000160#endif
161#ifdef HAVE_PW_CHANGE_IN_PASSWD
Ben Lindstrom3af4d462001-06-21 03:11:27 +0000162 copy->pw_change = pw->pw_change;
Kevin Steves82456952001-06-22 21:14:18 +0000163#endif
Ben Lindstrom0f68db42001-03-05 07:57:09 +0000164#ifdef HAVE_PW_CLASS_IN_PASSWD
Ben Lindstrom086cf212001-03-05 05:56:40 +0000165 copy->pw_class = xstrdup(pw->pw_class);
Ben Lindstrom0f68db42001-03-05 07:57:09 +0000166#endif
Ben Lindstrom086cf212001-03-05 05:56:40 +0000167 copy->pw_dir = xstrdup(pw->pw_dir);
168 copy->pw_shell = xstrdup(pw->pw_shell);
169 return copy;
170}
171
Ben Lindstrom4cc240d2001-07-04 04:46:56 +0000172/*
173 * Convert ASCII string to TCP/IP port number.
174 * Port must be >0 and <=65535.
175 * Return 0 if invalid.
176 */
177int
178a2port(const char *s)
Ben Lindstrom19066a12001-04-12 23:39:26 +0000179{
180 long port;
181 char *endp;
182
183 errno = 0;
184 port = strtol(s, &endp, 0);
185 if (s == endp || *endp != '\0' ||
186 (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) ||
187 port <= 0 || port > 65535)
188 return 0;
189
190 return port;
191}
192
Ben Lindstrom1bda4c82001-06-05 19:59:08 +0000193#define SECONDS 1
194#define MINUTES (SECONDS * 60)
195#define HOURS (MINUTES * 60)
196#define DAYS (HOURS * 24)
197#define WEEKS (DAYS * 7)
198
Ben Lindstrom4cc240d2001-07-04 04:46:56 +0000199/*
200 * Convert a time string into seconds; format is
201 * a sequence of:
202 * time[qualifier]
203 *
204 * Valid time qualifiers are:
205 * <none> seconds
206 * s|S seconds
207 * m|M minutes
208 * h|H hours
209 * d|D days
210 * w|W weeks
211 *
212 * Examples:
213 * 90m 90 minutes
214 * 1h30m 90 minutes
215 * 2d 2 days
216 * 1w 1 week
217 *
218 * Return -1 if time string is invalid.
219 */
220long
221convtime(const char *s)
Ben Lindstrom1bda4c82001-06-05 19:59:08 +0000222{
223 long total, secs;
224 const char *p;
225 char *endp;
226
227 errno = 0;
228 total = 0;
229 p = s;
230
231 if (p == NULL || *p == '\0')
232 return -1;
233
234 while (*p) {
235 secs = strtol(p, &endp, 10);
236 if (p == endp ||
237 (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
238 secs < 0)
239 return -1;
240
241 switch (*endp++) {
242 case '\0':
243 endp--;
244 case 's':
245 case 'S':
246 break;
247 case 'm':
248 case 'M':
249 secs *= MINUTES;
250 break;
251 case 'h':
252 case 'H':
253 secs *= HOURS;
254 break;
255 case 'd':
256 case 'D':
257 secs *= DAYS;
258 break;
259 case 'w':
260 case 'W':
261 secs *= WEEKS;
262 break;
263 default:
264 return -1;
265 }
266 total += secs;
267 if (total < 0)
268 return -1;
269 p = endp;
270 }
271
272 return total;
273}
274
Ben Lindstrom4529b702001-05-03 23:39:53 +0000275char *
276cleanhostname(char *host)
277{
278 if (*host == '[' && host[strlen(host) - 1] == ']') {
279 host[strlen(host) - 1] = '\0';
280 return (host + 1);
281 } else
282 return host;
283}
284
285char *
286colon(char *cp)
287{
288 int flag = 0;
289
290 if (*cp == ':') /* Leading colon is part of file name. */
291 return (0);
292 if (*cp == '[')
293 flag = 1;
294
295 for (; *cp; ++cp) {
296 if (*cp == '@' && *(cp+1) == '[')
297 flag = 1;
298 if (*cp == ']' && *(cp+1) == ':' && flag)
299 return (cp+1);
300 if (*cp == ':' && !flag)
301 return (cp);
302 if (*cp == '/')
303 return (0);
304 }
305 return (0);
306}
307
Ben Lindstrom4cc240d2001-07-04 04:46:56 +0000308/* function to assist building execv() arguments */
Ben Lindstrom387c4722001-05-08 20:27:25 +0000309void
310addargs(arglist *args, char *fmt, ...)
311{
312 va_list ap;
313 char buf[1024];
314
315 va_start(ap, fmt);
316 vsnprintf(buf, sizeof(buf), fmt, ap);
317 va_end(ap);
318
319 if (args->list == NULL) {
320 args->nalloc = 32;
321 args->num = 0;
Damien Miller9f0f5c62001-12-21 14:45:46 +1100322 } else if (args->num+2 >= args->nalloc)
Ben Lindstrom387c4722001-05-08 20:27:25 +0000323 args->nalloc *= 2;
324
325 args->list = xrealloc(args->list, args->nalloc * sizeof(char *));
326 args->list[args->num++] = xstrdup(buf);
327 args->list[args->num] = NULL;
328}
329
Kevin Stevesb6e773a2001-02-04 13:20:36 +0000330mysig_t
331mysignal(int sig, mysig_t act)
332{
333#ifdef HAVE_SIGACTION
334 struct sigaction sa, osa;
335
Kevin Stevese74ebd02001-02-17 17:10:16 +0000336 if (sigaction(sig, NULL, &osa) == -1)
Kevin Stevesb6e773a2001-02-04 13:20:36 +0000337 return (mysig_t) -1;
338 if (osa.sa_handler != act) {
Kevin Stevese74ebd02001-02-17 17:10:16 +0000339 memset(&sa, 0, sizeof(sa));
Kevin Stevesb6e773a2001-02-04 13:20:36 +0000340 sigemptyset(&sa.sa_mask);
341 sa.sa_flags = 0;
Damien Miller722ccb12001-02-18 15:18:43 +1100342#if defined(SA_INTERRUPT)
343 if (sig == SIGALRM)
Damien Miller0318e2e2001-02-18 13:04:23 +1100344 sa.sa_flags |= SA_INTERRUPT;
345#endif
Kevin Stevesb6e773a2001-02-04 13:20:36 +0000346 sa.sa_handler = act;
Kevin Stevese74ebd02001-02-17 17:10:16 +0000347 if (sigaction(sig, &sa, NULL) == -1)
Kevin Stevesb6e773a2001-02-04 13:20:36 +0000348 return (mysig_t) -1;
349 }
350 return (osa.sa_handler);
351#else
352 return (signal(sig, act));
353#endif
354}