xref: /illumos-gate/usr/src/lib/libc/port/gen/attrat.c (revision 2cb5535af222653abf2eba5c180ded4a7b85d8b6)
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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include "synonyms.h"
29 #include <string.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <mtlib.h>
34 #include <attr.h>
35 #include <sys/types.h>
36 #include <sys/syscall.h>
37 #include <sys/stat.h>
38 #include <sys/filio.h>
39 #include <unistd.h>
40 #include <dlfcn.h>
41 #include <stdio.h>
42 
43 static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int);
44 static int (*nvsize)(nvlist_t *, size_t *, int);
45 static int (*nvunpacker)(char *, size_t, nvlist_t **);
46 static int (*nvfree)(nvlist_t *);
47 static int (*nvlookupint64)(nvlist_t *, const char *, uint64_t *);
48 
49 static mutex_t attrlock = DEFAULTMUTEX;
50 static int initialized;
51 extern int __openattrdirat(int basefd, const char *name);
52 
53 static char *xattr_view_name[XATTR_VIEW_LAST] = {
54 	VIEW_READONLY,
55 	VIEW_READWRITE
56 };
57 
58 static int
59 attrat_init()
60 {
61 	if (initialized == 0) {
62 		void *libnvhandle = dlopen("libnvpair.so.1", RTLD_LAZY);
63 
64 		lmutex_lock(&attrlock);
65 		if (initialized == 1) {
66 			lmutex_unlock(&attrlock);
67 			if (libnvhandle)
68 				dlclose(libnvhandle);
69 			return (0);
70 		}
71 
72 		if (libnvhandle == NULL || (nvpacker = (int (*)(nvlist_t *,
73 		    char **, size_t *, int, int)) dlsym(libnvhandle,
74 		    "nvlist_pack")) == NULL ||
75 		    (nvsize = (int (*)(nvlist_t *,
76 		    size_t *, int)) dlsym(libnvhandle,
77 		    "nvlist_size")) == NULL ||
78 		    (nvfree = (int (*)(nvlist_t *)) dlsym(libnvhandle,
79 		    "nvlist_free")) == NULL ||
80 		    (nvlookupint64 = (int (*)(nvlist_t *, const char *,
81 		    uint64_t *)) dlsym(libnvhandle,
82 		    "nvlist_lookup_uint64")) == NULL ||
83 		    (nvunpacker = (int (*)(char *, size_t,
84 		    nvlist_t **)) dlsym(libnvhandle,
85 		    "nvlist_unpack")) == NULL) {
86 			if (libnvhandle)
87 				dlclose(libnvhandle);
88 			lmutex_unlock(&attrlock);
89 			return (-1);
90 		}
91 
92 		initialized = 1;
93 		lmutex_unlock(&attrlock);
94 	}
95 	return (0);
96 }
97 
98 static int
99 attr_nv_pack(nvlist_t *request, void **nv_request, size_t *nv_requestlen)
100 {
101 	size_t bufsize;
102 	char *packbuf = NULL;
103 
104 	if (nvsize(request, &bufsize, NV_ENCODE_XDR) != 0) {
105 		errno = EINVAL;
106 		return (-1);
107 	}
108 
109 	packbuf = malloc(bufsize);
110 	if (packbuf == NULL)
111 		return (-1);
112 	if (nvpacker(request, &packbuf, &bufsize, NV_ENCODE_XDR, 0) != 0) {
113 		free(packbuf);
114 		errno = EINVAL;
115 		return (-1);
116 	} else {
117 		*nv_request = (void *)packbuf;
118 		*nv_requestlen = bufsize;
119 	}
120 	return (0);
121 }
122 
123 static const char *
124 view_to_name(xattr_view_t view)
125 {
126 	if (view >= XATTR_VIEW_LAST || view < 0)
127 		return (NULL);
128 	return (xattr_view_name[view]);
129 }
130 
131 static int
132 xattr_openat(int basefd, xattr_view_t view, int mode)
133 {
134 	const char *xattrname;
135 	int xattrfd;
136 	int oflag;
137 
138 	switch (view) {
139 	case XATTR_VIEW_READONLY:
140 		oflag = O_RDONLY;
141 		break;
142 	case XATTR_VIEW_READWRITE:
143 		oflag = mode & O_RDWR;
144 		break;
145 	default:
146 		errno = EINVAL;
147 		return (-1);
148 	}
149 	if (mode & O_XATTR)
150 		oflag |= O_XATTR;
151 
152 	xattrname = view_to_name(view);
153 	xattrfd = openat(basefd, xattrname, oflag);
154 	if (xattrfd < 0)
155 		return (xattrfd);
156 	/* Don't cache sysattr info (advisory) */
157 	(void) directio(xattrfd, DIRECTIO_ON);
158 	return (xattrfd);
159 }
160 
161 static int
162 cgetattr(int fd, nvlist_t **response)
163 {
164 	int error;
165 	int bytesread;
166 	void *nv_response;
167 	size_t nv_responselen;
168 	struct stat buf;
169 
170 	if (error = attrat_init())
171 		return (error);
172 	if ((error = fstat(fd, &buf)) != 0)
173 		return (error);
174 	nv_responselen = buf.st_size;
175 
176 	if ((nv_response = malloc(nv_responselen)) == NULL)
177 		return (-1);
178 	bytesread = read(fd, nv_response, nv_responselen);
179 	if (bytesread != nv_responselen) {
180 		free(nv_response);
181 		errno = EFAULT;
182 		return (-1);
183 	}
184 
185 	if (nvunpacker(nv_response, nv_responselen, response)) {
186 		free(nv_response);
187 		errno = ENOMEM;
188 		return (-1);
189 	}
190 
191 	free(nv_response);
192 	return (0);
193 }
194 
195 static int
196 csetattr(int fd, nvlist_t *request)
197 {
198 	int error, saveerrno;
199 	int byteswritten;
200 	void *nv_request;
201 	size_t nv_requestlen;
202 
203 	if (error = attrat_init())
204 		return (error);
205 
206 	if ((error = attr_nv_pack(request, &nv_request, &nv_requestlen)) != 0)
207 		return (error);
208 
209 	byteswritten = write(fd, nv_request, nv_requestlen);
210 	if (byteswritten != nv_requestlen) {
211 		saveerrno = errno;
212 		free(nv_request);
213 		errno = saveerrno;
214 		return (-1);
215 	}
216 
217 	free(nv_request);
218 	return (0);
219 }
220 
221 int
222 fgetattr(int basefd, xattr_view_t view, nvlist_t **response)
223 {
224 	int error, saveerrno, xattrfd;
225 
226 	if ((xattrfd = xattr_openat(basefd, view, O_XATTR)) < 0)
227 		return (xattrfd);
228 
229 	error = cgetattr(xattrfd, response);
230 	saveerrno = errno;
231 	(void) close(xattrfd);
232 	errno = saveerrno;
233 	return (error);
234 }
235 
236 int
237 fsetattr(int basefd, xattr_view_t view, nvlist_t *request)
238 {
239 	int error, saveerrno, xattrfd;
240 
241 	if ((xattrfd = xattr_openat(basefd, view, O_RDWR | O_XATTR)) < 0)
242 		return (xattrfd);
243 	error = csetattr(xattrfd, request);
244 	saveerrno = errno;
245 	(void) close(xattrfd);
246 	errno = saveerrno;
247 	return (error);
248 }
249 
250 int
251 getattrat(int basefd, xattr_view_t view, const char *name, nvlist_t **response)
252 {
253 	int error, saveerrno, namefd, xattrfd;
254 
255 	if ((namefd = __openattrdirat(basefd, name)) < 0)
256 		return (namefd);
257 
258 	if ((xattrfd = xattr_openat(namefd, view, 0)) < 0) {
259 		saveerrno = errno;
260 		(void) close(namefd);
261 		errno = saveerrno;
262 		return (xattrfd);
263 	}
264 
265 	error = cgetattr(xattrfd, response);
266 	saveerrno = errno;
267 	(void) close(namefd);
268 	(void) close(xattrfd);
269 	errno = saveerrno;
270 	return (error);
271 }
272 
273 int
274 setattrat(int basefd, xattr_view_t view, const char *name, nvlist_t *request)
275 {
276 	int error, saveerrno, namefd, xattrfd;
277 
278 	if ((namefd = __openattrdirat(basefd, name)) < 0)
279 		return (namefd);
280 
281 	if ((xattrfd = xattr_openat(namefd, view, O_RDWR)) < 0) {
282 		saveerrno = errno;
283 		(void) close(namefd);
284 		errno = saveerrno;
285 		return (xattrfd);
286 	}
287 
288 	error = csetattr(xattrfd, request);
289 	saveerrno = errno;
290 	(void) close(namefd);
291 	(void) close(xattrfd);
292 	errno = saveerrno;
293 	return (error);
294 }
295 
296 void
297 libc_nvlist_free(nvlist_t *nvp)
298 {
299 	nvfree(nvp);
300 }
301 
302 int
303 libc_nvlist_lookup_uint64(nvlist_t *nvp, const char *name, uint64_t *value)
304 {
305 	return (nvlookupint64(nvp, name, value));
306 }
307