Hi Jim, > FYI, building failed on Solaris 10, > > file-has-acl.c: In function 'acl_ace_nontrivial': > file-has-acl.c:166: error: 'ALLOW' undeclared (first use in this function) > file-has-acl.c:166: error: (Each undeclared identifier is reported only once > file-has-acl.c:166: error: for each function it appears in.) > file-has-acl.c:169: error: 'ACE_OTHER' undeclared (first use in this > function) > make[3]: *** [file-has-acl.o] Error 1 > > With this patch, it compiles:
But you got no link error? So you must be on a Solaris 10+ system with augmented ACL API. > +# if defined ACE_GETACL && defined ALLOW && defined ACE_OWNER It's the macro ACE_OTHER, not ACE_OWNER, which was removed. I've now found a copy of the "augmented" Solaris 10+ <sys/acl.h>. The differences between these two versions are: - New acl_t type - New ACL_NO_TRIVIAL macro - ACE_OTHER macro replaced with ACE_EVERYONE macro - ACE_OWNER, ACE_GROUP changed their values(!) - many other ACE_* macros were changed - ACE_READ_DATA, ACE_WRITE_DATA, ACE_EXECUTE changed their values(!) - ALLOW, DENY macros removed(!) - New EACL_* macros for aclcheck - New functions acl_check acl_free acl_fromtext acl_get acl_set acl_strip acl_totext acl_trivial facl_get facl_set So, Sun has shipped an ABI changed in a Solaris 10 patch. Great. Fun. Of course, everyone expects that coreutils programs, built on a pristine Solaris 10, still work after the Solaris 10 patch is applied. Here's the workaround. 2008-06-09 Bruno Haible <[EMAIL PROTECTED]> 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. *** doc/acl-resources.txt.orig 2008-06-10 02:39:42.000000000 +0200 --- doc/acl-resources.txt 2008-06-09 23:56:05.000000000 +0200 *************** *** 90,95 **** --- 90,111 ---- aclsort acltomode acltotext + Additionally in Solaris 10 patch 118833-17 (<sys/acl.h> 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 *** lib/acl-internal.h.orig 2008-06-10 02:39:42.000000000 +0200 --- lib/acl-internal.h 2008-06-10 01:33:36.000000000 +0200 *************** *** 168,182 **** # define MODE_INSIDE_ACL 1 # endif /* 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 /* 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); # endif # elif HAVE_GETACL /* HP-UX */ --- 168,203 ---- # 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 /* 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 */ *** lib/file-has-acl.c.orig 2008-06-10 02:39:42.000000000 +0200 --- lib/file-has-acl.c 2008-06-10 01:38:19.000000000 +0200 *************** *** 120,125 **** --- 120,127 ---- #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,152 **** return 0; } ! # if defined ACE_GETACL && defined ALLOW && defined ACE_OWNER /* Test an ACL retrieved with ACE_GETACL. Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. --- 148,154 ---- return 0; } ! # ifdef ACE_GETACL /* Test an ACL retrieved with ACE_GETACL. Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. *************** *** 156,177 **** { int i; 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; - } return 0; } # endif #elif USE_ACL && HAVE_GETACL /* HP-UX */ --- 158,216 ---- { int i; + /* The flags in the ace_t structure changed in a binary incompatible way + when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> 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++) ! 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; ! } ! 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,316 **** # elif HAVE_ACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ ! # if HAVE_ACL_TRIVIAL /* Solaris 10 (newer version), which has additional API declared in <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial, --- 349,355 ---- # elif HAVE_ACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ ! # if defined ACL_NO_TRIVIAL /* Solaris 10 (newer version), which has additional API declared in <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial, *** lib/set-mode-acl.c.orig 2008-06-10 02:39:42.000000000 +0200 --- lib/set-mode-acl.c 2008-06-10 02:39:39.000000000 +0200 *************** *** 249,282 **** # 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). */ - { - ace_t entries[3]; - int ret; ! 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; ! 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 { --- 249,366 ---- # 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 <sys/acl.h> 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; ! { ! int count; ! ace_t *entries; ! ! 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; ! ! 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 {