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