diff --git a/configure.ac b/configure.ac
index a5f9de5..e68c3d9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,6 +20,7 @@ AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_HEADER([include/config.h])
 AC_PREFIX_DEFAULT(/usr)
 
+AC_CANONICAL_HOST
 AM_INIT_AUTOMAKE([-Wall foreign 1.11 dist-xz subdir-objects])
 AM_SILENT_RULES([yes])
 
@@ -46,6 +47,18 @@ dnl Automatically increment the revision for every release.
 LT_REVISION=$(echo "${PACKAGE_VERSION}" | tr -d .)
 AC_SUBST(LT_REVISION)
 
+dnl Solaris support requires extra boilerplate.
+AS_CASE("$host_os", [*solaris*],
+	[have_solaris="true"],
+	[have_solaris="false"])
+AM_CONDITIONAL(HAVE_SOLARIS, ["$have_solaris"])
+
+dnl Determine how to pass mapfiles to the linker.
+AS_IF([test "x$lt_cv_prog_gnu_ld" = "xyes"],
+	[version_script="--version-script"],
+	[version_script="-M"])
+AC_SUBST(VERSION_SCRIPT, ["$version_script"])
+
 AC_CONFIG_COMMANDS([include/attr],
 	[dnl
 	rm -rf include/attr
diff --git a/exports b/exports
index 9b92721..f9e0d37 100644
--- a/exports
+++ b/exports
@@ -31,6 +31,20 @@ ATTR_1.0 {
 	removexattr;
 	setxattr;
 
+	# Dumb wrappers (for backwards compat)
+	libattr_fgetxattr;
+	libattr_flistxattr;
+	libattr_fremovexattr;
+	libattr_fsetxattr;
+	libattr_getxattr;
+	libattr_lgetxattr;
+	libattr_listxattr;
+	libattr_llistxattr;
+	libattr_lremovexattr;
+	libattr_lsetxattr;
+	libattr_removexattr;
+	libattr_setxattr;
+
 	# SGI Irix compatibility extensions
 	attr_get;
 	attr_getf;
diff --git a/include/Makemodule.am b/include/Makemodule.am
index 2ab600a..0ddd646 100644
--- a/include/Makemodule.am
+++ b/include/Makemodule.am
@@ -6,4 +6,5 @@ pkginclude_HEADERS += \
 noinst_HEADERS += \
 	include/misc.h \
 	include/nls.h \
-	include/walk_tree.h
+	include/walk_tree.h \
+	include/xattr.h
diff --git a/include/nls.h b/include/nls.h
index 06f84bb..fa90fa1 100644
--- a/include/nls.h
+++ b/include/nls.h
@@ -1,9 +1,9 @@
 #ifdef ENABLE_NLS
 # include <libintl.h>
+# include <locale.h>
 # define _(x)                   gettext(x)
 #else
 # define _(x)                   (x)
 # define textdomain(d)          do { } while (0)
 # define bindtextdomain(d,dir)  do { } while (0)
 #endif
-#include <locale.h>
diff --git a/include/xattr.h b/include/xattr.h
new file mode 100644
index 0000000..eccf5ee
--- /dev/null
+++ b/include/xattr.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2001-2002 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __XATTR_H__
+#define __XATTR_H__
+
+#include <sys/types.h>
+#include <errno.h>
+
+#ifndef ENOATTR
+# define ENOATTR ENODATA        /* No such attribute */
+#endif
+
+#define XATTR_CREATE  0x1       /* set value, fail if attr already exists */
+#define XATTR_REPLACE 0x2       /* set value, fail if attr does not exist */
+
+extern int setxattr (const char *__path, const char *__name,
+		      const void *__value, size_t __size, int __flags);
+extern int lsetxattr (const char *__path, const char *__name,
+		      const void *__value, size_t __size, int __flags);
+extern int fsetxattr (int __filedes, const char *__name,
+		      const void *__value, size_t __size, int __flags);
+
+extern ssize_t getxattr (const char *__path, const char *__name,
+				void *__value, size_t __size);
+extern ssize_t lgetxattr (const char *__path, const char *__name,
+				void *__value, size_t __size);
+extern ssize_t fgetxattr (int __filedes, const char *__name,
+				void *__value, size_t __size);
+
+extern ssize_t listxattr (const char *__path, char *__list,
+				size_t __size);
+extern ssize_t llistxattr (const char *__path, char *__list,
+				size_t __size);
+extern ssize_t flistxattr (int __filedes, char *__list,
+				size_t __size);
+
+extern int removexattr (const char *__path, const char *__name);
+extern int lremovexattr (const char *__path, const char *__name);
+extern int fremovexattr (int __filedes,   const char *__name);
+
+#endif	/* __XATTR_H__ */
diff --git a/libattr/Makemodule.am b/libattr/Makemodule.am
index 4b3720c..c5e0506 100644
--- a/libattr/Makemodule.am
+++ b/libattr/Makemodule.am
@@ -8,7 +8,7 @@ LT_CURRENT = 2
 LT_AGE = 1
 LTVERSION = $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
 
-libattr_la_DEPENDENCIES = exports libattr/libattr.lds
+libattr_la_DEPENDENCIES = exports
 libattr_la_SOURCES = \
 	libattr/attr_copy_action.c \
 	libattr/attr_copy_check.c \
@@ -17,10 +17,10 @@ libattr_la_SOURCES = \
 	libattr/libattr.c \
 	libattr/syscalls.c \
 	libattr/libattr.h
+if HAVE_SOLARIS
+libattr_la_SOURCES += libattr/solaris.c
+endif
 libattr_la_CFLAGS = -include libattr/libattr.h
 libattr_la_LDFLAGS = \
-	-Wl,--version-script,$(top_srcdir)/exports \
-	-Wl,$(top_srcdir)/libattr/libattr.lds \
+	-Wl,@VERSION_SCRIPT@,$(top_srcdir)/exports \
 	-version-info $(LTVERSION)
-
-EXTRA_DIST += libattr/libattr.lds
diff --git a/libattr/attr_copy_fd.c b/libattr/attr_copy_fd.c
index af237c9..e93fdce 100644
--- a/libattr/attr_copy_fd.c
+++ b/libattr/attr_copy_fd.c
@@ -22,7 +22,6 @@
 #endif
 
 #include <sys/types.h>
-# include <sys/xattr.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
@@ -38,6 +37,7 @@
 #define ERROR_CONTEXT_MACROS
 #include "error_context.h"
 #include "nls.h"
+#include "xattr.h"
 
 #if !defined(ENOTSUP)
 # define ENOTSUP (-1)
diff --git a/libattr/attr_copy_file.c b/libattr/attr_copy_file.c
index 6cd8f81..1da6a7a 100644
--- a/libattr/attr_copy_file.c
+++ b/libattr/attr_copy_file.c
@@ -22,7 +22,6 @@
 #endif
 
 #include <sys/types.h>
-# include <sys/xattr.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
@@ -38,6 +37,7 @@
 #define ERROR_CONTEXT_MACROS
 #include "error_context.h"
 #include "nls.h"
+#include "xattr.h"
 
 #if !defined(ENOTSUP)
 # define ENOTSUP (-1)
diff --git a/libattr/libattr.c b/libattr/libattr.c
index 0e8fffe..ad8a6df 100644
--- a/libattr/libattr.c
+++ b/libattr/libattr.c
@@ -20,9 +20,10 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <strings.h>
 #include <sys/types.h>
-#include <sys/xattr.h>
 
+#include <attr/xattr.h>
 #include <attr/attributes.h>
 
 #ifndef ENOATTR
diff --git a/libattr/libattr.lds b/libattr/libattr.lds
deleted file mode 100644
index 947f15d..0000000
--- a/libattr/libattr.lds
+++ /dev/null
@@ -1,12 +0,0 @@
-"fgetxattr@ATTR_1.0" = libattr_fgetxattr;
-"flistxattr@ATTR_1.0" = libattr_flistxattr;
-"fremovexattr@ATTR_1.0" = libattr_fremovexattr;
-"fsetxattr@ATTR_1.0" = libattr_fsetxattr;
-"getxattr@ATTR_1.0" = libattr_getxattr;
-"lgetxattr@ATTR_1.0" = libattr_lgetxattr;
-"listxattr@ATTR_1.0" = libattr_listxattr;
-"llistxattr@ATTR_1.0" = libattr_llistxattr;
-"lremovexattr@ATTR_1.0" = libattr_lremovexattr;
-"lsetxattr@ATTR_1.0" = libattr_lsetxattr;
-"removexattr@ATTR_1.0" = libattr_removexattr;
-"setxattr@ATTR_1.0" = libattr_setxattr;
diff --git a/libattr/solaris.c b/libattr/solaris.c
new file mode 100644
index 0000000..75abd53
--- /dev/null
+++ b/libattr/solaris.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2012 Igor Pashev <pashev.igor@gmail.com>
+ * All Rights Reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "xattr.h"
+
+ssize_t
+fgetxattr (int filedes, const char *name,
+           void *value, size_t size)
+{
+    int xfd;
+    ssize_t rv;
+    struct stat sb;
+
+    xfd = openat(filedes, name, O_RDONLY | O_XATTR);
+    if (xfd == -1) {
+        if (errno == ENOENT)
+            errno = ENOATTR;
+        return (-1);
+    }
+
+    if (fstat(xfd, &sb) == -1) {
+        rv = -1;
+    } else if (sb.st_size > SSIZE_MAX) {
+        errno = ERANGE;
+        rv = -1;
+    } else if (value == NULL || size == 0) {
+        rv = sb.st_size;
+    } else if (sb.st_size > size) {
+        errno = ERANGE;
+        rv = -1;
+    } else {
+        rv = read(xfd, value, size);
+    }
+
+    (void) close(xfd);
+    return (rv);
+}
+
+ssize_t
+getxattr (const char *path, const char *name,
+           void *value, size_t size)
+{
+    int fd;
+    ssize_t rv;
+
+    fd = open(path, O_RDONLY);
+    if (fd == -1) {
+        return (-1);
+    }
+
+    rv = fgetxattr(fd, name, value, size);
+
+    (void) close(fd);
+    return (rv);
+}
+
+static
+ssize_t
+__fflistxattr (int xfd, char *list, size_t size)
+{
+    ssize_t rv;
+    DIR *d;
+    struct dirent *de;
+    size_t l;
+/*
+ * The fdopendir() function opens a directory  stream  for  the
+ * directory   file   descriptor  "xfd".  The  directory  file
+ * descriptor should not be used or closed following a successful
+ * function  call.
+ * ...
+ * The closedir() function closes the directory stream referred
+ * to  by the argument "d". Upon return, the value of dirp may
+ * no longer point to an accessible object of the type DIR.  If
+ * a  file  descriptor is used to implement type DIR, that file
+ * descriptor will be closed.
+ */
+    d = fdopendir(xfd);
+    if (d == NULL) {
+        (void) close(xfd);
+        return (-1);
+    }
+
+    rv = 0;
+    while ((de = readdir(d)) != NULL) {
+        if (
+            !strcmp(de->d_name, ".")           ||
+            !strcmp(de->d_name, "..")          ||
+            !strcmp(de->d_name, "SUNWattr_rw") ||
+            !strcmp(de->d_name, "SUNWattr_ro")
+            )
+        {
+            continue;
+        }
+
+        /* if size == 0 we calculate the size of a buffer
+         * which is sufficiently large to hold the list of names
+         */
+        if (size == 0) {
+            rv += strlen(de->d_name) + 1;
+            continue;
+        }
+
+        l = strlcpy(list, de->d_name, size);
+        if (l >= size) {
+            errno = ERANGE;
+            rv = -1;
+            break;
+        }
+
+        rv   += l + 1;
+        size -= l + 1;
+        list += l + 1;
+    }
+
+    (void) closedir(d);
+    return (rv);
+}
+
+ssize_t
+flistxattr (int fd, char *list, size_t size)
+{
+    int xfd;
+    ssize_t rv;
+
+    xfd = openat(fd, ".", O_RDONLY);
+    if (xfd == -1) {
+        return (-1);
+    }
+
+    rv = __fflistxattr(xfd, list, size);
+
+    /* xfd is closed on __fflistxattr() */
+    return (rv);
+}
+
+ssize_t
+listxattr (const char * path, char *list, size_t size)
+{
+    int xfd;
+    ssize_t rv;
+
+    xfd = attropen(path, ".", O_RDONLY);
+    if (xfd == -1) {
+        return (-1);
+    }
+
+    rv = __fflistxattr(xfd, list, size);
+
+    /* xfd is closed on __fflistxattr() */
+    return (rv);
+}
+
+int
+fremovexattr (int filedes, const char *name)
+{
+    int xfd;
+    int rv;
+
+    xfd = openat(filedes, ".", O_XATTR, 0644);
+    if (xfd == -1) {
+        return (-1);
+    }
+
+    rv = unlinkat(xfd, name, 0);
+    (void) close(xfd);
+
+    if (rv == -1) {
+        if (errno == ENOENT)
+            errno = ENOATTR;
+    }
+    return (rv);
+}
+
+int
+removexattr (const char *path, const char *name)
+{
+    int fd;
+    int rv;
+
+    fd = open(path, O_RDONLY);
+    if (fd == -1) {
+        return (-1);
+    }
+
+    rv = fremovexattr(fd, name);
+
+    (void) close(fd);
+    return (rv);
+}
+
+int
+fsetxattr (int filedes, const char *name,
+        const void *value, size_t size, int flags)
+{
+    int xfd;
+    ssize_t w;
+
+    xfd = openat(filedes, name,
+         O_XATTR | O_TRUNC |
+         ((flags & XATTR_CREATE) ? O_EXCL : 0) |
+         ((flags & XATTR_REPLACE) ? O_RDWR : O_WRONLY | O_CREAT),
+         0644);
+
+    if (xfd == -1) {
+        return (-1);
+    }
+
+    while (size > 0) {
+        w = write(xfd, value, size);
+        if (w == -1) {
+            break;
+        }
+        size  -= w;
+        value += w;
+    }
+
+    (void) close(xfd);
+    return ((w == -1) ? -1 : 0);
+}
+
+int
+setxattr (const char *path, const char *name,
+        const void *value, size_t size, int flags)
+{
+    int fd;
+    int rv;
+
+    fd = open(path, O_RDONLY);
+    if (fd == -1) {
+        return (-1);
+    }
+
+    rv = fsetxattr(fd, name, value, size, flags);
+
+    (void) close(fd);
+    return (rv);
+}
+
+
+
+
+/*
+ * Extended attributes for symlinks are not supported
+ *
+ */
+
+
+ssize_t
+lgetxattr (const char *path, const char *name,
+           void *value, size_t size)
+{
+    struct stat s;
+    if (lstat(path, &s) == -1) {
+        return (-1);
+    }
+    if (S_ISLNK(s.st_mode)) {
+        errno = ENOTSUP;
+        return (-1);
+    }
+
+    return getxattr(path, name, value, size);
+}
+
+int
+lsetxattr (const char *path, const char *name,
+        const void *value, size_t size, int flags)
+{
+    struct stat s;
+    if (lstat(path, &s) == -1) {
+        return (-1);
+    }
+    if (S_ISLNK(s.st_mode)) {
+        errno = ENOTSUP;
+        return (-1);
+    }
+
+    return setxattr(path, name, value, size, flags);
+}
+
+int
+lremovexattr (const char *path, const char *name)
+{
+    struct stat s;
+    if (lstat(path, &s) == -1) {
+        return (-1);
+    }
+    if (S_ISLNK(s.st_mode)) {
+        errno = ENOTSUP;
+        return (-1);
+    }
+
+    return removexattr(path, name);
+}
+
+ssize_t
+llistxattr (const char *path, char *list, size_t size)
+{
+    struct stat s;
+    if (lstat(path, &s) == -1) {
+        return (-1);
+    }
+    if (S_ISLNK(s.st_mode)) {
+        errno = ENOTSUP;
+        return (-1);
+    }
+
+    return listxattr(path, list, size);
+}
diff --git a/libattr/syscalls.c b/libattr/syscalls.c
index 5e7db67..b0f58b8 100644
--- a/libattr/syscalls.c
+++ b/libattr/syscalls.c
@@ -20,7 +20,7 @@
  * Actual syscall wrappers are long gone to libc.
  */
 
-#include <sys/xattr.h>
+#include "xattr.h"
 
 int libattr_setxattr(const char *path, const char *name,
 		     void *value, size_t size, int flags)
diff --git a/tools/attr.c b/tools/attr.c
index d68a62c..5ea78e5 100644
--- a/tools/attr.c
+++ b/tools/attr.c
@@ -28,6 +28,8 @@
 #include <errno.h>
 #include <string.h>
 #include <locale.h>
+#include <libgen.h>
+#include <strings.h>
 
 #include <attr/attributes.h>
 
diff --git a/tools/getfattr.c b/tools/getfattr.c
index cc55d5f..6c75e33 100644
--- a/tools/getfattr.c
+++ b/tools/getfattr.c
@@ -28,11 +28,11 @@
 #include <regex.h>
 #include <locale.h>
 #include <libgen.h>
-#include <sys/xattr.h>
 
 #include "config.h"
 #include "walk_tree.h"
 #include "misc.h"
+#include "xattr.h"
 
 #define CMD_LINE_OPTIONS "n:de:m:hRLP"
 #define CMD_LINE_SPEC "[-hRLP] [-n name|-d] [-e en] [-m pattern] path..."
diff --git a/tools/setfattr.c b/tools/setfattr.c
index 9556c6c..61cf70a 100644
--- a/tools/setfattr.c
+++ b/tools/setfattr.c
@@ -27,11 +27,11 @@
 #include <locale.h>
 #include <ctype.h>
 #include <libgen.h>
-#include <sys/xattr.h>
 #include <sys/errno.h>
 
 #include "config.h"
 #include "misc.h"
+#include "xattr.h"
 
 #define CMD_LINE_OPTIONS "n:x:v:h"
 #define CMD_LINE_SPEC1 "{-n name} [-v value] [-h] file..."
