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