xref: /illumos-gate/usr/src/lib/libc/port/gen/attrat.c (revision 00ae5933)
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  */
218fd04b83SRoger A. Faulkner 
22da6c28aaSamw /*
238fd04b83SRoger A. Faulkner  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24da6c28aaSamw  * Use is subject to license terms.
25da6c28aaSamw  */
26da6c28aaSamw 
277257d1b4Sraf #include "lint.h"
28da6c28aaSamw #include <string.h>
29da6c28aaSamw #include <stdlib.h>
30da6c28aaSamw #include <errno.h>
31da6c28aaSamw #include <fcntl.h>
32da6c28aaSamw #include <mtlib.h>
33da6c28aaSamw #include <attr.h>
34da6c28aaSamw #include <sys/types.h>
35da6c28aaSamw #include <sys/syscall.h>
36da6c28aaSamw #include <sys/stat.h>
378fd04b83SRoger A. Faulkner #include <sys/file.h>
38da6c28aaSamw #include <unistd.h>
39da6c28aaSamw #include <dlfcn.h>
40da6c28aaSamw #include <stdio.h>
418cd45542Sraf #include <atomic.h>
42da6c28aaSamw 
43da6c28aaSamw static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int);
44da6c28aaSamw static int (*nvsize)(nvlist_t *, size_t *, int);
45da6c28aaSamw static int (*nvunpacker)(char *, size_t, nvlist_t **);
46d8ac9b2dSmarks static int (*nvfree)(nvlist_t *);
47d8ac9b2dSmarks static int (*nvlookupint64)(nvlist_t *, const char *, uint64_t *);
48d8ac9b2dSmarks 
49da6c28aaSamw static mutex_t attrlock = DEFAULTMUTEX;
50da6c28aaSamw static int initialized;
51da6c28aaSamw 
52da6c28aaSamw static char *xattr_view_name[XATTR_VIEW_LAST] = {
53da6c28aaSamw 	VIEW_READONLY,
54da6c28aaSamw 	VIEW_READWRITE
55da6c28aaSamw };
56da6c28aaSamw 
578fd04b83SRoger A. Faulkner int
__openattrdirat(int fd,const char * name)588fd04b83SRoger A. Faulkner __openattrdirat(int fd, const char *name)
598fd04b83SRoger A. Faulkner {
608fd04b83SRoger A. Faulkner 	return (syscall(SYS_openat, fd, name, FXATTRDIROPEN, 0));
618fd04b83SRoger A. Faulkner }
628fd04b83SRoger A. Faulkner 
63da6c28aaSamw static int
attrat_init()64da6c28aaSamw attrat_init()
65da6c28aaSamw {
668cd45542Sraf 	void *packer;
678cd45542Sraf 	void *sizer;
688cd45542Sraf 	void *unpacker;
698cd45542Sraf 	void *freer;
708cd45542Sraf 	void *looker;
718cd45542Sraf 
72da6c28aaSamw 	if (initialized == 0) {
738cd45542Sraf 		void *handle = dlopen("libnvpair.so.1", RTLD_LAZY);
748cd45542Sraf 
758cd45542Sraf 		if (handle == NULL ||
768cd45542Sraf 		    (packer = dlsym(handle, "nvlist_pack")) == NULL ||
778cd45542Sraf 		    (sizer = dlsym(handle, "nvlist_size")) == NULL ||
788cd45542Sraf 		    (unpacker = dlsym(handle, "nvlist_unpack")) == NULL ||
798cd45542Sraf 		    (freer = dlsym(handle, "nvlist_free")) == NULL ||
808cd45542Sraf 		    (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL) {
818cd45542Sraf 			if (handle)
825ad42b1bSSurya Prakki 				(void) dlclose(handle);
838cd45542Sraf 			return (-1);
848cd45542Sraf 		}
85f90fe29eSraf 
86da6c28aaSamw 		lmutex_lock(&attrlock);
878cd45542Sraf 
888cd45542Sraf 		if (initialized != 0) {
89da6c28aaSamw 			lmutex_unlock(&attrlock);
905ad42b1bSSurya Prakki 			(void) dlclose(handle);
91da6c28aaSamw 			return (0);
92da6c28aaSamw 		}
93da6c28aaSamw 
948cd45542Sraf 		nvpacker = (int (*)(nvlist_t *, char **, size_t *, int, int))
958cd45542Sraf 		    packer;
968cd45542Sraf 		nvsize = (int (*)(nvlist_t *, size_t *, int))
978cd45542Sraf 		    sizer;
988cd45542Sraf 		nvunpacker = (int (*)(char *, size_t, nvlist_t **))
998cd45542Sraf 		    unpacker;
1008cd45542Sraf 		nvfree = (int (*)(nvlist_t *))
1018cd45542Sraf 		    freer;
1028cd45542Sraf 		nvlookupint64 = (int (*)(nvlist_t *, const char *, uint64_t *))
1038cd45542Sraf 		    looker;
104da6c28aaSamw 
1058cd45542Sraf 		membar_producer();
106da6c28aaSamw 		initialized = 1;
107da6c28aaSamw 		lmutex_unlock(&attrlock);
108da6c28aaSamw 	}
109da6c28aaSamw 	return (0);
110da6c28aaSamw }
111da6c28aaSamw 
112da6c28aaSamw static int
attr_nv_pack(nvlist_t * request,void ** nv_request,size_t * nv_requestlen)113da6c28aaSamw attr_nv_pack(nvlist_t *request, void **nv_request, size_t *nv_requestlen)
114da6c28aaSamw {
115da6c28aaSamw 	size_t bufsize;
116da6c28aaSamw 	char *packbuf = NULL;
117da6c28aaSamw 
118da6c28aaSamw 	if (nvsize(request, &bufsize, NV_ENCODE_XDR) != 0) {
119575bd8a2Smarks 		errno = EINVAL;
120575bd8a2Smarks 		return (-1);
121da6c28aaSamw 	}
122da6c28aaSamw 
123da6c28aaSamw 	packbuf = malloc(bufsize);
124da6c28aaSamw 	if (packbuf == NULL)
125575bd8a2Smarks 		return (-1);
126da6c28aaSamw 	if (nvpacker(request, &packbuf, &bufsize, NV_ENCODE_XDR, 0) != 0) {
127da6c28aaSamw 		free(packbuf);
128575bd8a2Smarks 		errno = EINVAL;
129575bd8a2Smarks 		return (-1);
130da6c28aaSamw 	} else {
131da6c28aaSamw 		*nv_request = (void *)packbuf;
132da6c28aaSamw 		*nv_requestlen = bufsize;
133da6c28aaSamw 	}
134da6c28aaSamw 	return (0);
135da6c28aaSamw }
136da6c28aaSamw 
137da6c28aaSamw static const char *
view_to_name(xattr_view_t view)138da6c28aaSamw view_to_name(xattr_view_t view)
139da6c28aaSamw {
140da6c28aaSamw 	if (view >= XATTR_VIEW_LAST || view < 0)
141da6c28aaSamw 		return (NULL);
142da6c28aaSamw 	return (xattr_view_name[view]);
143da6c28aaSamw }
144da6c28aaSamw 
145da6c28aaSamw static int
xattr_openat(int basefd,xattr_view_t view,int mode)146da6c28aaSamw xattr_openat(int basefd, xattr_view_t view, int mode)
147da6c28aaSamw {
148da6c28aaSamw 	const char *xattrname;
149da6c28aaSamw 	int xattrfd;
150da6c28aaSamw 	int oflag;
151da6c28aaSamw 
152da6c28aaSamw 	switch (view) {
153da6c28aaSamw 	case XATTR_VIEW_READONLY:
154da6c28aaSamw 		oflag = O_RDONLY;
155da6c28aaSamw 		break;
156da6c28aaSamw 	case XATTR_VIEW_READWRITE:
157da6c28aaSamw 		oflag = mode & O_RDWR;
158da6c28aaSamw 		break;
159da6c28aaSamw 	default:
160575bd8a2Smarks 		errno = EINVAL;
161da6c28aaSamw 		return (-1);
162da6c28aaSamw 	}
163da6c28aaSamw 	if (mode & O_XATTR)
164da6c28aaSamw 		oflag |= O_XATTR;
165da6c28aaSamw 
166da6c28aaSamw 	xattrname = view_to_name(view);
167da6c28aaSamw 	xattrfd = openat(basefd, xattrname, oflag);
168da6c28aaSamw 	if (xattrfd < 0)
169da6c28aaSamw 		return (xattrfd);
170da6c28aaSamw 	/* Don't cache sysattr info (advisory) */
171da6c28aaSamw 	(void) directio(xattrfd, DIRECTIO_ON);
172da6c28aaSamw 	return (xattrfd);
173da6c28aaSamw }
174da6c28aaSamw 
175da6c28aaSamw static int
cgetattr(int fd,nvlist_t ** response)176da6c28aaSamw cgetattr(int fd, nvlist_t **response)
177da6c28aaSamw {
178da6c28aaSamw 	int error;
179da6c28aaSamw 	int bytesread;
180da6c28aaSamw 	void *nv_response;
181da6c28aaSamw 	size_t nv_responselen;
182da6c28aaSamw 	struct stat buf;
183da6c28aaSamw 
184*00ae5933SToomas Soome 	if ((error = attrat_init()) != 0)
185575bd8a2Smarks 		return (error);
186da6c28aaSamw 	if ((error = fstat(fd, &buf)) != 0)
187575bd8a2Smarks 		return (error);
188da6c28aaSamw 	nv_responselen = buf.st_size;
189da6c28aaSamw 
190da6c28aaSamw 	if ((nv_response = malloc(nv_responselen)) == NULL)
191575bd8a2Smarks 		return (-1);
192da6c28aaSamw 	bytesread = read(fd, nv_response, nv_responselen);
193575bd8a2Smarks 	if (bytesread != nv_responselen) {
194575bd8a2Smarks 		free(nv_response);
195575bd8a2Smarks 		errno = EFAULT;
196575bd8a2Smarks 		return (-1);
197575bd8a2Smarks 	}
198575bd8a2Smarks 
199575bd8a2Smarks 	if (nvunpacker(nv_response, nv_responselen, response)) {
200575bd8a2Smarks 		free(nv_response);
201575bd8a2Smarks 		errno = ENOMEM;
202575bd8a2Smarks 		return (-1);
203575bd8a2Smarks 	}
204da6c28aaSamw 
205da6c28aaSamw 	free(nv_response);
206575bd8a2Smarks 	return (0);
207da6c28aaSamw }
208da6c28aaSamw 
209da6c28aaSamw static int
csetattr(int fd,nvlist_t * request)210da6c28aaSamw csetattr(int fd, nvlist_t *request)
211da6c28aaSamw {
212da6c28aaSamw 	int error, saveerrno;
213da6c28aaSamw 	int byteswritten;
214da6c28aaSamw 	void *nv_request;
215da6c28aaSamw 	size_t nv_requestlen;
216da6c28aaSamw 
217*00ae5933SToomas Soome 	if ((error = attrat_init()) != 0)
218575bd8a2Smarks 		return (error);
219da6c28aaSamw 
220da6c28aaSamw 	if ((error = attr_nv_pack(request, &nv_request, &nv_requestlen)) != 0)
221575bd8a2Smarks 		return (error);
222da6c28aaSamw 
223da6c28aaSamw 	byteswritten = write(fd, nv_request, nv_requestlen);
224da6c28aaSamw 	if (byteswritten != nv_requestlen) {
225da6c28aaSamw 		saveerrno = errno;
226da6c28aaSamw 		free(nv_request);
227da6c28aaSamw 		errno = saveerrno;
228575bd8a2Smarks 		return (-1);
229da6c28aaSamw 	}
230da6c28aaSamw 
231da6c28aaSamw 	free(nv_request);
232da6c28aaSamw 	return (0);
233da6c28aaSamw }
234da6c28aaSamw 
235da6c28aaSamw int
fgetattr(int basefd,xattr_view_t view,nvlist_t ** response)236da6c28aaSamw fgetattr(int basefd, xattr_view_t view, nvlist_t **response)
237da6c28aaSamw {
238da6c28aaSamw 	int error, saveerrno, xattrfd;
239da6c28aaSamw 
240da6c28aaSamw 	if ((xattrfd = xattr_openat(basefd, view, O_XATTR)) < 0)
241da6c28aaSamw 		return (xattrfd);
242da6c28aaSamw 
243da6c28aaSamw 	error = cgetattr(xattrfd, response);
244da6c28aaSamw 	saveerrno = errno;
245da6c28aaSamw 	(void) close(xattrfd);
246da6c28aaSamw 	errno = saveerrno;
247da6c28aaSamw 	return (error);
248da6c28aaSamw }
249da6c28aaSamw 
250da6c28aaSamw int
fsetattr(int basefd,xattr_view_t view,nvlist_t * request)251da6c28aaSamw fsetattr(int basefd, xattr_view_t view, nvlist_t *request)
252da6c28aaSamw {
253da6c28aaSamw 	int error, saveerrno, xattrfd;
254da6c28aaSamw 
255da6c28aaSamw 	if ((xattrfd = xattr_openat(basefd, view, O_RDWR | O_XATTR)) < 0)
256da6c28aaSamw 		return (xattrfd);
257da6c28aaSamw 	error = csetattr(xattrfd, request);
258da6c28aaSamw 	saveerrno = errno;
259da6c28aaSamw 	(void) close(xattrfd);
260da6c28aaSamw 	errno = saveerrno;
261da6c28aaSamw 	return (error);
262da6c28aaSamw }
263da6c28aaSamw 
264da6c28aaSamw int
getattrat(int basefd,xattr_view_t view,const char * name,nvlist_t ** response)265da6c28aaSamw getattrat(int basefd, xattr_view_t view, const char *name, nvlist_t **response)
266da6c28aaSamw {
267da6c28aaSamw 	int error, saveerrno, namefd, xattrfd;
268da6c28aaSamw 
269da6c28aaSamw 	if ((namefd = __openattrdirat(basefd, name)) < 0)
270da6c28aaSamw 		return (namefd);
271da6c28aaSamw 
272da6c28aaSamw 	if ((xattrfd = xattr_openat(namefd, view, 0)) < 0) {
273da6c28aaSamw 		saveerrno = errno;
274da6c28aaSamw 		(void) close(namefd);
275da6c28aaSamw 		errno = saveerrno;
276da6c28aaSamw 		return (xattrfd);
277da6c28aaSamw 	}
278da6c28aaSamw 
279da6c28aaSamw 	error = cgetattr(xattrfd, response);
280da6c28aaSamw 	saveerrno = errno;
281da6c28aaSamw 	(void) close(namefd);
282da6c28aaSamw 	(void) close(xattrfd);
283da6c28aaSamw 	errno = saveerrno;
284da6c28aaSamw 	return (error);
285da6c28aaSamw }
286da6c28aaSamw 
287da6c28aaSamw int
setattrat(int basefd,xattr_view_t view,const char * name,nvlist_t * request)288da6c28aaSamw setattrat(int basefd, xattr_view_t view, const char *name, nvlist_t *request)
289da6c28aaSamw {
290da6c28aaSamw 	int error, saveerrno, namefd, xattrfd;
291da6c28aaSamw 
292da6c28aaSamw 	if ((namefd = __openattrdirat(basefd, name)) < 0)
293da6c28aaSamw 		return (namefd);
294da6c28aaSamw 
295da6c28aaSamw 	if ((xattrfd = xattr_openat(namefd, view, O_RDWR)) < 0) {
296da6c28aaSamw 		saveerrno = errno;
297da6c28aaSamw 		(void) close(namefd);
298da6c28aaSamw 		errno = saveerrno;
299da6c28aaSamw 		return (xattrfd);
300da6c28aaSamw 	}
301da6c28aaSamw 
302da6c28aaSamw 	error = csetattr(xattrfd, request);
303da6c28aaSamw 	saveerrno = errno;
304da6c28aaSamw 	(void) close(namefd);
305da6c28aaSamw 	(void) close(xattrfd);
306da6c28aaSamw 	errno = saveerrno;
307da6c28aaSamw 	return (error);
308da6c28aaSamw }
309d8ac9b2dSmarks 
310d8ac9b2dSmarks void
libc_nvlist_free(nvlist_t * nvp)311d8ac9b2dSmarks libc_nvlist_free(nvlist_t *nvp)
312d8ac9b2dSmarks {
313ce87906fSToomas Soome 	(void) nvfree(nvp);
314d8ac9b2dSmarks }
315d8ac9b2dSmarks 
316d8ac9b2dSmarks int
libc_nvlist_lookup_uint64(nvlist_t * nvp,const char * name,uint64_t * value)317d8ac9b2dSmarks libc_nvlist_lookup_uint64(nvlist_t *nvp, const char *name, uint64_t *value)
318d8ac9b2dSmarks {
319d8ac9b2dSmarks 	return (nvlookupint64(nvp, name, value));
320d8ac9b2dSmarks }
321