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 */
21*11798SRoger.Faulkner@Sun.COM
225331Samw /*
23*11798SRoger.Faulkner@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
245331Samw * Use is subject to license terms.
255331Samw */
265331Samw
276812Sraf #include "lint.h"
285331Samw #include <string.h>
295331Samw #include <stdlib.h>
305331Samw #include <errno.h>
315331Samw #include <fcntl.h>
325331Samw #include <mtlib.h>
335331Samw #include <attr.h>
345331Samw #include <sys/types.h>
355331Samw #include <sys/syscall.h>
365331Samw #include <sys/stat.h>
37*11798SRoger.Faulkner@Sun.COM #include <sys/file.h>
385331Samw #include <unistd.h>
395331Samw #include <dlfcn.h>
405331Samw #include <stdio.h>
416515Sraf #include <atomic.h>
425331Samw
435331Samw static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int);
445331Samw static int (*nvsize)(nvlist_t *, size_t *, int);
455331Samw static int (*nvunpacker)(char *, size_t, nvlist_t **);
466082Smarks static int (*nvfree)(nvlist_t *);
476082Smarks static int (*nvlookupint64)(nvlist_t *, const char *, uint64_t *);
486082Smarks
495331Samw static mutex_t attrlock = DEFAULTMUTEX;
505331Samw static int initialized;
515331Samw
525331Samw static char *xattr_view_name[XATTR_VIEW_LAST] = {
535331Samw VIEW_READONLY,
545331Samw VIEW_READWRITE
555331Samw };
565331Samw
57*11798SRoger.Faulkner@Sun.COM int
__openattrdirat(int fd,const char * name)58*11798SRoger.Faulkner@Sun.COM __openattrdirat(int fd, const char *name)
59*11798SRoger.Faulkner@Sun.COM {
60*11798SRoger.Faulkner@Sun.COM return (syscall(SYS_openat, fd, name, FXATTRDIROPEN, 0));
61*11798SRoger.Faulkner@Sun.COM }
62*11798SRoger.Faulkner@Sun.COM
635331Samw static int
attrat_init()645331Samw attrat_init()
655331Samw {
666515Sraf void *packer;
676515Sraf void *sizer;
686515Sraf void *unpacker;
696515Sraf void *freer;
706515Sraf void *looker;
716515Sraf
725331Samw if (initialized == 0) {
736515Sraf void *handle = dlopen("libnvpair.so.1", RTLD_LAZY);
746515Sraf
756515Sraf if (handle == NULL ||
766515Sraf (packer = dlsym(handle, "nvlist_pack")) == NULL ||
776515Sraf (sizer = dlsym(handle, "nvlist_size")) == NULL ||
786515Sraf (unpacker = dlsym(handle, "nvlist_unpack")) == NULL ||
796515Sraf (freer = dlsym(handle, "nvlist_free")) == NULL ||
806515Sraf (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL) {
816515Sraf if (handle)
8211411SSurya.Prakki@Sun.COM (void) dlclose(handle);
836515Sraf return (-1);
846515Sraf }
855914Sraf
865331Samw lmutex_lock(&attrlock);
876515Sraf
886515Sraf if (initialized != 0) {
895331Samw lmutex_unlock(&attrlock);
9011411SSurya.Prakki@Sun.COM (void) dlclose(handle);
915331Samw return (0);
925331Samw }
935331Samw
946515Sraf nvpacker = (int (*)(nvlist_t *, char **, size_t *, int, int))
956515Sraf packer;
966515Sraf nvsize = (int (*)(nvlist_t *, size_t *, int))
976515Sraf sizer;
986515Sraf nvunpacker = (int (*)(char *, size_t, nvlist_t **))
996515Sraf unpacker;
1006515Sraf nvfree = (int (*)(nvlist_t *))
1016515Sraf freer;
1026515Sraf nvlookupint64 = (int (*)(nvlist_t *, const char *, uint64_t *))
1036515Sraf looker;
1045331Samw
1056515Sraf membar_producer();
1065331Samw initialized = 1;
1075331Samw lmutex_unlock(&attrlock);
1085331Samw }
1095331Samw return (0);
1105331Samw }
1115331Samw
1125331Samw static int
attr_nv_pack(nvlist_t * request,void ** nv_request,size_t * nv_requestlen)1135331Samw attr_nv_pack(nvlist_t *request, void **nv_request, size_t *nv_requestlen)
1145331Samw {
1155331Samw size_t bufsize;
1165331Samw char *packbuf = NULL;
1175331Samw
1185331Samw if (nvsize(request, &bufsize, NV_ENCODE_XDR) != 0) {
1195902Smarks errno = EINVAL;
1205902Smarks return (-1);
1215331Samw }
1225331Samw
1235331Samw packbuf = malloc(bufsize);
1245331Samw if (packbuf == NULL)
1255902Smarks return (-1);
1265331Samw if (nvpacker(request, &packbuf, &bufsize, NV_ENCODE_XDR, 0) != 0) {
1275331Samw free(packbuf);
1285902Smarks errno = EINVAL;
1295902Smarks return (-1);
1305331Samw } else {
1315331Samw *nv_request = (void *)packbuf;
1325331Samw *nv_requestlen = bufsize;
1335331Samw }
1345331Samw return (0);
1355331Samw }
1365331Samw
1375331Samw static const char *
view_to_name(xattr_view_t view)1385331Samw view_to_name(xattr_view_t view)
1395331Samw {
1405331Samw if (view >= XATTR_VIEW_LAST || view < 0)
1415331Samw return (NULL);
1425331Samw return (xattr_view_name[view]);
1435331Samw }
1445331Samw
1455331Samw static int
xattr_openat(int basefd,xattr_view_t view,int mode)1465331Samw xattr_openat(int basefd, xattr_view_t view, int mode)
1475331Samw {
1485331Samw const char *xattrname;
1495331Samw int xattrfd;
1505331Samw int oflag;
1515331Samw
1525331Samw switch (view) {
1535331Samw case XATTR_VIEW_READONLY:
1545331Samw oflag = O_RDONLY;
1555331Samw break;
1565331Samw case XATTR_VIEW_READWRITE:
1575331Samw oflag = mode & O_RDWR;
1585331Samw break;
1595331Samw default:
1605902Smarks errno = EINVAL;
1615331Samw return (-1);
1625331Samw }
1635331Samw if (mode & O_XATTR)
1645331Samw oflag |= O_XATTR;
1655331Samw
1665331Samw xattrname = view_to_name(view);
1675331Samw xattrfd = openat(basefd, xattrname, oflag);
1685331Samw if (xattrfd < 0)
1695331Samw return (xattrfd);
1705331Samw /* Don't cache sysattr info (advisory) */
1715331Samw (void) directio(xattrfd, DIRECTIO_ON);
1725331Samw return (xattrfd);
1735331Samw }
1745331Samw
1755331Samw static int
cgetattr(int fd,nvlist_t ** response)1765331Samw cgetattr(int fd, nvlist_t **response)
1775331Samw {
1785331Samw int error;
1795331Samw int bytesread;
1805331Samw void *nv_response;
1815331Samw size_t nv_responselen;
1825331Samw struct stat buf;
1835331Samw
1845331Samw if (error = attrat_init())
1855902Smarks return (error);
1865331Samw if ((error = fstat(fd, &buf)) != 0)
1875902Smarks return (error);
1885331Samw nv_responselen = buf.st_size;
1895331Samw
1905331Samw if ((nv_response = malloc(nv_responselen)) == NULL)
1915902Smarks return (-1);
1925331Samw bytesread = read(fd, nv_response, nv_responselen);
1935902Smarks if (bytesread != nv_responselen) {
1945902Smarks free(nv_response);
1955902Smarks errno = EFAULT;
1965902Smarks return (-1);
1975902Smarks }
1985331Samw
1995902Smarks if (nvunpacker(nv_response, nv_responselen, response)) {
2005902Smarks free(nv_response);
2015902Smarks errno = ENOMEM;
2025902Smarks return (-1);
2035902Smarks }
2045902Smarks
2055331Samw free(nv_response);
2065902Smarks return (0);
2075331Samw }
2085331Samw
2095331Samw static int
csetattr(int fd,nvlist_t * request)2105331Samw csetattr(int fd, nvlist_t *request)
2115331Samw {
2125331Samw int error, saveerrno;
2135331Samw int byteswritten;
2145331Samw void *nv_request;
2155331Samw size_t nv_requestlen;
2165331Samw
2175331Samw if (error = attrat_init())
2185902Smarks return (error);
2195331Samw
2205331Samw if ((error = attr_nv_pack(request, &nv_request, &nv_requestlen)) != 0)
2215902Smarks return (error);
2225331Samw
2235331Samw byteswritten = write(fd, nv_request, nv_requestlen);
2245331Samw if (byteswritten != nv_requestlen) {
2255331Samw saveerrno = errno;
2265331Samw free(nv_request);
2275331Samw errno = saveerrno;
2285902Smarks return (-1);
2295331Samw }
2305331Samw
2315331Samw free(nv_request);
2325331Samw return (0);
2335331Samw }
2345331Samw
2355331Samw int
fgetattr(int basefd,xattr_view_t view,nvlist_t ** response)2365331Samw fgetattr(int basefd, xattr_view_t view, nvlist_t **response)
2375331Samw {
2385331Samw int error, saveerrno, xattrfd;
2395331Samw
2405331Samw if ((xattrfd = xattr_openat(basefd, view, O_XATTR)) < 0)
2415331Samw return (xattrfd);
2425331Samw
2435331Samw error = cgetattr(xattrfd, response);
2445331Samw saveerrno = errno;
2455331Samw (void) close(xattrfd);
2465331Samw errno = saveerrno;
2475331Samw return (error);
2485331Samw }
2495331Samw
2505331Samw int
fsetattr(int basefd,xattr_view_t view,nvlist_t * request)2515331Samw fsetattr(int basefd, xattr_view_t view, nvlist_t *request)
2525331Samw {
2535331Samw int error, saveerrno, xattrfd;
2545331Samw
2555331Samw if ((xattrfd = xattr_openat(basefd, view, O_RDWR | O_XATTR)) < 0)
2565331Samw return (xattrfd);
2575331Samw error = csetattr(xattrfd, request);
2585331Samw saveerrno = errno;
2595331Samw (void) close(xattrfd);
2605331Samw errno = saveerrno;
2615331Samw return (error);
2625331Samw }
2635331Samw
2645331Samw int
getattrat(int basefd,xattr_view_t view,const char * name,nvlist_t ** response)2655331Samw getattrat(int basefd, xattr_view_t view, const char *name, nvlist_t **response)
2665331Samw {
2675331Samw int error, saveerrno, namefd, xattrfd;
2685331Samw
2695331Samw if ((namefd = __openattrdirat(basefd, name)) < 0)
2705331Samw return (namefd);
2715331Samw
2725331Samw if ((xattrfd = xattr_openat(namefd, view, 0)) < 0) {
2735331Samw saveerrno = errno;
2745331Samw (void) close(namefd);
2755331Samw errno = saveerrno;
2765331Samw return (xattrfd);
2775331Samw }
2785331Samw
2795331Samw error = cgetattr(xattrfd, response);
2805331Samw saveerrno = errno;
2815331Samw (void) close(namefd);
2825331Samw (void) close(xattrfd);
2835331Samw errno = saveerrno;
2845331Samw return (error);
2855331Samw }
2865331Samw
2875331Samw int
setattrat(int basefd,xattr_view_t view,const char * name,nvlist_t * request)2885331Samw setattrat(int basefd, xattr_view_t view, const char *name, nvlist_t *request)
2895331Samw {
2905331Samw int error, saveerrno, namefd, xattrfd;
2915331Samw
2925331Samw if ((namefd = __openattrdirat(basefd, name)) < 0)
2935331Samw return (namefd);
2945331Samw
2955331Samw if ((xattrfd = xattr_openat(namefd, view, O_RDWR)) < 0) {
2965331Samw saveerrno = errno;
2975331Samw (void) close(namefd);
2985331Samw errno = saveerrno;
2995331Samw return (xattrfd);
3005331Samw }
3015331Samw
3025331Samw error = csetattr(xattrfd, request);
3035331Samw saveerrno = errno;
3045331Samw (void) close(namefd);
3055331Samw (void) close(xattrfd);
3065331Samw errno = saveerrno;
3075331Samw return (error);
3085331Samw }
3096082Smarks
3106082Smarks void
libc_nvlist_free(nvlist_t * nvp)3116082Smarks libc_nvlist_free(nvlist_t *nvp)
3126082Smarks {
3136082Smarks nvfree(nvp);
3146082Smarks }
3156082Smarks
3166082Smarks int
libc_nvlist_lookup_uint64(nvlist_t * nvp,const char * name,uint64_t * value)3176082Smarks libc_nvlist_lookup_uint64(nvlist_t *nvp, const char *name, uint64_t *value)
3186082Smarks {
3196082Smarks return (nvlookupint64(nvp, name, value));
3206082Smarks }
321