misc.c revision 124208
176259Sgreen/*
276259Sgreen * Copyright (c) 2000 Markus Friedl.  All rights reserved.
376259Sgreen *
476259Sgreen * Redistribution and use in source and binary forms, with or without
576259Sgreen * modification, are permitted provided that the following conditions
676259Sgreen * are met:
776259Sgreen * 1. Redistributions of source code must retain the above copyright
876259Sgreen *    notice, this list of conditions and the following disclaimer.
976259Sgreen * 2. Redistributions in binary form must reproduce the above copyright
1076259Sgreen *    notice, this list of conditions and the following disclaimer in the
1176259Sgreen *    documentation and/or other materials provided with the distribution.
1276259Sgreen *
1376259Sgreen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1476259Sgreen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1576259Sgreen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1676259Sgreen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1776259Sgreen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1876259Sgreen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1976259Sgreen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2076259Sgreen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2176259Sgreen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2276259Sgreen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2376259Sgreen */
2476259Sgreen
2576259Sgreen#include "includes.h"
26124208SdesRCSID("$OpenBSD: misc.c,v 1.22 2003/09/18 08:49:45 markus Exp $");
2776259Sgreen
2876259Sgreen#include "misc.h"
2976259Sgreen#include "log.h"
3076259Sgreen#include "xmalloc.h"
3176259Sgreen
3292555Sdes/* remove newline at end of string */
3376259Sgreenchar *
3476259Sgreenchop(char *s)
3576259Sgreen{
3676259Sgreen	char *t = s;
3776259Sgreen	while (*t) {
3892555Sdes		if (*t == '\n' || *t == '\r') {
3976259Sgreen			*t = '\0';
4076259Sgreen			return s;
4176259Sgreen		}
4276259Sgreen		t++;
4376259Sgreen	}
4476259Sgreen	return s;
4576259Sgreen
4676259Sgreen}
4776259Sgreen
4892555Sdes/* set/unset filedescriptor to non-blocking */
4976259Sgreenvoid
5076259Sgreenset_nonblock(int fd)
5176259Sgreen{
5276259Sgreen	int val;
5392555Sdes
5476259Sgreen	val = fcntl(fd, F_GETFL, 0);
5576259Sgreen	if (val < 0) {
5676259Sgreen		error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
5776259Sgreen		return;
5876259Sgreen	}
5976259Sgreen	if (val & O_NONBLOCK) {
6092555Sdes		debug2("fd %d is O_NONBLOCK", fd);
6176259Sgreen		return;
6276259Sgreen	}
63124208Sdes	debug2("fd %d setting O_NONBLOCK", fd);
6476259Sgreen	val |= O_NONBLOCK;
6576259Sgreen	if (fcntl(fd, F_SETFL, val) == -1)
6692555Sdes		debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
6792555Sdes		    fd, strerror(errno));
6876259Sgreen}
6976259Sgreen
7092555Sdesvoid
7192555Sdesunset_nonblock(int fd)
7292555Sdes{
7392555Sdes	int val;
7492555Sdes
7592555Sdes	val = fcntl(fd, F_GETFL, 0);
7692555Sdes	if (val < 0) {
7792555Sdes		error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
7892555Sdes		return;
7992555Sdes	}
8092555Sdes	if (!(val & O_NONBLOCK)) {
8192555Sdes		debug2("fd %d is not O_NONBLOCK", fd);
8292555Sdes		return;
8392555Sdes	}
8492555Sdes	debug("fd %d clearing O_NONBLOCK", fd);
8592555Sdes	val &= ~O_NONBLOCK;
8692555Sdes	if (fcntl(fd, F_SETFL, val) == -1)
8792555Sdes		debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
8892555Sdes		    fd, strerror(errno));
8992555Sdes}
9092555Sdes
9192555Sdes/* disable nagle on socket */
9292555Sdesvoid
9392555Sdesset_nodelay(int fd)
9492555Sdes{
9592555Sdes	int opt;
9692555Sdes	socklen_t optlen;
9792555Sdes
9892555Sdes	optlen = sizeof opt;
9992555Sdes	if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
10092555Sdes		error("getsockopt TCP_NODELAY: %.100s", strerror(errno));
10192555Sdes		return;
10292555Sdes	}
10392555Sdes	if (opt == 1) {
10492555Sdes		debug2("fd %d is TCP_NODELAY", fd);
10592555Sdes		return;
10692555Sdes	}
10792555Sdes	opt = 1;
108113908Sdes	debug2("fd %d setting TCP_NODELAY", fd);
10992555Sdes	if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
11092555Sdes		error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
11192555Sdes}
11292555Sdes
11376259Sgreen/* Characters considered whitespace in strsep calls. */
11476259Sgreen#define WHITESPACE " \t\r\n"
11576259Sgreen
11692555Sdes/* return next token in configuration line */
11776259Sgreenchar *
11876259Sgreenstrdelim(char **s)
11976259Sgreen{
12076259Sgreen	char *old;
12176259Sgreen	int wspace = 0;
12276259Sgreen
12376259Sgreen	if (*s == NULL)
12476259Sgreen		return NULL;
12576259Sgreen
12676259Sgreen	old = *s;
12776259Sgreen
12876259Sgreen	*s = strpbrk(*s, WHITESPACE "=");
12976259Sgreen	if (*s == NULL)
13076259Sgreen		return (old);
13176259Sgreen
13276259Sgreen	/* Allow only one '=' to be skipped */
13376259Sgreen	if (*s[0] == '=')
13476259Sgreen		wspace = 1;
13576259Sgreen	*s[0] = '\0';
13676259Sgreen
13776259Sgreen	*s += strspn(*s + 1, WHITESPACE) + 1;
13876259Sgreen	if (*s[0] == '=' && !wspace)
13976259Sgreen		*s += strspn(*s + 1, WHITESPACE) + 1;
14076259Sgreen
14176259Sgreen	return (old);
14276259Sgreen}
14376259Sgreen
14476259Sgreenstruct passwd *
14576259Sgreenpwcopy(struct passwd *pw)
14676259Sgreen{
14776259Sgreen	struct passwd *copy = xmalloc(sizeof(*copy));
14876259Sgreen
14976259Sgreen	memset(copy, 0, sizeof(*copy));
15076259Sgreen	copy->pw_name = xstrdup(pw->pw_name);
15176259Sgreen	copy->pw_passwd = xstrdup(pw->pw_passwd);
15276259Sgreen	copy->pw_gecos = xstrdup(pw->pw_gecos);
15376259Sgreen	copy->pw_uid = pw->pw_uid;
15476259Sgreen	copy->pw_gid = pw->pw_gid;
15598937Sdes#ifdef HAVE_PW_EXPIRE_IN_PASSWD
15692555Sdes	copy->pw_expire = pw->pw_expire;
15798937Sdes#endif
15898937Sdes#ifdef HAVE_PW_CHANGE_IN_PASSWD
15992555Sdes	copy->pw_change = pw->pw_change;
16098937Sdes#endif
16198937Sdes#ifdef HAVE_PW_CLASS_IN_PASSWD
16276259Sgreen	copy->pw_class = xstrdup(pw->pw_class);
16398937Sdes#endif
16476259Sgreen	copy->pw_dir = xstrdup(pw->pw_dir);
16576259Sgreen	copy->pw_shell = xstrdup(pw->pw_shell);
16676259Sgreen	return copy;
16776259Sgreen}
16876259Sgreen
16992555Sdes/*
17092555Sdes * Convert ASCII string to TCP/IP port number.
17192555Sdes * Port must be >0 and <=65535.
17292555Sdes * Return 0 if invalid.
17392555Sdes */
17492555Sdesint
17592555Sdesa2port(const char *s)
17676259Sgreen{
17776259Sgreen	long port;
17876259Sgreen	char *endp;
17976259Sgreen
18076259Sgreen	errno = 0;
18176259Sgreen	port = strtol(s, &endp, 0);
18276259Sgreen	if (s == endp || *endp != '\0' ||
18376259Sgreen	    (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) ||
18476259Sgreen	    port <= 0 || port > 65535)
18576259Sgreen		return 0;
18676259Sgreen
18776259Sgreen	return port;
18876259Sgreen}
18992555Sdes
19092555Sdes#define SECONDS		1
19192555Sdes#define MINUTES		(SECONDS * 60)
19292555Sdes#define HOURS		(MINUTES * 60)
19392555Sdes#define DAYS		(HOURS * 24)
19492555Sdes#define WEEKS		(DAYS * 7)
19592555Sdes
19692555Sdes/*
19792555Sdes * Convert a time string into seconds; format is
19892555Sdes * a sequence of:
19992555Sdes *      time[qualifier]
20092555Sdes *
20192555Sdes * Valid time qualifiers are:
20292555Sdes *      <none>  seconds
20392555Sdes *      s|S     seconds
20492555Sdes *      m|M     minutes
20592555Sdes *      h|H     hours
20692555Sdes *      d|D     days
20792555Sdes *      w|W     weeks
20892555Sdes *
20992555Sdes * Examples:
21092555Sdes *      90m     90 minutes
21192555Sdes *      1h30m   90 minutes
21292555Sdes *      2d      2 days
21392555Sdes *      1w      1 week
21492555Sdes *
21592555Sdes * Return -1 if time string is invalid.
21692555Sdes */
21792555Sdeslong
21892555Sdesconvtime(const char *s)
21992555Sdes{
22092555Sdes	long total, secs;
22192555Sdes	const char *p;
22292555Sdes	char *endp;
22392555Sdes
22492555Sdes	errno = 0;
22592555Sdes	total = 0;
22692555Sdes	p = s;
22792555Sdes
22892555Sdes	if (p == NULL || *p == '\0')
22992555Sdes		return -1;
23092555Sdes
23192555Sdes	while (*p) {
23292555Sdes		secs = strtol(p, &endp, 10);
23392555Sdes		if (p == endp ||
23492555Sdes		    (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
23592555Sdes		    secs < 0)
23692555Sdes			return -1;
23792555Sdes
23892555Sdes		switch (*endp++) {
23992555Sdes		case '\0':
24092555Sdes			endp--;
24192555Sdes		case 's':
24292555Sdes		case 'S':
24392555Sdes			break;
24492555Sdes		case 'm':
24592555Sdes		case 'M':
24692555Sdes			secs *= MINUTES;
24792555Sdes			break;
24892555Sdes		case 'h':
24992555Sdes		case 'H':
25092555Sdes			secs *= HOURS;
25192555Sdes			break;
25292555Sdes		case 'd':
25392555Sdes		case 'D':
25492555Sdes			secs *= DAYS;
25592555Sdes			break;
25692555Sdes		case 'w':
25792555Sdes		case 'W':
25892555Sdes			secs *= WEEKS;
25992555Sdes			break;
26092555Sdes		default:
26192555Sdes			return -1;
26292555Sdes		}
26392555Sdes		total += secs;
26492555Sdes		if (total < 0)
26592555Sdes			return -1;
26692555Sdes		p = endp;
26792555Sdes	}
26892555Sdes
26992555Sdes	return total;
27092555Sdes}
27192555Sdes
27292555Sdeschar *
27392555Sdescleanhostname(char *host)
27492555Sdes{
27592555Sdes	if (*host == '[' && host[strlen(host) - 1] == ']') {
27692555Sdes		host[strlen(host) - 1] = '\0';
27792555Sdes		return (host + 1);
27892555Sdes	} else
27992555Sdes		return host;
28092555Sdes}
28192555Sdes
28292555Sdeschar *
28392555Sdescolon(char *cp)
28492555Sdes{
28592555Sdes	int flag = 0;
28692555Sdes
28792555Sdes	if (*cp == ':')		/* Leading colon is part of file name. */
28892555Sdes		return (0);
28992555Sdes	if (*cp == '[')
29092555Sdes		flag = 1;
29192555Sdes
29292555Sdes	for (; *cp; ++cp) {
29392555Sdes		if (*cp == '@' && *(cp+1) == '[')
29492555Sdes			flag = 1;
29592555Sdes		if (*cp == ']' && *(cp+1) == ':' && flag)
29692555Sdes			return (cp+1);
29792555Sdes		if (*cp == ':' && !flag)
29892555Sdes			return (cp);
29992555Sdes		if (*cp == '/')
30092555Sdes			return (0);
30192555Sdes	}
30292555Sdes	return (0);
30392555Sdes}
30492555Sdes
30592555Sdes/* function to assist building execv() arguments */
30692555Sdesvoid
30792555Sdesaddargs(arglist *args, char *fmt, ...)
30892555Sdes{
30992555Sdes	va_list ap;
31092555Sdes	char buf[1024];
311120161Snectar	int nalloc;
31292555Sdes
31392555Sdes	va_start(ap, fmt);
31492555Sdes	vsnprintf(buf, sizeof(buf), fmt, ap);
31592555Sdes	va_end(ap);
31692555Sdes
317120161Snectar	nalloc = args->nalloc;
31892555Sdes	if (args->list == NULL) {
319120161Snectar		nalloc = 32;
32092555Sdes		args->num = 0;
321120161Snectar	} else if (args->num+2 >= nalloc)
322120161Snectar		nalloc *= 2;
32392555Sdes
324120161Snectar	args->list = xrealloc(args->list, nalloc * sizeof(char *));
325120161Snectar	args->nalloc = nalloc;
32692555Sdes	args->list[args->num++] = xstrdup(buf);
32792555Sdes	args->list[args->num] = NULL;
32892555Sdes}
329