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