misc.c revision 126274
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"
26RCSID("$OpenBSD: misc.c,v 1.23 2003/10/28 09:08:06 markus Exp $");
27
28#include "misc.h"
29#include "log.h"
30#include "xmalloc.h"
31
32/* remove newline at end of string */
33char *
34chop(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 */
49void
50set_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
70void
71unset_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 */
92void
93set_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		debug("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 */
117char *
118strdelim(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
144struct passwd *
145pwcopy(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#ifdef HAVE_PW_EXPIRE_IN_PASSWD
156	copy->pw_expire = pw->pw_expire;
157#endif
158#ifdef HAVE_PW_CHANGE_IN_PASSWD
159	copy->pw_change = pw->pw_change;
160#endif
161#ifdef HAVE_PW_CLASS_IN_PASSWD
162	copy->pw_class = xstrdup(pw->pw_class);
163#endif
164	copy->pw_dir = xstrdup(pw->pw_dir);
165	copy->pw_shell = xstrdup(pw->pw_shell);
166	return copy;
167}
168
169/*
170 * Convert ASCII string to TCP/IP port number.
171 * Port must be >0 and <=65535.
172 * Return 0 if invalid.
173 */
174int
175a2port(const char *s)
176{
177	long port;
178	char *endp;
179
180	errno = 0;
181	port = strtol(s, &endp, 0);
182	if (s == endp || *endp != '\0' ||
183	    (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) ||
184	    port <= 0 || port > 65535)
185		return 0;
186
187	return port;
188}
189
190#define SECONDS		1
191#define MINUTES		(SECONDS * 60)
192#define HOURS		(MINUTES * 60)
193#define DAYS		(HOURS * 24)
194#define WEEKS		(DAYS * 7)
195
196/*
197 * Convert a time string into seconds; format is
198 * a sequence of:
199 *      time[qualifier]
200 *
201 * Valid time qualifiers are:
202 *      <none>  seconds
203 *      s|S     seconds
204 *      m|M     minutes
205 *      h|H     hours
206 *      d|D     days
207 *      w|W     weeks
208 *
209 * Examples:
210 *      90m     90 minutes
211 *      1h30m   90 minutes
212 *      2d      2 days
213 *      1w      1 week
214 *
215 * Return -1 if time string is invalid.
216 */
217long
218convtime(const char *s)
219{
220	long total, secs;
221	const char *p;
222	char *endp;
223
224	errno = 0;
225	total = 0;
226	p = s;
227
228	if (p == NULL || *p == '\0')
229		return -1;
230
231	while (*p) {
232		secs = strtol(p, &endp, 10);
233		if (p == endp ||
234		    (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
235		    secs < 0)
236			return -1;
237
238		switch (*endp++) {
239		case '\0':
240			endp--;
241		case 's':
242		case 'S':
243			break;
244		case 'm':
245		case 'M':
246			secs *= MINUTES;
247			break;
248		case 'h':
249		case 'H':
250			secs *= HOURS;
251			break;
252		case 'd':
253		case 'D':
254			secs *= DAYS;
255			break;
256		case 'w':
257		case 'W':
258			secs *= WEEKS;
259			break;
260		default:
261			return -1;
262		}
263		total += secs;
264		if (total < 0)
265			return -1;
266		p = endp;
267	}
268
269	return total;
270}
271
272char *
273cleanhostname(char *host)
274{
275	if (*host == '[' && host[strlen(host) - 1] == ']') {
276		host[strlen(host) - 1] = '\0';
277		return (host + 1);
278	} else
279		return host;
280}
281
282char *
283colon(char *cp)
284{
285	int flag = 0;
286
287	if (*cp == ':')		/* Leading colon is part of file name. */
288		return (0);
289	if (*cp == '[')
290		flag = 1;
291
292	for (; *cp; ++cp) {
293		if (*cp == '@' && *(cp+1) == '[')
294			flag = 1;
295		if (*cp == ']' && *(cp+1) == ':' && flag)
296			return (cp+1);
297		if (*cp == ':' && !flag)
298			return (cp);
299		if (*cp == '/')
300			return (0);
301	}
302	return (0);
303}
304
305/* function to assist building execv() arguments */
306void
307addargs(arglist *args, char *fmt, ...)
308{
309	va_list ap;
310	char buf[1024];
311	int nalloc;
312
313	va_start(ap, fmt);
314	vsnprintf(buf, sizeof(buf), fmt, ap);
315	va_end(ap);
316
317	nalloc = args->nalloc;
318	if (args->list == NULL) {
319		nalloc = 32;
320		args->num = 0;
321	} else if (args->num+2 >= nalloc)
322		nalloc *= 2;
323
324	args->list = xrealloc(args->list, nalloc * sizeof(char *));
325	args->nalloc = nalloc;
326	args->list[args->num++] = xstrdup(buf);
327	args->list[args->num] = NULL;
328}
329