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 */ 21da6c28aaSamw /* 22575bd8a2Smarks * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw #pragma ident "%Z%%M% %I% %E% SMI" 27da6c28aaSamw 28*7257d1b4Sraf #include "lint.h" 29da6c28aaSamw #include <string.h> 30da6c28aaSamw #include <stdlib.h> 31da6c28aaSamw #include <errno.h> 32da6c28aaSamw #include <fcntl.h> 33da6c28aaSamw #include <mtlib.h> 34da6c28aaSamw #include <attr.h> 35da6c28aaSamw #include <sys/types.h> 36da6c28aaSamw #include <sys/syscall.h> 37da6c28aaSamw #include <sys/stat.h> 38da6c28aaSamw #include <sys/filio.h> 39da6c28aaSamw #include <unistd.h> 40da6c28aaSamw #include <dlfcn.h> 41da6c28aaSamw #include <stdio.h> 428cd45542Sraf #include <atomic.h> 43da6c28aaSamw 44da6c28aaSamw static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int); 45da6c28aaSamw static int (*nvsize)(nvlist_t *, size_t *, int); 46da6c28aaSamw static int (*nvunpacker)(char *, size_t, nvlist_t **); 47d8ac9b2dSmarks static int (*nvfree)(nvlist_t *); 48d8ac9b2dSmarks static int (*nvlookupint64)(nvlist_t *, const char *, uint64_t *); 49d8ac9b2dSmarks 50da6c28aaSamw static mutex_t attrlock = DEFAULTMUTEX; 51da6c28aaSamw static int initialized; 52da6c28aaSamw extern int __openattrdirat(int basefd, const char *name); 53da6c28aaSamw 54da6c28aaSamw static char *xattr_view_name[XATTR_VIEW_LAST] = { 55da6c28aaSamw VIEW_READONLY, 56da6c28aaSamw VIEW_READWRITE 57da6c28aaSamw }; 58da6c28aaSamw 59da6c28aaSamw static int 60da6c28aaSamw attrat_init() 61da6c28aaSamw { 628cd45542Sraf void *packer; 638cd45542Sraf void *sizer; 648cd45542Sraf void *unpacker; 658cd45542Sraf void *freer; 668cd45542Sraf void *looker; 678cd45542Sraf 68da6c28aaSamw if (initialized == 0) { 698cd45542Sraf void *handle = dlopen("libnvpair.so.1", RTLD_LAZY); 708cd45542Sraf 718cd45542Sraf if (handle == NULL || 728cd45542Sraf (packer = dlsym(handle, "nvlist_pack")) == NULL || 738cd45542Sraf (sizer = dlsym(handle, "nvlist_size")) == NULL || 748cd45542Sraf (unpacker = dlsym(handle, "nvlist_unpack")) == NULL || 758cd45542Sraf (freer = dlsym(handle, "nvlist_free")) == NULL || 768cd45542Sraf (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL) { 778cd45542Sraf if (handle) 788cd45542Sraf dlclose(handle); 798cd45542Sraf return (-1); 808cd45542Sraf } 81f90fe29eSraf 82da6c28aaSamw lmutex_lock(&attrlock); 838cd45542Sraf 848cd45542Sraf if (initialized != 0) { 85da6c28aaSamw lmutex_unlock(&attrlock); 868cd45542Sraf dlclose(handle); 87da6c28aaSamw return (0); 88da6c28aaSamw } 89da6c28aaSamw 908cd45542Sraf nvpacker = (int (*)(nvlist_t *, char **, size_t *, int, int)) 918cd45542Sraf packer; 928cd45542Sraf nvsize = (int (*)(nvlist_t *, size_t *, int)) 938cd45542Sraf sizer; 948cd45542Sraf nvunpacker = (int (*)(char *, size_t, nvlist_t **)) 958cd45542Sraf unpacker; 968cd45542Sraf nvfree = (int (*)(nvlist_t *)) 978cd45542Sraf freer; 988cd45542Sraf nvlookupint64 = (int (*)(nvlist_t *, const char *, uint64_t *)) 998cd45542Sraf looker; 100da6c28aaSamw 1018cd45542Sraf membar_producer(); 102da6c28aaSamw initialized = 1; 103da6c28aaSamw lmutex_unlock(&attrlock); 104da6c28aaSamw } 105da6c28aaSamw return (0); 106da6c28aaSamw } 107da6c28aaSamw 108da6c28aaSamw static int 109da6c28aaSamw attr_nv_pack(nvlist_t *request, void **nv_request, size_t *nv_requestlen) 110da6c28aaSamw { 111da6c28aaSamw size_t bufsize; 112da6c28aaSamw char *packbuf = NULL; 113da6c28aaSamw 114da6c28aaSamw if (nvsize(request, &bufsize, NV_ENCODE_XDR) != 0) { 115575bd8a2Smarks errno = EINVAL; 116575bd8a2Smarks return (-1); 117da6c28aaSamw } 118da6c28aaSamw 119da6c28aaSamw packbuf = malloc(bufsize); 120da6c28aaSamw if (packbuf == NULL) 121575bd8a2Smarks return (-1); 122da6c28aaSamw if (nvpacker(request, &packbuf, &bufsize, NV_ENCODE_XDR, 0) != 0) { 123da6c28aaSamw free(packbuf); 124575bd8a2Smarks errno = EINVAL; 125575bd8a2Smarks return (-1); 126da6c28aaSamw } else { 127da6c28aaSamw *nv_request = (void *)packbuf; 128da6c28aaSamw *nv_requestlen = bufsize; 129da6c28aaSamw } 130da6c28aaSamw return (0); 131da6c28aaSamw } 132da6c28aaSamw 133da6c28aaSamw static const char * 134da6c28aaSamw view_to_name(xattr_view_t view) 135da6c28aaSamw { 136da6c28aaSamw if (view >= XATTR_VIEW_LAST || view < 0) 137da6c28aaSamw return (NULL); 138da6c28aaSamw return (xattr_view_name[view]); 139da6c28aaSamw } 140da6c28aaSamw 141da6c28aaSamw static int 142da6c28aaSamw xattr_openat(int basefd, xattr_view_t view, int mode) 143da6c28aaSamw { 144da6c28aaSamw const char *xattrname; 145da6c28aaSamw int xattrfd; 146da6c28aaSamw int oflag; 147da6c28aaSamw 148da6c28aaSamw switch (view) { 149da6c28aaSamw case XATTR_VIEW_READONLY: 150da6c28aaSamw oflag = O_RDONLY; 151da6c28aaSamw break; 152da6c28aaSamw case XATTR_VIEW_READWRITE: 153da6c28aaSamw oflag = mode & O_RDWR; 154da6c28aaSamw break; 155da6c28aaSamw default: 156575bd8a2Smarks errno = EINVAL; 157da6c28aaSamw return (-1); 158da6c28aaSamw } 159da6c28aaSamw if (mode & O_XATTR) 160da6c28aaSamw oflag |= O_XATTR; 161da6c28aaSamw 162da6c28aaSamw xattrname = view_to_name(view); 163da6c28aaSamw xattrfd = openat(basefd, xattrname, oflag); 164da6c28aaSamw if (xattrfd < 0) 165da6c28aaSamw return (xattrfd); 166da6c28aaSamw /* Don't cache sysattr info (advisory) */ 167da6c28aaSamw (void) directio(xattrfd, DIRECTIO_ON); 168da6c28aaSamw return (xattrfd); 169da6c28aaSamw } 170da6c28aaSamw 171da6c28aaSamw static int 172da6c28aaSamw cgetattr(int fd, nvlist_t **response) 173da6c28aaSamw { 174da6c28aaSamw int error; 175da6c28aaSamw int bytesread; 176da6c28aaSamw void *nv_response; 177da6c28aaSamw size_t nv_responselen; 178da6c28aaSamw struct stat buf; 179da6c28aaSamw 180da6c28aaSamw if (error = attrat_init()) 181575bd8a2Smarks return (error); 182da6c28aaSamw if ((error = fstat(fd, &buf)) != 0) 183575bd8a2Smarks return (error); 184da6c28aaSamw nv_responselen = buf.st_size; 185da6c28aaSamw 186da6c28aaSamw if ((nv_response = malloc(nv_responselen)) == NULL) 187575bd8a2Smarks return (-1); 188da6c28aaSamw bytesread = read(fd, nv_response, nv_responselen); 189575bd8a2Smarks if (bytesread != nv_responselen) { 190575bd8a2Smarks free(nv_response); 191575bd8a2Smarks errno = EFAULT; 192575bd8a2Smarks return (-1); 193575bd8a2Smarks } 194575bd8a2Smarks 195575bd8a2Smarks if (nvunpacker(nv_response, nv_responselen, response)) { 196575bd8a2Smarks free(nv_response); 197575bd8a2Smarks errno = ENOMEM; 198575bd8a2Smarks return (-1); 199575bd8a2Smarks } 200da6c28aaSamw 201da6c28aaSamw free(nv_response); 202575bd8a2Smarks return (0); 203da6c28aaSamw } 204da6c28aaSamw 205da6c28aaSamw static int 206da6c28aaSamw csetattr(int fd, nvlist_t *request) 207da6c28aaSamw { 208da6c28aaSamw int error, saveerrno; 209da6c28aaSamw int byteswritten; 210da6c28aaSamw void *nv_request; 211da6c28aaSamw size_t nv_requestlen; 212da6c28aaSamw 213da6c28aaSamw if (error = attrat_init()) 214575bd8a2Smarks return (error); 215da6c28aaSamw 216da6c28aaSamw if ((error = attr_nv_pack(request, &nv_request, &nv_requestlen)) != 0) 217575bd8a2Smarks return (error); 218da6c28aaSamw 219da6c28aaSamw byteswritten = write(fd, nv_request, nv_requestlen); 220da6c28aaSamw if (byteswritten != nv_requestlen) { 221da6c28aaSamw saveerrno = errno; 222da6c28aaSamw free(nv_request); 223da6c28aaSamw errno = saveerrno; 224575bd8a2Smarks return (-1); 225da6c28aaSamw } 226da6c28aaSamw 227da6c28aaSamw free(nv_request); 228da6c28aaSamw return (0); 229da6c28aaSamw } 230da6c28aaSamw 231da6c28aaSamw int 232da6c28aaSamw fgetattr(int basefd, xattr_view_t view, nvlist_t **response) 233da6c28aaSamw { 234da6c28aaSamw int error, saveerrno, xattrfd; 235da6c28aaSamw 236da6c28aaSamw if ((xattrfd = xattr_openat(basefd, view, O_XATTR)) < 0) 237da6c28aaSamw return (xattrfd); 238da6c28aaSamw 239da6c28aaSamw error = cgetattr(xattrfd, response); 240da6c28aaSamw saveerrno = errno; 241da6c28aaSamw (void) close(xattrfd); 242da6c28aaSamw errno = saveerrno; 243da6c28aaSamw return (error); 244da6c28aaSamw } 245da6c28aaSamw 246da6c28aaSamw int 247da6c28aaSamw fsetattr(int basefd, xattr_view_t view, nvlist_t *request) 248da6c28aaSamw { 249da6c28aaSamw int error, saveerrno, xattrfd; 250da6c28aaSamw 251da6c28aaSamw if ((xattrfd = xattr_openat(basefd, view, O_RDWR | O_XATTR)) < 0) 252da6c28aaSamw return (xattrfd); 253da6c28aaSamw error = csetattr(xattrfd, request); 254da6c28aaSamw saveerrno = errno; 255da6c28aaSamw (void) close(xattrfd); 256da6c28aaSamw errno = saveerrno; 257da6c28aaSamw return (error); 258da6c28aaSamw } 259da6c28aaSamw 260da6c28aaSamw int 261da6c28aaSamw getattrat(int basefd, xattr_view_t view, const char *name, nvlist_t **response) 262da6c28aaSamw { 263da6c28aaSamw int error, saveerrno, namefd, xattrfd; 264da6c28aaSamw 265da6c28aaSamw if ((namefd = __openattrdirat(basefd, name)) < 0) 266da6c28aaSamw return (namefd); 267da6c28aaSamw 268da6c28aaSamw if ((xattrfd = xattr_openat(namefd, view, 0)) < 0) { 269da6c28aaSamw saveerrno = errno; 270da6c28aaSamw (void) close(namefd); 271da6c28aaSamw errno = saveerrno; 272da6c28aaSamw return (xattrfd); 273da6c28aaSamw } 274da6c28aaSamw 275da6c28aaSamw error = cgetattr(xattrfd, response); 276da6c28aaSamw saveerrno = errno; 277da6c28aaSamw (void) close(namefd); 278da6c28aaSamw (void) close(xattrfd); 279da6c28aaSamw errno = saveerrno; 280da6c28aaSamw return (error); 281da6c28aaSamw } 282da6c28aaSamw 283da6c28aaSamw int 284da6c28aaSamw setattrat(int basefd, xattr_view_t view, const char *name, nvlist_t *request) 285da6c28aaSamw { 286da6c28aaSamw int error, saveerrno, namefd, xattrfd; 287da6c28aaSamw 288da6c28aaSamw if ((namefd = __openattrdirat(basefd, name)) < 0) 289da6c28aaSamw return (namefd); 290da6c28aaSamw 291da6c28aaSamw if ((xattrfd = xattr_openat(namefd, view, O_RDWR)) < 0) { 292da6c28aaSamw saveerrno = errno; 293da6c28aaSamw (void) close(namefd); 294da6c28aaSamw errno = saveerrno; 295da6c28aaSamw return (xattrfd); 296da6c28aaSamw } 297da6c28aaSamw 298da6c28aaSamw error = csetattr(xattrfd, request); 299da6c28aaSamw saveerrno = errno; 300da6c28aaSamw (void) close(namefd); 301da6c28aaSamw (void) close(xattrfd); 302da6c28aaSamw errno = saveerrno; 303da6c28aaSamw return (error); 304da6c28aaSamw } 305d8ac9b2dSmarks 306d8ac9b2dSmarks void 307d8ac9b2dSmarks libc_nvlist_free(nvlist_t *nvp) 308d8ac9b2dSmarks { 309d8ac9b2dSmarks nvfree(nvp); 310d8ac9b2dSmarks } 311d8ac9b2dSmarks 312d8ac9b2dSmarks int 313d8ac9b2dSmarks libc_nvlist_lookup_uint64(nvlist_t *nvp, const char *name, uint64_t *value) 314d8ac9b2dSmarks { 315d8ac9b2dSmarks return (nvlookupint64(nvp, name, value)); 316d8ac9b2dSmarks } 317