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 /*
  23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2011, Joyent, Inc. All rights reserved.
  25  */
  26 
  27 #include <sys/param.h>
  28 #include <libintl.h>
  29 #include <stdarg.h>
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <strings.h>
  33 #include <syslog.h>
  34 #include <unistd.h>
  35 #include <errno.h>
  36 
  37 #include "utils.h"
  38 
  39 static char ERRNO_FMT[] = ": %s";
  40 
  41 static char *pname = NULL;
  42 static rcm_level_t message_priority = RCM_WARN;
  43 static rcm_dst_t message_dst = RCD_STD;
  44 
  45 static void dmesg(int level, char *msg);
  46 
  47 /*PRINTFLIKE2*/
  48 void
  49 dprintfe(int level, char *format, ...)
  50 {
  51         va_list alist;
  52 
  53         va_start(alist, format);
  54         vdprintfe(level, format, alist);
  55         va_end(alist);
  56 }
  57 
  58 /*PRINTFLIKE2*/
  59 void
  60 vdprintfe(int level, const char *format, va_list alist)
  61 {
  62         char buf[LINELEN];
  63         char *c;
  64         int err = errno;
  65 
  66         *buf = 0;
  67 
  68         if ((strlen(buf) + 1) < LINELEN)
  69                 (void) vsnprintf(buf + strlen(buf), LINELEN - 1 - strlen(buf),
  70                     format, alist);
  71         if ((c = strchr(buf, '\n')) == NULL) {
  72                 if ((strlen(buf) + 1) < LINELEN)
  73                         (void) snprintf(buf + strlen(buf), LINELEN - 1 -
  74                             strlen(buf), gettext(ERRNO_FMT), strerror(err));
  75         } else
  76                 *c = 0;
  77 
  78         dmesg(level, buf);
  79 }
  80 
  81 #ifdef DEBUG_MSG
  82 /*PRINTFLIKE1*/
  83 void
  84 debug(char *format, ...)
  85 {
  86         va_list alist;
  87 
  88         if (get_message_priority() < RCM_DEBUG)
  89                 return;
  90 
  91         va_start(alist, format);
  92         vdprintfe(RCM_DEBUG, format, alist);
  93         va_end(alist);
  94 }
  95 
  96 /*PRINTFLIKE1*/
  97 void
  98 debug_high(char *format, ...)
  99 {
 100         va_list alist;
 101 
 102         if (get_message_priority() < RCM_DEBUG_HIGH)
 103                 return;
 104 
 105         va_start(alist, format);
 106         vdprintfe(RCM_DEBUG_HIGH, format, alist);
 107         va_end(alist);
 108 }
 109 #endif /* DEBUG_MSG */
 110 
 111 /*PRINTFLIKE1*/
 112 void
 113 warn(const char *format, ...)
 114 {
 115         va_list alist;
 116 
 117         if (get_message_priority() < RCM_WARN)
 118                 return;
 119 
 120         va_start(alist, format);
 121         vdprintfe(RCM_WARN, format, alist);
 122         va_end(alist);
 123 }
 124 
 125 /*PRINTFLIKE1*/
 126 void
 127 die(char *format, ...)
 128 {
 129         va_list alist;
 130 
 131         if (get_message_priority() < RCM_ERR)
 132                 return;
 133 
 134         va_start(alist, format);
 135         vdprintfe(RCM_ERR, format, alist);
 136         va_end(alist);
 137 
 138         exit(E_ERROR);
 139 }
 140 
 141 /*PRINTFLIKE1*/
 142 void
 143 info(char *format, ...)
 144 {
 145         va_list alist;
 146 
 147         if (get_message_priority() < RCM_INFO)
 148                 return;
 149 
 150         va_start(alist, format);
 151         vdprintfe(RCM_INFO, format, alist);
 152         va_end(alist);
 153 }
 154 
 155 char *
 156 setpname(char *arg0)
 157 {
 158         char *p = strrchr(arg0, '/');
 159 
 160         if (p == NULL)
 161                 p = arg0;
 162         else
 163                 p++;
 164         pname = p;
 165         return (pname);
 166 }
 167 
 168 /*
 169  * Output a message to the controlling tty or log, depending on which is
 170  * configured.  The message should contain no newlines.
 171  */
 172 static void
 173 dmesg(int level, char *msg)
 174 {
 175         if (message_priority >= level) {
 176                 FILE *fp;
 177                 int syslog_severity = -1;
 178 
 179                 switch (message_dst) {
 180                 case RCD_STD:
 181                         fp = level >= RCM_DEBUG ? stderr : stdout;
 182 
 183                         if (pname != NULL) {
 184                                 (void) fputs(pname, fp);
 185                                 (void) fputs(": ", fp);
 186                         }
 187                         (void) fputs(msg, fp);
 188                         (void) fputc('\n', fp);
 189                         (void) fflush(fp);
 190                         break;
 191                 case RCD_SYSLOG:
 192                         switch (level) {
 193                         case RCM_ERR:
 194                                 syslog_severity = LOG_ERR;
 195                                 break;
 196                         case RCM_WARN:
 197                                 syslog_severity = LOG_WARNING;
 198                                 break;
 199                         case RCM_INFO:
 200                                 syslog_severity = LOG_INFO;
 201                                 break;
 202                         case RCM_DEBUG:
 203                                 syslog_severity = LOG_DEBUG;
 204                                 break;
 205                         }
 206                         if (syslog_severity >= 0)
 207                                 (void) syslog(syslog_severity, "%s", msg);
 208                         break;
 209                 }
 210         }
 211 }
 212 
 213 rcm_level_t
 214 get_message_priority(void)
 215 {
 216         return (message_priority);
 217 }
 218 
 219 rcm_level_t
 220 set_message_priority(rcm_level_t new_priority)
 221 {
 222         rcm_level_t old_priority = message_priority;
 223 
 224         message_priority = new_priority;
 225         return (old_priority);
 226 }
 227 
 228 rcm_dst_t
 229 set_message_destination(rcm_dst_t new_dst)
 230 {
 231         rcm_dst_t old_dst = message_dst;
 232 
 233         if ((message_dst = new_dst) == RCD_SYSLOG)
 234                 openlog(pname, LOG_ODELAY | LOG_PID, LOG_DAEMON);
 235 
 236         return (old_dst);
 237 }
 238 
 239 void
 240 hrt2ts(hrtime_t hrt, timestruc_t *tsp)
 241 {
 242         tsp->tv_sec = hrt / NANOSEC;
 243         tsp->tv_nsec = hrt % NANOSEC;
 244 }
 245 
 246 int
 247 xatoi(char *p)
 248 {
 249         int i;
 250         char *q;
 251 
 252         errno = 0;
 253         i = (int)strtol(p, &q, 10);
 254         if (errno != 0 || q == p || i < 0 || *q != '\0') {
 255                 warn(gettext("illegal argument -- %s\n"), p);
 256                 return (-1);
 257         } else {
 258                 return (i);
 259         }
 260 }