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
__openattrdirat(int fd,const char * name)58 __openattrdirat(int fd, const char *name)
59 {
60 return (syscall(SYS_openat, fd, name, FXATTRDIROPEN, 0));
61 }
62
63 static int
attrat_init()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
attr_nv_pack(nvlist_t * request,void ** nv_request,size_t * nv_requestlen)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 *
view_to_name(xattr_view_t view)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
xattr_openat(int basefd,xattr_view_t view,int mode)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
cgetattr(int fd,nvlist_t ** response)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
csetattr(int fd,nvlist_t * request)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
fgetattr(int basefd,xattr_view_t view,nvlist_t ** response)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
fsetattr(int basefd,xattr_view_t view,nvlist_t * request)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
getattrat(int basefd,xattr_view_t view,const char * name,nvlist_t ** response)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
setattrat(int basefd,xattr_view_t view,const char * name,nvlist_t * request)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
libc_nvlist_free(nvlist_t * nvp)311 libc_nvlist_free(nvlist_t *nvp)
312 {
313 nvfree(nvp);
314 }
315
316 int
libc_nvlist_lookup_uint64(nvlist_t * nvp,const char * name,uint64_t * value)317 libc_nvlist_lookup_uint64(nvlist_t *nvp, const char *name, uint64_t *value)
318 {
319 return (nvlookupint64(nvp, name, value));
320 }
321