xref: /illumos-gate/usr/src/lib/libc/port/gen/attrat.c (revision 56f33205c9ed776c3c909e07d52e94610a675740)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include "lint.h"
27 #include <string.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <mtlib.h>
32 #include <attr.h>
33 #include <sys/types.h>
34 #include <sys/syscall.h>
35 #include <sys/stat.h>
36 #include <sys/filio.h>
37 #include <unistd.h>
38 #include <dlfcn.h>
39 #include <stdio.h>
40 #include <atomic.h>
41 
42 static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int);
43 static int (*nvsize)(nvlist_t *, size_t *, int);
44 static int (*nvunpacker)(char *, size_t, nvlist_t **);
45 static int (*nvfree)(nvlist_t *);
46 static int (*nvlookupint64)(nvlist_t *, const char *, uint64_t *);
47 
48 static mutex_t attrlock = DEFAULTMUTEX;
49 static int initialized;
50 extern int __openattrdirat(int basefd, const char *name);
51 
52 static char *xattr_view_name[XATTR_VIEW_LAST] = {
53 	VIEW_READONLY,
54 	VIEW_READWRITE
55 };
56 
57 static int
58 attrat_init()
59 {
60 	void *packer;
61 	void *sizer;
62 	void *unpacker;
63 	void *freer;
64 	void *looker;
65 
66 	if (initialized == 0) {
67 		void *handle = dlopen("libnvpair.so.1", RTLD_LAZY);
68 
69 		if (handle == NULL ||
70 		    (packer = dlsym(handle, "nvlist_pack")) == NULL ||
71 		    (sizer = dlsym(handle, "nvlist_size")) == NULL ||
72 		    (unpacker = dlsym(handle, "nvlist_unpack")) == NULL ||
73 		    (freer = dlsym(handle, "nvlist_free")) == NULL ||
74 		    (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL) {
75 			if (handle)
76 				(void) dlclose(handle);
77 			return (-1);
78 		}
79 
80 		lmutex_lock(&attrlock);
81 
82 		if (initialized != 0) {
83 			lmutex_unlock(&attrlock);
84 			(void) dlclose(handle);
85 			return (0);
86 		}
87 
88 		nvpacker = (int (*)(nvlist_t *, char **, size_t *, int, int))
89 		    packer;
90 		nvsize = (int (*)(nvlist_t *, size_t *, int))
91 		    sizer;
92 		nvunpacker = (int (*)(char *, size_t, nvlist_t **))
93 		    unpacker;
94 		nvfree = (int (*)(nvlist_t *))
95 		    freer;
96 		nvlookupint64 = (int (*)(nvlist_t *, const char *, uint64_t *))
97 		    looker;
98 
99 		membar_producer();
100 		initialized = 1;
101 		lmutex_unlock(&attrlock);
102 	}
103 	return (0);
104 }
105 
106 static int
107 attr_nv_pack(nvlist_t *request, void **nv_request, size_t *nv_requestlen)
108 {
109 	size_t bufsize;
110 	char *packbuf = NULL;
111 
112 	if (nvsize(request, &bufsize, NV_ENCODE_XDR) != 0) {
113 		errno = EINVAL;
114 		return (-1);
115 	}
116 
117 	packbuf = malloc(bufsize);
118 	if (packbuf == NULL)
119 		return (-1);
120 	if (nvpacker(request, &packbuf, &bufsize, NV_ENCODE_XDR, 0) != 0) {
121 		free(packbuf);
122 		errno = EINVAL;
123 		return (-1);
124 	} else {
125 		*nv_request = (void *)packbuf;
126 		*nv_requestlen = bufsize;
127 	}
128 	return (0);
129 }
130 
131 static const char *
132 view_to_name(xattr_view_t view)
133 {
134 	if (view >= XATTR_VIEW_LAST || view < 0)
135 		return (NULL);
136 	return (xattr_view_name[view]);
137 }
138 
139 static int
140 xattr_openat(int basefd, xattr_view_t view, int mode)
141 {
142 	const char *xattrname;
143 	int xattrfd;
144 	int oflag;
145 
146 	switch (view) {
147 	case XATTR_VIEW_READONLY:
148 		oflag = O_RDONLY;
149 		break;
150 	case XATTR_VIEW_READWRITE:
151 		oflag = mode & O_RDWR;
152 		break;
153 	default:
154 		errno = EINVAL;
155 		return (-1);
156 	}
157 	if (mode & O_XATTR)
158 		oflag |= O_XATTR;
159 
160 	xattrname = view_to_name(view);
161 	xattrfd = openat(basefd, xattrname, oflag);
162 	if (xattrfd < 0)
163 		return (xattrfd);
164 	/* Don't cache sysattr info (advisory) */
165 	(void) directio(xattrfd, DIRECTIO_ON);
166 	return (xattrfd);
167 }
168 
169 static int
170 cgetattr(int fd, nvlist_t **response)
171 {
172 	int error;
173 	int bytesread;
174 	void *nv_response;
175 	size_t nv_responselen;
176 	struct stat buf;
177 
178 	if (error = attrat_init())
179 		return (error);
180 	if ((error = fstat(fd, &buf)) != 0)
181 		return (error);
182 	nv_responselen = buf.st_size;
183 
184 	if ((nv_response = malloc(nv_responselen)) == NULL)
185 		return (-1);
186 	bytesread = read(fd, nv_response, nv_responselen);
187 	if (bytesread != nv_responselen) {
188 		free(nv_response);
189 		errno = EFAULT;
190 		return (-1);
191 	}
192 
193 	if (nvunpacker(nv_response, nv_responselen, response)) {
194 		free(nv_response);
195 		errno = ENOMEM;
196 		return (-1);
197 	}
198 
199 	free(nv_response);
200 	return (0);
201 }
202 
203 static int
204 csetattr(int fd, nvlist_t *request)
205 {
206 	int error, saveerrno;
207 	int byteswritten;
208 	void *nv_request;
209 	size_t nv_requestlen;
210 
211 	if (error = attrat_init())
212 		return (error);
213 
214 	if ((error = attr_nv_pack(request, &nv_request, &nv_requestlen)) != 0)
215 		return (error);
216 
217 	byteswritten = write(fd, nv_request, nv_requestlen);
218 	if (byteswritten != nv_requestlen) {
219 		saveerrno = errno;
220 		free(nv_request);
221 		errno = saveerrno;
222 		return (-1);
223 	}
224 
225 	free(nv_request);
226 	return (0);
227 }
228 
229 int
230 fgetattr(int basefd, xattr_view_t view, nvlist_t **response)
231 {
232 	int error, saveerrno, xattrfd;
233 
234 	if ((xattrfd = xattr_openat(basefd, view, O_XATTR)) < 0)
235 		return (xattrfd);
236 
237 	error = cgetattr(xattrfd, response);
238 	saveerrno = errno;
239 	(void) close(xattrfd);
240 	errno = saveerrno;
241 	return (error);
242 }
243 
244 int
245 fsetattr(int basefd, xattr_view_t view, nvlist_t *request)
246 {
247 	int error, saveerrno, xattrfd;
248 
249 	if ((xattrfd = xattr_openat(basefd, view, O_RDWR | O_XATTR)) < 0)
250 		return (xattrfd);
251 	error = csetattr(xattrfd, request);
252 	saveerrno = errno;
253 	(void) close(xattrfd);
254 	errno = saveerrno;
255 	return (error);
256 }
257 
258 int
259 getattrat(int basefd, xattr_view_t view, const char *name, nvlist_t **response)
260 {
261 	int error, saveerrno, namefd, xattrfd;
262 
263 	if ((namefd = __openattrdirat(basefd, name)) < 0)
264 		return (namefd);
265 
266 	if ((xattrfd = xattr_openat(namefd, view, 0)) < 0) {
267 		saveerrno = errno;
268 		(void) close(namefd);
269 		errno = saveerrno;
270 		return (xattrfd);
271 	}
272 
273 	error = cgetattr(xattrfd, response);
274 	saveerrno = errno;
275 	(void) close(namefd);
276 	(void) close(xattrfd);
277 	errno = saveerrno;
278 	return (error);
279 }
280 
281 int
282 setattrat(int basefd, xattr_view_t view, const char *name, nvlist_t *request)
283 {
284 	int error, saveerrno, namefd, xattrfd;
285 
286 	if ((namefd = __openattrdirat(basefd, name)) < 0)
287 		return (namefd);
288 
289 	if ((xattrfd = xattr_openat(namefd, view, O_RDWR)) < 0) {
290 		saveerrno = errno;
291 		(void) close(namefd);
292 		errno = saveerrno;
293 		return (xattrfd);
294 	}
295 
296 	error = csetattr(xattrfd, request);
297 	saveerrno = errno;
298 	(void) close(namefd);
299 	(void) close(xattrfd);
300 	errno = saveerrno;
301 	return (error);
302 }
303 
304 void
305 libc_nvlist_free(nvlist_t *nvp)
306 {
307 	nvfree(nvp);
308 }
309 
310 int
311 libc_nvlist_lookup_uint64(nvlist_t *nvp, const char *name, uint64_t *value)
312 {
313 	return (nvlookupint64(nvp, name, value));
314 }
315