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