xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.lib/inetd/util.c (revision 533affcbc7fc4d0c8132976ea454aaa715fe2307)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * General utility routines.
28  */
29 
30 #include <syslog.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <stdarg.h>
34 #include <strings.h>
35 #include <time.h>
36 #include <errno.h>
37 #include <libintl.h>
38 #include <unistd.h>
39 #include "inetd_impl.h"
40 
41 
42 /* size of buffer used in msg() to expand printf() like messages into */
43 #define	MSG_BUF_SIZE		1024
44 
45 /* number of pollfd we grow the pollfd array by at a time in set_pollfd() */
46 #define	POLLFDS_GROWTH_SIZE	16
47 
48 /* enumeration of message types supported by msg() */
49 typedef enum {
50 	MT_ERROR,
51 	MT_DEBUG,
52 	MT_WARN
53 } si_msg_type_t;
54 
55 /*
56  * Collection of information for each method type.
57  * NOTE:  This table is indexed into using the instance_method_t
58  * enumeration, so the ordering needs to be kept in synch.
59  */
60 method_type_info_t methods[] = {
61 	{IM_START, START_METHOD_NAME, IIS_NONE},
62 	{IM_ONLINE, ONLINE_METHOD_NAME, IIS_ONLINE},
63 	{IM_OFFLINE, OFFLINE_METHOD_NAME, IIS_OFFLINE},
64 	{IM_DISABLE, DISABLE_METHOD_NAME, IIS_DISABLED},
65 	{IM_REFRESH, REFRESH_METHOD_NAME, IIS_ONLINE},
66 	{IM_NONE, "none", IIS_NONE}
67 };
68 
69 struct pollfd	*poll_fds = NULL;
70 nfds_t		num_pollfds;
71 
72 boolean_t	syslog_open = B_FALSE;
73 boolean_t	debug_enabled = B_FALSE;
74 
75 void
76 msg_init(void)
77 {
78 	openlog(SYSLOG_IDENT, LOG_PID|LOG_CONS, LOG_DAEMON);
79 	syslog_open = B_TRUE;
80 }
81 
82 void
83 msg_fini(void)
84 {
85 	syslog_open = B_FALSE;
86 	closelog();
87 }
88 
89 /*
90  * Outputs a msg. If 'type' is set tp MT_ERROR or MT_WARN the message goes
91  * to syslog with severitys LOG_ERROR and LOG_WARN respectively. For all
92  * values of 'type' the message is written to the debug log file, if it
93  * was openable when inetd started.
94  */
95 static void
96 msg(si_msg_type_t type, const char *format, va_list ap)
97 {
98 	/*
99 	 * Use a stack buffer so we stand more chance of reporting a
100 	 * memory shortage failure.
101 	 */
102 	char		buf[MSG_BUF_SIZE];
103 
104 	if (!syslog_open)
105 		return;
106 
107 	(void) vsnprintf(buf, sizeof (buf), format, ap);
108 
109 	/*
110 	 * Log error and warning messages to syslog with appropriate severity.
111 	 */
112 	if (type == MT_ERROR) {
113 		syslog(LOG_ERR, "%s", buf);
114 	} else if (type == MT_WARN) {
115 		syslog(LOG_WARNING, "%s", buf);
116 	} else if (debug_enabled && type == MT_DEBUG) {
117 		syslog(LOG_DEBUG, "%s", buf);
118 	}
119 }
120 
121 /*
122  * Output a warning message. Unlike error_msg(), syslog doesn't get told
123  * to log to the console if syslogd isn't around.
124  */
125 void
126 warn_msg(const char *format, ...)
127 {
128 	va_list ap;
129 
130 	closelog();
131 	openlog(SYSLOG_IDENT, LOG_PID, LOG_DAEMON);
132 
133 	va_start(ap, format);
134 	msg(MT_WARN, format, ap);
135 	va_end(ap);
136 
137 	closelog();
138 	openlog(SYSLOG_IDENT, LOG_PID|LOG_CONS, LOG_DAEMON);
139 }
140 
141 void
142 debug_msg(const char *format, ...)
143 {
144 	va_list ap;
145 
146 	va_start(ap, format);
147 	msg(MT_DEBUG, format, ap);
148 	va_end(ap);
149 }
150 
151 void
152 error_msg(const char *format, ...)
153 {
154 	va_list ap;
155 
156 	va_start(ap, format);
157 	msg(MT_ERROR, format, ap);
158 	va_end(ap);
159 }
160 
161 void
162 poll_fini(void)
163 {
164 	if (poll_fds != NULL) {
165 		free(poll_fds);
166 		poll_fds = NULL;
167 	}
168 }
169 
170 struct pollfd *
171 find_pollfd(int fd)
172 {
173 	nfds_t n;
174 
175 	for (n = 0; n < num_pollfds; n++) {
176 		if (poll_fds[n].fd == fd)
177 			return (&(poll_fds[n]));
178 	}
179 	return (NULL);
180 }
181 
182 int
183 set_pollfd(int fd, uint16_t events)
184 {
185 	struct pollfd	*p;
186 	int		i;
187 
188 	p = find_pollfd(fd);
189 	if ((p == NULL) && ((p = find_pollfd(-1)) == NULL)) {
190 		if ((p = realloc(poll_fds,
191 		    ((num_pollfds + POLLFDS_GROWTH_SIZE) *
192 		    sizeof (struct pollfd)))) == NULL) {
193 			return (-1);
194 		}
195 		poll_fds = p;
196 
197 		for (i = 1; i < POLLFDS_GROWTH_SIZE; i++)
198 			poll_fds[num_pollfds + i].fd = -1;
199 
200 		p = &poll_fds[num_pollfds];
201 		num_pollfds += POLLFDS_GROWTH_SIZE;
202 	}
203 
204 	p->fd = fd;
205 	p->events = events;
206 	p->revents = 0;
207 
208 	return (0);
209 }
210 
211 void
212 clear_pollfd(int fd)
213 {
214 	struct pollfd *p;
215 
216 	if ((p = find_pollfd(fd)) != NULL) {
217 		p->fd = -1;
218 		p->events = 0;
219 		p->revents = 0;
220 	}
221 }
222 
223 boolean_t
224 isset_pollfd(int fd)
225 {
226 	struct pollfd *p = find_pollfd(fd);
227 
228 	return ((p != NULL) && (p->revents & POLLIN));
229 }
230 
231 /*
232  * An extension of read() that keeps retrying until either the full request has
233  * completed, the other end of the connection/pipe is closed, no data is
234  * readable for a non-blocking socket/pipe, or an unexpected error occurs.
235  * Returns 0 if the data is successfully read, 1 if the other end of the pipe/
236  * socket is closed or there's nothing to read from a non-blocking socket/pipe,
237  * else -1 if an unexpected error occurs.
238  */
239 int
240 safe_read(int fd, void *buf, size_t sz)
241 {
242 	int	ret;
243 	size_t  cnt = 0;
244 	char    *cp = (char *)buf;
245 
246 	if (sz == 0)
247 		return (0);
248 
249 	do {
250 		switch (ret = read(fd, cp + cnt, sz - cnt)) {
251 		case 0:			/* other end of pipe/socket closed */
252 			return (1);
253 		case -1:
254 			if (errno == EAGAIN) {		/* nothing to read */
255 				return (1);
256 			} else if (errno != EINTR) {
257 				error_msg(gettext("Unexpected read error: %s"),
258 				    strerror(errno));
259 				return (-1);
260 			}
261 			break;
262 
263 		default:
264 			cnt += ret;
265 		}
266 	} while (cnt != sz);
267 
268 	return (0);
269 }
270 
271 /*
272  * Return B_TRUE if instance 'inst' has exceeded its configured maximum
273  * concurrent copies limit, else B_FALSE.
274  */
275 boolean_t
276 copies_limit_exceeded(instance_t *inst)
277 {
278 	/* any value <=0 means that copies limits are disabled */
279 	return ((inst->config->basic->max_copies > 0) &&
280 	    (inst->copies >= inst->config->basic->max_copies));
281 }
282 
283 /*
284  * Cancel the method/con-rate offline timer associated with the instance.
285  */
286 void
287 cancel_inst_timer(instance_t *inst)
288 {
289 	(void) iu_cancel_timer(timer_queue, inst->timer_id, NULL);
290 	inst->timer_id = -1;
291 }
292 
293 /*
294  * Cancel the bind retry timer associated with the instance.
295  */
296 void
297 cancel_bind_timer(instance_t *inst)
298 {
299 	(void) iu_cancel_timer(timer_queue, inst->bind_timer_id, NULL);
300 	inst->bind_timer_id = -1;
301 }
302 
303 void
304 enable_blocking(int fd)
305 {
306 	int flags = fcntl(fd, F_GETFL, 0);
307 	(void) fcntl(fd, F_SETFL, (flags & ~O_NONBLOCK));
308 }
309 
310 void
311 disable_blocking(int fd)
312 {
313 	int flags = fcntl(fd, F_GETFL, 0);
314 	(void) fcntl(fd, F_SETFL, (flags | O_NONBLOCK));
315 }
316