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