# HG changeset patch # User Bruno Haible # Date 1213058428 -7200 # Node ID ccfd3047da7278a9d249f88fca803d6a9103b972 # Parent e33912e3fd26ef1537ddd53c23e02c9d1dbd2c78 Work around the Solaris 10 ACE ACLs ABI change. diff -r e33912e3fd26 -r ccfd3047da72 ChangeLog --- a/ChangeLog Mon Jun 09 16:41:11 2008 -0600 +++ b/ChangeLog Tue Jun 10 02:40:28 2008 +0200 @@ -1,3 +1,21 @@ +2008-06-09 Bruno Haible + + Work around the Solaris 10 ACE ACLs ABI change. + * lib/acl-internal.h (acl_nontrivial, acl_ace_nontrivial): Don't + declare if ACL_NO_TRIVIAL is present. + (ACE_ACCESS_ALLOWED_ACE_TYPE, ACE_ACCESS_DENIED_ACE_TYPE, + NEW_ACE_OWNER, NEW_ACE_GROUP, NEW_ACE_IDENTIFIER_GROUP, ACE_EVERYONE, + NEW_ACE_READ_DATA, NEW_ACE_WRITE_DATA, NEW_ACE_EXECUTE): New macros. + * lib/file-has-acl.c (acl_nontrivial, acl_ace_nontrivial): Don't + define if ACL_NO_TRIVIAL is present. + (acl_ace_nontrivial): Detect whether the old or new ABI is in use, + and use the current ABI. + (file_has_acl): Use same #if condition as elsewhere. + * lib/set-mode-acl.c (qset_acl): Detect whether the old or new ABI is + in use, and use the current ABI. + * doc/acl-resources.txt: More doc about newer Solaris 10 versions. + Reported by Jim Meyering. + 2008-06-09 Eric Blake Work around environments that (stupidly) ignore SIGALRM. diff -r e33912e3fd26 -r ccfd3047da72 doc/acl-resources.txt --- a/doc/acl-resources.txt Mon Jun 09 16:41:11 2008 -0600 +++ b/doc/acl-resources.txt Tue Jun 10 02:40:28 2008 +0200 @@ -90,6 +90,22 @@ aclsort acltomode acltotext +Additionally in Solaris 10 patch 118833-17 ( version 1.15): + acl_t type + ACL_NO_TRIVIAL macro + ACE_OTHER macro replaced with ACE_EVERYONE macro + ACE_OWNER, ACE_GROUP changed their values(!) + ALLOW, DENY macros removed(!) + acl_check + acl_free + acl_fromtext + acl_get + acl_set + acl_strip + acl_totext + acl_trivial + facl_get + facl_set Utilities: getfacl setfacl diff -r e33912e3fd26 -r ccfd3047da72 lib/acl-internal.h --- a/lib/acl-internal.h Mon Jun 09 16:41:11 2008 -0600 +++ b/lib/acl-internal.h Tue Jun 10 02:40:28 2008 +0200 @@ -168,15 +168,36 @@ # define MODE_INSIDE_ACL 1 # endif +# if !defined ACL_NO_TRIVIAL /* Solaris <= 10, Cygwin */ + /* Return 1 if the given ACL is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ extern int acl_nontrivial (int count, aclent_t *entries); -# ifdef ACE_GETACL +# ifdef ACE_GETACL /* Solaris 10 */ + /* Test an ACL retrieved with ACE_GETACL. Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ extern int acl_ace_nontrivial (int count, ace_t *entries); + +/* Definitions for when the built executable is executed on Solaris 10 + (newer version) or Solaris 11. */ +/* For a_type. */ +# define ACE_ACCESS_ALLOWED_ACE_TYPE 0 /* replaces ALLOW */ +# define ACE_ACCESS_DENIED_ACE_TYPE 1 /* replaces DENY */ +/* For a_flags. */ +# define NEW_ACE_OWNER 0x1000 +# define NEW_ACE_GROUP 0x2000 +# define NEW_ACE_IDENTIFIER_GROUP 0x0040 +# define ACE_EVERYONE 0x4000 +/* For a_access_mask. */ +# define NEW_ACE_READ_DATA 0x001 /* corresponds to 'r' */ +# define NEW_ACE_WRITE_DATA 0x002 /* corresponds to 'w' */ +# define NEW_ACE_EXECUTE 0x004 /* corresponds to 'x' */ + +# endif + # endif # elif HAVE_GETACL /* HP-UX */ diff -r e33912e3fd26 -r ccfd3047da72 lib/file-has-acl.c --- a/lib/file-has-acl.c Mon Jun 09 16:41:11 2008 -0600 +++ b/lib/file-has-acl.c Tue Jun 10 02:40:28 2008 +0200 @@ -120,6 +120,8 @@ #elif USE_ACL && HAVE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ +# if !defined ACL_NO_TRIVIAL /* Solaris <= 10, Cygwin */ + /* Test an ACL retrieved with GETACL. Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ @@ -146,7 +148,7 @@ return 0; } -# if defined ACE_GETACL && defined ALLOW && defined ACE_OWNER +# ifdef ACE_GETACL /* Test an ACL retrieved with ACE_GETACL. Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. @@ -156,22 +158,59 @@ { int i; + /* The flags in the ace_t structure changed in a binary incompatible way + when ACL_NO_TRIVIAL etc. were introduced in version 1.15. + How to distinguish the two conventions at runtime? + In the old convention, usually three ACEs have a_flags = ACE_OWNER / + ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400. In the new + convention, these values are not used. */ + int old_convention = 0; + for (i = 0; i < count; i++) - { - ace_t *ace = &entries[i]; + if (entries[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_OTHER)) + { + old_convention = 1; + break; + } + + if (old_convention) + /* Running on Solaris 10. */ + for (i = 0; i < count; i++) + { + ace_t *ace = &entries[i]; - /* Note: If ace->a_flags = ACE_OWNER, ace->a_who is the st_uid from - stat(). If ace->a_flags = ACE_GROUP, ace->a_who is the st_gid from - stat(). We don't need to check ace->a_who in these cases. */ - if (!(ace->a_type == ALLOW - && (ace->a_flags == ACE_OWNER - || ace->a_flags == ACE_GROUP - || ace->a_flags == ACE_OTHER))) - return 1; - } + /* Note: + If ace->a_flags = ACE_OWNER, ace->a_who is the st_uid from stat(). + If ace->a_flags = ACE_GROUP, ace->a_who is the st_gid from stat(). + We don't need to check ace->a_who in these cases. */ + if (!(ace->a_type == ALLOW + && (ace->a_flags == ACE_OWNER + || ace->a_flags == ACE_GROUP + || ace->a_flags == ACE_OTHER))) + return 1; + } + else + /* Running on Solaris 10 (newer version) or Solaris 11. */ + for (i = 0; i < count; i++) + { + ace_t *ace = &entries[i]; + + if (!(ace->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE + && (ace->a_flags == NEW_ACE_OWNER + || ace->a_flags + == (NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP) + || ace->a_flags == ACE_EVERYONE) + && (ace->a_access_mask + & ~(NEW_ACE_READ_DATA | NEW_ACE_WRITE_DATA | NEW_ACE_EXECUTE)) + == 0)) + return 1; + } + return 0; } +# endif + # endif #elif USE_ACL && HAVE_GETACL /* HP-UX */ @@ -310,7 +349,7 @@ # elif HAVE_ACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ -# if HAVE_ACL_TRIVIAL +# if defined ACL_NO_TRIVIAL /* Solaris 10 (newer version), which has additional API declared in (acl_t) and implemented in libsec (acl_set, acl_trivial, diff -r e33912e3fd26 -r ccfd3047da72 lib/set-mode-acl.c --- a/lib/set-mode-acl.c Mon Jun 09 16:41:11 2008 -0600 +++ b/lib/set-mode-acl.c Tue Jun 10 02:40:28 2008 +0200 @@ -249,34 +249,118 @@ # ifdef ACE_GETACL /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 file systems (whereas the other ones are used in UFS file systems). */ + + /* The flags in the ace_t structure changed in a binary incompatible way + when ACL_NO_TRIVIAL etc. were introduced in version 1.15. + How to distinguish the two conventions at runtime? + We fetch the existing ACL. In the old convention, usually three ACEs have + a_flags = ACE_OWNER / ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400. + In the new convention, these values are not used. */ + int convention; + { - ace_t entries[3]; - int ret; + int count; + ace_t *entries; - entries[0].a_type = ALLOW; - entries[0].a_flags = ACE_OWNER; - entries[0].a_who = 0; /* irrelevant */ - entries[0].a_access_mask = (mode >> 6) & 7; - entries[1].a_type = ALLOW; - entries[1].a_flags = ACE_GROUP; - entries[1].a_who = 0; /* irrelevant */ - entries[1].a_access_mask = (mode >> 3) & 7; - entries[2].a_type = ALLOW; - entries[2].a_flags = ACE_OTHER; - entries[2].a_who = 0; - entries[2].a_access_mask = mode & 7; + for (;;) + { + if (desc != -1) + count = facl (desc, ACE_GETACLCNT, 0, NULL); + else + count = acl (name, ACE_GETACLCNT, 0, NULL); + if (count <= 0) + { + convention = -1; + break; + } + entries = (ace_t *) malloc (count * sizeof (ace_t)); + if (entries == NULL) + { + errno = ENOMEM; + return -1; + } + if ((desc != -1 + ? facl (desc, ACE_GETACL, count, entries) + : acl (name, ACE_GETACL, count, entries)) + == count) + { + int i; - if (desc != -1) - ret = facl (desc, ACE_SETACL, sizeof (entries) / sizeof (aclent_t), entries); - else - ret = acl (name, ACE_SETACL, sizeof (entries) / sizeof (aclent_t), entries); - if (ret < 0 && errno != EINVAL && errno != ENOTSUP) - { - if (errno == ENOSYS) - return chmod_or_fchmod (name, desc, mode); - return -1; + convention = 0; + for (i = 0; i < count; i++) + if (entries[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_OTHER)) + { + convention = 1; + break; + } + free (entries); + break; + } + /* Huh? The number of ACL entries changed since the last call. + Repeat. */ + free (entries); } } + + if (convention >= 0) + { + ace_t entries[3]; + int ret; + + if (convention) + { + /* Running on Solaris 10. */ + entries[0].a_type = ALLOW; + entries[0].a_flags = ACE_OWNER; + entries[0].a_who = 0; /* irrelevant */ + entries[0].a_access_mask = (mode >> 6) & 7; + entries[1].a_type = ALLOW; + entries[1].a_flags = ACE_GROUP; + entries[1].a_who = 0; /* irrelevant */ + entries[1].a_access_mask = (mode >> 3) & 7; + entries[2].a_type = ALLOW; + entries[2].a_flags = ACE_OTHER; + entries[2].a_who = 0; + entries[2].a_access_mask = mode & 7; + } + else + { + /* Running on Solaris 10 (newer version) or Solaris 11. */ + entries[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; + entries[0].a_flags = NEW_ACE_OWNER; + entries[0].a_who = 0; /* irrelevant */ + entries[0].a_access_mask = + (mode & 0400 ? NEW_ACE_READ_DATA : 0) + | (mode & 0200 ? NEW_ACE_WRITE_DATA : 0) + | (mode & 0100 ? NEW_ACE_EXECUTE : 0); + entries[1].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; + entries[1].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP; + entries[1].a_who = 0; /* irrelevant */ + entries[1].a_access_mask = + (mode & 0040 ? NEW_ACE_READ_DATA : 0) + | (mode & 0020 ? NEW_ACE_WRITE_DATA : 0) + | (mode & 0010 ? NEW_ACE_EXECUTE : 0); + entries[2].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; + entries[2].a_flags = ACE_EVERYONE; + entries[2].a_who = 0; + entries[2].a_access_mask = + (mode & 0004 ? NEW_ACE_READ_DATA : 0) + | (mode & 0002 ? NEW_ACE_WRITE_DATA : 0) + | (mode & 0001 ? NEW_ACE_EXECUTE : 0); + } + if (desc != -1) + ret = facl (desc, ACE_SETACL, + sizeof (entries) / sizeof (aclent_t), entries); + else + ret = acl (name, ACE_SETACL, + sizeof (entries) / sizeof (aclent_t), entries); + if (ret < 0 && errno != EINVAL && errno != ENOTSUP) + { + if (errno == ENOSYS) + return chmod_or_fchmod (name, desc, mode); + return -1; + } + } # endif {