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 */
21*8fd04b83SRoger A. Faulkner
22da6c28aaSamw /*
23*8fd04b83SRoger 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>
37*8fd04b83SRoger 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
57*8fd04b83SRoger A. Faulkner int
__openattrdirat(int fd,const char * name)58*8fd04b83SRoger A. Faulkner __openattrdirat(int fd, const char *name)
59*8fd04b83SRoger A. Faulkner {
60*8fd04b83SRoger A. Faulkner return (syscall(SYS_openat, fd, name, FXATTRDIROPEN, 0));
61*8fd04b83SRoger A. Faulkner }
62*8fd04b83SRoger 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);
74f90fe29eSraf
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);
83575bd8a2Smarks return (-1);
84da6c28aaSamw }
85da6c28aaSamw
868cd45542Sraf lmutex_lock(&attrlock);
878cd45542Sraf
888cd45542Sraf if (initialized != 0) {
898cd45542Sraf lmutex_unlock(&attrlock);
905ad42b1bSSurya Prakki (void) dlclose(handle);
918cd45542Sraf return (0);
928cd45542Sraf }
938cd45542Sraf
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;
1048cd45542Sraf
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
184da6c28aaSamw if (error = attrat_init())
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) {
194da6c28aaSamw 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 }
204575bd8a2Smarks
205575bd8a2Smarks 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
217da6c28aaSamw if (error = attrat_init())
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 {
313d8ac9b2dSmarks 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