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