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