attrat.c revision 5902:0a35a89d8450
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#include "synonyms.h"
29#include <string.h>
30#include <stdlib.h>
31#include <errno.h>
32#include <fcntl.h>
33#include <mtlib.h>
34#include <attr.h>
35#include <sys/types.h>
36#include <sys/syscall.h>
37#include <sys/stat.h>
38#include <sys/filio.h>
39#include <unistd.h>
40#include <dlfcn.h>
41#include <stdio.h>
42
43static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int);
44static int (*nvsize)(nvlist_t *, size_t *, int);
45static int (*nvunpacker)(char *, size_t, nvlist_t **);
46static mutex_t attrlock = DEFAULTMUTEX;
47static int initialized;
48extern int __openattrdirat(int basefd, const char *name);
49
50static char *xattr_view_name[XATTR_VIEW_LAST] = {
51	VIEW_READONLY,
52	VIEW_READWRITE
53};
54
55static int
56attrat_init()
57{
58	if (initialized == 0) {
59		lmutex_lock(&attrlock);
60		if (initialized == 1) {
61			lmutex_unlock(&attrlock);
62			return (0);
63		}
64
65		void *libnvhandle = dlopen("libnvpair.so.1", RTLD_LAZY);
66		if (libnvhandle == NULL || (nvpacker = (int (*)(nvlist_t *,
67		    char **, size_t *, int, int)) dlsym(libnvhandle,
68		    "nvlist_pack")) == NULL ||
69		    (nvsize = (int (*)(nvlist_t *,
70		    size_t *, int)) dlsym(libnvhandle,
71		    "nvlist_size")) == NULL ||
72		    (nvunpacker = (int (*)(char *, size_t,
73		    nvlist_t **)) dlsym(libnvhandle,
74		    "nvlist_unpack")) == NULL) {
75			if (libnvhandle)
76				dlclose(libnvhandle);
77			lmutex_unlock(&attrlock);
78			return (-1);
79		}
80
81		initialized = 1;
82		lmutex_unlock(&attrlock);
83	}
84	return (0);
85}
86
87static int
88attr_nv_pack(nvlist_t *request, void **nv_request, size_t *nv_requestlen)
89{
90	size_t bufsize;
91	char *packbuf = NULL;
92
93	if (nvsize(request, &bufsize, NV_ENCODE_XDR) != 0) {
94		errno = EINVAL;
95		return (-1);
96	}
97
98	packbuf = malloc(bufsize);
99	if (packbuf == NULL)
100		return (-1);
101	if (nvpacker(request, &packbuf, &bufsize, NV_ENCODE_XDR, 0) != 0) {
102		free(packbuf);
103		errno = EINVAL;
104		return (-1);
105	} else {
106		*nv_request = (void *)packbuf;
107		*nv_requestlen = bufsize;
108	}
109	return (0);
110}
111
112static const char *
113view_to_name(xattr_view_t view)
114{
115	if (view >= XATTR_VIEW_LAST || view < 0)
116		return (NULL);
117	return (xattr_view_name[view]);
118}
119
120static int
121xattr_openat(int basefd, xattr_view_t view, int mode)
122{
123	const char *xattrname;
124	int xattrfd;
125	int oflag;
126
127	switch (view) {
128	case XATTR_VIEW_READONLY:
129		oflag = O_RDONLY;
130		break;
131	case XATTR_VIEW_READWRITE:
132		oflag = mode & O_RDWR;
133		break;
134	default:
135		errno = EINVAL;
136		return (-1);
137	}
138	if (mode & O_XATTR)
139		oflag |= O_XATTR;
140
141	xattrname = view_to_name(view);
142	xattrfd = openat(basefd, xattrname, oflag);
143	if (xattrfd < 0)
144		return (xattrfd);
145	/* Don't cache sysattr info (advisory) */
146	(void) directio(xattrfd, DIRECTIO_ON);
147	return (xattrfd);
148}
149
150static int
151cgetattr(int fd, nvlist_t **response)
152{
153	int error;
154	int bytesread;
155	void *nv_response;
156	size_t nv_responselen;
157	struct stat buf;
158
159	if (error = attrat_init())
160		return (error);
161	if ((error = fstat(fd, &buf)) != 0)
162		return (error);
163	nv_responselen = buf.st_size;
164
165	if ((nv_response = malloc(nv_responselen)) == NULL)
166		return (-1);
167	bytesread = read(fd, nv_response, nv_responselen);
168	if (bytesread != nv_responselen) {
169		free(nv_response);
170		errno = EFAULT;
171		return (-1);
172	}
173
174	if (nvunpacker(nv_response, nv_responselen, response)) {
175		free(nv_response);
176		errno = ENOMEM;
177		return (-1);
178	}
179
180	free(nv_response);
181	return (0);
182}
183
184static int
185csetattr(int fd, nvlist_t *request)
186{
187	int error, saveerrno;
188	int byteswritten;
189	void *nv_request;
190	size_t nv_requestlen;
191
192	if (error = attrat_init())
193		return (error);
194
195	if ((error = attr_nv_pack(request, &nv_request, &nv_requestlen)) != 0)
196		return (error);
197
198	byteswritten = write(fd, nv_request, nv_requestlen);
199	if (byteswritten != nv_requestlen) {
200		saveerrno = errno;
201		free(nv_request);
202		errno = saveerrno;
203		return (-1);
204	}
205
206	free(nv_request);
207	return (0);
208}
209
210int
211fgetattr(int basefd, xattr_view_t view, nvlist_t **response)
212{
213	int error, saveerrno, xattrfd;
214
215	if ((xattrfd = xattr_openat(basefd, view, O_XATTR)) < 0)
216		return (xattrfd);
217
218	error = cgetattr(xattrfd, response);
219	saveerrno = errno;
220	(void) close(xattrfd);
221	errno = saveerrno;
222	return (error);
223}
224
225int
226fsetattr(int basefd, xattr_view_t view, nvlist_t *request)
227{
228	int error, saveerrno, xattrfd;
229
230	if ((xattrfd = xattr_openat(basefd, view, O_RDWR | O_XATTR)) < 0)
231		return (xattrfd);
232	error = csetattr(xattrfd, request);
233	saveerrno = errno;
234	(void) close(xattrfd);
235	errno = saveerrno;
236	return (error);
237}
238
239int
240getattrat(int basefd, xattr_view_t view, const char *name, nvlist_t **response)
241{
242	int error, saveerrno, namefd, xattrfd;
243
244	if ((namefd = __openattrdirat(basefd, name)) < 0)
245		return (namefd);
246
247	if ((xattrfd = xattr_openat(namefd, view, 0)) < 0) {
248		saveerrno = errno;
249		(void) close(namefd);
250		errno = saveerrno;
251		return (xattrfd);
252	}
253
254	error = cgetattr(xattrfd, response);
255	saveerrno = errno;
256	(void) close(namefd);
257	(void) close(xattrfd);
258	errno = saveerrno;
259	return (error);
260}
261
262int
263setattrat(int basefd, xattr_view_t view, const char *name, nvlist_t *request)
264{
265	int error, saveerrno, namefd, xattrfd;
266
267	if ((namefd = __openattrdirat(basefd, name)) < 0)
268		return (namefd);
269
270	if ((xattrfd = xattr_openat(namefd, view, O_RDWR)) < 0) {
271		saveerrno = errno;
272		(void) close(namefd);
273		errno = saveerrno;
274		return (xattrfd);
275	}
276
277	error = csetattr(xattrfd, request);
278	saveerrno = errno;
279	(void) close(namefd);
280	(void) close(xattrfd);
281	errno = saveerrno;
282	return (error);
283}
284