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  */
  25 
  26 #include <sys/param.h>
  27 #include <libintl.h>
  28 #include <stdarg.h>
  29 #include <stdio.h>
  30 #include <stdlib.h>
  31 #include <strings.h>
  32 #include <syslog.h>
  33 #include <unistd.h>
  34 #include <errno.h>
  35 
  36 #include "utils.h"
  37 
  38 static char ERRNO_FMT[] = ": %s";
  39 
  40 static char *pname = NULL;
  41 static rcm_level_t message_priority = RCM_WARN;
  42 static rcm_dst_t message_dst = RCD_STD;
  43 
  44 static void dmesg(int level, char *msg);
  45 
  46 /*PRINTFLIKE2*/
  47 void
  48 dprintfe(int level, char *format, ...)
  49 {
  50         va_list alist;
  51 
  52         va_start(alist, format);
  53         vdprintfe(level, format, alist);
  54         va_end(alist);
  55 }
  56 
  57 /*PRINTFLIKE2*/
  58 void
  59 vdprintfe(int level, const char *format, va_list alist)
  60 {
  61         char buf[LINELEN];
  62         char *c;
  63         int err = errno;
  64 
  65         *buf = 0;
  66 
  67         if ((strlen(buf) + 1) < LINELEN)
  68                 (void) vsnprintf(buf + strlen(buf), LINELEN - 1 - strlen(buf),
  69                     format, alist);
  70         if ((c = strchr(buf, '\n')) == NULL) {
  71                 if ((strlen(buf) + 1) < LINELEN)
  72                         (void) snprintf(buf + strlen(buf), LINELEN - 1 -
  73                             strlen(buf), gettext(ERRNO_FMT), strerror(err));
  74         } else
  75                 *c = 0;
  76 
  77         dmesg(level, buf);
  78 }
  79 
  80 #ifdef DEBUG_MSG
  81 /*PRINTFLIKE1*/
  82 void
  83 debug(char *format, ...)
  84 {
  85         va_list alist;
  86 
  87         if (get_message_priority() < RCM_DEBUG)
  88                 return;
  89 
  90         va_start(alist, format);
  91         vdprintfe(RCM_DEBUG, format, alist);
  92         va_end(alist);
  93 }
  94 
  95 /*PRINTFLIKE1*/
  96 void
  97 debug_high(char *format, ...)
  98 {
  99         va_list alist;
 100 
 101         if (get_message_priority() < RCM_DEBUG_HIGH)
 102                 return;
 103 
 104         va_start(alist, format);
 105         vdprintfe(RCM_DEBUG_HIGH, format, alist);
 106         va_end(alist);
 107 }
 108 #endif /* DEBUG_MSG */
 109 
 110 /*PRINTFLIKE1*/
 111 void
 112 warn(const char *format, ...)
 113 {
 114         va_list alist;
 115 
 116         if (get_message_priority() < RCM_WARN)
 117                 return;
 118 
 119         va_start(alist, format);
 120         vdprintfe(RCM_WARN, format, alist);
 121         va_end(alist);
 122 }
 123 
 124 /*PRINTFLIKE1*/
 125 void
 126 die(char *format, ...)
 127 {
 128         va_list alist;
 129 
 130         if (get_message_priority() < RCM_ERR)
 131                 return;
 132 
 133         va_start(alist, format);
 134         vdprintfe(RCM_ERR, format, alist);
 135         va_end(alist);
 136 
 137         exit(E_ERROR);
 138 }
 139 
 140 /*PRINTFLIKE1*/
 141 void
 142 info(char *format, ...)
 143 {
 144         va_list alist;
 145 
 146         if (get_message_priority() < RCM_INFO)
 147                 return;
 148 
 149         va_start(alist, format);
 150         vdprintfe(RCM_INFO, format, alist);
 151         va_end(alist);
 152 }
 153 
 154 char *
 155 setpname(char *arg0)
 156 {
 157         char *p = strrchr(arg0, '/');
 158 
 159         if (p == NULL)
 160                 p = arg0;
 161         else
 162                 p++;
 163         pname = p;
 164         return (pname);
 165 }
 166 
 167 /*
 168  * Output a message to the controlling tty or log, depending on which is
 169  * configured.  The message should contain no newlines.
 170  */
 171 static void
 172 dmesg(int level, char *msg)
 173 {
 174         if (message_priority >= level) {
 175                 FILE *fp;
 176                 int syslog_severity = -1;
 177 
 178                 switch (message_dst) {
 179                 case RCD_STD:
 180                         fp = level >= RCM_DEBUG ? stderr : stdout;
 181 
 182                         if (pname != NULL) {
 183                                 (void) fputs(pname, fp);
 184                                 (void) fputs(": ", fp);
 185                         }
 186                         (void) fputs(msg, fp);
 187                         (void) fputc('\n', fp);
 188                         (void) fflush(fp);
 189                         break;
 190                 case RCD_SYSLOG:
 191                         switch (level) {
 192                         case RCM_ERR:
 193                                 syslog_severity = LOG_ERR;
 194                                 break;
 195                         case RCM_WARN:
 196                                 syslog_severity = LOG_WARNING;
 197                                 break;
 198                         case RCM_INFO:
 199                                 syslog_severity = LOG_INFO;
 200                                 break;
 201                         case RCM_DEBUG:
 202                                 syslog_severity = LOG_DEBUG;
 203                                 break;
 204                         }
 205                         if (syslog_severity >= 0)
 206                                 (void) syslog(syslog_severity, "%s", msg);
 207                         break;
 208                 }
 209         }
 210 }
 211 
 212 rcm_level_t
 213 get_message_priority(void)
 214 {
 215         return (message_priority);
 216 }
 217 
 218 rcm_level_t
 219 set_message_priority(rcm_level_t new_priority)
 220 {
 221         rcm_level_t old_priority = message_priority;
 222 
 223         message_priority = new_priority;
 224         return (old_priority);
 225 }
 226 
 227 rcm_dst_t
 228 set_message_destination(rcm_dst_t new_dst)
 229 {
 230         rcm_dst_t old_dst = message_dst;
 231 
 232         if ((message_dst = new_dst) == RCD_SYSLOG)
 233                 openlog(pname, LOG_ODELAY | LOG_PID, LOG_DAEMON);
 234 
 235         return (old_dst);
 236 }
 237 
 238 void
 239 hrt2ts(hrtime_t hrt, timestruc_t *tsp)
 240 {
 241         tsp->tv_sec = hrt / NANOSEC;
 242         tsp->tv_nsec = hrt % NANOSEC;
 243 }
 244 
 245 int
 246 xatoi(char *p)
 247 {
 248         int i;
 249         char *q;
 250 
 251         errno = 0;
 252         i = (int)strtol(p, &q, 10);
 253         if (errno != 0 || q == p || i < 0 || *q != '\0') {
 254                 warn(gettext("illegal argument -- %s\n"), p);
 255                 return (-1);
 256         } else {
 257                 return (i);
 258         }
 259 }
 260 
 261 /*
 262  * get_running_zones() calls zone_list(2) to find out how many zones are
 263  * running.  It then calls zone_list(2) again to fetch the list of running
 264  * zones (stored in *zents).
 265  */
 266 int
 267 get_running_zones(uint_t *nzents, zone_entry_t **zents)
 268 {
 269         zoneid_t *zids;
 270         uint_t nzents_saved;
 271         int i;
 272         zone_entry_t *zentp;
 273         zone_state_t zstate;
 274 
 275         *zents = NULL;
 276         if (zone_list(NULL, nzents) != 0) {
 277                 warn(gettext("could not get zoneid list\n"));
 278                 return (E_ERROR);
 279         }
 280 
 281 again:
 282         if (*nzents == 0)
 283                 return (E_SUCCESS);
 284 
 285         if ((zids = (zoneid_t *)calloc(*nzents, sizeof (zoneid_t))) == NULL) {
 286                 warn(gettext("out of memory: zones will not be capped\n"));
 287                 return (E_ERROR);
 288         }
 289 
 290         nzents_saved = *nzents;
 291 
 292         if (zone_list(zids, nzents) != 0) {
 293                 warn(gettext("could not get zone list\n"));
 294                 free(zids);
 295                 return (E_ERROR);
 296         }
 297         if (*nzents != nzents_saved) {
 298                 /* list changed, try again */
 299                 free(zids);
 300                 goto again;
 301         }
 302 
 303         *zents = calloc(*nzents, sizeof (zone_entry_t));
 304         if (*zents == NULL) {
 305                 warn(gettext("out of memory: zones will not be capped\n"));
 306                 free(zids);
 307                 return (E_ERROR);
 308         }
 309 
 310         zentp = *zents;
 311         for (i = 0; i < *nzents; i++) {
 312                 char name[ZONENAME_MAX];
 313 
 314                 if (getzonenamebyid(zids[i], name, sizeof (name)) < 0) {
 315                         warn(gettext("could not get name for "
 316                             "zoneid %d\n"), zids[i]);
 317                         continue;
 318                 }
 319 
 320                 (void) strlcpy(zentp->zname, name, sizeof (zentp->zname));
 321                 zentp->zid = zids[i];
 322                 if (zone_get_state(name, &zstate) != Z_OK ||
 323                     zstate != ZONE_STATE_RUNNING)
 324                         continue;
 325 
 326 
 327                 zentp++;
 328         }
 329         *nzents = zentp - *zents;
 330 
 331         free(zids);
 332         return (E_SUCCESS);
 333 }