diff options
Diffstat (limited to 'usr/src/cmd/cmd-inet/usr.lib/inetd/util.c')
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.lib/inetd/util.c | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.lib/inetd/util.c b/usr/src/cmd/cmd-inet/usr.lib/inetd/util.c new file mode 100644 index 0000000000..4772a71162 --- /dev/null +++ b/usr/src/cmd/cmd-inet/usr.lib/inetd/util.c @@ -0,0 +1,365 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * General utility routines. + */ + +#include <syslog.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <strings.h> +#include <time.h> +#include <errno.h> +#include <libintl.h> +#include <unistd.h> +#include "inetd_impl.h" + + +/* location of inetd's debug log file */ +#define DEBUG_LOG_FILE "/var/tmp/inetd.log" + +/* size of buffer used in msg() to expand printf() like messages into */ +#define MSG_BUF_SIZE 1024 + +/* size of buffer used in msg() to store a date/time string */ +#define TIME_BUF_SIZE 50 + +/* number of pollfd we grow the pollfd array by at a time in set_pollfd() */ +#define POLLFDS_GROWTH_SIZE 16 + +/* enumeration of message types supported by msg() */ +typedef enum { + MT_ERROR, + MT_DEBUG, + MT_WARN +} si_msg_type_t; + +/* + * Collection of information for each method type. + * NOTE: This table is indexed into using the instance_method_t + * enumeration, so the ordering needs to be kept in synch. + */ +method_type_info_t methods[] = { + {IM_START, START_METHOD_NAME, IIS_NONE}, + {IM_ONLINE, ONLINE_METHOD_NAME, IIS_ONLINE}, + {IM_OFFLINE, OFFLINE_METHOD_NAME, IIS_OFFLINE}, + {IM_DISABLE, DISABLE_METHOD_NAME, IIS_DISABLED}, + {IM_REFRESH, REFRESH_METHOD_NAME, IIS_ONLINE}, + {IM_NONE, "none", IIS_NONE} +}; + +struct pollfd *poll_fds = NULL; +nfds_t num_pollfds; +static FILE *debug_fp = NULL; + +boolean_t logging_enabled; + +void +msg_init(void) +{ + openlog(SYSLOG_IDENT, LOG_PID|LOG_CONS, LOG_DAEMON); + + /* Try once at startup to open the log file. */ + debug_fp = fopen(DEBUG_LOG_FILE, "r+"); + if (debug_fp != NULL) + (void) fseeko(debug_fp, 0, SEEK_END); + logging_enabled = B_TRUE; +} + +void +msg_fini(void) +{ + logging_enabled = B_FALSE; + if (debug_fp != NULL) { + (void) fclose(debug_fp); + debug_fp = NULL; + } + closelog(); +} + +/* + * Outputs a msg. If 'type' is set tp MT_ERROR or MT_WARN the message goes + * to syslog with severitys LOG_ERROR and LOG_WARN respectively. For all + * values of 'type' the message is written to the debug log file, if it + * was openable when inetd started. + */ +static void +msg(si_msg_type_t type, const char *format, va_list ap) +{ + /* + * Use a stack buffer so we stand more chance of reporting a + * memory shortage failure. + */ + char buf[MSG_BUF_SIZE]; + char timebuf[TIME_BUF_SIZE]; + + if (!logging_enabled) + return; + + (void) vsnprintf(buf, sizeof (buf), format, ap); + + /* + * Log error and warning messages to syslog with appropriate severity. + */ + if (type == MT_ERROR) { + syslog(LOG_ERR, "%s", buf); + } else if (type == MT_WARN) { + syslog(LOG_WARNING, "%s", buf); + } + + if (debug_fp != NULL) { + struct tm tms; + time_t tm; + + /* + * We managed to open the log file at startup. Log all + * message types there - in addition to syslog. + */ + tm = time(NULL); + (void) strftime(timebuf, sizeof (timebuf), NULL, + localtime_r(&tm, &tms)); + (void) fputs(timebuf, debug_fp); + (void) fputs(": ", debug_fp); + + if (type == MT_ERROR) { + (void) fputs("ERROR: ", debug_fp); + } else if (type == MT_DEBUG) { + (void) fputs("DEBUG: ", debug_fp); + } else if (type == MT_WARN) { + (void) fputs("WARN: ", debug_fp); + } + + (void) fputs(buf, debug_fp); + + if (buf[strlen(buf) - 1] != '\n') + (void) fputc('\n', debug_fp); + + (void) fflush(debug_fp); + } +} + +/* + * Output a warning message. Unlike error_msg(), syslog doesn't get told + * to log to the console if syslogd isn't around. + */ +void +warn_msg(const char *format, ...) +{ + va_list ap; + + closelog(); + openlog(SYSLOG_IDENT, LOG_PID, LOG_DAEMON); + + va_start(ap, format); + msg(MT_WARN, format, ap); + va_end(ap); + + closelog(); + openlog(SYSLOG_IDENT, LOG_PID|LOG_CONS, LOG_DAEMON); +} + +void +debug_msg(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + msg(MT_DEBUG, format, ap); + va_end(ap); +} + +void +error_msg(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + msg(MT_ERROR, format, ap); + va_end(ap); +} + +void +poll_fini(void) +{ + if (poll_fds != NULL) { + free(poll_fds); + poll_fds = NULL; + } +} + +struct pollfd * +find_pollfd(int fd) +{ + nfds_t n; + + for (n = 0; n < num_pollfds; n++) { + if (poll_fds[n].fd == fd) + return (&(poll_fds[n])); + } + return (NULL); +} + +int +set_pollfd(int fd, uint16_t events) +{ + struct pollfd *p; + int i; + + debug_msg("Entering set_pollfd, fd: %d, num_pollfds: %d, fds: %x," + " events: %hu", fd, num_pollfds, poll_fds, events); + + p = find_pollfd(fd); + if ((p == NULL) && ((p = find_pollfd(-1)) == NULL)) { + if ((p = realloc(poll_fds, + ((num_pollfds + POLLFDS_GROWTH_SIZE) * + sizeof (struct pollfd)))) == NULL) { + return (-1); + } + poll_fds = p; + + for (i = 1; i < POLLFDS_GROWTH_SIZE; i++) + poll_fds[num_pollfds + i].fd = -1; + + p = &poll_fds[num_pollfds]; + num_pollfds += POLLFDS_GROWTH_SIZE; + } + + p->fd = fd; + p->events = events; + p->revents = 0; + + return (0); +} + +void +clear_pollfd(int fd) +{ + struct pollfd *p; + + if ((p = find_pollfd(fd)) != NULL) { + p->fd = -1; + p->events = 0; + p->revents = 0; + } +} + +boolean_t +isset_pollfd(int fd) +{ + struct pollfd *p = find_pollfd(fd); + + return ((p != NULL) && (p->revents & POLLIN)); +} + +/* + * An extension of read() that keeps retrying until either the full request has + * completed, the other end of the connection/pipe is closed, no data is + * readable for a non-blocking socket/pipe, or an unexpected error occurs. + * Returns 0 if the data is successfully read, 1 if the other end of the pipe/ + * socket is closed or there's nothing to read from a non-blocking socket/pipe, + * else -1 if an unexpected error occurs. + */ +int +safe_read(int fd, void *buf, size_t sz) +{ + int ret; + size_t cnt = 0; + char *cp = (char *)buf; + + if (sz == 0) + return (0); + + do { + switch (ret = read(fd, cp + cnt, sz - cnt)) { + case 0: /* other end of pipe/socket closed */ + return (1); + case -1: + if (errno == EAGAIN) { /* nothing to read */ + return (1); + } else if (errno != EINTR) { + error_msg(gettext("Unexpected read error: %s"), + strerror(errno)); + return (-1); + } + break; + + default: + cnt += ret; + } + } while (cnt != sz); + + return (0); +} + +/* + * Return B_TRUE if instance 'inst' has exceeded its configured maximum + * concurrent copies limit, else B_FALSE. + */ +boolean_t +copies_limit_exceeded(instance_t *inst) +{ + /* any value <=0 means that copies limits are disabled */ + return ((inst->config->basic->max_copies > 0) && + (inst->copies >= inst->config->basic->max_copies)); +} + +/* + * Cancel the method/con-rate offline timer associated with the instance. + */ +void +cancel_inst_timer(instance_t *inst) +{ + (void) iu_cancel_timer(timer_queue, inst->timer_id, NULL); + inst->timer_id = -1; +} + +/* + * Cancel the bind retry timer associated with the instance. + */ +void +cancel_bind_timer(instance_t *inst) +{ + (void) iu_cancel_timer(timer_queue, inst->bind_timer_id, NULL); + inst->bind_timer_id = -1; +} + +void +enable_blocking(int fd) +{ + int flags = fcntl(fd, F_GETFL, 0); + (void) fcntl(fd, F_SETFL, (flags & ~O_NONBLOCK)); +} + +void +disable_blocking(int fd) +{ + int flags = fcntl(fd, F_GETFL, 0); + (void) fcntl(fd, F_SETFL, (flags | O_NONBLOCK)); +} |