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