15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 225902Smarks * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #pragma ident "%Z%%M% %I% %E% SMI" 275331Samw 28*6812Sraf #include "lint.h" 295331Samw #include <string.h> 305331Samw #include <stdlib.h> 315331Samw #include <errno.h> 325331Samw #include <fcntl.h> 335331Samw #include <mtlib.h> 345331Samw #include <attr.h> 355331Samw #include <sys/types.h> 365331Samw #include <sys/syscall.h> 375331Samw #include <sys/stat.h> 385331Samw #include <sys/filio.h> 395331Samw #include <unistd.h> 405331Samw #include <dlfcn.h> 415331Samw #include <stdio.h> 426515Sraf #include <atomic.h> 435331Samw 445331Samw static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int); 455331Samw static int (*nvsize)(nvlist_t *, size_t *, int); 465331Samw static int (*nvunpacker)(char *, size_t, nvlist_t **); 476082Smarks static int (*nvfree)(nvlist_t *); 486082Smarks static int (*nvlookupint64)(nvlist_t *, const char *, uint64_t *); 496082Smarks 505331Samw static mutex_t attrlock = DEFAULTMUTEX; 515331Samw static int initialized; 525331Samw extern int __openattrdirat(int basefd, const char *name); 535331Samw 545331Samw static char *xattr_view_name[XATTR_VIEW_LAST] = { 555331Samw VIEW_READONLY, 565331Samw VIEW_READWRITE 575331Samw }; 585331Samw 595331Samw static int 605331Samw attrat_init() 615331Samw { 626515Sraf void *packer; 636515Sraf void *sizer; 646515Sraf void *unpacker; 656515Sraf void *freer; 666515Sraf void *looker; 676515Sraf 685331Samw if (initialized == 0) { 696515Sraf void *handle = dlopen("libnvpair.so.1", RTLD_LAZY); 706515Sraf 716515Sraf if (handle == NULL || 726515Sraf (packer = dlsym(handle, "nvlist_pack")) == NULL || 736515Sraf (sizer = dlsym(handle, "nvlist_size")) == NULL || 746515Sraf (unpacker = dlsym(handle, "nvlist_unpack")) == NULL || 756515Sraf (freer = dlsym(handle, "nvlist_free")) == NULL || 766515Sraf (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL) { 776515Sraf if (handle) 786515Sraf dlclose(handle); 796515Sraf return (-1); 806515Sraf } 815914Sraf 825331Samw lmutex_lock(&attrlock); 836515Sraf 846515Sraf if (initialized != 0) { 855331Samw lmutex_unlock(&attrlock); 866515Sraf dlclose(handle); 875331Samw return (0); 885331Samw } 895331Samw 906515Sraf nvpacker = (int (*)(nvlist_t *, char **, size_t *, int, int)) 916515Sraf packer; 926515Sraf nvsize = (int (*)(nvlist_t *, size_t *, int)) 936515Sraf sizer; 946515Sraf nvunpacker = (int (*)(char *, size_t, nvlist_t **)) 956515Sraf unpacker; 966515Sraf nvfree = (int (*)(nvlist_t *)) 976515Sraf freer; 986515Sraf nvlookupint64 = (int (*)(nvlist_t *, const char *, uint64_t *)) 996515Sraf looker; 1005331Samw 1016515Sraf membar_producer(); 1025331Samw initialized = 1; 1035331Samw lmutex_unlock(&attrlock); 1045331Samw } 1055331Samw return (0); 1065331Samw } 1075331Samw 1085331Samw static int 1095331Samw attr_nv_pack(nvlist_t *request, void **nv_request, size_t *nv_requestlen) 1105331Samw { 1115331Samw size_t bufsize; 1125331Samw char *packbuf = NULL; 1135331Samw 1145331Samw if (nvsize(request, &bufsize, NV_ENCODE_XDR) != 0) { 1155902Smarks errno = EINVAL; 1165902Smarks return (-1); 1175331Samw } 1185331Samw 1195331Samw packbuf = malloc(bufsize); 1205331Samw if (packbuf == NULL) 1215902Smarks return (-1); 1225331Samw if (nvpacker(request, &packbuf, &bufsize, NV_ENCODE_XDR, 0) != 0) { 1235331Samw free(packbuf); 1245902Smarks errno = EINVAL; 1255902Smarks return (-1); 1265331Samw } else { 1275331Samw *nv_request = (void *)packbuf; 1285331Samw *nv_requestlen = bufsize; 1295331Samw } 1305331Samw return (0); 1315331Samw } 1325331Samw 1335331Samw static const char * 1345331Samw view_to_name(xattr_view_t view) 1355331Samw { 1365331Samw if (view >= XATTR_VIEW_LAST || view < 0) 1375331Samw return (NULL); 1385331Samw return (xattr_view_name[view]); 1395331Samw } 1405331Samw 1415331Samw static int 1425331Samw xattr_openat(int basefd, xattr_view_t view, int mode) 1435331Samw { 1445331Samw const char *xattrname; 1455331Samw int xattrfd; 1465331Samw int oflag; 1475331Samw 1485331Samw switch (view) { 1495331Samw case XATTR_VIEW_READONLY: 1505331Samw oflag = O_RDONLY; 1515331Samw break; 1525331Samw case XATTR_VIEW_READWRITE: 1535331Samw oflag = mode & O_RDWR; 1545331Samw break; 1555331Samw default: 1565902Smarks errno = EINVAL; 1575331Samw return (-1); 1585331Samw } 1595331Samw if (mode & O_XATTR) 1605331Samw oflag |= O_XATTR; 1615331Samw 1625331Samw xattrname = view_to_name(view); 1635331Samw xattrfd = openat(basefd, xattrname, oflag); 1645331Samw if (xattrfd < 0) 1655331Samw return (xattrfd); 1665331Samw /* Don't cache sysattr info (advisory) */ 1675331Samw (void) directio(xattrfd, DIRECTIO_ON); 1685331Samw return (xattrfd); 1695331Samw } 1705331Samw 1715331Samw static int 1725331Samw cgetattr(int fd, nvlist_t **response) 1735331Samw { 1745331Samw int error; 1755331Samw int bytesread; 1765331Samw void *nv_response; 1775331Samw size_t nv_responselen; 1785331Samw struct stat buf; 1795331Samw 1805331Samw if (error = attrat_init()) 1815902Smarks return (error); 1825331Samw if ((error = fstat(fd, &buf)) != 0) 1835902Smarks return (error); 1845331Samw nv_responselen = buf.st_size; 1855331Samw 1865331Samw if ((nv_response = malloc(nv_responselen)) == NULL) 1875902Smarks return (-1); 1885331Samw bytesread = read(fd, nv_response, nv_responselen); 1895902Smarks if (bytesread != nv_responselen) { 1905902Smarks free(nv_response); 1915902Smarks errno = EFAULT; 1925902Smarks return (-1); 1935902Smarks } 1945331Samw 1955902Smarks if (nvunpacker(nv_response, nv_responselen, response)) { 1965902Smarks free(nv_response); 1975902Smarks errno = ENOMEM; 1985902Smarks return (-1); 1995902Smarks } 2005902Smarks 2015331Samw free(nv_response); 2025902Smarks return (0); 2035331Samw } 2045331Samw 2055331Samw static int 2065331Samw csetattr(int fd, nvlist_t *request) 2075331Samw { 2085331Samw int error, saveerrno; 2095331Samw int byteswritten; 2105331Samw void *nv_request; 2115331Samw size_t nv_requestlen; 2125331Samw 2135331Samw if (error = attrat_init()) 2145902Smarks return (error); 2155331Samw 2165331Samw if ((error = attr_nv_pack(request, &nv_request, &nv_requestlen)) != 0) 2175902Smarks return (error); 2185331Samw 2195331Samw byteswritten = write(fd, nv_request, nv_requestlen); 2205331Samw if (byteswritten != nv_requestlen) { 2215331Samw saveerrno = errno; 2225331Samw free(nv_request); 2235331Samw errno = saveerrno; 2245902Smarks return (-1); 2255331Samw } 2265331Samw 2275331Samw free(nv_request); 2285331Samw return (0); 2295331Samw } 2305331Samw 2315331Samw int 2325331Samw fgetattr(int basefd, xattr_view_t view, nvlist_t **response) 2335331Samw { 2345331Samw int error, saveerrno, xattrfd; 2355331Samw 2365331Samw if ((xattrfd = xattr_openat(basefd, view, O_XATTR)) < 0) 2375331Samw return (xattrfd); 2385331Samw 2395331Samw error = cgetattr(xattrfd, response); 2405331Samw saveerrno = errno; 2415331Samw (void) close(xattrfd); 2425331Samw errno = saveerrno; 2435331Samw return (error); 2445331Samw } 2455331Samw 2465331Samw int 2475331Samw fsetattr(int basefd, xattr_view_t view, nvlist_t *request) 2485331Samw { 2495331Samw int error, saveerrno, xattrfd; 2505331Samw 2515331Samw if ((xattrfd = xattr_openat(basefd, view, O_RDWR | O_XATTR)) < 0) 2525331Samw return (xattrfd); 2535331Samw error = csetattr(xattrfd, request); 2545331Samw saveerrno = errno; 2555331Samw (void) close(xattrfd); 2565331Samw errno = saveerrno; 2575331Samw return (error); 2585331Samw } 2595331Samw 2605331Samw int 2615331Samw getattrat(int basefd, xattr_view_t view, const char *name, nvlist_t **response) 2625331Samw { 2635331Samw int error, saveerrno, namefd, xattrfd; 2645331Samw 2655331Samw if ((namefd = __openattrdirat(basefd, name)) < 0) 2665331Samw return (namefd); 2675331Samw 2685331Samw if ((xattrfd = xattr_openat(namefd, view, 0)) < 0) { 2695331Samw saveerrno = errno; 2705331Samw (void) close(namefd); 2715331Samw errno = saveerrno; 2725331Samw return (xattrfd); 2735331Samw } 2745331Samw 2755331Samw error = cgetattr(xattrfd, response); 2765331Samw saveerrno = errno; 2775331Samw (void) close(namefd); 2785331Samw (void) close(xattrfd); 2795331Samw errno = saveerrno; 2805331Samw return (error); 2815331Samw } 2825331Samw 2835331Samw int 2845331Samw setattrat(int basefd, xattr_view_t view, const char *name, nvlist_t *request) 2855331Samw { 2865331Samw int error, saveerrno, namefd, xattrfd; 2875331Samw 2885331Samw if ((namefd = __openattrdirat(basefd, name)) < 0) 2895331Samw return (namefd); 2905331Samw 2915331Samw if ((xattrfd = xattr_openat(namefd, view, O_RDWR)) < 0) { 2925331Samw saveerrno = errno; 2935331Samw (void) close(namefd); 2945331Samw errno = saveerrno; 2955331Samw return (xattrfd); 2965331Samw } 2975331Samw 2985331Samw error = csetattr(xattrfd, request); 2995331Samw saveerrno = errno; 3005331Samw (void) close(namefd); 3015331Samw (void) close(xattrfd); 3025331Samw errno = saveerrno; 3035331Samw return (error); 3045331Samw } 3056082Smarks 3066082Smarks void 3076082Smarks libc_nvlist_free(nvlist_t *nvp) 3086082Smarks { 3096082Smarks nvfree(nvp); 3106082Smarks } 3116082Smarks 3126082Smarks int 3136082Smarks libc_nvlist_lookup_uint64(nvlist_t *nvp, const char *name, uint64_t *value) 3146082Smarks { 3156082Smarks return (nvlookupint64(nvp, name, value)); 3166082Smarks } 317