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