xref: /illumos-gate/usr/src/cmd/rcap/common/utils.c (revision 438b5f69eb4f998015cc0835f19f2f80663f2f53)
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 }
334