1ac88567aSHyon Kim /*
2ac88567aSHyon Kim  * CDDL HEADER START
3ac88567aSHyon Kim  *
4ac88567aSHyon Kim  * The contents of this file are subject to the terms of the
5ac88567aSHyon Kim  * Common Development and Distribution License (the "License").
6ac88567aSHyon Kim  * You may not use this file except in compliance with the License.
7ac88567aSHyon Kim  *
8ac88567aSHyon Kim  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ac88567aSHyon Kim  * or http://www.opensolaris.org/os/licensing.
10ac88567aSHyon Kim  * See the License for the specific language governing permissions
11ac88567aSHyon Kim  * and limitations under the License.
12ac88567aSHyon Kim  *
13ac88567aSHyon Kim  * When distributing Covered Code, include this CDDL HEADER in each
14ac88567aSHyon Kim  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ac88567aSHyon Kim  * If applicable, add the following below this CDDL HEADER, with the
16ac88567aSHyon Kim  * fields enclosed by brackets "[]" replaced with your own identifying
17ac88567aSHyon Kim  * information: Portions Copyright [yyyy] [name of copyright owner]
18ac88567aSHyon Kim  *
19ac88567aSHyon Kim  * CDDL HEADER END
20ac88567aSHyon Kim  */
21ac88567aSHyon Kim 
22ac88567aSHyon Kim /*
23ac88567aSHyon Kim  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24ac88567aSHyon Kim  */
25ac88567aSHyon Kim 
26*44bf619dSJohn Levon /*
27*44bf619dSJohn Levon  * Copyright 2019 Joyent, Inc.
28*44bf619dSJohn Levon  */
29*44bf619dSJohn Levon 
30ac88567aSHyon Kim #include <sys/types.h>
31ac88567aSHyon Kim 
32ac88567aSHyon Kim #include <stddef.h>
33ac88567aSHyon Kim #include <stdlib.h>
34ac88567aSHyon Kim #include <string.h>
35ac88567aSHyon Kim #include <strings.h>
36ac88567aSHyon Kim #include <alloca.h>
37ac88567aSHyon Kim #include <stdio.h>
38ac88567aSHyon Kim #include <unistd.h>
39ac88567aSHyon Kim #include <dlfcn.h>
40ac88567aSHyon Kim #include <thread.h>
41ac88567aSHyon Kim #include <pthread.h>
42ac88567aSHyon Kim #include <ctype.h>
43ac88567aSHyon Kim 
44ac88567aSHyon Kim #include <scsi/libsmp.h>
45ac88567aSHyon Kim #include <scsi/libsmp_plugin.h>
46ac88567aSHyon Kim #include "smp_impl.h"
47ac88567aSHyon Kim 
48ac88567aSHyon Kim __thread smp_errno_t _smp_errno;
49ac88567aSHyon Kim __thread char _smp_errmsg[LIBSMP_ERRMSGLEN];
50ac88567aSHyon Kim 
51ac88567aSHyon Kim int
smp_assert(const char * expr,const char * file,int line)52ac88567aSHyon Kim smp_assert(const char *expr, const char *file, int line)
53ac88567aSHyon Kim {
54ac88567aSHyon Kim 	char *msg;
55ac88567aSHyon Kim 	size_t len;
56ac88567aSHyon Kim 
57ac88567aSHyon Kim 	len = snprintf(NULL, 0,
58ac88567aSHyon Kim 	    "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
59ac88567aSHyon Kim 
60ac88567aSHyon Kim 	msg = alloca(len + 1);
61ac88567aSHyon Kim 
62ac88567aSHyon Kim 	(void) snprintf(msg, len + 1,
63ac88567aSHyon Kim 	    "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
64ac88567aSHyon Kim 
65ac88567aSHyon Kim 	(void) write(STDERR_FILENO, msg, strlen(msg));
66ac88567aSHyon Kim 
67ac88567aSHyon Kim 	abort();
68ac88567aSHyon Kim 	/*NOTREACHED*/
69ac88567aSHyon Kim }
70ac88567aSHyon Kim 
71ac88567aSHyon Kim int
smp_set_errno(smp_errno_t err)72ac88567aSHyon Kim smp_set_errno(smp_errno_t err)
73ac88567aSHyon Kim {
74ac88567aSHyon Kim 	_smp_errno = err;
75ac88567aSHyon Kim 	_smp_errmsg[0] = '\0';
76ac88567aSHyon Kim 
77ac88567aSHyon Kim 	return (-1);
78ac88567aSHyon Kim }
79ac88567aSHyon Kim 
80ac88567aSHyon Kim /*
81ac88567aSHyon Kim  * Internal routine for setting both _smp_errno and _smp_errmsg.  We save
82ac88567aSHyon Kim  * and restore the UNIX errno across this routing so the caller can use either
83ac88567aSHyon Kim  * smp_set_errno(), smp_error(), or smp_verror() without this value changing.
84ac88567aSHyon Kim  */
85ac88567aSHyon Kim int
smp_verror(smp_errno_t err,const char * fmt,va_list ap)86ac88567aSHyon Kim smp_verror(smp_errno_t err, const char *fmt, va_list ap)
87ac88567aSHyon Kim {
88ac88567aSHyon Kim 	size_t n;
89ac88567aSHyon Kim 	char *errmsg;
90ac88567aSHyon Kim 
91ac88567aSHyon Kim 	/*
92ac88567aSHyon Kim 	 * To allow the existing error message to itself be used in an error
93ac88567aSHyon Kim 	 * message, we put the new error message into a buffer on the stack,
94ac88567aSHyon Kim 	 * and then copy it into lsh_errmsg.  We also need to set the errno,
95ac88567aSHyon Kim 	 * but because the call to smp_set_errno() is destructive to
96ac88567aSHyon Kim 	 * lsh_errmsg, we do this after we print into our temporary buffer
97ac88567aSHyon Kim 	 * (in case _smp_errmsg is part of the error message) and before we
98ac88567aSHyon Kim 	 * copy the temporary buffer on to _smp_errmsg (to prevent our new
99ac88567aSHyon Kim 	 * message from being nuked by the call to smp_set_errno()).
100ac88567aSHyon Kim 	 */
101ac88567aSHyon Kim 	errmsg = alloca(sizeof (_smp_errmsg));
102ac88567aSHyon Kim 	(void) vsnprintf(errmsg, sizeof (_smp_errmsg), fmt, ap);
103ac88567aSHyon Kim 	(void) smp_set_errno(err);
104ac88567aSHyon Kim 
105ac88567aSHyon Kim 	n = strlen(errmsg);
106ac88567aSHyon Kim 
107ac88567aSHyon Kim 	if (n != 0 && errmsg[n - 1] == '\n')
108ac88567aSHyon Kim 		errmsg[n - 1] = '\0';
109ac88567aSHyon Kim 
110ac88567aSHyon Kim 	bcopy(errmsg, _smp_errmsg, n + 1);
111ac88567aSHyon Kim 
112ac88567aSHyon Kim 	return (-1);
113ac88567aSHyon Kim }
114ac88567aSHyon Kim 
115ac88567aSHyon Kim int
smp_error(smp_errno_t err,const char * fmt,...)116ac88567aSHyon Kim smp_error(smp_errno_t err, const char *fmt, ...)
117ac88567aSHyon Kim {
118ac88567aSHyon Kim 	va_list ap;
119ac88567aSHyon Kim 
120ac88567aSHyon Kim 	if (fmt == NULL)
121ac88567aSHyon Kim 		return (smp_set_errno(err));
122ac88567aSHyon Kim 
123ac88567aSHyon Kim 	va_start(ap, fmt);
124ac88567aSHyon Kim 	err = smp_verror(err, fmt, ap);
125ac88567aSHyon Kim 	va_end(ap);
126ac88567aSHyon Kim 
127ac88567aSHyon Kim 	return (err);
128ac88567aSHyon Kim }
129ac88567aSHyon Kim 
130ac88567aSHyon Kim smp_errno_t
smp_errno(void)131ac88567aSHyon Kim smp_errno(void)
132ac88567aSHyon Kim {
133ac88567aSHyon Kim 	return (_smp_errno);
134ac88567aSHyon Kim }
135ac88567aSHyon Kim 
136ac88567aSHyon Kim const char *
smp_errmsg(void)137ac88567aSHyon Kim smp_errmsg(void)
138ac88567aSHyon Kim {
139ac88567aSHyon Kim 	if (_smp_errmsg[0] == '\0')
140ac88567aSHyon Kim 		(void) strlcpy(_smp_errmsg, smp_strerror(_smp_errno),
141ac88567aSHyon Kim 		    sizeof (_smp_errmsg));
142ac88567aSHyon Kim 
143ac88567aSHyon Kim 	return (_smp_errmsg);
144ac88567aSHyon Kim }
145ac88567aSHyon Kim 
146ac88567aSHyon Kim /*ARGSUSED*/
147ac88567aSHyon Kim void *
smp_alloc(size_t size)148ac88567aSHyon Kim smp_alloc(size_t size)
149ac88567aSHyon Kim {
150ac88567aSHyon Kim 	void *mem;
151ac88567aSHyon Kim 
152ac88567aSHyon Kim 	if (size == 0) {
153ac88567aSHyon Kim 		(void) smp_set_errno(ESMP_ZERO_LENGTH);
154ac88567aSHyon Kim 		return (NULL);
155ac88567aSHyon Kim 	}
156ac88567aSHyon Kim 
157ac88567aSHyon Kim 	if ((mem = malloc(size)) == NULL)
158ac88567aSHyon Kim 		(void) smp_set_errno(ESMP_NOMEM);
159ac88567aSHyon Kim 
160ac88567aSHyon Kim 	return (mem);
161ac88567aSHyon Kim }
162ac88567aSHyon Kim 
163ac88567aSHyon Kim void *
smp_zalloc(size_t size)164ac88567aSHyon Kim smp_zalloc(size_t size)
165ac88567aSHyon Kim {
166ac88567aSHyon Kim 	void *mem;
167ac88567aSHyon Kim 
168ac88567aSHyon Kim 	if ((mem = smp_alloc(size)) == NULL)
169ac88567aSHyon Kim 		return (NULL);
170ac88567aSHyon Kim 
171ac88567aSHyon Kim 	bzero(mem, size);
172ac88567aSHyon Kim 
173ac88567aSHyon Kim 	return (mem);
174ac88567aSHyon Kim }
175ac88567aSHyon Kim 
176ac88567aSHyon Kim char *
smp_strdup(const char * str)177ac88567aSHyon Kim smp_strdup(const char *str)
178ac88567aSHyon Kim {
179ac88567aSHyon Kim 	size_t len = strlen(str);
180ac88567aSHyon Kim 	char *dup = smp_alloc(len + 1);
181ac88567aSHyon Kim 
182ac88567aSHyon Kim 	if (dup == NULL)
183ac88567aSHyon Kim 		return (NULL);
184ac88567aSHyon Kim 
185ac88567aSHyon Kim 	return (strcpy(dup, str));
186ac88567aSHyon Kim }
187ac88567aSHyon Kim 
188ac88567aSHyon Kim void
smp_free(void * ptr)189ac88567aSHyon Kim smp_free(void *ptr)
190ac88567aSHyon Kim {
191ac88567aSHyon Kim 	free(ptr);
192ac88567aSHyon Kim }
193ac88567aSHyon Kim 
194ac88567aSHyon Kim /*
195ac88567aSHyon Kim  * Trim any leading and/or trailing spaces from the fixed-length string
196ac88567aSHyon Kim  * argument and return a newly-allocated copy of it.
197ac88567aSHyon Kim  */
198ac88567aSHyon Kim char *
smp_trim_strdup(const char * str,size_t len)199ac88567aSHyon Kim smp_trim_strdup(const char *str, size_t len)
200ac88567aSHyon Kim {
201ac88567aSHyon Kim 	const char *p;
202ac88567aSHyon Kim 	char *r;
203ac88567aSHyon Kim 
204ac88567aSHyon Kim 	for (p = str; p - str < len && isspace(*p); p++)
205ac88567aSHyon Kim 		;
206ac88567aSHyon Kim 
207ac88567aSHyon Kim 	len -= (p - str);
208ac88567aSHyon Kim 
209ac88567aSHyon Kim 	if (len == 0)
210ac88567aSHyon Kim 		return (NULL);
211ac88567aSHyon Kim 
212ac88567aSHyon Kim 	for (str = p + len - 1; str > p && isspace(*str); str--, len--)
213ac88567aSHyon Kim 		;
214ac88567aSHyon Kim 
215ac88567aSHyon Kim 	if (len == 0)
216ac88567aSHyon Kim 		return (NULL);
217ac88567aSHyon Kim 
218ac88567aSHyon Kim 	r = smp_alloc(len + 1);
219ac88567aSHyon Kim 	if (r == NULL)
220ac88567aSHyon Kim 		return (NULL);
221ac88567aSHyon Kim 
222ac88567aSHyon Kim 	bcopy(p, r, len);
223ac88567aSHyon Kim 	r[len] = '\0';
224ac88567aSHyon Kim 
225ac88567aSHyon Kim 	return (r);
226ac88567aSHyon Kim }
227ac88567aSHyon Kim 
228ac88567aSHyon Kim int
smp_init(int version)229ac88567aSHyon Kim smp_init(int version)
230ac88567aSHyon Kim {
231ac88567aSHyon Kim 	if (version != LIBSMP_VERSION)
232ac88567aSHyon Kim 		return (smp_error(ESMP_VERSION,
233ac88567aSHyon Kim 		    "library version %d does not match requested version %d",
234ac88567aSHyon Kim 		    LIBSMP_VERSION, version));
235ac88567aSHyon Kim 
236ac88567aSHyon Kim 	smp_engine_init();
237ac88567aSHyon Kim 
238ac88567aSHyon Kim 	return (0);
239ac88567aSHyon Kim }
240ac88567aSHyon Kim 
241ac88567aSHyon Kim void
smp_fini(void)242ac88567aSHyon Kim smp_fini(void)
243ac88567aSHyon Kim {
244ac88567aSHyon Kim 	smp_engine_fini();
245ac88567aSHyon Kim }