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