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