xref: /illumos-gate/usr/src/lib/libc/port/gen/attrat.c (revision 7b209c2c)
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 
43 static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int);
44 static int (*nvsize)(nvlist_t *, size_t *, int);
45 static int (*nvunpacker)(char *, size_t, nvlist_t **);
46 static mutex_t attrlock = DEFAULTMUTEX;
47 static int initialized;
48 extern int __openattrdirat(int basefd, const char *name);
49 
50 static char *xattr_view_name[XATTR_VIEW_LAST] = {
51 	VIEW_READONLY,
52 	VIEW_READWRITE
53 };
54 
55 static int
56 attrat_init()
57 {
58 	if (initialized == 0) {
59 		void *libnvhandle = dlopen("libnvpair.so.1", RTLD_LAZY);
60 
61 		lmutex_lock(&attrlock);
62 		if (initialized == 1) {
63 			lmutex_unlock(&attrlock);
64 			if (libnvhandle)
65 				dlclose(libnvhandle);
66 			return (0);
67 		}
68 
69 		if (libnvhandle == NULL || (nvpacker = (int (*)(nvlist_t *,
70 		    char **, size_t *, int, int)) dlsym(libnvhandle,
71 		    "nvlist_pack")) == NULL ||
72 		    (nvsize = (int (*)(nvlist_t *,
73 		    size_t *, int)) dlsym(libnvhandle,
74 		    "nvlist_size")) == NULL ||
75 		    (nvunpacker = (int (*)(char *, size_t,
76 		    nvlist_t **)) dlsym(libnvhandle,
77 		    "nvlist_unpack")) == NULL) {
78 			if (libnvhandle)
79 				dlclose(libnvhandle);
80 			lmutex_unlock(&attrlock);
81 			return (-1);
82 		}
83 
84 		initialized = 1;
85 		lmutex_unlock(&attrlock);
86 	}
87 	return (0);
88 }
89 
90 static int
91 attr_nv_pack(nvlist_t *request, void **nv_request, size_t *nv_requestlen)
92 {
93 	size_t bufsize;
94 	char *packbuf = NULL;
95 
96 	if (nvsize(request, &bufsize, NV_ENCODE_XDR) != 0) {
97 		errno = EINVAL;
98 		return (-1);
99 	}
100 
101 	packbuf = malloc(bufsize);
102 	if (packbuf == NULL)
103 		return (-1);
104 	if (nvpacker(request, &packbuf, &bufsize, NV_ENCODE_XDR, 0) != 0) {
105 		free(packbuf);
106 		errno = EINVAL;
107 		return (-1);
108 	} else {
109 		*nv_request = (void *)packbuf;
110 		*nv_requestlen = bufsize;
111 	}
112 	return (0);
113 }
114 
115 static const char *
116 view_to_name(xattr_view_t view)
117 {
118 	if (view >= XATTR_VIEW_LAST || view < 0)
119 		return (NULL);
120 	return (xattr_view_name[view]);
121 }
122 
123 static int
124 xattr_openat(int basefd, xattr_view_t view, int mode)
125 {
126 	const char *xattrname;
127 	int xattrfd;
128 	int oflag;
129 
130 	switch (view) {
131 	case XATTR_VIEW_READONLY:
132 		oflag = O_RDONLY;
133 		break;
134 	case XATTR_VIEW_READWRITE:
135 		oflag = mode & O_RDWR;
136 		break;
137 	default:
138 		errno = EINVAL;
139 		return (-1);
140 	}
141 	if (mode & O_XATTR)
142 		oflag |= O_XATTR;
143 
144 	xattrname = view_to_name(view);
145 	xattrfd = openat(basefd, xattrname, oflag);
146 	if (xattrfd < 0)
147 		return (xattrfd);
148 	/* Don't cache sysattr info (advisory) */
149 	(void) directio(xattrfd, DIRECTIO_ON);
150 	return (xattrfd);
151 }
152 
153 static int
154 cgetattr(int fd, nvlist_t **response)
155 {
156 	int error;
157 	int bytesread;
158 	void *nv_response;
159 	size_t nv_responselen;
160 	struct stat buf;
161 
162 	if (error = attrat_init())
163 		return (error);
164 	if ((error = fstat(fd, &buf)) != 0)
165 		return (error);
166 	nv_responselen = buf.st_size;
167 
168 	if ((nv_response = malloc(nv_responselen)) == NULL)
169 		return (-1);
170 	bytesread = read(fd, nv_response, nv_responselen);
171 	if (bytesread != nv_responselen) {
172 		free(nv_response);
173 		errno = EFAULT;
174 		return (-1);
175 	}
176 
177 	if (nvunpacker(nv_response, nv_responselen, response)) {
178 		free(nv_response);
179 		errno = ENOMEM;
180 		return (-1);
181 	}
182 
183 	free(nv_response);
184 	return (0);
185 }
186 
187 static int
188 csetattr(int fd, nvlist_t *request)
189 {
190 	int error, saveerrno;
191 	int byteswritten;
192 	void *nv_request;
193 	size_t nv_requestlen;
194 
195 	if (error = attrat_init())
196 		return (error);
197 
198 	if ((error = attr_nv_pack(request, &nv_request, &nv_requestlen)) != 0)
199 		return (error);
200 
201 	byteswritten = write(fd, nv_request, nv_requestlen);
202 	if (byteswritten != nv_requestlen) {
203 		saveerrno = errno;
204 		free(nv_request);
205 		errno = saveerrno;
206 		return (-1);
207 	}
208 
209 	free(nv_request);
210 	return (0);
211 }
212 
213 int
214 fgetattr(int basefd, xattr_view_t view, nvlist_t **response)
215 {
216 	int error, saveerrno, xattrfd;
217 
218 	if ((xattrfd = xattr_openat(basefd, view, O_XATTR)) < 0)
219 		return (xattrfd);
220 
221 	error = cgetattr(xattrfd, response);
222 	saveerrno = errno;
223 	(void) close(xattrfd);
224 	errno = saveerrno;
225 	return (error);
226 }
227 
228 int
229 fsetattr(int basefd, xattr_view_t view, nvlist_t *request)
230 {
231 	int error, saveerrno, xattrfd;
232 
233 	if ((xattrfd = xattr_openat(basefd, view, O_RDWR | O_XATTR)) < 0)
234 		return (xattrfd);
235 	error = csetattr(xattrfd, request);
236 	saveerrno = errno;
237 	(void) close(xattrfd);
238 	errno = saveerrno;
239 	return (error);
240 }
241 
242 int
243 getattrat(int basefd, xattr_view_t view, const char *name, nvlist_t **response)
244 {
245 	int error, saveerrno, namefd, xattrfd;
246 
247 	if ((namefd = __openattrdirat(basefd, name)) < 0)
248 		return (namefd);
249 
250 	if ((xattrfd = xattr_openat(namefd, view, 0)) < 0) {
251 		saveerrno = errno;
252 		(void) close(namefd);
253 		errno = saveerrno;
254 		return (xattrfd);
255 	}
256 
257 	error = cgetattr(xattrfd, response);
258 	saveerrno = errno;
259 	(void) close(namefd);
260 	(void) close(xattrfd);
261 	errno = saveerrno;
262 	return (error);
263 }
264 
265 int
266 setattrat(int basefd, xattr_view_t view, const char *name, nvlist_t *request)
267 {
268 	int error, saveerrno, namefd, xattrfd;
269 
270 	if ((namefd = __openattrdirat(basefd, name)) < 0)
271 		return (namefd);
272 
273 	if ((xattrfd = xattr_openat(namefd, view, O_RDWR)) < 0) {
274 		saveerrno = errno;
275 		(void) close(namefd);
276 		errno = saveerrno;
277 		return (xattrfd);
278 	}
279 
280 	error = csetattr(xattrfd, request);
281 	saveerrno = errno;
282 	(void) close(namefd);
283 	(void) close(xattrfd);
284 	errno = saveerrno;
285 	return (error);
286 }
287