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 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/types.h>
28 #include <inttypes.h>
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <pthread.h>
36 #include <smbios.h>
37 
38 #include <fm/fmd_api.h>
39 
40 #include "util.h"
41 #include "disk_monitor.h"
42 
43 extern log_class_t g_verbose;
44 
45 static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
46 
47 static void
verror(const char * fmt,va_list ap)48 verror(const char *fmt, va_list ap)
49 {
50 	int error = errno;
51 
52 	dm_assert(pthread_mutex_lock(&log_mutex) == 0);
53 	fmd_hdl_vdebug(g_fm_hdl, fmt, ap);
54 
55 	if (fmt[strlen(fmt) - 1] != '\n')
56 		fmd_hdl_debug(g_fm_hdl, ": %s\n", strerror(error));
57 
58 	dm_assert(pthread_mutex_unlock(&log_mutex) == 0);
59 }
60 
61 static void
vwarn_e(const char * fmt,va_list ap)62 vwarn_e(const char *fmt, va_list ap)
63 {
64 	int error = errno;
65 
66 	dm_assert(pthread_mutex_lock(&log_mutex) == 0);
67 	fmd_hdl_debug(g_fm_hdl, "WARNING: ");
68 	fmd_hdl_vdebug(g_fm_hdl, fmt, ap);
69 
70 	if (fmt[strlen(fmt) - 1] != '\n')
71 		fmd_hdl_debug(g_fm_hdl, ": %s\n", strerror(error));
72 
73 	dm_assert(pthread_mutex_unlock(&log_mutex) == 0);
74 }
75 
76 static void
vwarn(const char * fmt,va_list ap)77 vwarn(const char *fmt, va_list ap)
78 {
79 	dm_assert(pthread_mutex_lock(&log_mutex) == 0);
80 	fmd_hdl_debug(g_fm_hdl, "WARNING: ");
81 	fmd_hdl_vdebug(g_fm_hdl, fmt, ap);
82 	dm_assert(pthread_mutex_unlock(&log_mutex) == 0);
83 }
84 
85 void
vcont(log_class_t cl,const char * fmt,va_list ap)86 vcont(log_class_t cl, const char *fmt, va_list ap)
87 {
88 	int error = errno;
89 
90 	if ((g_verbose & cl) != cl)
91 		return;
92 
93 	dm_assert(pthread_mutex_lock(&log_mutex) == 0);
94 	fmd_hdl_vdebug(g_fm_hdl, fmt, ap);
95 
96 	if (fmt[strlen(fmt) - 1] != '\n')
97 		fmd_hdl_debug(g_fm_hdl, ": %s\n", strerror(error));
98 
99 	dm_assert(pthread_mutex_unlock(&log_mutex) == 0);
100 }
101 
102 void
log_msg(log_class_t cl,const char * fmt,...)103 log_msg(log_class_t cl, const char *fmt, ...)
104 {
105 	va_list ap;
106 
107 	if ((g_verbose & cl) != cl)
108 		return;
109 
110 	dm_assert(pthread_mutex_lock(&log_mutex) == 0);
111 	va_start(ap, fmt);
112 	fmd_hdl_vdebug(g_fm_hdl, fmt, ap);
113 	va_end(ap);
114 	dm_assert(pthread_mutex_unlock(&log_mutex) == 0);
115 }
116 
117 /*PRINTFLIKE1*/
118 void
log_err(const char * fmt,...)119 log_err(const char *fmt, ...)
120 {
121 	va_list ap;
122 
123 	if ((g_verbose & MM_ERR) != MM_ERR)
124 		return;
125 
126 	va_start(ap, fmt);
127 	verror(fmt, ap);
128 	va_end(ap);
129 }
130 
131 /*PRINTFLIKE1*/
132 void
log_warn(const char * fmt,...)133 log_warn(const char *fmt, ...)
134 {
135 	va_list ap;
136 
137 	if ((g_verbose & MM_WARN) != MM_WARN)
138 		return;
139 
140 	va_start(ap, fmt);
141 	vwarn(fmt, ap);
142 	va_end(ap);
143 }
144 
145 /*PRINTFLIKE1*/
146 void
log_warn_e(const char * fmt,...)147 log_warn_e(const char *fmt, ...)
148 {
149 	va_list ap;
150 
151 	if ((g_verbose & MM_WARN) != MM_WARN)
152 		return;
153 
154 	va_start(ap, fmt);
155 	vwarn_e(fmt, ap);
156 	va_end(ap);
157 }
158 
159 void
dfree(void * p,size_t sz)160 dfree(void *p, size_t sz)
161 {
162 	fmd_hdl_free(g_fm_hdl, p, sz);
163 }
164 
165 void
dstrfree(char * s)166 dstrfree(char *s)
167 {
168 	fmd_hdl_strfree(g_fm_hdl, s);
169 }
170 
171 void *
dmalloc(size_t sz)172 dmalloc(size_t sz)
173 {
174 	return (fmd_hdl_alloc(g_fm_hdl, sz, FMD_SLEEP));
175 }
176 
177 void *
dzmalloc(size_t sz)178 dzmalloc(size_t sz)
179 {
180 	return (fmd_hdl_zalloc(g_fm_hdl, sz, FMD_SLEEP));
181 }
182 
183 
184 char *
dstrdup(const char * s)185 dstrdup(const char *s)
186 {
187 	return (fmd_hdl_strdup(g_fm_hdl, s, FMD_SLEEP));
188 }
189 
190 void
queue_add(qu_t * qp,void * data)191 queue_add(qu_t *qp, void *data)
192 {
193 	struct q_node *qnp =
194 	    (struct q_node *)qp->nalloc(sizeof (struct q_node));
195 	struct q_node *nodep;
196 
197 	qnp->data = data;
198 	qnp->next = NULL;
199 	dm_assert(pthread_mutex_lock(&qp->mutex) == 0);
200 
201 	if (qp->nodep == NULL)
202 		qp->nodep = qnp;
203 	else {
204 		nodep = qp->nodep;
205 
206 		while (nodep->next != NULL)
207 			nodep = nodep->next;
208 
209 		nodep->next = qnp;
210 	}
211 
212 	/* If the queue was empty, we need to wake people up */
213 	if (qp->boe && qp->nodep == qnp)
214 		dm_assert(pthread_cond_broadcast(&qp->cvar) == 0);
215 	dm_assert(pthread_mutex_unlock(&qp->mutex) == 0);
216 }
217 
218 void *
queue_remove(qu_t * qp)219 queue_remove(qu_t *qp)
220 {
221 	void *rv = NULL;
222 	struct q_node *nextnode;
223 
224 	dm_assert(pthread_mutex_lock(&qp->mutex) == 0);
225 
226 	/* Wait while the queue is empty */
227 	while (qp->boe && qp->nodep == NULL) {
228 		(void) pthread_cond_wait(&qp->cvar, &qp->mutex);
229 	}
230 
231 	/*
232 	 * If Block-On-Empty is false, the queue may be empty
233 	 */
234 	if (qp->nodep != NULL) {
235 		rv = qp->nodep->data;
236 		nextnode = qp->nodep->next;
237 		qp->nfree(qp->nodep, sizeof (struct q_node));
238 		qp->nodep = nextnode;
239 	}
240 
241 	dm_assert(pthread_mutex_unlock(&qp->mutex) == 0);
242 	return (rv);
243 }
244 
245 qu_t *
new_queue(boolean_t block_on_empty,void * (* nodealloc)(size_t),void (* nodefree)(void *,size_t),void (* data_deallocator)(void *))246 new_queue(boolean_t block_on_empty, void *(*nodealloc)(size_t),
247     void (*nodefree)(void *, size_t), void (*data_deallocator)(void *))
248 {
249 	qu_t *newqp = (qu_t *)dmalloc(sizeof (qu_t));
250 
251 	newqp->boe = block_on_empty;
252 	newqp->nalloc = nodealloc;
253 	newqp->nfree = nodefree;
254 	newqp->data_dealloc = data_deallocator;
255 	dm_assert(pthread_mutex_init(&newqp->mutex, NULL) == 0);
256 	dm_assert(pthread_cond_init(&newqp->cvar, NULL) == 0);
257 	newqp->nodep = NULL;
258 
259 	return (newqp);
260 }
261 
262 void
queue_free(qu_t ** qpp)263 queue_free(qu_t **qpp)
264 {
265 	qu_t *qp = *qpp;
266 	void *item;
267 
268 	dm_assert(pthread_mutex_destroy(&qp->mutex) == 0);
269 	dm_assert(pthread_cond_destroy(&qp->cvar) == 0);
270 
271 	qp->boe = B_FALSE;
272 
273 	while ((item = queue_remove(qp)) != NULL) {
274 		qp->data_dealloc(item);
275 	}
276 
277 	dm_assert(qp->nodep == NULL);
278 
279 	dfree(qp, sizeof (qu_t));
280 	*qpp = NULL;
281 }
282 
283 int
_dm_assert(const char * assertion,const char * file,int line,const char * func)284 _dm_assert(const char *assertion, const char *file, int line, const char *func)
285 {
286 	/*
287 	 * No newline is appended to the assertion message so that
288 	 * errno can be translated for us by fmd_hdl_abort().
289 	 */
290 	if (func)
291 		fmd_hdl_abort(g_fm_hdl, "Assertion failed: "
292 		    "%s, file: %s, line: %d, function: %s", assertion, file,
293 		    line, func);
294 	else
295 		fmd_hdl_abort(g_fm_hdl, "Assertion failed: "
296 		    "%s, file: %s, line: %d", assertion, file, line);
297 	/*NOTREACHED*/
298 	return (0);
299 }
300