1da6c28aamw/*
2da6c28aamw * CDDL HEADER START
3da6c28aamw *
4da6c28aamw * The contents of this file are subject to the terms of the
5da6c28aamw * Common Development and Distribution License (the "License").
6da6c28aamw * You may not use this file except in compliance with the License.
7da6c28aamw *
8da6c28aamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aamw * or http://www.opensolaris.org/os/licensing.
10da6c28aamw * See the License for the specific language governing permissions
11da6c28aamw * and limitations under the License.
12da6c28aamw *
13da6c28aamw * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aamw * If applicable, add the following below this CDDL HEADER, with the
16da6c28aamw * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aamw * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aamw *
19da6c28aamw * CDDL HEADER END
20da6c28aamw */
218fd04b8Roger A. Faulkner
22da6c28aamw/*
238fd04b8Roger A. Faulkner * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24da6c28aamw * Use is subject to license terms.
25da6c28aamw */
26da6c28aamw
277257d1braf#include "lint.h"
28da6c28aamw#include <string.h>
29da6c28aamw#include <stdlib.h>
30da6c28aamw#include <errno.h>
31da6c28aamw#include <fcntl.h>
32da6c28aamw#include <mtlib.h>
33da6c28aamw#include <attr.h>
34da6c28aamw#include <sys/types.h>
35da6c28aamw#include <sys/syscall.h>
36da6c28aamw#include <sys/stat.h>
378fd04b8Roger A. Faulkner#include <sys/file.h>
38da6c28aamw#include <unistd.h>
39da6c28aamw#include <dlfcn.h>
40da6c28aamw#include <stdio.h>
418cd4554raf#include <atomic.h>
42da6c28aamw
43da6c28aamwstatic int (*nvpacker)(nvlist_t *, char **, size_t *, int, int);
44da6c28aamwstatic int (*nvsize)(nvlist_t *, size_t *, int);
45da6c28aamwstatic int (*nvunpacker)(char *, size_t, nvlist_t **);
46d8ac9b2marksstatic int (*nvfree)(nvlist_t *);
47d8ac9b2marksstatic int (*nvlookupint64)(nvlist_t *, const char *, uint64_t *);
48d8ac9b2marks
49da6c28aamwstatic mutex_t attrlock = DEFAULTMUTEX;
50da6c28aamwstatic int initialized;
51da6c28aamw
52da6c28aamwstatic char *xattr_view_name[XATTR_VIEW_LAST] = {
53da6c28aamw	VIEW_READONLY,
54da6c28aamw	VIEW_READWRITE
55da6c28aamw};
56da6c28aamw
578fd04b8Roger A. Faulknerint
588fd04b8Roger A. Faulkner__openattrdirat(int fd, const char *name)
598fd04b8Roger A. Faulkner{
608fd04b8Roger A. Faulkner	return (syscall(SYS_openat, fd, name, FXATTRDIROPEN, 0));
618fd04b8Roger A. Faulkner}
628fd04b8Roger A. Faulkner
63da6c28aamwstatic int
64da6c28aamwattrat_init()
65da6c28aamw{
668cd4554raf	void *packer;
678cd4554raf	void *sizer;
688cd4554raf	void *unpacker;
698cd4554raf	void *freer;
708cd4554raf	void *looker;
718cd4554raf
72da6c28aamw	if (initialized == 0) {
738cd4554raf		void *handle = dlopen("libnvpair.so.1", RTLD_LAZY);
748cd4554raf
758cd4554raf		if (handle == NULL ||
768cd4554raf		    (packer = dlsym(handle, "nvlist_pack")) == NULL ||
778cd4554raf		    (sizer = dlsym(handle, "nvlist_size")) == NULL ||
788cd4554raf		    (unpacker = dlsym(handle, "nvlist_unpack")) == NULL ||
798cd4554raf		    (freer = dlsym(handle, "nvlist_free")) == NULL ||
808cd4554raf		    (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL) {
818cd4554raf			if (handle)
825ad42b1Surya Prakki				(void) dlclose(handle);
838cd4554raf			return (-1);
848cd4554raf		}
85f90fe29raf
86da6c28aamw		lmutex_lock(&attrlock);
878cd4554raf
888cd4554raf		if (initialized != 0) {
89da6c28aamw			lmutex_unlock(&attrlock);
905ad42b1Surya Prakki			(void) dlclose(handle);
91da6c28aamw			return (0);
92da6c28aamw		}
93da6c28aamw
948cd4554raf		nvpacker = (int (*)(nvlist_t *, char **, size_t *, int, int))
958cd4554raf		    packer;
968cd4554raf		nvsize = (int (*)(nvlist_t *, size_t *, int))
978cd4554raf		    sizer;
988cd4554raf		nvunpacker = (int (*)(char *, size_t, nvlist_t **))
998cd4554raf		    unpacker;
1008cd4554raf		nvfree = (int (*)(nvlist_t *))
1018cd4554raf		    freer;
1028cd4554raf		nvlookupint64 = (int (*)(nvlist_t *, const char *, uint64_t *))
1038cd4554raf		    looker;
104da6c28aamw
1058cd4554raf		membar_producer();
106da6c28aamw		initialized = 1;
107da6c28aamw		lmutex_unlock(&attrlock);
108da6c28aamw	}
109da6c28aamw	return (0);
110da6c28aamw}
111da6c28aamw
112da6c28aamwstatic int
113da6c28aamwattr_nv_pack(nvlist_t *request, void **nv_request, size_t *nv_requestlen)
114da6c28aamw{
115da6c28aamw	size_t bufsize;
116da6c28aamw	char *packbuf = NULL;
117da6c28aamw
118da6c28aamw	if (nvsize(request, &bufsize, NV_ENCODE_XDR) != 0) {
119575bd8amarks		errno = EINVAL;
120575bd8amarks		return (-1);
121da6c28aamw	}
122da6c28aamw
123da6c28aamw	packbuf = malloc(bufsize);
124da6c28aamw	if (packbuf == NULL)
125575bd8amarks		return (-1);
126da6c28aamw	if (nvpacker(request, &packbuf, &bufsize, NV_ENCODE_XDR, 0) != 0) {
127da6c28aamw		free(packbuf);
128575bd8amarks		errno = EINVAL;
129575bd8amarks		return (-1);
130da6c28aamw	} else {
131da6c28aamw		*nv_request = (void *)packbuf;
132da6c28aamw		*nv_requestlen = bufsize;
133da6c28aamw	}
134da6c28aamw	return (0);
135da6c28aamw}
136da6c28aamw
137da6c28aamwstatic const char *
138da6c28aamwview_to_name(xattr_view_t view)
139da6c28aamw{
140da6c28aamw	if (view >= XATTR_VIEW_LAST || view < 0)
141da6c28aamw		return (NULL);
142da6c28aamw	return (xattr_view_name[view]);
143da6c28aamw}
144da6c28aamw
145da6c28aamwstatic int
146da6c28aamwxattr_openat(int basefd, xattr_view_t view, int mode)
147da6c28aamw{
148da6c28aamw	const char *xattrname;
149da6c28aamw	int xattrfd;
150da6c28aamw	int oflag;
151da6c28aamw
152da6c28aamw	switch (view) {
153da6c28aamw	case XATTR_VIEW_READONLY:
154da6c28aamw		oflag = O_RDONLY;
155da6c28aamw		break;
156da6c28aamw	case XATTR_VIEW_READWRITE:
157da6c28aamw		oflag = mode & O_RDWR;
158da6c28aamw		break;
159da6c28aamw	default:
160575bd8amarks		errno = EINVAL;
161da6c28aamw		return (-1);
162da6c28aamw	}
163da6c28aamw	if (mode & O_XATTR)
164da6c28aamw		oflag |= O_XATTR;
165da6c28aamw
166da6c28aamw	xattrname = view_to_name(view);
167da6c28aamw	xattrfd = openat(basefd, xattrname, oflag);
168da6c28aamw	if (xattrfd < 0)
169da6c28aamw		return (xattrfd);
170da6c28aamw	/* Don't cache sysattr info (advisory) */
171da6c28aamw	(void) directio(xattrfd, DIRECTIO_ON);
172da6c28aamw	return (xattrfd);
173da6c28aamw}
174da6c28aamw
175da6c28aamwstatic int
176da6c28aamwcgetattr(int fd, nvlist_t **response)
177da6c28aamw{
178da6c28aamw	int error;
179da6c28aamw	int bytesread;
180da6c28aamw	void *nv_response;
181da6c28aamw	size_t nv_responselen;
182da6c28aamw	struct stat buf;
183da6c28aamw
184da6c28aamw	if (error = attrat_init())
185575bd8amarks		return (error);
186da6c28aamw	if ((error = fstat(fd, &buf)) != 0)
187575bd8amarks		return (error);
188da6c28aamw	nv_responselen = buf.st_size;
189da6c28aamw
190da6c28aamw	if ((nv_response = malloc(nv_responselen)) == NULL)
191575bd8amarks		return (-1);
192da6c28aamw	bytesread = read(fd, nv_response, nv_responselen);
193575bd8amarks	if (bytesread != nv_responselen) {
194575bd8amarks		free(nv_response);
195575bd8amarks		errno = EFAULT;
196575bd8amarks		return (-1);
197575bd8amarks	}
198575bd8amarks
199575bd8amarks	if (nvunpacker(nv_response, nv_responselen, response)) {
200575bd8amarks		free(nv_response);
201575bd8amarks		errno = ENOMEM;
202575bd8amarks		return (-1);
203575bd8amarks	}
204da6c28aamw
205da6c28aamw	free(nv_response);
206575bd8amarks	return (0);
207da6c28aamw}
208da6c28aamw
209da6c28aamwstatic int
210da6c28aamwcsetattr(int fd, nvlist_t *request)
211da6c28aamw{
212da6c28aamw	int error, saveerrno;
213da6c28aamw	int byteswritten;
214da6c28aamw	void *nv_request;
215da6c28aamw	size_t nv_requestlen;
216da6c28aamw
217da6c28aamw	if (error = attrat_init())
218575bd8amarks		return (error);
219