xref: /illumos-gate/usr/src/lib/libc/port/gen/attrat.c (revision 7257d1b4d25bfac0c802847390e98a464fd787ac)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22575bd8a2Smarks  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27da6c28aaSamw 
28*7257d1b4Sraf #include "lint.h"
29da6c28aaSamw #include <string.h>
30da6c28aaSamw #include <stdlib.h>
31da6c28aaSamw #include <errno.h>
32da6c28aaSamw #include <fcntl.h>
33da6c28aaSamw #include <mtlib.h>
34da6c28aaSamw #include <attr.h>
35da6c28aaSamw #include <sys/types.h>
36da6c28aaSamw #include <sys/syscall.h>
37da6c28aaSamw #include <sys/stat.h>
38da6c28aaSamw #include <sys/filio.h>
39da6c28aaSamw #include <unistd.h>
40da6c28aaSamw #include <dlfcn.h>
41da6c28aaSamw #include <stdio.h>
428cd45542Sraf #include <atomic.h>
43da6c28aaSamw 
44da6c28aaSamw static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int);
45da6c28aaSamw static int (*nvsize)(nvlist_t *, size_t *, int);
46da6c28aaSamw static int (*nvunpacker)(char *, size_t, nvlist_t **);
47d8ac9b2dSmarks static int (*nvfree)(nvlist_t *);
48d8ac9b2dSmarks static int (*nvlookupint64)(nvlist_t *, const char *, uint64_t *);
49d8ac9b2dSmarks 
50da6c28aaSamw static mutex_t attrlock = DEFAULTMUTEX;
51da6c28aaSamw static int initialized;
52da6c28aaSamw extern int __openattrdirat(int basefd, const char *name);
53da6c28aaSamw 
54da6c28aaSamw static char *xattr_view_name[XATTR_VIEW_LAST] = {
55da6c28aaSamw 	VIEW_READONLY,
56da6c28aaSamw 	VIEW_READWRITE
57da6c28aaSamw };
58da6c28aaSamw 
59da6c28aaSamw static int
60da6c28aaSamw attrat_init()
61da6c28aaSamw {
628cd45542Sraf 	void *packer;
638cd45542Sraf 	void *sizer;
648cd45542Sraf 	void *unpacker;
658cd45542Sraf 	void *freer;
668cd45542Sraf 	void *looker;
678cd45542Sraf 
68da6c28aaSamw 	if (initialized == 0) {
698cd45542Sraf 		void *handle = dlopen("libnvpair.so.1", RTLD_LAZY);
708cd45542Sraf 
718cd45542Sraf 		if (handle == NULL ||
728cd45542Sraf 		    (packer = dlsym(handle, "nvlist_pack")) == NULL ||
738cd45542Sraf 		    (sizer = dlsym(handle, "nvlist_size")) == NULL ||
748cd45542Sraf 		    (unpacker = dlsym(handle, "nvlist_unpack")) == NULL ||
758cd45542Sraf 		    (freer = dlsym(handle, "nvlist_free")) == NULL ||
768cd45542Sraf 		    (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL) {
778cd45542Sraf 			if (handle)
788cd45542Sraf 				dlclose(handle);
798cd45542Sraf 			return (-1);
808cd45542Sraf 		}
81f90fe29eSraf 
82da6c28aaSamw 		lmutex_lock(&attrlock);
838cd45542Sraf 
848cd45542Sraf 		if (initialized != 0) {
85da6c28aaSamw 			lmutex_unlock(&attrlock);
868cd45542Sraf 			dlclose(handle);
87da6c28aaSamw 			return (0);
88da6c28aaSamw 		}
89da6c28aaSamw 
908cd45542Sraf 		nvpacker = (int (*)(nvlist_t *, char **, size_t *, int, int))
918cd45542Sraf 		    packer;
928cd45542Sraf 		nvsize = (int (*)(nvlist_t *, size_t *, int))
938cd45542Sraf 		    sizer;
948cd45542Sraf 		nvunpacker = (int (*)(char *, size_t, nvlist_t **))
958cd45542Sraf 		    unpacker;
968cd45542Sraf 		nvfree = (int (*)(nvlist_t *))
978cd45542Sraf 		    freer;
988cd45542Sraf 		nvlookupint64 = (int (*)(nvlist_t *, const char *, uint64_t *))
998cd45542Sraf 		    looker;
100da6c28aaSamw 
1018cd45542Sraf 		membar_producer();
102da6c28aaSamw 		initialized = 1;
103da6c28aaSamw 		lmutex_unlock(&attrlock);
104da6c28aaSamw 	}
105da6c28aaSamw 	return (0);
106da6c28aaSamw }
107da6c28aaSamw 
108da6c28aaSamw static int
109da6c28aaSamw attr_nv_pack(nvlist_t *request, void **nv_request, size_t *nv_requestlen)
110da6c28aaSamw {
111da6c28aaSamw 	size_t bufsize;
112da6c28aaSamw 	char *packbuf = NULL;
113da6c28aaSamw 
114da6c28aaSamw 	if (nvsize(request, &bufsize, NV_ENCODE_XDR) != 0) {
115575bd8a2Smarks 		errno = EINVAL;
116575bd8a2Smarks 		return (-1);
117da6c28aaSamw 	}
118da6c28aaSamw 
119da6c28aaSamw 	packbuf = malloc(bufsize);
120da6c28aaSamw 	if (packbuf == NULL)
121575bd8a2Smarks 		return (-1);
122da6c28aaSamw 	if (nvpacker(request, &packbuf, &bufsize, NV_ENCODE_XDR, 0) != 0) {
123da6c28aaSamw 		free(packbuf);
124575bd8a2Smarks 		errno = EINVAL;
125575bd8a2Smarks 		return (-1);
126da6c28aaSamw 	} else {
127da6c28aaSamw 		*nv_request = (void *)packbuf;
128da6c28aaSamw 		*nv_requestlen = bufsize;
129da6c28aaSamw 	}
130da6c28aaSamw 	return (0);
131da6c28aaSamw }
132da6c28aaSamw 
133da6c28aaSamw static const char *
134da6c28aaSamw view_to_name(xattr_view_t view)
135da6c28aaSamw {
136da6c28aaSamw 	if (view >= XATTR_VIEW_LAST || view < 0)
137da6c28aaSamw 		return (NULL);
138da6c28aaSamw 	return (xattr_view_name[view]);
139da6c28aaSamw }
140da6c28aaSamw 
141da6c28aaSamw static int
142da6c28aaSamw xattr_openat(int basefd, xattr_view_t view, int mode)
143da6c28aaSamw {
144da6c28aaSamw 	const char *xattrname;
145da6c28aaSamw 	int xattrfd;
146da6c28aaSamw 	int oflag;
147da6c28aaSamw 
148da6c28aaSamw 	switch (view) {
149da6c28aaSamw 	case XATTR_VIEW_READONLY:
150da6c28aaSamw 		oflag = O_RDONLY;
151da6c28aaSamw 		break;
152da6c28aaSamw 	case XATTR_VIEW_READWRITE:
153da6c28aaSamw 		oflag = mode & O_RDWR;
154da6c28aaSamw 		break;
155da6c28aaSamw 	default:
156575bd8a2Smarks 		errno = EINVAL;
157da6c28aaSamw 		return (-1);
158da6c28aaSamw 	}
159da6c28aaSamw 	if (mode & O_XATTR)
160da6c28aaSamw 		oflag |= O_XATTR;
161da6c28aaSamw 
162da6c28aaSamw 	xattrname = view_to_name(view);
163da6c28aaSamw 	xattrfd = openat(basefd, xattrname, oflag);
164da6c28aaSamw 	if (xattrfd < 0)
165da6c28aaSamw 		return (xattrfd);
166da6c28aaSamw 	/* Don't cache sysattr info (advisory) */
167da6c28aaSamw 	(void) directio(xattrfd, DIRECTIO_ON);
168da6c28aaSamw 	return (xattrfd);
169da6c28aaSamw }
170da6c28aaSamw 
171da6c28aaSamw static int
172da6c28aaSamw cgetattr(int fd, nvlist_t **response)
173da6c28aaSamw {
174da6c28aaSamw 	int error;
175da6c28aaSamw 	int bytesread;
176da6c28aaSamw 	void *nv_response;
177da6c28aaSamw 	size_t nv_responselen;
178da6c28aaSamw 	struct stat buf;
179da6c28aaSamw 
180da6c28aaSamw 	if (error = attrat_init())
181575bd8a2Smarks 		return (error);
182da6c28aaSamw 	if ((error = fstat(fd, &buf)) != 0)
183575bd8a2Smarks 		return (error);
184da6c28aaSamw 	nv_responselen = buf.st_size;
185da6c28aaSamw 
186da6c28aaSamw 	if ((nv_response = malloc(nv_responselen)) == NULL)
187575bd8a2Smarks 		return (-1);
188da6c28aaSamw 	bytesread = read(fd, nv_response, nv_responselen);
189575bd8a2Smarks 	if (bytesread != nv_responselen) {
190575bd8a2Smarks 		free(nv_response);
191575bd8a2Smarks 		errno = EFAULT;
192575bd8a2Smarks 		return (-1);
193575bd8a2Smarks 	}
194575bd8a2Smarks 
195575bd8a2Smarks 	if (nvunpacker(nv_response, nv_responselen, response)) {
196575bd8a2Smarks 		free(nv_response);
197575bd8a2Smarks 		errno = ENOMEM;
198575bd8a2Smarks 		return (-1);
199575bd8a2Smarks 	}
200da6c28aaSamw 
201da6c28aaSamw 	free(nv_response);
202575bd8a2Smarks 	return (0);
203da6c28aaSamw }
204da6c28aaSamw 
205da6c28aaSamw static int
206da6c28aaSamw csetattr(int fd, nvlist_t *request)
207da6c28aaSamw {
208da6c28aaSamw 	int error, saveerrno;
209da6c28aaSamw 	int byteswritten;
210da6c28aaSamw 	void *nv_request;
211da6c28aaSamw 	size_t nv_requestlen;
212da6c28aaSamw 
213da6c28aaSamw 	if (error = attrat_init())
214575bd8a2Smarks 		return (error);
215da6c28aaSamw 
216da6c28aaSamw 	if ((error = attr_nv_pack(request, &nv_request, &nv_requestlen)) != 0)
217575bd8a2Smarks 		return (error);
218da6c28aaSamw 
219da6c28aaSamw 	byteswritten = write(fd, nv_request, nv_requestlen);
220da6c28aaSamw 	if (byteswritten != nv_requestlen) {
221da6c28aaSamw 		saveerrno = errno;
222da6c28aaSamw 		free(nv_request);
223da6c28aaSamw 		errno = saveerrno;
224575bd8a2Smarks 		return (-1);
225da6c28aaSamw 	}
226da6c28aaSamw 
227da6c28aaSamw 	free(nv_request);
228da6c28aaSamw 	return (0);
229da6c28aaSamw }
230da6c28aaSamw 
231da6c28aaSamw int
232da6c28aaSamw fgetattr(int basefd, xattr_view_t view, nvlist_t **response)
233da6c28aaSamw {
234da6c28aaSamw 	int error, saveerrno, xattrfd;
235da6c28aaSamw 
236da6c28aaSamw 	if ((xattrfd = xattr_openat(basefd, view, O_XATTR)) < 0)
237da6c28aaSamw 		return (xattrfd);
238da6c28aaSamw 
239da6c28aaSamw 	error = cgetattr(xattrfd, response);
240da6c28aaSamw 	saveerrno = errno;
241da6c28aaSamw 	(void) close(xattrfd);
242da6c28aaSamw 	errno = saveerrno;
243da6c28aaSamw 	return (error);
244da6c28aaSamw }
245da6c28aaSamw 
246da6c28aaSamw int
247da6c28aaSamw fsetattr(int basefd, xattr_view_t view, nvlist_t *request)
248da6c28aaSamw {
249da6c28aaSamw 	int error, saveerrno, xattrfd;
250da6c28aaSamw 
251da6c28aaSamw 	if ((xattrfd = xattr_openat(basefd, view, O_RDWR | O_XATTR)) < 0)
252da6c28aaSamw 		return (xattrfd);
253da6c28aaSamw 	error = csetattr(xattrfd, request);
254da6c28aaSamw 	saveerrno = errno;
255da6c28aaSamw 	(void) close(xattrfd);
256da6c28aaSamw 	errno = saveerrno;
257da6c28aaSamw 	return (error);
258da6c28aaSamw }
259da6c28aaSamw 
260da6c28aaSamw int
261da6c28aaSamw getattrat(int basefd, xattr_view_t view, const char *name, nvlist_t **response)
262da6c28aaSamw {
263da6c28aaSamw 	int error, saveerrno, namefd, xattrfd;
264da6c28aaSamw 
265da6c28aaSamw 	if ((namefd = __openattrdirat(basefd, name)) < 0)
266da6c28aaSamw 		return (namefd);
267da6c28aaSamw 
268da6c28aaSamw 	if ((xattrfd = xattr_openat(namefd, view, 0)) < 0) {
269da6c28aaSamw 		saveerrno = errno;
270da6c28aaSamw 		(void) close(namefd);
271da6c28aaSamw 		errno = saveerrno;
272da6c28aaSamw 		return (xattrfd);
273da6c28aaSamw 	}
274da6c28aaSamw 
275da6c28aaSamw 	error = cgetattr(xattrfd, response);
276da6c28aaSamw 	saveerrno = errno;
277da6c28aaSamw 	(void) close(namefd);
278da6c28aaSamw 	(void) close(xattrfd);
279da6c28aaSamw 	errno = saveerrno;
280da6c28aaSamw 	return (error);
281da6c28aaSamw }
282da6c28aaSamw 
283da6c28aaSamw int
284da6c28aaSamw setattrat(int basefd, xattr_view_t view, const char *name, nvlist_t *request)
285da6c28aaSamw {
286da6c28aaSamw 	int error, saveerrno, namefd, xattrfd;
287da6c28aaSamw 
288da6c28aaSamw 	if ((namefd = __openattrdirat(basefd, name)) < 0)
289da6c28aaSamw 		return (namefd);
290da6c28aaSamw 
291da6c28aaSamw 	if ((xattrfd = xattr_openat(namefd, view, O_RDWR)) < 0) {
292da6c28aaSamw 		saveerrno = errno;
293da6c28aaSamw 		(void) close(namefd);
294da6c28aaSamw 		errno = saveerrno;
295da6c28aaSamw 		return (xattrfd);
296da6c28aaSamw 	}
297da6c28aaSamw 
298da6c28aaSamw 	error = csetattr(xattrfd, request);
299da6c28aaSamw 	saveerrno = errno;
300da6c28aaSamw 	(void) close(namefd);
301da6c28aaSamw 	(void) close(xattrfd);
302da6c28aaSamw 	errno = saveerrno;
303da6c28aaSamw 	return (error);
304da6c28aaSamw }
305d8ac9b2dSmarks 
306d8ac9b2dSmarks void
307d8ac9b2dSmarks libc_nvlist_free(nvlist_t *nvp)
308d8ac9b2dSmarks {
309d8ac9b2dSmarks 	nvfree(nvp);
310d8ac9b2dSmarks }
311d8ac9b2dSmarks 
312d8ac9b2dSmarks int
313d8ac9b2dSmarks libc_nvlist_lookup_uint64(nvlist_t *nvp, const char *name, uint64_t *value)
314d8ac9b2dSmarks {
315d8ac9b2dSmarks 	return (nvlookupint64(nvp, name, value));
316d8ac9b2dSmarks }
317