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