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
msg_init(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
msg_fini(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
msg(si_msg_type_t type,const char * format,va_list ap)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
warn_msg(const char * format,...)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
debug_msg(const char * format,...)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
error_msg(const char * format,...)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
poll_fini(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 *
find_pollfd(int fd)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
set_pollfd(int fd,uint16_t events)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
clear_pollfd(int fd)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
isset_pollfd(int fd)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
safe_read(int fd,void * buf,size_t sz)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
copies_limit_exceeded(instance_t * inst)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
cancel_inst_timer(instance_t * inst)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
cancel_bind_timer(instance_t * inst)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
enable_blocking(int fd)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
disable_blocking(int fd)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