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