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 78 msg_init(void) 79 { 80 openlog(SYSLOG_IDENT, LOG_PID|LOG_CONS, LOG_DAEMON); 81 syslog_open = B_TRUE; 82 } 83 84 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 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 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 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 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 164 poll_fini(void) 165 { 166 if (poll_fds != NULL) { 167 free(poll_fds); 168 poll_fds = NULL; 169 } 170 } 171 172 struct pollfd * 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 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 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 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 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 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 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 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 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 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