1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21*8fd04b83SRoger A. Faulkner 22da6c28aaSamw /* 23*8fd04b83SRoger A. Faulkner * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24da6c28aaSamw * Use is subject to license terms. 25da6c28aaSamw */ 26da6c28aaSamw 277257d1b4Sraf #include "lint.h" 28da6c28aaSamw #include <string.h> 29da6c28aaSamw #include <stdlib.h> 30da6c28aaSamw #include <errno.h> 31da6c28aaSamw #include <fcntl.h> 32da6c28aaSamw #include <mtlib.h> 33da6c28aaSamw #include <attr.h> 34da6c28aaSamw #include <sys/types.h> 35da6c28aaSamw #include <sys/syscall.h> 36da6c28aaSamw #include <sys/stat.h> 37*8fd04b83SRoger A. Faulkner #include <sys/file.h> 38da6c28aaSamw #include <unistd.h> 39da6c28aaSamw #include <dlfcn.h> 40da6c28aaSamw #include <stdio.h> 418cd45542Sraf #include <atomic.h> 42da6c28aaSamw 43da6c28aaSamw static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int); 44da6c28aaSamw static int (*nvsize)(nvlist_t *, size_t *, int); 45da6c28aaSamw static int (*nvunpacker)(char *, size_t, nvlist_t **); 46d8ac9b2dSmarks static int (*nvfree)(nvlist_t *); 47d8ac9b2dSmarks static int (*nvlookupint64)(nvlist_t *, const char *, uint64_t *); 48d8ac9b2dSmarks 49da6c28aaSamw static mutex_t attrlock = DEFAULTMUTEX; 50da6c28aaSamw static int initialized; 51da6c28aaSamw 52da6c28aaSamw static char *xattr_view_name[XATTR_VIEW_LAST] = { 53da6c28aaSamw VIEW_READONLY, 54da6c28aaSamw VIEW_READWRITE 55da6c28aaSamw }; 56da6c28aaSamw 57*8fd04b83SRoger A. Faulkner int 58*8fd04b83SRoger A. Faulkner __openattrdirat(int fd, const char *name) 59*8fd04b83SRoger A. Faulkner { 60*8fd04b83SRoger A. Faulkner return (syscall(SYS_openat, fd, name, FXATTRDIROPEN, 0)); 61*8fd04b83SRoger A. Faulkner } 62*8fd04b83SRoger A. Faulkner 63da6c28aaSamw static int 64da6c28aaSamw attrat_init() 65da6c28aaSamw { 668cd45542Sraf void *packer; 678cd45542Sraf void *sizer; 688cd45542Sraf void *unpacker; 698cd45542Sraf void *freer; 708cd45542Sraf void *looker; 718cd45542Sraf 72da6c28aaSamw if (initialized == 0) { 738cd45542Sraf void *handle = dlopen("libnvpair.so.1", RTLD_LAZY); 74f90fe29eSraf 758cd45542Sraf if (handle == NULL || 768cd45542Sraf (packer = dlsym(handle, "nvlist_pack")) == NULL || 778cd45542Sraf (sizer = dlsym(handle, "nvlist_size")) == NULL || 788cd45542Sraf (unpacker = dlsym(handle, "nvlist_unpack")) == NULL || 798cd45542Sraf (freer = dlsym(handle, "nvlist_free")) == NULL || 808cd45542Sraf (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL) { 818cd45542Sraf if (handle) 825ad42b1bSSurya Prakki (void) dlclose(handle); 83575bd8a2Smarks return (-1); 84da6c28aaSamw } 85da6c28aaSamw 868cd45542Sraf lmutex_lock(&attrlock); 878cd45542Sraf 888cd45542Sraf if (initialized != 0) { 898cd45542Sraf lmutex_unlock(&attrlock); 905ad42b1bSSurya Prakki (void) dlclose(handle); 918cd45542Sraf return (0); 928cd45542Sraf } 938cd45542Sraf 948cd45542Sraf nvpacker = (int (*)(nvlist_t *, char **, size_t *, int, int)) 958cd45542Sraf packer; 968cd45542Sraf nvsize = (int (*)(nvlist_t *, size_t *, int)) 978cd45542Sraf sizer; 988cd45542Sraf nvunpacker = (int (*)(char *, size_t, nvlist_t **)) 998cd45542Sraf unpacker; 1008cd45542Sraf nvfree = (int (*)(nvlist_t *)) 1018cd45542Sraf freer; 1028cd45542Sraf nvlookupint64 = (int (*)(nvlist_t *, const char *, uint64_t *)) 1038cd45542Sraf looker; 1048cd45542Sraf 1058cd45542Sraf membar_producer(); 106da6c28aaSamw initialized = 1; 107da6c28aaSamw lmutex_unlock(&attrlock); 108da6c28aaSamw } 109da6c28aaSamw return (0); 110da6c28aaSamw } 111da6c28aaSamw 112da6c28aaSamw static int 113da6c28aaSamw attr_nv_pack(nvlist_t *request, void **nv_request, size_t *nv_requestlen) 114da6c28aaSamw { 115da6c28aaSamw size_t bufsize; 116da6c28aaSamw char *packbuf = NULL; 117da6c28aaSamw 118da6c28aaSamw if (nvsize(request, &bufsize, NV_ENCODE_XDR) != 0) { 119575bd8a2Smarks errno = EINVAL; 120575bd8a2Smarks return (-1); 121da6c28aaSamw } 122da6c28aaSamw 123da6c28aaSamw packbuf = malloc(bufsize); 124da6c28aaSamw if (packbuf == NULL) 125575bd8a2Smarks return (-1); 126da6c28aaSamw if (nvpacker(request, &packbuf, &bufsize, NV_ENCODE_XDR, 0) != 0) { 127da6c28aaSamw free(packbuf); 128575bd8a2Smarks errno = EINVAL; 129575bd8a2Smarks return (-1); 130da6c28aaSamw } else { 131da6c28aaSamw *nv_request = (void *)packbuf; 132da6c28aaSamw *nv_requestlen = bufsize; 133da6c28aaSamw } 134da6c28aaSamw return (0); 135da6c28aaSamw } 136da6c28aaSamw 137da6c28aaSamw static const char * 138da6c28aaSamw view_to_name(xattr_view_t view) 139da6c28aaSamw { 140da6c28aaSamw if (view >= XATTR_VIEW_LAST || view < 0) 141da6c28aaSamw return (NULL); 142da6c28aaSamw return (xattr_view_name[view]); 143da6c28aaSamw } 144da6c28aaSamw 145da6c28aaSamw static int 146da6c28aaSamw xattr_openat(int basefd, xattr_view_t view, int mode) 147da6c28aaSamw { 148da6c28aaSamw const char *xattrname; 149da6c28aaSamw int xattrfd; 150da6c28aaSamw int oflag; 151da6c28aaSamw 152da6c28aaSamw switch (view) { 153da6c28aaSamw case XATTR_VIEW_READONLY: 154da6c28aaSamw oflag = O_RDONLY; 155da6c28aaSamw break; 156da6c28aaSamw case XATTR_VIEW_READWRITE: 157da6c28aaSamw oflag = mode & O_RDWR; 158da6c28aaSamw break; 159da6c28aaSamw default: 160575bd8a2Smarks errno = EINVAL; 161da6c28aaSamw return (-1); 162da6c28aaSamw } 163da6c28aaSamw if (mode & O_XATTR) 164da6c28aaSamw oflag |= O_XATTR; 165da6c28aaSamw 166da6c28aaSamw xattrname = view_to_name(view); 167da6c28aaSamw xattrfd = openat(basefd, xattrname, oflag); 168da6c28aaSamw if (xattrfd < 0) 169da6c28aaSamw return (xattrfd); 170da6c28aaSamw /* Don't cache sysattr info (advisory) */ 171da6c28aaSamw (void) directio(xattrfd, DIRECTIO_ON); 172da6c28aaSamw return (xattrfd); 173da6c28aaSamw } 174da6c28aaSamw 175da6c28aaSamw static int 176da6c28aaSamw cgetattr(int fd, nvlist_t **response) 177da6c28aaSamw { 178da6c28aaSamw int error; 179da6c28aaSamw int bytesread; 180da6c28aaSamw void *nv_response; 181da6c28aaSamw size_t nv_responselen; 182da6c28aaSamw struct stat buf; 183da6c28aaSamw 184da6c28aaSamw if (error = attrat_init()) 185575bd8a2Smarks return (error); 186da6c28aaSamw if ((error = fstat(fd, &buf)) != 0) 187575bd8a2Smarks return (error); 188da6c28aaSamw nv_responselen = buf.st_size; 189da6c28aaSamw 190da6c28aaSamw if ((nv_response = malloc(nv_responselen)) == NULL) 191575bd8a2Smarks return (-1); 192da6c28aaSamw bytesread = read(fd, nv_response, nv_responselen); 193575bd8a2Smarks if (bytesread != nv_responselen) { 194da6c28aaSamw free(nv_response); 195575bd8a2Smarks errno = EFAULT; 196575bd8a2Smarks return (-1); 197575bd8a2Smarks } 198575bd8a2Smarks 199575bd8a2Smarks if (nvunpacker(nv_response, nv_responselen, response)) { 200575bd8a2Smarks free(nv_response); 201575bd8a2Smarks errno = ENOMEM; 202575bd8a2Smarks return (-1); 203575bd8a2Smarks } 204575bd8a2Smarks 205575bd8a2Smarks free(nv_response); 206575bd8a2Smarks return (0); 207da6c28aaSamw } 208da6c28aaSamw 209da6c28aaSamw static int 210da6c28aaSamw csetattr(int fd, nvlist_t *request) 211da6c28aaSamw { 212da6c28aaSamw int error, saveerrno; 213da6c28aaSamw int byteswritten; 214da6c28aaSamw void *nv_request; 215da6c28aaSamw size_t nv_requestlen; 216da6c28aaSamw 217da6c28aaSamw if (error = attrat_init()) 218575bd8a2Smarks return (error); 219da6c28aaSamw 220da6c28aaSamw if ((error = attr_nv_pack(request, &nv_request, &nv_requestlen)) != 0) 221575bd8a2Smarks return (error); 222da6c28aaSamw 223da6c28aaSamw byteswritten = write(fd, nv_request, nv_requestlen); 224da6c28aaSamw if (byteswritten != nv_requestlen) { 225da6c28aaSamw saveerrno = errno; 226da6c28aaSamw free(nv_request); 227da6c28aaSamw errno = saveerrno; 228575bd8a2Smarks return (-1); 229da6c28aaSamw } 230da6c28aaSamw 231da6c28aaSamw free(nv_request); 232da6c28aaSamw return (0); 233da6c28aaSamw } 234da6c28aaSamw 235da6c28aaSamw int 236da6c28aaSamw fgetattr(int basefd, xattr_view_t view, nvlist_t **response) 237da6c28aaSamw { 238da6c28aaSamw int error, saveerrno, xattrfd; 239da6c28aaSamw 240da6c28aaSamw if ((xattrfd = xattr_openat(basefd, view, O_XATTR)) < 0) 241da6c28aaSamw return (xattrfd); 242da6c28aaSamw 243da6c28aaSamw error = cgetattr(xattrfd, response); 244da6c28aaSamw saveerrno = errno; 245da6c28aaSamw (void) close(xattrfd); 246da6c28aaSamw errno = saveerrno; 247da6c28aaSamw return (error); 248da6c28aaSamw } 249da6c28aaSamw 250da6c28aaSamw int 251da6c28aaSamw fsetattr(int basefd, xattr_view_t view, nvlist_t *request) 252da6c28aaSamw { 253da6c28aaSamw int error, saveerrno, xattrfd; 254da6c28aaSamw 255da6c28aaSamw if ((xattrfd = xattr_openat(basefd, view, O_RDWR | O_XATTR)) < 0) 256da6c28aaSamw return (xattrfd); 257da6c28aaSamw error = csetattr(xattrfd, request); 258da6c28aaSamw saveerrno = errno; 259da6c28aaSamw (void) close(xattrfd); 260da6c28aaSamw errno = saveerrno; 261da6c28aaSamw return (error); 262da6c28aaSamw } 263da6c28aaSamw 264da6c28aaSamw int 265da6c28aaSamw getattrat(int basefd, xattr_view_t view, const char *name, nvlist_t **response) 266da6c28aaSamw { 267da6c28aaSamw int error, saveerrno, namefd, xattrfd; 268da6c28aaSamw 269da6c28aaSamw if ((namefd = __openattrdirat(basefd, name)) < 0) 270da6c28aaSamw return (namefd); 271da6c28aaSamw 272da6c28aaSamw if ((xattrfd = xattr_openat(namefd, view, 0)) < 0) { 273da6c28aaSamw saveerrno = errno; 274da6c28aaSamw (void) close(namefd); 275da6c28aaSamw errno = saveerrno; 276da6c28aaSamw return (xattrfd); 277da6c28aaSamw } 278da6c28aaSamw 279da6c28aaSamw error = cgetattr(xattrfd, response); 280da6c28aaSamw saveerrno = errno; 281da6c28aaSamw (void) close(namefd); 282da6c28aaSamw (void) close(xattrfd); 283da6c28aaSamw errno = saveerrno; 284da6c28aaSamw return (error); 285da6c28aaSamw } 286da6c28aaSamw 287da6c28aaSamw int 288da6c28aaSamw setattrat(int basefd, xattr_view_t view, const char *name, nvlist_t *request) 289da6c28aaSamw { 290da6c28aaSamw int error, saveerrno, namefd, xattrfd; 291da6c28aaSamw 292da6c28aaSamw if ((namefd = __openattrdirat(basefd, name)) < 0) 293da6c28aaSamw return (namefd); 294da6c28aaSamw 295da6c28aaSamw if ((xattrfd = xattr_openat(namefd, view, O_RDWR)) < 0) { 296da6c28aaSamw saveerrno = errno; 297da6c28aaSamw (void) close(namefd); 298da6c28aaSamw errno = saveerrno; 299da6c28aaSamw return (xattrfd); 300da6c28aaSamw } 301da6c28aaSamw 302da6c28aaSamw error = csetattr(xattrfd, request); 303da6c28aaSamw saveerrno = errno; 304da6c28aaSamw (void) close(namefd); 305da6c28aaSamw (void) close(xattrfd); 306da6c28aaSamw errno = saveerrno; 307da6c28aaSamw return (error); 308da6c28aaSamw } 309d8ac9b2dSmarks 310d8ac9b2dSmarks void 311d8ac9b2dSmarks libc_nvlist_free(nvlist_t *nvp) 312d8ac9b2dSmarks { 313d8ac9b2dSmarks nvfree(nvp); 314d8ac9b2dSmarks } 315d8ac9b2dSmarks 316d8ac9b2dSmarks int 317d8ac9b2dSmarks libc_nvlist_lookup_uint64(nvlist_t *nvp, const char *name, uint64_t *value) 318d8ac9b2dSmarks { 319d8ac9b2dSmarks return (nvlookupint64(nvp, name, value)); 320d8ac9b2dSmarks } 321