PSARC/2006/043 ls -V
authormarks
Mon, 13 Feb 2006 08:52:39 -0800
changeset 1420 4cb3c26a37e0
parent 1419 b4250a879844
child 1421 8fd08807fdcc
PSARC/2006/043 ls -V PSARC/2006/047 acl_totext PSARC/2006/048 Compact chmod ACL syntax 6362641 tar does not store ACLs in a suitable format 6379909 Need compact ACL utility support for NFSv4/ZFS
usr/src/cmd/bart/create.c
usr/src/cmd/chmod/chmod.c
usr/src/cmd/cmd-inet/usr.bin/rcp.c
usr/src/cmd/cpio/cpio.c
usr/src/cmd/ls/ls.c
usr/src/cmd/tar/tar.c
usr/src/lib/libsec/Makefile
usr/src/lib/libsec/Makefile.com
usr/src/lib/libsec/common/acl.y
usr/src/lib/libsec/common/acl_lex.l
usr/src/lib/libsec/common/acltext.c
usr/src/lib/libsec/common/aclutils.c
usr/src/lib/libsec/common/aclutils.h
usr/src/lib/libsec/spec/acl.spec
usr/src/uts/common/sys/acl.h
--- a/usr/src/cmd/bart/create.c	Mon Feb 13 02:31:44 2006 -0800
+++ b/usr/src/cmd/bart/create.c	Mon Feb 13 08:52:39 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -642,7 +642,7 @@
 		(void) fprintf(stderr, "%s: %s\n", fname, acl_strerror(error));
 		return (safe_strdup("-"));
 	} else {
-		acltext = acl_totext(aclp);
+		acltext = acl_totext(aclp, 0);
 		acl_free(aclp);
 		return (acltext);
 	}
--- a/usr/src/cmd/chmod/chmod.c	Mon Feb 13 02:31:44 2006 -0800
+++ b/usr/src/cmd/chmod/chmod.c	Mon Feb 13 08:52:39 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -429,7 +429,6 @@
 {
 	acl_t *new_acl = NULL;
 	int slot;
-	int error;
 	int len;
 	int action;
 	acl_args_t *new_acl_args;
@@ -478,9 +477,8 @@
 		return (1);
 
 	if (acl_spec) {
-		if (error = acl_fromtext(acl_spec, &new_acl)) {
-			errmsg(1, 1, "%s\n", acl_strerror(error));
-			return (1);
+		if (acl_parse(acl_spec, &new_acl)) {
+			exit(1);
 		}
 	}
 
--- a/usr/src/cmd/cmd-inet/usr.bin/rcp.c	Mon Feb 13 02:31:44 2006 -0800
+++ b/usr/src/cmd/cmd-inet/usr.bin/rcp.c	Mon Feb 13 08:52:39 2006 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1826,7 +1826,7 @@
 	 * imply its not trivial.
 	 */
 	if (aclp && (trivial != ACL_IS_TRIVIAL)) {
-		acltext = acl_totext(aclp);
+		acltext = acl_totext(aclp, 0);
 		if (acltext == NULL) {
 			error("rcp: failed to convert to text\n");
 			acl_free(aclp);
--- a/usr/src/cmd/cpio/cpio.c	Mon Feb 13 02:31:44 2006 -0800
+++ b/usr/src/cmd/cpio/cpio.c	Mon Feb 13 08:52:39 2006 -0800
@@ -6645,7 +6645,7 @@
 	case ACLENT_T:
 	case ACE_T:
 		/* LINTED alignment */
-		attrtext = acl_totext(aclp);
+		attrtext = acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT);
 		if (attrtext == NULL) {
 			(void) fprintf(stderr, "acltotext failed\n");
 			return (-1);
--- a/usr/src/cmd/ls/ls.c	Mon Feb 13 02:31:44 2006 -0800
+++ b/usr/src/cmd/ls/ls.c	Mon Feb 13 08:52:39 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -221,6 +221,7 @@
 static int		Rflg;
 static int		Sflg;
 static int		vflg;
+static int		Vflg;
 static long		hscale;
 static mode_t		flags;
 static int		err = 0;	/* Contains return code */
@@ -287,7 +288,7 @@
 	}
 
 	while ((c = getopt(argc, argv,
-	    "aAbcCdeEfFghHilLmnopqrRsStux1@v")) != EOF)
+	    "aAbcCdeEfFghHilLmnopqrRsStux1@vV")) != EOF)
 		switch (c) {
 		case 'a':
 			aflg++;
@@ -416,6 +417,9 @@
 			cflg = 0;
 			uflg++;
 			continue;
+		case 'V':
+			Vflg++;
+			/*FALLTHROUGH*/
 		case 'v':
 			vflg++;
 #if !defined(XPG4)
@@ -460,7 +464,7 @@
 		}
 	if (opterr) {
 		(void) fprintf(stderr, gettext(
-		    "usage: ls -aAbcCdeEfFghHilLmnopqrRsStuxv1@ [files]\n"));
+		    "usage: ls -aAbcCdeEfFghHilLmnopqrRsStuxvV1@ [files]\n"));
 		exit(2);
 	}
 
@@ -868,7 +872,7 @@
 	if (vflg) {
 		new_line();
 		if (p->aclp) {
-			acl_printacl(p->aclp, num_cols);
+			acl_printacl(p->aclp, num_cols, Vflg);
 		}
 	}
 }
@@ -1378,6 +1382,11 @@
 				}
 			}
 
+			if (!vflg && !Vflg && rep->aclp) {
+				acl_free(rep->aclp);
+				rep->aclp = NULL;
+			}
+
 			if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1)
 				rep->acl = '@';
 		} else
--- a/usr/src/cmd/tar/tar.c	Mon Feb 13 02:31:44 2006 -0800
+++ b/usr/src/cmd/tar/tar.c	Mon Feb 13 08:52:39 2006 -0800
@@ -3025,7 +3025,6 @@
 						/* header is 8 */
 						attrsize = 8 + (int)strlen(
 						    &attr->attr_info[0]) + 1;
-
 						error =
 						    acl_fromtext(
 						    &attr->attr_info[0], &aclp);
@@ -5571,7 +5570,7 @@
 	switch (acl_type(aclp)) {
 	case ACLENT_T:
 	case ACE_T:
-		attrtext = acl_totext(aclp);
+		attrtext = acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT);
 		if (attrtext == NULL) {
 			(void) fprintf(stderr, "acltotext failed\n");
 			return (-1);
--- a/usr/src/lib/libsec/Makefile	Mon Feb 13 02:31:44 2006 -0800
+++ b/usr/src/lib/libsec/Makefile	Mon Feb 13 08:52:39 2006 -0800
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -41,7 +41,9 @@
 lint :=		TARGET= lint
 
 MSGFILES=	common/acltext.c common/aclutils.c common/aclmode.c \
-		common/aclsort.c common/aclcheck.c
+		common/aclsort.c common/aclcheck.c common/acl_lex.l \
+		common/acl.y
+
 POFILE=		libsec.po
 
 .KEEP_STATE:
--- a/usr/src/lib/libsec/Makefile.com	Mon Feb 13 02:31:44 2006 -0800
+++ b/usr/src/lib/libsec/Makefile.com	Mon Feb 13 08:52:39 2006 -0800
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -31,9 +31,14 @@
 LIBRARY= libsec.a
 VERS= .1
 
+YFLAGS =	-d -v -b acl
+LFLAGS = 	-t
 OBJS_SHARED= acl_common.o
+GENERATED_SRCS = acl.tab.o acl_lex.o
 OBJS_COMMON= aclcheck.o aclmode.o aclsort.o acltext.o aclutils.o
-OBJECTS= $(OBJS_COMMON) $(OBJS_SHARED)
+OBJECTS= $(OBJS_COMMON) $(OBJS_SHARED) $(GENERATED_SRCS)
+CLEANFILES += acl_lex.c acl.tab.c acl.tab.h
+LINTSRCS = $(OBJS_COMMON)
 
 # include library definitions
 include ../../Makefile.lib
@@ -41,8 +46,8 @@
 LIBS =		$(DYNLIB) $(LINTLIB)
 
 CFLAGS +=	$(CCVERBOSE)
-CPPFLAGS +=	-I$(SRCDIR) -I../../../common/acl
-LDLIBS += -lc 
+CPPFLAGS +=	-I$(SRCDIR) -I. -I../../../common/acl
+LDLIBS += -lc
 
 # install this library in the root filesystem
 include ../../Makefile.rootfs
@@ -66,4 +71,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(POST_PROCESS_O)
 
+acl.tab.c acl.tab.h:	$(SRCDIR)/acl.y
+	$(YACC) $(YFLAGS) $(SRCDIR)/acl.y
+
+acl_lex.c: $(SRCDIR)/acl_lex.l acl.tab.h
+	$(LEX) $(LFLAGS) $(SRCDIR)/acl_lex.l > $@
+
 include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsec/common/acl.y	Mon Feb 13 08:52:39 2006 -0800
@@ -0,0 +1,484 @@
+%{
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma	ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/acl.h>
+#include <aclutils.h>
+
+extern int yyinteractive;
+extern acl_t *yyacl;
+%}
+
+
+%union {
+	char *str;
+	int val;
+	struct acl_perm_type acl_perm;
+	ace_t ace;
+	aclent_t aclent;
+	acl_t *acl;
+}
+
+
+%token USER_TOK GROUP_TOK MASK_TOK OTHER_TOK OWNERAT_TOK 
+%token GROUPAT_TOK EVERYONEAT_TOK DEFAULT_USER_TOK DEFAULT_GROUP_TOK
+%token DEFAULT_MASK_TOK DEFAULT_OTHER_TOK COLON COMMA NL SLASH 
+%token <str> IDNAME PERM_TOK INHERIT_TOK
+%token <val> ID ERROR ACE_PERM ACE_INHERIT ENTRY_TYPE ACCESS_TYPE
+
+%type <str> idname
+%type <acl_perm> perms perm aclent_perm ace_perms
+%type <acl> acl_entry
+%type <ace> ace 
+%type <aclent> aclent
+%type <val> iflags verbose_iflag compact_iflag access_type id entry_type
+
+%left	ERROR COLON
+
+%%
+
+acl:	acl_entry NL 
+	{ 
+		yyacl = $1;
+		return (0);
+	} 
+
+	/* This seems illegal, but the old aclfromtext() allows it */
+	| acl_entry COMMA NL	
+	{
+		yyacl = $1;
+		return (0);
+	}
+	| acl_entry COMMA acl 
+	{ 
+		yyacl = $1;
+		return (0);
+	}
+	
+acl_entry: ace 
+	{
+		ace_t *acep;
+
+		if (yyacl == NULL) {
+			yyacl = acl_alloc(ACE_T);
+			if (yyacl == NULL) 
+				return (EACL_MEM_ERROR);
+		} 
+
+		$$ = yyacl;
+		if ($$->acl_type == ACLENT_T) {
+			acl_error(gettext("Cannot have POSIX draft ACL entries"
+			     " with NFSV4/ZFS ACL entries\n"));
+			acl_free(yyacl);
+			yyacl = NULL;
+			return (EACL_DIFF_TYPE);
+		}
+			
+		$$->acl_aclp = realloc($$->acl_aclp,
+		    ($$->acl_entry_size * ($$->acl_cnt + 1)));
+		if ($$->acl_aclp == NULL) {
+			free (yyacl);
+			return (EACL_MEM_ERROR);	
+		}
+		acep = $$->acl_aclp;
+		acep[$$->acl_cnt] = $1;
+		$$->acl_cnt++;
+	}
+	| aclent
+	{
+		aclent_t *aclent;
+
+		if (yyacl == NULL) {
+			yyacl = acl_alloc(ACLENT_T);
+			if (yyacl == NULL) 
+				return (EACL_MEM_ERROR);
+		} 
+
+		$$ = yyacl;
+		if ($$->acl_type == ACE_T) {
+			acl_error(gettext("Cannot have NFSv4/ZFS ACL entries"
+			     " with POSIX draft ACL entries\n"));
+			acl_free(yyacl);
+			yyacl = NULL;
+			return (EACL_DIFF_TYPE);
+		}
+
+		$$->acl_aclp = realloc($$->acl_aclp,
+		    ($$->acl_entry_size  * ($$->acl_cnt +1)));
+		if ($$->acl_aclp == NULL) {
+			free (yyacl);
+			return (EACL_MEM_ERROR);	
+		}
+		aclent = $$->acl_aclp;
+		aclent[$$->acl_cnt] = $1;
+		$$->acl_cnt++;
+	}
+
+ace:	entry_type idname ace_perms access_type
+	{
+		int error;
+		int id;
+		int mask;
+
+		error = get_id($1, $2, &id);
+		if (error) {
+			acl_error(gettext("Invalid user %s specified\n"), $2);
+			free($2);
+			return (EACL_INVALID_USER_GROUP);
+		}
+			
+		$$.a_who = id;
+		$$.a_flags = ace_entry_type($1);
+		free($2);
+		error = ace_perm_mask(&$3, &$$.a_access_mask);
+		if (error)
+			return (error);
+		$$.a_type = $4;
+
+	}
+	| entry_type idname ace_perms access_type COLON id
+	{
+		int error;
+		int id;
+
+		if (yyinteractive) {
+			acl_error(gettext("Extra fields on the end of "
+			    "ACL specification\n"));
+			return (EACL_UNKNOWN_DATA);
+		}
+		error = get_id($1, $2, &id);
+		if (error) {
+			$$.a_who = $6;
+		} else {
+			$$.a_who = id;
+		}
+		$$.a_flags = ace_entry_type($1);
+		free($2);
+		error = ace_perm_mask(&$3, &$$.a_access_mask);
+		if (error)
+			return (error);
+		$$.a_type = $4;
+	}
+	| entry_type idname ace_perms iflags access_type 
+	{
+		int error;
+		int id;
+
+		error = get_id($1, $2, &id);
+		if (error) {
+			acl_error(gettext("Invalid user %s specified\n"), $2);
+			free($2);
+			return (EACL_INVALID_USER_GROUP);
+		}
+		
+		$$.a_who = id;
+		$$.a_flags = ace_entry_type($1);
+		free($2);
+		error = ace_perm_mask(&$3, &$$.a_access_mask);
+		if (error)
+			return (error);
+		$$.a_type = $5;
+		$$.a_flags |= $4;
+	}
+	| entry_type idname ace_perms iflags access_type COLON id
+	{
+		int error;
+		int  id;
+
+		if (yyinteractive) {
+			acl_error(gettext("Extra fields on the end of "
+			    "ACL specification\n"));
+			return (EACL_UNKNOWN_DATA);
+		}
+		error = get_id($1, $2, &id);
+		if (error) {
+			$$.a_who = $7;
+		} else {
+			$$.a_who = id;
+		}
+
+		$$.a_flags = ace_entry_type($1);
+		free($2);
+		error = ace_perm_mask(&$3, &$$.a_access_mask);
+		if (error)
+			return (error);
+
+		$$.a_type = $5;
+		$$.a_flags |= $4;
+	}
+	| entry_type ace_perms access_type
+	{ 
+		int error;
+
+		$$.a_who = -1;
+		$$.a_flags = ace_entry_type($1);
+		error = ace_perm_mask(&$2, &$$.a_access_mask);
+		if (error) {
+			return (error);
+		}
+		$$.a_type = $3;
+	} 
+	| entry_type ace_perms access_type COLON id
+	{
+		if (yyinteractive) {
+			acl_error(gettext("Extra fields on the end of "
+			    "ACL specification\n"));
+			return (EACL_UNKNOWN_DATA);
+		}
+
+		return (EACL_ENTRY_ERROR);
+	}
+	| entry_type ace_perms iflags access_type 
+	{
+		int error;
+
+		$$.a_who = -1;
+		$$.a_flags = ace_entry_type($1);
+		error = ace_perm_mask(&$2, &$$.a_access_mask);
+		if (error)
+			return (error);
+		$$.a_type = $4;
+		$$.a_flags |= $3;
+
+	}
+	| entry_type ace_perms iflags access_type COLON id
+	{
+		if (yyinteractive) {
+			acl_error(gettext("Extra fields on the end of "
+			    "ACL specification\n"));
+			return (EACL_UNKNOWN_DATA);
+		}
+		return (EACL_ENTRY_ERROR);
+	}
+
+aclent: entry_type idname aclent_perm	/* user or group */
+	{
+		int error;
+		int id;
+
+		error = get_id($1, $2, &id);
+		if (error) {
+			acl_error(gettext("Invalid user '%s' specified\n"),
+			    $2);
+			free($2);
+			return (EACL_INVALID_USER_GROUP);
+		}
+
+		error = compute_aclent_perms($3.perm_str, &$$.a_perm);
+		if (error) {
+			free($2);
+			acl_error(gettext(
+			    "Invalid permission(s) '%s' specified\n"),
+			    $3.perm_str);
+			return (error);
+		}
+		$$.a_id = id;
+		error = aclent_entry_type($1, 0, &$$.a_type);
+		free($2);
+		if (error) {
+			acl_error(
+			    gettext("Invalid ACL entry type '%s' specified\n"),
+			    $1);
+			return (error);
+		}
+	}
+	| entry_type COLON aclent_perm		/* owner group other */
+	{
+		int error;
+
+		error = compute_aclent_perms($3.perm_str, &$$.a_perm);
+		if (error) {
+			acl_error(gettext(
+			    "Invalid permission(s) '%s' specified\n"),
+			    $3.perm_str);
+			return (error);
+		}
+		$$.a_id = -1;
+		error = aclent_entry_type($1, 1, &$$.a_type);
+		if (error) {
+			acl_error(
+			    gettext("Invalid ACL entry type '%s' specified\n"),
+			    $1);
+			return (error);
+		}
+	}
+	| entry_type COLON aclent_perm COLON id
+	{ 
+		if (yyinteractive) {
+			acl_error(gettext("Extra fields on the end of "
+			    "ACL specification\n"));
+			return (EACL_UNKNOWN_DATA);
+		}
+		return (EACL_ENTRY_ERROR);
+	}
+	| entry_type idname aclent_perm COLON id 	/* user or group */
+	{	
+		int error;
+		int id;
+
+		if (yyinteractive) {
+			acl_error(gettext("Extra fields on the end of "
+			    "ACL specification\n"));
+			return (EACL_UNKNOWN_DATA);
+		}
+		error = compute_aclent_perms($3.perm_str, &$$.a_perm);
+		if (error) {
+			free($2);
+			acl_error(gettext(
+			    "Invalid permission(s) '%s' specified\n"),
+			    $3.perm_str);
+			return (error);
+		}
+		error = get_id($1, $2, &id);
+		if (error)
+			$$.a_id = $5;	
+		else 
+			$$.a_id = id;
+
+		error = aclent_entry_type($1, 0, &$$.a_type);
+		free($2);
+		if (error) {
+			acl_error(
+			    gettext("Invalid ACL entry type '%s' specified\n"),
+			    $1);
+			return (error);
+		}
+	}
+	| entry_type aclent_perm  /* mask entry */
+	{
+		int error;
+
+		error = compute_aclent_perms($2.perm_str, &$$.a_perm);
+		if (error) {
+			acl_error(gettext(
+			    "Invalid permission(s) '%s' specified\n"),
+			    $2.perm_str);
+			return (error);
+		}
+		$$.a_id = -1;
+		error = aclent_entry_type($1, 0, &$$.a_type);
+		if (error) {
+			acl_error(
+			    gettext("Invalid ACL entry type specified %d\n"),
+			    error);
+			return (error);
+		}
+	}
+	| entry_type aclent_perm COLON id
+	{
+		if (yyinteractive) {
+			acl_error(gettext("Extra fields on the end of "
+			    "ACL specification\n"));
+			return (EACL_UNKNOWN_DATA);
+		}
+		return (EACL_ENTRY_ERROR);
+	}
+
+iflags: compact_iflag COLON {$$ = $1;}
+	| verbose_iflag COLON {$$ = $1;}
+	| COLON {$$ = 0;}
+
+compact_iflag : INHERIT_TOK
+	{
+		int error;
+		uint32_t iflags;
+
+		error = compute_ace_inherit($1, &iflags);
+		if (error) {
+			acl_error(gettext("Invalid inheritance flags "
+			    "'%s' specified\n"), $1);
+			free($1);
+			return (error);
+		}
+		$$ = iflags;
+	}
+	| INHERIT_TOK SLASH verbose_iflag
+	{
+		acl_error(gettext("Can't mix compact inherit flags with"
+		    " verbose inheritance flags\n"));
+		return (EACL_INHERIT_ERROR);
+	}
+
+verbose_iflag: ACE_INHERIT	{$$ |= $1;}
+	| ACE_INHERIT SLASH verbose_iflag {$$ = $1 | $3;}
+	| ACE_INHERIT SLASH compact_iflag
+	{
+		acl_error(gettext("Can't mix verbose inherit flags with"
+		    " compact inheritance flags\n"));
+		return (EACL_INHERIT_ERROR);
+	}
+	| ACE_INHERIT SLASH ERROR {return ($3);}
+	
+aclent_perm: PERM_TOK
+	{
+		$$.perm_style = PERM_TYPE_UNKNOWN;
+		$$.perm_str = $1;
+		$$.perm_val = 0;
+	}
+	| PERM_TOK ERROR 
+	{
+		acl_error(gettext("ACL entry permissions are incorrectly "
+		    "specified\n"));
+		return ($2);
+	}
+
+access_type: ACCESS_TYPE { $$ = $1;}
+	   | ERROR {return ($1);}
+
+id: ID {$$ = $1;}
+	| ERROR {return ($1);}
+
+ace_perms: perm {$$ = $1;}
+	| aclent_perm COLON {$$ = $1;}
+	| ERROR {return ($1);}
+
+perm: perms COLON {$$ = $1;}
+    	| COLON {$$.perm_style = PERM_TYPE_EMPTY;}
+
+perms: ACE_PERM 
+     	{
+		$$.perm_style = PERM_TYPE_ACE;
+		$$.perm_val |= $1;
+	}
+	| ACE_PERM SLASH perms
+	{
+		$$.perm_style = PERM_TYPE_ACE;
+		$$.perm_val = $1 | $3.perm_val;
+	}
+	| ACE_PERM SLASH aclent_perm
+	{
+
+		acl_error(gettext("Can't mix verbose permissions with"
+		    " compact permission\n"));
+		return (EACL_PERM_MASK_ERROR);
+
+	}
+
+idname: IDNAME {$$ = $1;}
+
+entry_type: ENTRY_TYPE {$$ = $1;}
+	| ERROR {return ($1);}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsec/common/acl_lex.l	Mon Feb 13 08:52:39 2006 -0800
@@ -0,0 +1,719 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma	ident	"%Z%%M%	%I%	%E% SMI"
+
+%{
+#include <sys/acl.h>
+#include <aclutils.h>
+#include <errno.h>
+#include "acl.tab.h"
+
+#ifdef input
+#undef input
+#endif
+
+#ifdef unput
+#undef unput
+#endif
+
+int grab_string(char *terminators);
+static int input();
+static void unput(int);
+
+int 
+yyerror(const char *s)
+{
+	return (0);
+}
+
+int
+yywrap(void)
+{
+	return (1);
+}
+
+extern char *yybuf;
+int yybufpos;
+
+%}
+
+%s TS NS PS AIS US ES
+/*
+ * TS = type state
+ * NS = name state
+ * PS = Permission state
+ * AIS = Allow/deny/inheritance state
+ * US = UID/GID state
+ * ES = End state
+ */
+
+ID	[1-9][0-9]*
+LOGNAME [a-z0-9A-Z]+:
+BADLOGNAME [a-z0-9A-Z]+
+PERM_STR [rRwWxpdDaAcCos-]+
+INHERIT_STR [fdinFS-]+
+
+%%
+
+<TS>user:		{
+				BEGIN NS;
+				yylval.val = USER_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>owner@:		{
+				BEGIN PS;
+				yylval.val = OWNERAT_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>group@:		{
+				BEGIN PS;
+				yylval.val = GROUPAT_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>everyone@:		{
+				BEGIN PS;
+				yylval.val = EVERYONEAT_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>group:		{
+				BEGIN NS;
+				yylval.val = GROUP_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>mask:		{
+				BEGIN PS;
+				yylval.val = MASK_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>mask::		{
+				BEGIN PS;
+				yylval.val = MASK_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>other:		{
+				BEGIN PS;
+				yylval.val = OTHER_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>other::		{
+				BEGIN PS;
+				yylval.val = OTHER_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>defaultuser: 	{
+				BEGIN NS;
+				yylval.val = DEFAULT_USER_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>default:user:	{
+				BEGIN NS;
+				yylval.val = DEFAULT_USER_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>defaultgroup: 	{
+				BEGIN NS;
+				yylval.val = DEFAULT_GROUP_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>default:group:	{
+				BEGIN NS;
+				yylval.val = DEFAULT_GROUP_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>defaultother: 	{
+				BEGIN PS;
+				yylval.val = DEFAULT_OTHER_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>defaultother:: 	{
+				BEGIN PS;
+				yylval.val = DEFAULT_OTHER_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>default:other:	{
+				BEGIN PS;
+				yylval.val = DEFAULT_OTHER_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>defaultmask: 	{
+				BEGIN PS;
+				yylval.val = DEFAULT_MASK_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>defaultmask:: 	{
+				BEGIN PS;
+				yylval.val = DEFAULT_MASK_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>default:mask:		{
+				BEGIN PS;
+				yylval.val = DEFAULT_MASK_TOK;
+				return (ENTRY_TYPE);
+			}
+<TS>"\n"		{
+				return (NL);
+			}
+<TS>.			{
+				if (grab_string(":\n") != 0) {
+					acl_error(gettext("Failed to retrieve"
+					    " error string\n"));
+					yylval.val = EACL_MEM_ERROR;
+					return (ERROR);
+				}
+				acl_error(gettext("Invalid ACL entry "
+				    "type '%s' specified\n"), yylval.str);
+				free(yylval.str);
+				yylval.val = EACL_ENTRY_ERROR;
+				return (ERROR);
+			}
+<NS>:			{
+				BEGIN PS;
+				return (COLON);
+			}
+<NS>{LOGNAME}		{
+				yylval.str = strdup(yytext);
+				if (yylval.str == NULL) {
+					yylval.val = EACL_MEM_ERROR;
+					return (ERROR);
+				}
+				yylval.str[strlen(yylval.str) -1] = '\0';
+				BEGIN PS;
+				return (IDNAME);
+			}
+<NS>{BADLOGNAME}	{
+				acl_error(gettext("Missing fields after "
+				    "user/group '%s'\n"), yytext);
+				yylval.val = EACL_MISSING_FIELDS;
+				return (ERROR);
+			}
+<NS>"\n"		{
+				acl_error(gettext("Missing user/group name"
+				    " from ACL specification\n"));
+				yylval.val = EACL_MISSING_FIELDS;
+				return (ERROR);
+			}
+<NS>.			{
+				int error;
+				
+				error = grab_string(":\n");
+				if (error != 0) {
+					acl_error(gettext("Invalid user/group "
+					    "name specification\n"));
+					yylval.val = EACL_INVALID_USER_GROUP;
+				} else {
+					acl_error(gettext("User/Group name "
+					    "'%s' not specified correctly\n"),
+					    yylval.str);
+					free(yylval.str);
+					yylval.val = EACL_ENTRY_ERROR;
+				}
+				return (ERROR);
+			}
+<PS>read_data/[:/]	{
+				yylval.val = ACE_READ_DATA;
+				return (ACE_PERM);
+			}
+<PS>list_directory/[:/] {
+				yylval.val = ACE_LIST_DIRECTORY;
+			 	return (ACE_PERM);
+			}
+<PS>write_data/[:/]	{
+				yylval.val = ACE_WRITE_DATA;
+				return (ACE_PERM);
+			}
+<PS>add_file/[:/]	{
+				yylval.val = ACE_ADD_FILE;
+				return (ACE_PERM);
+			}
+<PS>append_data/[:/]	{
+				yylval.val = ACE_APPEND_DATA;
+				return (ACE_PERM);
+			}
+<PS>add_subdirectory/[:/] {
+				yylval.val = ACE_ADD_SUBDIRECTORY;
+				return (ACE_PERM);
+			}
+<PS>read_xattr/[:/]	{
+				yylval.val = ACE_READ_NAMED_ATTRS;
+				return (ACE_PERM);
+			}
+<PS>write_xattr/[:/]	{
+				yylval.val = ACE_WRITE_NAMED_ATTRS;
+				return (ACE_PERM);
+			}
+<PS>execute/[:/]	{
+				yylval.val = ACE_EXECUTE;
+				return (ACE_PERM);
+			}
+<PS>delete_child/[:/]	{
+				yylval.val = ACE_DELETE_CHILD;
+				return (ACE_PERM);
+			}
+<PS>read_attributes/[:/] {
+				yylval.val = ACE_READ_ATTRIBUTES;
+				return (ACE_PERM);
+			}
+<PS>write_attributes/[:/] {
+				yylval.val = ACE_WRITE_ATTRIBUTES;
+			 	return (ACE_PERM);
+			}
+<PS>delete/[:/]		{
+				yylval.val = ACE_DELETE;
+				return (ACE_PERM);
+			}
+<PS>read_acl/[:/]	{
+				yylval.val = ACE_READ_ACL;
+				return (ACE_PERM);
+			}
+<PS>write_acl/[:/]	{
+				yylval.val = ACE_WRITE_ACL;
+				return (ACE_PERM);
+			}
+<PS>write_owner/[:/]	{
+				yylval.val = ACE_WRITE_OWNER;
+				return (ACE_PERM);
+			}
+<PS>synchronize/[:/]	{
+				yylval.val = ACE_SYNCHRONIZE;
+				return (ACE_PERM);
+			}
+<PS>{PERM_STR}		{
+				int c;
+
+				c = input();
+				unput(c);
+				yylval.str = strdup(yytext);
+				if (yylval.str == NULL) {
+					yylval.val = EACL_MEM_ERROR;
+					return (ERROR);
+				}
+
+				/*
+				 * aclent are done after permissions.
+				 */
+				if (isdigit(c))
+					BEGIN US;
+				else if (c != ':')
+					BEGIN ES;
+				
+				return (PERM_TOK);	
+			}
+<PS>"/:"		{
+				acl_error(gettext("Invalid permission /: "
+				    "specified\n"));
+				yylval.val = EACL_ENTRY_ERROR;
+				return (ERROR);
+			}
+<PS>:			{
+				int c;
+
+				c = input();
+				unput(c);
+				if (isdigit(c))
+					BEGIN (US);
+				else
+					BEGIN AIS;
+				return (COLON);
+			}
+<PS>"/"			{
+				return (SLASH);
+			}
+<PS>"\n"		{
+				acl_error(gettext("ACL entry is missing "
+				    "permission fields\n"));
+				yylval.val = EACL_MISSING_FIELDS;
+				return (ERROR);
+			}
+<PS>. 			{
+				if (grab_string("/:\n") != 0) {
+					acl_error(gettext("Failed to retrieve"
+					    " error string\n"));
+					yylval.val = EACL_MEM_ERROR;
+					return (ERROR);
+				}
+				acl_error(gettext("Invalid permission '%s' "
+				    "specified\n"), yylval.str); 
+				free(yylval.str);
+				yylval.val = EACL_PERM_MASK_ERROR;
+				return (ERROR);
+			}
+<AIS>allow/[:,\n]	{
+
+				int c;
+			
+				c = input();
+				if (c == ',' || c == '\n')
+					BEGIN ES;
+				unput(c);
+				yylval.val = ACE_ACCESS_ALLOWED_ACE_TYPE;
+				return (ACCESS_TYPE);
+			}
+<AIS>deny/[:,\n]	{
+
+				int c;
+		
+				c = input();
+				if (c == ',' || c == '\n')
+					BEGIN ES;
+				unput(c);
+				yylval.val = ACE_ACCESS_DENIED_ACE_TYPE;
+				return (ACCESS_TYPE);
+			}
+
+<AIS>file_inherit/[:/] {
+				yylval.val = ACE_FILE_INHERIT_ACE;
+				return (ACE_INHERIT);
+			}
+<AIS>dir_inherit/[:/]	{
+				yylval.val = ACE_DIRECTORY_INHERIT_ACE;
+				return (ACE_INHERIT);
+			}
+<AIS>no_propagate/[/:]	{
+				yylval.val = ACE_NO_PROPAGATE_INHERIT_ACE;
+				return (ACE_INHERIT);
+			}
+<AIS>inherit_only/[/:]	{
+				yylval.val = ACE_INHERIT_ONLY_ACE;
+				return (ACE_INHERIT);
+			}
+<AIS>{INHERIT_STR}	{
+				yylval.str = strdup(yytext);
+				if (yylval.str == NULL) {
+					yylval.val = EACL_MEM_ERROR;
+					return (ERROR);
+				}
+				return (INHERIT_TOK);
+			}
+<AIS>:			{
+				int c;
+
+				c = input();
+				unput(c);
+
+				if (isdigit(c)) {
+					BEGIN US;
+				} 
+				return (COLON);
+			}
+<AIS>"/"		{
+				return (SLASH);
+			}
+<AIS>"\n"		{
+				acl_error(
+				    gettext("Extra data on end of ACL "
+				    "specification\n"), yylval.str);
+				yylval.val = EACL_UNKNOWN_DATA;
+				return (ERROR);
+			}
+<AIS>.			{
+				if (yytext[0] != '\n' && yytext[0] != '\0') {
+					if (grab_string(":\n") != 0) {
+						acl_error(gettext("Failed to "
+						    "retrieve error string\n"));
+						yylval.val = EACL_MEM_ERROR;
+						return (ERROR);
+					}
+					acl_error(
+					    gettext("Invalid inheritance or"
+				    	    " access type '%s' specified\n"),
+				    	    yylval.str);
+				} else {
+					acl_error(
+					    gettext("No inheritance or "
+					    "access type specified\n"),
+					    yylval.str);
+				}
+
+				free(yylval.str);
+				yylval.val = EACL_INVALID_ACCESS_TYPE;
+				return (ERROR);
+			}
+<US>{ID}		{
+				BEGIN ES;
+				yylval.val = atoi(yytext);
+				return (ID);
+			}
+<US>.			{ 
+				if (grab_string(",\n") != 0) {
+					acl_error(gettext("Failed to retrieve"
+					    " error string\n"));	
+					yylval.val = EACL_MEM_ERROR;
+					return (ERROR);
+				}
+				acl_error(
+				    gettext("Invalid uid/gid '%s' specified\n"),
+			    	    yylval.str);
+				free(yylval.str);
+				yylval.val = EACL_ENTRY_ERROR;
+				return (ERROR);
+			}
+<US>"\n"		{
+				acl_error(gettext("Missing fields in ACL "
+				    "specification.\nShould either have "
+				    "inheritance flags or uid/gid "
+				    "specified.\n"));
+				yylval.val = EACL_ENTRY_ERROR;
+				return (ERROR);
+			}
+<ES>","			{
+				BEGIN TS;
+				return (COMMA);
+			}
+<ES>.			{
+				if (grab_string("/:\n") != 0) {
+					acl_error(
+					    gettext("Failed to retrieve error"
+				    	    " string\n"));
+					yylval.val = EACL_MEM_ERROR;
+					return (ERROR);
+				}
+				acl_error(
+				    gettext("Unrecognized data '%s' found"
+			    	    " in ACL specification\n"), yylval.str);
+				free(yylval.str);
+				yylval.val = EACL_UNKNOWN_DATA;
+				return (ERROR);
+			}
+<ES>"\n"		{
+				return (NL);
+			}
+%%
+
+
+/*
+ * pull string up to terminator of off input string.
+ * used for retrieving illegal data in ACL specification.
+ */
+int
+grab_string(char *terminators)
+{
+		int c;
+		int done = 0;
+		int cnt;
+		int alloced;
+		int error = 0;
+		char *ptr;
+			
+		cnt = strlen(yytext);
+		yylval.str = calloc(cnt + 1, sizeof (char));
+		if (yylval.str == NULL) {
+			return (1);
+		}
+		alloced = cnt + 1;
+		strcpy(yylval.str, yytext);
+
+		do {
+			c = input();
+			if (c == EOF) 
+				break;
+
+			for (ptr = terminators; *ptr; ptr++) {
+				if (c == *ptr) {
+					done = 1;
+					break;
+				}
+			}
+			
+			if (done)
+				break;
+				
+			if (cnt >= alloced) {
+				yylval.str = realloc(yylval.str,
+				    alloced + 80);
+					alloced += 80;
+				if (yylval.str == NULL)
+					return (1);
+
+				memset(yylval.str + cnt, 0,
+				    alloced - strlen(yylval.str));
+			}
+			yylval.str[strlen(yylval.str)] = c;
+			cnt++;
+		} while (!done);
+
+		return (error);
+}
+
+static int
+input(void)
+{
+	int c;
+
+	c = yybuf[yybufpos++];
+	if (c == '\0') {
+		return (EOF);
+	}
+
+	return (c);	
+}
+
+static void
+unput(int c)
+{
+	if (c == '\0') {
+		return;
+	}
+
+	if (yybufpos > 0) {
+		--yybufpos;
+	}
+}
+
+/*
+ * return ACE entry type
+ */
+int
+ace_entry_type(int type)
+{
+	int ret = -1;
+	switch (type) {
+		case USER_TOK:
+			ret = 0;
+			break;
+		case GROUP_TOK:
+			ret = ACE_IDENTIFIER_GROUP;
+			break;
+		case OWNERAT_TOK:
+			ret = ACE_OWNER;
+			break;
+		case GROUPAT_TOK:
+			ret = ACE_IDENTIFIER_GROUP | ACE_GROUP;
+			break;
+		case EVERYONEAT_TOK:
+			ret = ACE_EVERYONE;
+			break;
+	}
+	return (ret);
+}
+
+
+/*
+ * return aclent entry type
+ */
+int
+aclent_entry_type(int type, int owning, int *ret)
+{
+
+	*ret = 0;
+
+	switch (type) {
+	case USER_TOK:
+		*ret = (owning == 0) ? USER : USER_OBJ;
+		break;
+	case GROUP_TOK:
+		*ret = (owning == 0) ? GROUP : GROUP_OBJ;
+		break;
+
+	case OTHER_TOK:
+		*ret = OTHER_OBJ;
+		break;
+
+	case MASK_TOK:
+		*ret = CLASS_OBJ;
+		break;
+	case DEFAULT_USER_TOK:
+		*ret = (owning == 0) ? DEF_USER : DEF_USER_OBJ;
+		break;
+	case DEFAULT_GROUP_TOK:
+		*ret = (owning == 0) ? DEF_GROUP : DEF_GROUP_OBJ;
+		break;
+	case DEFAULT_MASK_TOK:
+		*ret = DEF_CLASS_OBJ;
+		break;
+	case DEFAULT_OTHER_TOK:
+		*ret = DEF_OTHER_OBJ;
+		break;
+	default:
+		return (EACL_ENTRY_ERROR);
+	}
+
+	return (0);
+}
+
+/*
+ * convert string into numeric id.
+ */
+static int
+acl_str_to_id(char *str, int *id)
+{
+	char *end;
+	uid_t value;
+
+	value = strtol(str, &end, 10);
+
+	if (errno != 0 || *end != '\0')
+		return (EACL_INVALID_USER_GROUP);
+
+	*id = value;
+
+	return (0);
+}
+
+/*
+ * determine either uid/gid for given entry type
+ */
+int
+get_id(int entry_type, char *name, int *id)
+{
+	struct passwd *pw;
+	struct group *gr;
+	int error;
+
+	if (entry_type == USER_TOK || entry_type == DEFAULT_USER_TOK) {
+		pw = getpwnam(name);
+		if (pw) {
+			*id = pw->pw_uid;
+			return (0);
+		} 
+	} else {
+		gr = getgrnam(name);
+		if (gr) {
+			*id = gr->gr_gid;
+			return (0);
+		} 
+	}
+
+	/*
+	 * getpwnam or getgrnam failed, try and see if
+	 * they are numeric strings.
+	 */
+	error = acl_str_to_id(name, id);
+
+	if (error)
+		return (error);
+	return (0);
+}
+/*
+ * reset beginning state to TS and set character position
+ * back to zero.
+ */
+void
+yyreset()
+{
+	yybufpos = 0;
+	BEGIN TS;
+}
+
--- a/usr/src/lib/libsec/common/acltext.c	Mon Feb 13 02:31:44 2006 -0800
+++ b/usr/src/lib/libsec/common/acltext.c	Mon Feb 13 08:52:39 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -35,33 +35,24 @@
 #include <errno.h>
 #include <sys/param.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/acl.h>
 #include <aclutils.h>
-#include <libintl.h>
+
+#define	ID_STR_MAX	20	/* digits in LONG_MAX */
 
+#define	APPENDED_ID_MAX	ID_STR_MAX + 1		/* id + colon */
+/*
+ * yyinteractive controls whether yyparse should print out
+ * error messages to stderr, and whether or not id's should be
+ * allowed from acl_fromtext().
+ */
+int	yyinteractive;
+acl_t	*yyacl;
+char	*yybuf;
 
 extern acl_t *acl_alloc(enum acl_type);
 
-/*
- * acltotext() converts each ACL entry to look like this:
- *
- *    entry_type:uid^gid^name:perms
- *
- * The maximum length of entry_type is 14 ("defaultgroup::" and
- * "defaultother::") hence ENTRYTYPELEN is set to 14.
- *
- * The max length of a uid^gid^name entry (in theory) is 8, hence we use
- * LOGNAME_MAX.
- *
- * The length of a perms entry is 4 to allow for the comma appended to each
- * to each acl entry.  Hence PERMS is set to 4.
- */
-
-#define	ENTRYTYPELEN	14
-#define	PERMS		4
-#define	ACL_ENTRY_SIZE	(ENTRYTYPELEN + LOGNAME_MAX + PERMS)
-
-#define	UPDATE_WHERE	where = dstr->aclexport + strlen(dstr->aclexport)
 
 struct dynaclstr {
 	size_t bufsize;		/* current size of aclexport */
@@ -72,20 +63,504 @@
 static char *convert_perm(char *, o_mode_t);
 static int increase_length(struct dynaclstr *, size_t);
 
-static int
-acl_str_to_id(char *str, int *id)
+static void
+aclent_perms(int perm, char *txt_perms)
+{
+	if (perm & S_IROTH)
+		txt_perms[0] = 'r';
+	else
+		txt_perms[0] = '-';
+	if (perm & S_IWOTH)
+		txt_perms[1] = 'w';
+	else
+		txt_perms[1] = '-';
+	if (perm & S_IXOTH)
+		txt_perms[2] = 'x';
+	else
+		txt_perms[2] = '-';
+	txt_perms[3] = '\0';
+}
+
+static char *
+pruname(uid_t uid, char *uidp)
+{
+	struct passwd	*passwdp;
+
+	passwdp = getpwuid(uid);
+	if (passwdp == (struct passwd *)NULL) {
+		/* could not get passwd information: display uid instead */
+		(void) sprintf(uidp, "%ld", (long)uid);
+		return (uidp);
+	} else
+		return (passwdp->pw_name);
+}
+
+static char *
+prgname(gid_t gid, char *gidp)
+{
+	struct group	*groupp;
+
+	groupp = getgrgid(gid);
+	if (groupp == (struct group *)NULL) {
+		/* could not get group information: display gid instead */
+		(void) sprintf(gidp, "%ld", (long)gid);
+		return (gidp);
+	} else
+		return (groupp->gr_name);
+}
+static void
+aclent_printacl(acl_t *aclp)
 {
-	char *end;
-	uid_t value;
+	aclent_t *tp;
+	int aclcnt;
+	int mask;
+	int slot = 0;
+	char perm[4];
+	char uidp[10];
+	char gidp[10];
+
+	/* display ACL: assume it is sorted. */
+	aclcnt = aclp->acl_cnt;
+	for (tp = aclp->acl_aclp; tp && aclcnt--; tp++) {
+		if (tp->a_type == CLASS_OBJ)
+			mask = tp->a_perm;
+	}
+	aclcnt = aclp->acl_cnt;
+	for (tp = aclp->acl_aclp; aclcnt--; tp++) {
+		(void) printf("     %d:", slot++);
+		switch (tp->a_type) {
+		case USER:
+			aclent_perms(tp->a_perm, perm);
+			(void) printf("user:%s:%s\t\t",
+			    pruname(tp->a_id, uidp), perm);
+			aclent_perms((tp->a_perm & mask), perm);
+			(void) printf("#effective:%s\n", perm);
+			break;
+		case USER_OBJ:
+			/* no need to display uid */
+			aclent_perms(tp->a_perm, perm);
+			(void) printf("user::%s\n", perm);
+			break;
+		case GROUP:
+			aclent_perms(tp->a_perm, perm);
+			(void) printf("group:%s:%s\t\t",
+			    prgname(tp->a_id, gidp), perm);
+			aclent_perms(tp->a_perm & mask, perm);
+			(void) printf("#effective:%s\n", perm);
+			break;
+		case GROUP_OBJ:
+			aclent_perms(tp->a_perm, perm);
+			(void) printf("group::%s\t\t", perm);
+			aclent_perms(tp->a_perm & mask, perm);
+			(void) printf("#effective:%s\n", perm);
+			break;
+		case CLASS_OBJ:
+			aclent_perms(tp->a_perm, perm);
+			(void) printf("mask:%s\n", perm);
+			break;
+		case OTHER_OBJ:
+			aclent_perms(tp->a_perm, perm);
+			(void) printf("other:%s\n", perm);
+			break;
+		case DEF_USER:
+			aclent_perms(tp->a_perm, perm);
+			(void) printf("default:user:%s:%s\n",
+			    pruname(tp->a_id, uidp), perm);
+			break;
+		case DEF_USER_OBJ:
+			aclent_perms(tp->a_perm, perm);
+			(void) printf("default:user::%s\n", perm);
+			break;
+		case DEF_GROUP:
+			aclent_perms(tp->a_perm, perm);
+			(void) printf("default:group:%s:%s\n",
+			    prgname(tp->a_id, gidp), perm);
+			break;
+		case DEF_GROUP_OBJ:
+			aclent_perms(tp->a_perm, perm);
+			(void) printf("default:group::%s\n", perm);
+			break;
+		case DEF_CLASS_OBJ:
+			aclent_perms(tp->a_perm, perm);
+			(void) printf("default:mask:%s\n", perm);
+			break;
+		case DEF_OTHER_OBJ:
+			aclent_perms(tp->a_perm, perm);
+			(void) printf("default:other:%s\n", perm);
+			break;
+		default:
+			(void) fprintf(stderr,
+			    gettext("unrecognized entry\n"));
+			break;
+		}
+	}
+}
+
+static void
+split_line(char *str, int cols)
+{
+	char *ptr;
+	int len;
+	int i;
+	int last_split;
+	char *pad = "";
+	int pad_len;
+
+	len = strlen(str);
+	ptr = str;
+	pad_len = 0;
+
+	ptr = str;
+	last_split = 0;
+	for (i = 0; i != len; i++) {
+		if ((i + pad_len + 4) >= cols) {
+			(void) printf("%s%.*s\n", pad, last_split, ptr);
+			ptr = &ptr[last_split];
+			len = strlen(ptr);
+			i = 0;
+			pad_len = 4;
+			pad = "         ";
+		} else {
+			if (ptr[i] == '/' || ptr[i] == ':') {
+				last_split = i;
+			}
+		}
+	}
+	if (i == len) {
+		(void) printf("%s%s\n", pad, ptr);
+	}
+}
+
+#define	OWNERAT_TXT	"owner@"
+#define	GROUPAT_TXT	"group@"
+#define	EVERYONEAT_TXT	"everyone@"
+#define	GROUP_TXT	"group:"
+#define	USER_TXT	"user:"
+
+char *
+ace_type_txt(char *buf, char **endp, ace_t *acep)
+{
+
+	char idp[10];
+
+	if (buf == NULL)
+		return (NULL);
+
+	switch (acep->a_flags & ACE_TYPE_FLAGS) {
+	case ACE_OWNER:
+		strcpy(buf, OWNERAT_TXT);
+		*endp = buf + sizeof (OWNERAT_TXT) - 1;
+		break;
+
+	case ACE_GROUP|ACE_IDENTIFIER_GROUP:
+		strcpy(buf, GROUPAT_TXT);
+		*endp = buf + sizeof (GROUPAT_TXT) - 1;
+		break;
+
+	case ACE_IDENTIFIER_GROUP:
+		strcpy(buf, GROUP_TXT);
+		strcat(buf, prgname(acep->a_who, idp));
+		*endp = buf + strlen(buf);
+		break;
+
+	case ACE_EVERYONE:
+		strcpy(buf, EVERYONEAT_TXT);
+		*endp = buf + sizeof (EVERYONEAT_TXT) - 1;
+		break;
+
+	case 0:
+		strcpy(buf, USER_TXT);
+		strcat(buf, pruname(acep->a_who, idp));
+		*endp = buf + strlen(buf);
+		break;
+	}
+
+	return (buf);
+}
+
+#define	READ_DATA_TXT	"read_data/"
+#define	WRITE_DATA_TXT	"write_data/"
+#define	EXECUTE_TXT	"execute/"
+#define	READ_XATTR_TXT	"read_xattr/"
+#define	WRITE_XATTR_TXT	"write_xattr/"
+#define	READ_ATTRIBUTES_TXT "read_attributes/"
+#define	WRITE_ATTRIBUTES_TXT "write_attributes/"
+#define	DELETE_TXT	"delete/"
+#define	DELETE_CHILD_TXT "delete_child/"
+#define	WRITE_OWNER_TXT "write_owner/"
+#define	READ_ACL_TXT	"read_acl/"
+#define	WRITE_ACL_TXT	"write_acl/"
+#define	APPEND_DATA_TXT "append_data/"
+#define	READ_DIR_TXT	"list_directory/read_data/"
+#define	ADD_DIR_TXT	"add_subdirectory/append_data/"
+#define	ADD_FILE_TXT	"add_file/write_data/"
+#define	SYNCHRONIZE_TXT "synchronize"	/* not slash on this one */
+
+char *
+ace_perm_txt(char *buf, char **endp, uint32_t mask,
+    uint32_t iflags, int isdir, int flags)
+{
+	char *lend = buf;		/* local end */
+
+	if (buf == NULL)
+		return (NULL);
+
+	if (flags & ACL_COMPACT_FMT) {
 
-	value = strtol(str, &end, 10);
+		if (mask & ACE_READ_DATA)
+			buf[0] = 'r';
+		else
+			buf[0] = '-';
+		if (mask & ACE_WRITE_DATA)
+			buf[1] = 'w';
+		else
+			buf[1] = '-';
+		if (mask & ACE_EXECUTE)
+			buf[2] = 'x';
+		else
+			buf[2] = '-';
+		if (mask & ACE_APPEND_DATA)
+			buf[3] = 'p';
+		else
+			buf[3] = '-';
+		if (mask & ACE_DELETE)
+			buf[4] = 'd';
+		else
+			buf[4] = '-';
+		if (mask & ACE_DELETE_CHILD)
+			buf[5] = 'D';
+		else
+			buf[5] = '-';
+		if (mask & ACE_READ_ATTRIBUTES)
+			buf[6] = 'a';
+		else
+			buf[6] = '-';
+		if (mask & ACE_WRITE_ATTRIBUTES)
+			buf[7] = 'A';
+		else
+			buf[7] = '-';
+		if (mask & ACE_READ_NAMED_ATTRS)
+			buf[8] = 'R';
+		else
+			buf[8] = '-';
+		if (mask & ACE_WRITE_NAMED_ATTRS)
+			buf[9] = 'W';
+		else
+			buf[9] = '-';
+		if (mask & ACE_READ_ACL)
+			buf[10] = 'c';
+		else
+			buf[10] = '-';
+		if (mask & ACE_WRITE_ACL)
+			buf[11] = 'C';
+		else
+			buf[11] = '-';
+		if (mask & ACE_WRITE_OWNER)
+			buf[12] = 'o';
+		else
+			buf[12] = '-';
+		if (mask & ACE_SYNCHRONIZE)
+			buf[13] = 's';
+		else
+			buf[13] = '-';
+		buf[14] = '\0';
+		*endp = buf + 14;
+		return (buf);
+	} else {
+		/*
+		 * If ACE is a directory, but inheritance indicates its
+		 * for a file then print permissions for file rather than
+		 * dir.
+		 */
+		if (isdir) {
+			if (mask & ACE_LIST_DIRECTORY) {
+				if (iflags == ACE_FILE_INHERIT_ACE) {
+					strcpy(lend, READ_DATA_TXT);
+					lend += sizeof (READ_DATA_TXT) - 1;
+				} else {
+					strcpy(lend, READ_DIR_TXT);
+					lend += sizeof (READ_DIR_TXT) - 1;
+				}
+			}
+			if (mask & ACE_ADD_FILE) {
+				if (iflags == ACE_FILE_INHERIT_ACE) {
+					strcpy(lend, WRITE_DATA_TXT);
+					lend += sizeof (WRITE_DATA_TXT) - 1;
+				} else {
+					strcpy(lend, ADD_FILE_TXT);
+					lend +=
+					    sizeof (ADD_FILE_TXT) -1;
+				}
+			}
+			if (mask & ACE_ADD_SUBDIRECTORY) {
+				if (iflags == ACE_FILE_INHERIT_ACE) {
+					strcpy(lend, APPEND_DATA_TXT);
+					lend += sizeof (APPEND_DATA_TXT) - 1;
+				} else {
+					strcpy(lend, ADD_DIR_TXT);
+					lend += sizeof (ADD_DIR_TXT) - 1;
+				}
+			}
+		} else {
+			if (mask & ACE_READ_DATA) {
+				strcpy(lend, READ_DATA_TXT);
+				lend += sizeof (READ_DATA_TXT) - 1;
+			}
+			if (mask & ACE_WRITE_DATA) {
+				strcpy(lend, WRITE_DATA_TXT);
+				lend += sizeof (WRITE_DATA_TXT) - 1;
+			}
+			if (mask & ACE_APPEND_DATA) {
+				strcpy(lend, APPEND_DATA_TXT);
+				lend += sizeof (APPEND_DATA_TXT) - 1;
+			}
+		}
+		if (mask & ACE_READ_NAMED_ATTRS) {
+			strcpy(lend, READ_XATTR_TXT);
+			lend += sizeof (READ_XATTR_TXT) - 1;
+		}
+		if (mask & ACE_WRITE_NAMED_ATTRS) {
+			strcpy(lend, WRITE_XATTR_TXT);
+			lend += sizeof (WRITE_XATTR_TXT) - 1;
+		}
+		if (mask & ACE_EXECUTE) {
+			strcpy(lend, EXECUTE_TXT);
+			lend += sizeof (EXECUTE_TXT) - 1;
+		}
+		if (mask & ACE_DELETE_CHILD) {
+			strcpy(lend, DELETE_CHILD_TXT);
+			lend += sizeof (DELETE_CHILD_TXT) - 1;
+		}
+		if (mask & ACE_READ_ATTRIBUTES) {
+			strcpy(lend, READ_ATTRIBUTES_TXT);
+			lend += sizeof (READ_ATTRIBUTES_TXT) - 1;
+		}
+		if (mask & ACE_WRITE_ATTRIBUTES) {
+			strcpy(lend, WRITE_ATTRIBUTES_TXT);
+			lend += sizeof (WRITE_ATTRIBUTES_TXT) - 1;
+		}
+		if (mask & ACE_DELETE) {
+			strcpy(lend, DELETE_TXT);
+			lend += sizeof (DELETE_TXT) - 1;
+		}
+		if (mask & ACE_READ_ACL) {
+			strcpy(lend, READ_ACL_TXT);
+			lend += sizeof (READ_ACL_TXT) - 1;
+		}
+		if (mask & ACE_WRITE_ACL) {
+			strcpy(lend, WRITE_ACL_TXT);
+			lend += sizeof (WRITE_ACL_TXT) - 1;
+		}
+		if (mask & ACE_WRITE_OWNER) {
+			strcpy(lend, WRITE_OWNER_TXT);
+			lend += sizeof (WRITE_OWNER_TXT) - 1;
+		}
+		if (mask & ACE_SYNCHRONIZE) {
+			strcpy(lend, SYNCHRONIZE_TXT);
+			lend += sizeof (SYNCHRONIZE_TXT) - 1;
+		}
 
-	if (errno != 0 || *end != '\0')
-		return (EACL_INVALID_USER_GROUP);
+		if (*(lend - 1) == '/')
+			*--lend = '\0';
+	}
+
+	*endp = lend;
+	return (buf);
+}
+
+#define	ALLOW_TXT	"allow"
+#define	DENY_TXT	"deny"
+#define	ALARM_TXT	"alarm"
+#define	AUDIT_TXT	"audit"
+#define	UNKNOWN_TXT	"unknown"
+char *
+ace_access_txt(char *buf, char **endp, int type)
+{
+
+	if (buf == NULL)
+		return (NULL);
+
+	if (type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
+		strcpy(buf, ALLOW_TXT);
+		*endp += sizeof (ALLOW_TXT) - 1;
+	} else if (type == ACE_ACCESS_DENIED_ACE_TYPE) {
+		strcpy(buf, DENY_TXT);
+		*endp += sizeof (DENY_TXT) - 1;
+	} else if (type == ACE_SYSTEM_AUDIT_ACE_TYPE) {
+		strcpy(buf, AUDIT_TXT);
+		*endp += sizeof (AUDIT_TXT) - 1;
+	} else if (type == ACE_SYSTEM_ALARM_ACE_TYPE) {
+		strcpy(buf, ALARM_TXT);
+		*endp += sizeof (ALARM_TXT) - 1;
+	} else {
+		strcpy(buf, UNKNOWN_TXT);
+		*endp += sizeof (UNKNOWN_TXT) - 1;
+	}
+
+	return (buf);
+}
+
+static char *
+ace_inherit_txt(char *buf, char **endp, uint32_t iflags, int flags)
+{
+
+	char *lend = buf;
+
+	if (buf == NULL) {
+		return (NULL);
+	}
 
-	*id = value;
+	if (flags & ACL_COMPACT_FMT) {
+		if (iflags & ACE_FILE_INHERIT_ACE)
+			buf[0] = 'f';
+		else
+			buf[0] = '-';
+		if (iflags & ACE_DIRECTORY_INHERIT_ACE)
+			buf[1] = 'd';
+		else
+			buf[1] = '-';
+		if (iflags & ACE_INHERIT_ONLY_ACE)
+			buf[2] = 'i';
+		else
+			buf[2] = '-';
+		if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)
+			buf[3] = 'n';
+		else
+			buf[3] = '-';
+		if (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
+			buf[4] = 'S';
+		else
+			buf[4] = '-';
+		if (iflags & ACE_FAILED_ACCESS_ACE_FLAG)
+			buf[5] = 'F';
+		else
+			buf[5] = '-';
+		buf[6] = '\0';
+		*endp = buf + 6;
+	} else {
+		if (iflags & ACE_FILE_INHERIT_ACE) {
+			strcpy(lend, "file_inherit/");
+			lend += sizeof ("file_inherit/") - 1;
+		}
+		if (iflags & ACE_DIRECTORY_INHERIT_ACE) {
+			strcpy(lend, "dir_inherit/");
+			lend += sizeof ("dir_inherit/") - 1;
+		}
+		if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE) {
+			strcpy(lend, "no_propagate/");
+			lend += sizeof ("no_propagate/") - 1;
+		}
+		if (iflags & ACE_INHERIT_ONLY_ACE) {
+			strcpy(lend, "inherit_only/");
+			lend += sizeof ("inherit_only/") - 1;
+		}
 
-	return (0);
+		if (*(lend - 1) == '/')
+			*--lend = '\0';
+		*endp = lend;
+	}
+
+	return (buf);
 }
 
 /*
@@ -99,8 +574,29 @@
  * The LOGNAME_MAX, ENTRYTYPELEN and PERMS limits are otherwise always
  * adhered to.
  */
+
+/*
+ * acltotext() converts each ACL entry to look like this:
+ *
+ *    entry_type:uid^gid^name:perms[:id]
+ *
+ * The maximum length of entry_type is 14 ("defaultgroup::" and
+ * "defaultother::") hence ENTRYTYPELEN is set to 14.
+ *
+ * The max length of a uid^gid^name entry (in theory) is 8, hence we use,
+ * however the ID could be a number so we therefore use ID_STR_MAX
+ *
+ * The length of a perms entry is 4 to allow for the comma appended to each
+ * to each acl entry.  Hence PERMS is set to 4.
+ */
+
+#define	ENTRYTYPELEN	14
+#define	PERMS		4
+#define	ACL_ENTRY_SIZE	(ENTRYTYPELEN + ID_STR_MAX + PERMS + APPENDED_ID_MAX)
+#define	UPDATE_WHERE	where = dstr->aclexport + strlen(dstr->aclexport)
+
 char *
-acltotext(aclent_t *aclp, int aclcnt)
+aclent_acltotext(aclent_t  *aclp, int aclcnt, int flags)
 {
 	char		*aclexport;
 	char		*where;
@@ -109,6 +605,7 @@
 	struct dynaclstr *dstr;
 	int		i, rtn;
 	size_t		excess = 0;
+	char		id[20], *idstr;
 
 	if (aclp == NULL)
 		return (NULL);
@@ -218,240 +715,33 @@
 			return (NULL);
 
 		}
+
+		if ((flags & ACL_APPEND_ID) && ((aclp->a_type == USER) ||
+		    (aclp->a_type == DEF_USER) || (aclp->a_type == GROUP) ||
+		    (aclp->a_type == DEF_GROUP))) {
+			where = strappend(where, ":");
+			id[ID_STR_MAX - 1] = '\0'; /* null terminate buffer */
+			idstr = lltostr(aclp->a_id, &id[ID_STR_MAX - 1]);
+			where = strappend(where, idstr);
+		}
 		if (i < aclcnt - 1)
 			where = strappend(where, ",");
 	}
 	aclexport = dstr->aclexport;
 	free(dstr);
 	return (aclexport);
+
+
+
+
 }
 
-/*
- * Convert external acl representation to internal representation.
- * The accepted syntax is: <acl_entry>[,<acl_entry>]*[,]
- * The comma at the end is not prescribed by the man pages.
- * But it is needed not to break the old programs.
- */
-static int
-aclent_aclfromtext(char *aclstr, acl_t **ret_aclp)
+char *
+acltotext(aclent_t *aclp, int aclcnt)
 {
-	char		*fieldp;
-	char		*tp;
-	char		*nextp;
-	char		*allocp;
-	char		*aclimport;
-	int		entry_type;
-	int		id;
-	int		len;
-	int		error;
-	o_mode_t	perm;
-	aclent_t	*tmpaclp;
-	acl_t		*aclp;
-	struct group	*groupp;
-	struct passwd	*passwdp;
-
-	aclp = NULL;
-
-	if (! aclstr)
-		return (NULL);
-
-	aclp = acl_alloc(ACLENT_T);
-	if (aclp == NULL) {
-		return (EACL_MEM_ERROR);
-	}
-
-	*ret_aclp = NULL;
-
-	len = strlen(aclstr);
-
-	if ((aclimport = allocp = strdup(aclstr)) == NULL) {
-		return (EACL_MEM_ERROR);
-	}
-
-	if (aclimport[len - 1] == ',')
-		aclimport[len - 1] = '\0';
-
-	for (; aclimport; ) {
-		/* look for an ACL entry */
-		tp = strchr(aclimport, ',');
-		if (tp == NULL) {
-			nextp = NULL;
-		} else {
-			*tp = '\0';
-			nextp = tp + 1;
-		}
-
-		aclp->acl_cnt += 1;
-
-		/*
-		 * get additional memory:
-		 * can be more efficient by allocating a bigger block
-		 * each time.
-		 */
-		if (aclp->acl_cnt > 1)
-			tmpaclp = (aclent_t *)realloc(aclp->acl_aclp,
-			    sizeof (aclent_t) * (aclp->acl_cnt));
-		else
-			tmpaclp = (aclent_t *)malloc(sizeof (aclent_t));
-		if (tmpaclp == NULL) {
-			free(allocp);
-			acl_free(aclp);
-			return (EACL_MEM_ERROR);
-		}
-		aclp->acl_aclp = tmpaclp;
-		tmpaclp = (aclent_t *)aclp->acl_aclp + (aclp->acl_cnt - 1);
+	return (aclent_acltotext(aclp, aclcnt, 0));
+}
 
-		/* look for entry type field */
-		tp = strchr(aclimport, ':');
-		if (tp == NULL) {
-			free(allocp);
-			if (aclp)
-				acl_free(aclp);
-			return (EACL_ENTRY_ERROR);
-		} else
-			*tp = '\0';
-		if (strcmp(aclimport, "user") == 0) {
-			if (*(tp+1) == ':')
-				entry_type = USER_OBJ;
-			else
-				entry_type = USER;
-		} else if (strcmp(aclimport, "group") == 0) {
-			if (*(tp+1) == ':')
-				entry_type = GROUP_OBJ;
-			else
-				entry_type = GROUP;
-		} else if (strcmp(aclimport, "other") == 0)
-			entry_type = OTHER_OBJ;
-		else if (strcmp(aclimport, "mask") == 0)
-			entry_type = CLASS_OBJ;
-		else if (strcmp(aclimport, "defaultuser") == 0) {
-			if (*(tp+1) == ':')
-				entry_type = DEF_USER_OBJ;
-			else
-				entry_type = DEF_USER;
-		} else if (strcmp(aclimport, "defaultgroup") == 0) {
-			if (*(tp+1) == ':')
-				entry_type = DEF_GROUP_OBJ;
-			else
-				entry_type = DEF_GROUP;
-		} else if (strcmp(aclimport, "defaultmask") == 0)
-			entry_type = DEF_CLASS_OBJ;
-		else if (strcmp(aclimport, "defaultother") == 0)
-			entry_type = DEF_OTHER_OBJ;
-		else {
-			free(allocp);
-			acl_free(aclp);
-			return (EACL_ENTRY_ERROR);
-		}
-
-		/* look for user/group name */
-		if (entry_type != CLASS_OBJ && entry_type != OTHER_OBJ &&
-		    entry_type != DEF_CLASS_OBJ &&
-		    entry_type != DEF_OTHER_OBJ) {
-			fieldp = tp + 1;
-			tp = strchr(fieldp, ':');
-			if (tp == NULL) {
-				free(allocp);
-				acl_free(aclp);
-				return (EACL_INVALID_USER_GROUP);
-			} else
-				*tp = '\0';
-			if (fieldp != tp) {
-				/*
-				 * The second field could be empty. We only care
-				 * when the field has user/group name.
-				 */
-				if (entry_type == USER ||
-				    entry_type == DEF_USER) {
-					/*
-					 * The reentrant interface getpwnam_r()
-					 * is uncommitted and subject to
-					 * change. Use the friendlier interface
-					 * getpwnam().
-					 */
-					error = 0;
-					passwdp = getpwnam(fieldp);
-					if (passwdp == NULL) {
-						error = acl_str_to_id(fieldp,
-						    &id);
-					} else {
-						id = passwdp->pw_uid;
-					}
-
-					if (error) {
-						free(allocp);
-						acl_free(aclp);
-						return (error);
-					}
-
-				} else {
-					error = 0;
-					if (entry_type == GROUP ||
-					    entry_type == DEF_GROUP) {
-						groupp = getgrnam(fieldp);
-						if (groupp == NULL) {
-							error = acl_str_to_id(
-							    fieldp, &id);
-						}
-						if (error == 0)
-							id = groupp->gr_gid;
-					}
-					if (error) {
-						free(allocp);
-						acl_free(aclp);
-						return (error);
-					}
-				}
-			} else {
-				/*
-				 * The second field is empty.
-				 * Treat it as undefined (-1)
-				 */
-				id = -1;
-			}
-		} else {
-			/*
-			 * Let's not break the old applications
-			 * that use mask::rwx, other::rwx format,
-			 * though they violate the man pages.
-			 */
-			if (*(tp + 1) == ':')
-				*++tp = 0;
-		}
-
-		/* next field: permission */
-		fieldp = tp + 1;
-		if (strlen(fieldp) != 3) {
-			/*  not "rwx" format */
-			free(allocp);
-			acl_free(aclp);
-			return (EACL_PERM_MASK_ERROR);
-		} else {
-			char	s[] = "rwx";
-			int	mask = 0x04;
-			int	i;
-			perm = 0;
-
-			for (i = 0; i < 3; i++, mask /= 2) {
-				if (fieldp[i] == s[i])
-					perm |= mask;
-				else if (fieldp[i] != '-') {
-					free(allocp);
-					acl_free(aclp);
-					return (EACL_PERM_MASK_ERROR);
-				}
-			}
-		}
-
-		tmpaclp->a_type = entry_type;
-		tmpaclp->a_id = id;
-		tmpaclp->a_perm = perm;
-		aclimport = nextp;
-	}
-	free(allocp);
-	*ret_aclp = aclp;
-	return (0);
-}
 
 aclent_t *
 aclfromtext(char *aclstr, int *aclcnt)
@@ -460,15 +750,15 @@
 	aclent_t *aclentp;
 	int error;
 
-	error = aclent_aclfromtext(aclstr, &aclp);
+	error = acl_fromtext(aclstr, &aclp);
 	if (error)
 		return (NULL);
 
 	aclentp = aclp->acl_aclp;
 	aclp->acl_aclp = NULL;
-	acl_free(aclp);
+	*aclcnt = aclp->acl_cnt;
 
-	*aclcnt = aclp->acl_cnt;
+	acl_free(aclp);
 	return (aclentp);
 }
 
@@ -483,15 +773,15 @@
 static char *
 convert_perm(char *where, o_mode_t perm)
 {
-	if (perm & 04)
+	if (perm & S_IROTH)
 		where = strappend(where, "r");
 	else
 		where = strappend(where, "-");
-	if (perm & 02)
+	if (perm & S_IWOTH)
 		where = strappend(where, "w");
 	else
 		where = strappend(where, "-");
-	if (perm & 01)
+	if (perm & S_IXOTH)
 		where = strappend(where, "x");
 	else
 		where = strappend(where, "-");
@@ -499,129 +789,6 @@
 	return (where);
 }
 
-static char *
-ace_convert_perm(char *where, mode_t perm, int isdir, int iflags)
-{
-	char *start = where;
-
-	/*
-	 * The following mneumonics all have the
-	 * same value.  The only difference is the
-	 * first value is for files and second for directories
-	 * ACE_READ_DATA/ACE_LIST_DIRECTORY
-	 * ACE_WRITE_DATA/ACE_ADD_FILE
-	 * ACE_APPEND_DATA/ACE_ADD_SUBDIRECTORY
-	 */
-
-	/*
-	 * If ACE is a directory, but inheritance indicates its
-	 * for a file then print permissions for file rather than
-	 * dir.
-	 */
-	if (isdir) {
-		if (perm & ACE_LIST_DIRECTORY) {
-			if (iflags == ACE_FILE_INHERIT_ACE)
-				where = strappend(where, "read_data/");
-			else
-				where = strappend(where,
-				    "list_directory/read_data/");
-		}
-		if (perm & ACE_ADD_FILE) {
-			if (iflags == ACE_FILE_INHERIT_ACE)
-				where = strappend(where, "write_data/");
-			else
-				where = strappend(where,
-				    "add_file/write_data/");
-		}
-		if (perm & ACE_ADD_SUBDIRECTORY) {
-			if (iflags == ACE_FILE_INHERIT_ACE)
-				where = strappend(where, "append_data/");
-			else
-				where = strappend(where,
-				    "add_subdirectory/append_data/");
-		}
-	} else {
-		if (perm & ACE_READ_DATA)
-			where = strappend(where, "read_data/");
-		if (perm & ACE_WRITE_DATA)
-			where = strappend(where, "write_data/");
-		if (perm & ACE_APPEND_DATA)
-			where = strappend(where, "append_data/");
-	}
-	if (perm & ACE_READ_NAMED_ATTRS)
-		where = strappend(where, "read_xattr/");
-	if (perm & ACE_WRITE_NAMED_ATTRS)
-		where = strappend(where, "write_xattr/");
-	if (perm & ACE_EXECUTE)
-		where = strappend(where, "execute/");
-	if (perm & ACE_DELETE_CHILD)
-		where = strappend(where, "delete_child/");
-	if (perm & ACE_READ_ATTRIBUTES)
-		where = strappend(where, "read_attributes/");
-	if (perm & ACE_WRITE_ATTRIBUTES)
-		where = strappend(where, "write_attributes/");
-	if (perm & ACE_DELETE)
-		where = strappend(where, "delete/");
-	if (perm & ACE_READ_ACL)
-		where = strappend(where, "read_acl/");
-	if (perm & ACE_WRITE_ACL)
-		where = strappend(where, "write_acl/");
-	if (perm & ACE_WRITE_OWNER)
-		where = strappend(where, "write_owner/");
-	if (perm & ACE_SYNCHRONIZE)
-		where = strappend(where, "synchronize");
-
-	if (start[strlen(start) - 1] == '/') {
-		start[strlen(start) - 1] = '\0';
-		where = start + strlen(start);
-	}
-	return (where);
-}
-
-int
-ace_permask(char *perm_tok, int *perm)
-{
-	if (strcmp(perm_tok, "read_data") == 0)
-		*perm |= ACE_READ_DATA;
-	else if (strcmp(perm_tok, "list_directory") == 0)
-		*perm |= ACE_LIST_DIRECTORY;
-	else if (strcmp(perm_tok, "write_data") == 0)
-		*perm |= ACE_WRITE_DATA;
-	else if (strcmp(perm_tok, "add_file") == 0)
-		*perm |= ACE_ADD_FILE;
-	else if (strcmp(perm_tok, "append_data") == 0)
-		*perm |= ACE_APPEND_DATA;
-	else if (strcmp(perm_tok, "add_subdirectory") == 0)
-		*perm |= ACE_ADD_SUBDIRECTORY;
-	else if (strcmp(perm_tok, "read_xattr") == 0)
-		*perm |= ACE_READ_NAMED_ATTRS;
-	else if (strcmp(perm_tok, "write_xattr") == 0)
-		*perm |= ACE_WRITE_NAMED_ATTRS;
-	else if (strcmp(perm_tok, "execute") == 0)
-		*perm |= ACE_EXECUTE;
-	else if (strcmp(perm_tok, "delete_child") == 0)
-		*perm |= ACE_DELETE_CHILD;
-	else if (strcmp(perm_tok, "read_attributes") == 0)
-		*perm |= ACE_READ_ATTRIBUTES;
-	else if (strcmp(perm_tok, "write_attributes") == 0)
-		*perm |= ACE_WRITE_ATTRIBUTES;
-	else if (strcmp(perm_tok, "delete") == 0)
-		*perm |= ACE_DELETE;
-	else if (strcmp(perm_tok, "read_acl") == 0)
-		*perm |= ACE_READ_ACL;
-	else if (strcmp(perm_tok, "write_acl") == 0)
-		*perm |= ACE_WRITE_ACL;
-	else if (strcmp(perm_tok, "write_owner") == 0)
-		*perm |= ACE_WRITE_OWNER;
-	else if (strcmp(perm_tok, "synchronize") == 0)
-		*perm |= ACE_SYNCHRONIZE;
-	else {
-		return (1);
-	}
-
-	return (0);
-}
-
 /*
  * Callers should check the return code as this routine may change the string
  * pointer in dynaclstr.
@@ -643,14 +810,14 @@
 }
 
 /*
- * ace_acltotext() conver each ace formatted acl to look like this:
+ * ace_acltotext() convert each ace formatted acl to look like this:
  *
- * entry_type:uid^gid^name:perms:allow^deny[:flags][,]
+ * entry_type:uid^gid^name:perms[:flags]:<allow|deny>[:id][,]
  *
  * The maximum length of entry_type is 5 ("group")
  *
- * The max length of a uid^gid^name entry (in theory) is 8, hence we use
- * LOGNAME_MAX.
+ * The max length of a uid^gid^name entry (in theory) is 8,
+ * however id could be a number so we therefore use ID_STR_MAX
  *
  * The length of a perms entry is 144 i.e read_data/write_data...
  * to each acl entry.
@@ -661,517 +828,397 @@
 
 #define	ACE_ENTRYTYPLEN		6
 #define	IFLAGS_SIZE		51
-#define	ACCESS_TYPE_SIZE	5
+#define	ACCESS_TYPE_SIZE	7	/* if unknown */
 #define	COLON_CNT		3
 #define	PERMS_LEN		216
-#define	ACE_ENTRY_SIZE	(ACE_ENTRYTYPLEN + LOGNAME_MAX + PERMS_LEN +\
-    ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT)
+#define	ACE_ENTRY_SIZE	(ACE_ENTRYTYPLEN + ID_STR_MAX + PERMS_LEN +\
+    ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT + APPENDED_ID_MAX)
 
 static char *
-ace_acltotext(acl_t *aceaclp)
+ace_acltotext(acl_t *aceaclp, int flags)
 {
 	ace_t		*aclp = aceaclp->acl_aclp;
 	int		aclcnt = aceaclp->acl_cnt;
 	char		*aclexport;
-	char		*where;
-	char		*start;
-	struct group	*groupp;
-	struct passwd	*passwdp;
-	struct dynaclstr *dstr;
-	int		i, rtn;
+	char		*endp;
+	int		i;
+	char		id[ID_STR_MAX], *idstr;
 	int		isdir = (aceaclp->acl_flags & ACL_IS_DIR);
-	size_t		excess = 0;
 
 	if (aclp == NULL)
 		return (NULL);
-	if ((dstr = malloc(sizeof (struct dynaclstr))) == NULL)
+	if ((aclexport = malloc(aclcnt * ACE_ENTRY_SIZE)) == NULL)
 		return (NULL);
-	dstr->bufsize = aclcnt * ACE_ENTRY_SIZE;
-	if ((dstr->aclexport = malloc(dstr->bufsize)) == NULL)
-		return (NULL);
-	*dstr->aclexport = '\0';
-	where = dstr->aclexport;
 
+	aclexport[0] = '\0';
+	endp = aclexport;
 	for (i = 0; i < aclcnt; i++, aclp++) {
-		switch (aclp->a_flags & 0xf040) {
-		case ACE_OWNER:
-		case 0:
-			if ((aclp->a_flags & 0xf040) == ACE_OWNER)
-				where = strappend(where, "owner@");
-			else
-				where = strappend(where, "user:");
-			if ((aclp->a_flags & 0xf040) == 0) {
-				passwdp = getpwuid(aclp->a_who);
-				if (passwdp == (struct passwd *)NULL) {
-					/* put in uid instead */
-					(void) sprintf(where, "%d",
-					    aclp->a_who);
-				} else {
-					excess = strlen(passwdp->pw_name) -
-					    LOGNAME_MAX;
-					if (excess > 0) {
-						rtn = increase_length(dstr,
-						    excess);
-						if (rtn == 1)
-							/* reset where */
-							where =
-							    dstr->aclexport +
-							    strlen(
-							    dstr->aclexport);
-						else
-							return (NULL);
-					}
-					where = strappend(where,
-					    passwdp->pw_name);
-				}
-			} else {
-				where = strappend(where, "");
-			}
-			where = strappend(where, ":");
-			break;
-		case ACE_GROUP|ACE_IDENTIFIER_GROUP:
-		case ACE_IDENTIFIER_GROUP:
-			if ((aclp->a_flags & 0xf040) ==
-			    (ACE_GROUP | ACE_IDENTIFIER_GROUP))
-				where = strappend(where, "group@");
-			else
-				where = strappend(where, "group:");
-			if (!(aclp->a_flags & ACE_GROUP)) {
-				groupp = getgrgid(aclp->a_who);
-				if (groupp == (struct group *)NULL) {
-					/* put in gid instead */
-					(void) sprintf(where,
-					    "%d", aclp->a_who);
-				} else {
-					excess = strlen(groupp->gr_name) -
-					    LOGNAME_MAX;
-					if (excess > 0) {
-						rtn = increase_length(dstr,
-						    excess);
-						if (rtn == 1)
-							/* reset where */
-							where =
-							    dstr->aclexport +
-							    strlen(
-							    dstr->aclexport);
-						else
-							return (NULL);
-					}
-					where = strappend(where,
-					    groupp->gr_name);
-				}
-			} else {
-					where = strappend(where, "");
-			}
-			where = strappend(where, ":");
-			break;
-		case ACE_EVERYONE:
-			where = strappend(where, "everyone@:");
-			break;
-		default:
-			free(dstr->aclexport);
-			free(dstr);
-			return (NULL);
+
+		(void) ace_type_txt(endp, &endp, aclp);
+		*endp++ = ':';
+		*endp = '\0';
+		(void) ace_perm_txt(endp, &endp, aclp->a_access_mask,
+		    aclp->a_flags, isdir, flags);
+		*endp++ = ':';
+		*endp = '\0';
+		(void) ace_inherit_txt(endp, &endp, aclp->a_flags, flags);
+		if (flags & ACL_COMPACT_FMT || aclp->a_flags &
+		    (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE |
+		    (ACE_INHERIT_ONLY_ACE | ACE_NO_PROPAGATE_INHERIT_ACE))) {
+			*endp++ = ':';
+			*endp = '\0';
+		}
+		(void) ace_access_txt(endp, &endp, aclp->a_type);
 
+		if ((flags & ACL_APPEND_ID) &&
+		    (((aclp->a_flags & ACE_TYPE_FLAGS) == 0) ||
+		    ((aclp->a_flags & ACE_TYPE_FLAGS) ==
+		    ACE_IDENTIFIER_GROUP))) {
+			*endp++ = ':';
+			*endp = '\0';
+			id[ID_STR_MAX -1] = '\0'; /* null terminate buffer */
+			idstr = lltostr(aclp->a_who, &id[ID_STR_MAX - 1]);
+			strcpy(endp, idstr);
+			endp += strlen(idstr);
 		}
-		where = ace_convert_perm(where, aclp->a_access_mask,
-		    isdir, (aclp->a_flags &
-		    (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)));
-		where = strappend(where,
-		    (aclp->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) ?
-		    ":allow" : ":deny");
-
-		/*
-		 * slap on inheritance flags if we have any
-		 */
-
-		if (aclp->a_flags & 0xf) {
-			where = strappend(where, ":");
-			start = where;
-			if (aclp->a_flags & ACE_FILE_INHERIT_ACE)
-				where = strappend(where, "file_inherit/");
-			if (aclp->a_flags & ACE_DIRECTORY_INHERIT_ACE)
-				where = strappend(where, "dir_inherit/");
-			if (aclp->a_flags & ACE_NO_PROPAGATE_INHERIT_ACE)
-				where = strappend(where, "no_propagate/");
-			if (aclp->a_flags & ACE_INHERIT_ONLY_ACE)
-				where = strappend(where, "inherit_only");
-
-			/*
-			 * chop off trailing slash, if present
-			 */
-			if (start[strlen(start) - 1] == '/') {
-				start[strlen(start) - 1] = '\0';
-				where = start + strlen(start);
-			}
+		if (i < aclcnt - 1) {
+			*endp++ = ',';
+			*(endp + 1) = '\0';
 		}
-		if (i < aclcnt - 1)
-			where = strappend(where, ",");
 	}
-	aclexport = dstr->aclexport;
-	free(dstr);
 	return (aclexport);
 }
 
-static int
-build_iflags(char *str, int *iflags)
+char *
+acl_totext(acl_t *aclp, int flags)
 {
 
-	char *tok;
-	*iflags = 0;
-
-	tok = strtok(str, "/");
-
-	if (tok == NULL)
-		return (1);
-
-	do {
-		if (strcmp(tok, "file_inherit") == 0)
-			*iflags |= ACE_FILE_INHERIT_ACE;
-		else if (strcmp(tok, "dir_inherit") == 0)
-			*iflags |= ACE_DIRECTORY_INHERIT_ACE;
-		else if (strcmp(tok, "inherit_only") == 0)
-			*iflags |= ACE_INHERIT_ONLY_ACE;
-		else if (strcmp(tok, "no_propagate") == 0)
-			*iflags |= ACE_NO_PROPAGATE_INHERIT_ACE;
-		else
-			return (1);
-	} while (tok = strtok(NULL, "/"));
-	return (0);
-}
-
-/*
- * Convert external acl representation to internal representation.
- * The accepted syntax is: <acl_entry>[,<acl_entry>]*[,]
- * The comma at the end is not prescribed by the man pages.
- * But it is needed not to break the old programs.
- */
-
-int
-ace_aclfromtext(char *aclstr, acl_t **ret_aclp)
-{
-	char		*fieldp;
-	char		*tp;
-	char		*nextp;
-	char		*allocp;
-	char		*aclimport;
-	char 		*str;
-	char		*perm_tok;
-	int		entry_type;
-	int		id;
-	int		type;
-	int		iflags;
-	int		len;
-	int		error;
-	int32_t		perm;
-	ace_t		*tmpaclp;
-	acl_t		*aclp;
-	struct group	*groupp;
-	struct passwd	*passwdp;
-
-	if (! aclstr)
-		return (EACL_INVALID_STR);
-
-	len = strlen(aclstr);
-
-	aclp = acl_alloc(ACE_T);
-	if (aclp == NULL) {
-		return (EACL_MEM_ERROR);
-	}
-
-	*ret_aclp = NULL;
-
-	if ((aclimport = allocp = strdup(aclstr)) == NULL) {
-		return (EACL_MEM_ERROR);
-	}
-
-
-	if (aclimport[len - 1] == ',')
-		aclimport[len - 1] = '\0';
-
-	for (; aclimport; ) {
-		/* look for an ACL entry */
-		tp = strchr(aclimport, ',');
-		if (tp == NULL) {
-			nextp = NULL;
-		} else {
-			*tp = '\0';
-			nextp = tp + 1;
-		}
-
-		aclp->acl_cnt += 1;
-
-		/*
-		 * get additional memory:
-		 * can be more efficient by allocating a bigger block
-		 * each time.
-		 */
-		if (aclp->acl_cnt > 1)
-			tmpaclp = (ace_t *)realloc(aclp->acl_aclp,
-			    sizeof (ace_t) * (aclp->acl_cnt));
-		else
-			tmpaclp = (ace_t *)malloc(sizeof (ace_t));
-		if (tmpaclp == NULL) {
-			free(allocp);
-			acl_free(aclp);
-			return (EACL_MEM_ERROR);
-		}
-		aclp->acl_aclp = tmpaclp;
-		tmpaclp = (ace_t *)aclp->acl_aclp + (aclp->acl_cnt - 1);
-
-		/* look for entry type field */
-		tp = strchr(aclimport, ':');
-		if (tp == NULL) {
-			free(allocp);
-			acl_free(aclp);
-			return (EACL_ENTRY_ERROR);
-		} else
-			*tp = '\0';
-		if (strcmp(aclimport, "owner@") == 0) {
-			entry_type = ACE_OWNER;
-		} else if (strcmp(aclimport, "group@") == 0) {
-			entry_type = ACE_GROUP | ACE_IDENTIFIER_GROUP;
-		} else if (strcmp(aclimport, "everyone@") == 0) {
-			entry_type = ACE_EVERYONE;
-		} else if (strcmp(aclimport, "group") == 0) {
-			entry_type = ACE_IDENTIFIER_GROUP;
-		} else if (strcmp(aclimport, "user") == 0) {
-			entry_type = 0;
-		} else {
-			free(allocp);
-			acl_free(aclp);
-			return (EACL_ENTRY_ERROR);
-		}
-
-		/*
-		 * If not an abstraction owner@, group@ or everyone@
-		 * then we must have a user/group name next
-		 */
+	char *txtp;
 
-		if (entry_type == 0 || entry_type == ACE_IDENTIFIER_GROUP) {
-			fieldp = tp + 1;
-			tp = strchr(fieldp, ':');
-			if (tp == NULL) {
-				free(allocp);
-				acl_free(aclp);
-				return (EACL_INVALID_USER_GROUP);
-			} else
-				*tp = '\0';
-			if (fieldp != tp) {
-				/*
-				 * The second field could be empty. We only care
-				 * when the field has user/group name.
-				 */
-				if (entry_type == 0) {
-					/*
-					 * The reentrant interface getpwnam_r()
-					 * is uncommitted and subject to
-					 * change. Use the friendlier interface
-					 * getpwnam().
-					 */
-					error = 0;
-					passwdp = getpwnam(fieldp);
-					if (passwdp == NULL) {
-						error = acl_str_to_id(
-						    fieldp, &id);
-					} else {
-						id = passwdp->pw_uid;
-					}
-
-					if (error) {
-						free(allocp);
-						acl_free(aclp);
-						return (error);
-					}
-				} else {
-					error = 0;
-					if (entry_type ==
-					    ACE_IDENTIFIER_GROUP) {
-						groupp = getgrnam(fieldp);
-						if (groupp == NULL) {
-							/* no group? */
-							error = acl_str_to_id(
-							    fieldp, &id);
-						} else
-							id = groupp->gr_gid;
-
-					} else if ((entry_type == ACE_OWNER) ||
-					    (entry_type ==
-					    (ACE_IDENTIFIER_GROUP|ACE_GROUP)) ||
-					    (entry_type != ACE_EVERYONE)) {
-						error = EACL_FIELD_NOT_BLANK;
-					} else {
-						error = EACL_ENTRY_ERROR;
-					}
-
-					if (error) {
-						free(allocp);
-						acl_free(aclp);
-						return (error);
-					}
-				}
-			}
-		} else {
-			id = -1;
-		}
-
-		/* next field: permission */
-		fieldp = tp + 1;
-		tp = strchr(fieldp, ':');
-		if (tp == NULL) {
-			free(allocp);
-			acl_free(aclp);
-			return (EACL_PERM_MASK_ERROR);
-		} else
-			*tp = '\0';
-
-		perm = 0;
-
-		perm_tok = strtok(fieldp, "/");
-		if (perm_tok == NULL) {
-			perm = 0;
-		} else {
-			do {
-				if (ace_permask(perm_tok, &perm) != 0) {
-					free(allocp);
-					acl_free(aclp);
-					return (EACL_PERM_MASK_ERROR);
-				}
-			} while (perm_tok = strtok(NULL, "/"));
-		}
-
-		/* grab allow/deny */
-		fieldp = tp + 1;
-		tp = strchr(fieldp, ':');
-		if (tp != NULL)
-			*tp = '\0';
-
-		if (strcmp(fieldp, "allow") == 0)
-			type = ACE_ACCESS_ALLOWED_ACE_TYPE;
-		else if (strcmp(fieldp, "deny") == 0)
-			type = ACE_ACCESS_DENIED_ACE_TYPE;
-		else {
-			free(allocp);
-			acl_free(aclp);
-			return (EACL_INVALID_ACCESS_TYPE);
-		}
-
-		/* grab option inherit flags */
-
-		iflags = 0;
-		if (tp != NULL) {
-			fieldp = tp + 1;
-			if (fieldp != NULL) {
-				*tp = '\0';
-				str = fieldp;
-				if (build_iflags(str, &iflags) != 0) {
-					free(allocp);
-					acl_free(aclp);
-					return (EACL_INHERIT_ERROR);
-				}
-			} else {
-				free(allocp);
-				acl_free(aclp);
-				return (EACL_UNKNOWN_DATA);
-			}
-		}
-		/* slap fields into ace_t structure */
-
-		tmpaclp->a_flags = entry_type;
-		tmpaclp->a_flags |= iflags;
-		tmpaclp->a_who = id;
-		tmpaclp->a_access_mask = perm;
-		tmpaclp->a_type = type;
-		aclimport = nextp;
-	}
-	free(allocp);
-	*ret_aclp = aclp;
-	return (0);
-}
-
-char
-*acl_totext(acl_t *aclp)
-{
 	if (aclp == NULL)
 		return (NULL);
 
 	switch (aclp->acl_type) {
 	case ACE_T:
-		return (ace_acltotext(aclp));
+		txtp = ace_acltotext(aclp, flags);
+		break;
 	case ACLENT_T:
-		return (acltotext(aclp->acl_aclp, aclp->acl_cnt));
+		txtp = aclent_acltotext(aclp->acl_aclp, aclp->acl_cnt, flags);
+		break;
 	}
-	return (NULL);
+
+	return (txtp);
 }
 
 int
 acl_fromtext(const char *acltextp, acl_t **ret_aclp)
 {
-	acl_t *aclp;
-	char *token;
-	char *ptr;
-	char *textp;
-	enum acl_type flavor;
-	int colon_cnt = 0;
+	int error;
+	char *buf;
+
+	buf = malloc(strlen(acltextp) + 2);
+	if (buf == NULL)
+		return (EACL_MEM_ERROR);
+	strcpy(buf, acltextp);
+	strcat(buf, "\n");
+	yybuf = buf;
+	yyreset();
+	error = yyparse();
+	free(buf);
+
+	if (yyacl) {
+		if (error == 0)
+			*ret_aclp = yyacl;
+		else {
+			acl_free(yyacl);
+		}
+		yyacl = NULL;
+	}
+	return (error);
+}
+
+int
+acl_parse(const char *acltextp, acl_t **aclp)
+{
 	int error;
 
-	/*
-	 * first try and detect what type of acl entries we have
-	 *
-	 * aclent_t can have 1, 2 or 3 colons
-	 * if 3 then must have word default:
-	 *
-	 * ace_t can have 2, 3 or 4
-	 * for 2 then must be owner@, group@ or everyone@
-	 */
+	yyinteractive = 1;
+	error = acl_fromtext(acltextp, aclp);
+	yyinteractive = 0;
+	return (error);
+}
+
+static void
+ace_compact_printacl(acl_t *aclp)
+{
+	int cnt;
+	ace_t *acep;
+	char *endp;
+	char buf[ACE_ENTRY_SIZE];
 
-	textp = strdup(acltextp);
-	if (textp == NULL)
-		return (-1);
+	for (cnt = 0, acep = aclp->acl_aclp;
+	    cnt != aclp->acl_cnt; cnt++, acep++) {
+		buf[0] = '\0';
+		(void) printf("    %14s:", ace_type_txt(buf, &endp, acep));
+		(void) printf("%s:", ace_perm_txt(endp, &endp,
+		    acep->a_access_mask, acep->a_flags,
+		    aclp->acl_flags & ACL_IS_DIR, ACL_COMPACT_FMT));
+		(void) printf("%s:",
+		    ace_inherit_txt(endp, &endp, acep->a_flags,
+			ACL_COMPACT_FMT));
+		(void) printf("%s\n", ace_access_txt(endp, &endp,
+		    acep->a_type));
+	}
+}
 
-	token = strtok(textp, ",");
-	if (token == NULL) {
-		free(textp);
-		return (-1);
+static void
+ace_printacl(acl_t *aclp, int cols, int compact)
+{
+	int  slot = 0;
+	char *token;
+	char *acltext;
+
+	if (compact) {
+		ace_compact_printacl(aclp);
+		return;
 	}
 
-	for (ptr = token; *ptr; ptr++) {
-		if (*ptr == ':')
-			colon_cnt++;
+	acltext = acl_totext(aclp, 0);
+
+	if (acltext == NULL)
+		return;
+
+	token = strtok(acltext, ",");
+	if (token == NULL) {
+		free(acltext);
+		return;
 	}
 
-	if (colon_cnt == 1 || colon_cnt == 2) {
-		if ((strncmp(acltextp, "owner@", 6) == 0) ||
-		    (strncmp(acltextp, "group@", 6) == 0) ||
-		    (strncmp(acltextp, "everyone@", 9) == 0))
-			flavor = ACE_T;
-		else
-			flavor = ACLENT_T;
-	} else if (colon_cnt == 3) {
-		ptr = strtok(token, ":");
-		if (ptr == NULL) {
-			free(textp);
-			return (EACL_MISSING_FIELDS);
-		} else if (strcmp(ptr, "default") == 0) {
-			flavor = ACLENT_T;
-		} else {
-			flavor = ACE_T;
+	do {
+		(void) printf("     %d:", slot++);
+		split_line(token, cols - 5);
+	} while (token = strtok(NULL, ","));
+	free(acltext);
+}
+
+/*
+ * pretty print an ACL.
+ * For aclent_t ACL's the format is
+ * similar to the old format used by getfacl,
+ * with the addition of adding a "slot" number
+ * before each entry.
+ *
+ * for ace_t ACL's the cols variable will break up
+ * the long lines into multiple lines and will also
+ * print a "slot" number.
+ */
+void
+acl_printacl(acl_t *aclp, int cols, int compact)
+{
+
+	switch (aclp->acl_type) {
+	case ACLENT_T:
+		aclent_printacl(aclp);
+		break;
+	case ACE_T:
+		ace_printacl(aclp, cols, compact);
+		break;
+	}
+}
+
+typedef struct value_table {
+	char		p_letter; /* perm letter such as 'r' */
+	uint32_t	p_value; /* value for perm when pletter found */
+} value_table_t;
+
+#define	ACE_PERM_COUNT 14
+
+/*
+ * The permission tables are layed out in positional order
+ * a '-' character will indicate a permission at a given
+ * position is not specified.  The '-' is not part of the
+ * table, but will be checked for in the permission computation
+ * routine.
+ */
+value_table_t ace_perm_table[ACE_PERM_COUNT] = {
+	{ 'r', ACE_READ_DATA},
+	{ 'w', ACE_WRITE_DATA},
+	{ 'x', ACE_EXECUTE},
+	{ 'p', ACE_APPEND_DATA},
+	{ 'd', ACE_DELETE},
+	{ 'D', ACE_DELETE_CHILD},
+	{ 'a', ACE_READ_ATTRIBUTES},
+	{ 'A', ACE_WRITE_ATTRIBUTES},
+	{ 'R', ACE_READ_NAMED_ATTRS},
+	{ 'W', ACE_WRITE_NAMED_ATTRS},
+	{ 'c', ACE_READ_ACL},
+	{ 'C', ACE_WRITE_ACL},
+	{ 'o', ACE_WRITE_OWNER},
+	{ 's', ACE_SYNCHRONIZE}
+};
+
+#define	ACLENT_PERM_COUNT 3
+
+value_table_t aclent_perm_table[ACLENT_PERM_COUNT] = {
+	{ 'r', S_IROTH},
+	{ 'w', S_IWOTH},
+	{ 'x', S_IXOTH}
+};
+
+#define	IFLAG_COUNT	6
+value_table_t inherit_table[IFLAG_COUNT] = {
+	{'f', ACE_FILE_INHERIT_ACE},
+	{'d', ACE_DIRECTORY_INHERIT_ACE},
+	{'i', ACE_INHERIT_ONLY_ACE},
+	{'n', ACE_NO_PROPAGATE_INHERIT_ACE},
+	{'S', ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
+	{'F', ACE_FAILED_ACCESS_ACE_FLAG}
+};
+
+/*
+ * compute value from a permission table or inheritance table
+ * based on string passed in.  If positional is set then
+ * string must match order in permtab, otherwise any order
+ * is allowed.
+ */
+int
+compute_values(value_table_t *permtab, int count,
+    char *permstr, int positional, uint32_t *mask)
+{
+	uint32_t perm_val = 0;
+	char *pstr;
+	int i, found;
+
+	if (count < 0)
+		return (1);
+
+	if (positional) {
+		for (i = 0, pstr = permstr; i != count && pstr &&
+		    *pstr; i++, pstr++) {
+			if (*pstr == permtab[i].p_letter) {
+				perm_val |= permtab[i].p_value;
+			} else if (*pstr != '-') {
+				return (1);
+			}
 		}
-	} else if (colon_cnt == 4) {
-		flavor = ACE_T;
-	} else {
-		free(textp);
-		return (EACL_MISSING_FIELDS);
+	} else {  /* random order single letters with no '-' */
+		for (pstr = permstr; pstr && *pstr; pstr++) {
+			for (found = 0, i = 0; i != count; i++) {
+				if (*pstr == permtab[i].p_letter) {
+					perm_val |= permtab[i].p_value;
+					found = 1;
+					break;
+				}
+			}
+			if (found == 0)
+				return (1);
+		}
 	}
 
-
-	free(textp);
+	*mask = perm_val;
+	return (0);
+}
 
-	if (flavor == ACLENT_T)
-		error = aclent_aclfromtext((char *)acltextp, &aclp);
-	else
-		error = ace_aclfromtext((char *)acltextp, &aclp);
+/*
+ * compute value for inheritance flags.
+ */
+int
+compute_ace_inherit(char *str, uint32_t *imask)
+{
+	int error;
+	int positional = 0;
 
-	*ret_aclp = aclp;
+	if (strlen(str) == IFLAG_COUNT)
+		positional = 1;
+
+	error = compute_values(inherit_table, IFLAG_COUNT,
+	    str, positional, imask);
+
+	if (error)
+		return (EACL_INHERIT_ERROR);
+
 	return (error);
 }
+
+
+/*
+ * compute value for ACE permissions.
+ */
+int
+compute_ace_perms(char *str, uint32_t *mask)
+{
+	int positional = 0;
+	int error;
+
+	if (strlen(str) == ACE_PERM_COUNT)
+		positional = 1;
+
+	error = compute_values(ace_perm_table, ACE_PERM_COUNT,
+	    str, positional, mask);
+
+	if (error && positional) {
+		/*
+		 * If positional was set, then make sure permissions
+		 * aren't actually valid in non positional case where
+		 * all permissions are specified, just in random order.
+		 */
+		error = compute_values(ace_perm_table,
+		    ACE_PERM_COUNT, str, 0, mask);
+	}
+	if (error)
+		error = EACL_PERM_MASK_ERROR;
+
+	return (error);
+}
+
+
+
+/*
+ * compute values for aclent permissions.
+ */
+int
+compute_aclent_perms(char *str, o_mode_t *mask)
+{
+	int error;
+	uint32_t pmask;
+
+	if (strlen(str) != ACLENT_PERM_COUNT)
+		return (EACL_PERM_MASK_ERROR);
+
+	*mask = 0;
+	error = compute_values(aclent_perm_table, ACLENT_PERM_COUNT,
+	    str, 1, &pmask);
+	if (error == 0) {
+		*mask = (o_mode_t)pmask;
+	} else
+		error = EACL_PERM_MASK_ERROR;
+	return (error);
+}
+
+/*
+ * determine ACE permissions.
+ */
+int
+ace_perm_mask(struct acl_perm_type *aclperm, uint32_t *mask)
+{
+	int error;
+
+	if (aclperm->perm_style == PERM_TYPE_EMPTY) {
+		*mask = 0;
+		return (0);
+	}
+
+	if (aclperm->perm_style == PERM_TYPE_ACE) {
+		*mask = aclperm->perm_val;
+		return (0);
+	}
+
+	error = compute_ace_perms(aclperm->perm_str, mask);
+	if (error) {
+		acl_error(gettext("Invalid permission(s) '%s' specified\n"),
+		    aclperm->perm_str);
+		return (EACL_PERM_MASK_ERROR);
+	}
+
+	return (0);
+}
--- a/usr/src/lib/libsec/common/aclutils.c	Mon Feb 13 02:31:44 2006 -0800
+++ b/usr/src/lib/libsec/common/aclutils.c	Mon Feb 13 08:52:39 2006 -0800
@@ -36,6 +36,7 @@
 #include <sys/acl.h>
 #include <errno.h>
 #include <sys/stat.h>
+#include <sys/varargs.h>
 #include <locale.h>
 #include <aclutils.h>
 #include <acl_common.h>
@@ -1136,226 +1137,6 @@
 	return (0);
 }
 
-static void
-aclent_perms(int perm, char *txt_perms)
-{
-	if (perm & S_IROTH)
-		txt_perms[0] = 'r';
-	else
-		txt_perms[0] = '-';
-	if (perm & S_IWOTH)
-		txt_perms[1] = 'w';
-	else
-		txt_perms[1] = '-';
-	if (perm & S_IXOTH)
-		txt_perms[2] = 'x';
-	else
-		txt_perms[2] = '-';
-	txt_perms[3] = '\0';
-}
-
-static char *
-pruname(uid_t uid)
-{
-	struct passwd	*passwdp;
-	static char	uidp[10];	/* big enough */
-
-	passwdp = getpwuid(uid);
-	if (passwdp == (struct passwd *)NULL) {
-		/* could not get passwd information: display uid instead */
-		(void) sprintf(uidp, "%ld", (long)uid);
-		return (uidp);
-	} else
-		return (passwdp->pw_name);
-}
-
-static char *
-prgname(gid_t gid)
-{
-	struct group	*groupp;
-	static char	gidp[10];	/* big enough */
-
-	groupp = getgrgid(gid);
-	if (groupp == (struct group *)NULL) {
-		/* could not get group information: display gid instead */
-		(void) sprintf(gidp, "%ld", (long)gid);
-		return (gidp);
-	} else
-		return (groupp->gr_name);
-}
-static void
-aclent_printacl(acl_t *aclp)
-{
-	aclent_t *tp;
-	int aclcnt;
-	int mask;
-	int slot = 0;
-	char perm[4];
-
-	/* display ACL: assume it is sorted. */
-	aclcnt = aclp->acl_cnt;
-	for (tp = aclp->acl_aclp; aclcnt--; tp++) {
-		if (tp->a_type == CLASS_OBJ)
-			mask = tp->a_perm;
-	}
-	aclcnt = aclp->acl_cnt;
-	for (tp = aclp->acl_aclp; aclcnt--; tp++) {
-		(void) printf("     %d:", slot++);
-		switch (tp->a_type) {
-		case USER:
-			aclent_perms(tp->a_perm, perm);
-			(void) printf("user:%s:%s\t\t",
-			    pruname(tp->a_id), perm);
-			aclent_perms((tp->a_perm & mask), perm);
-			(void) printf("#effective:%s\n", perm);
-			break;
-		case USER_OBJ:
-			/* no need to display uid */
-			aclent_perms(tp->a_perm, perm);
-			(void) printf("user::%s\n", perm);
-			break;
-		case GROUP:
-			aclent_perms(tp->a_perm, perm);
-			(void) printf("group:%s:%s\t\t",
-			    prgname(tp->a_id), perm);
-			aclent_perms(tp->a_perm & mask, perm);
-			(void) printf("#effective:%s\n", perm);
-			break;
-		case GROUP_OBJ:
-			aclent_perms(tp->a_perm, perm);
-			(void) printf("group::%s\t\t", perm);
-			aclent_perms(tp->a_perm & mask, perm);
-			(void) printf("#effective:%s\n", perm);
-			break;
-		case CLASS_OBJ:
-			aclent_perms(tp->a_perm, perm);
-			(void) printf("mask:%s\n", perm);
-			break;
-		case OTHER_OBJ:
-			aclent_perms(tp->a_perm, perm);
-			(void) printf("other:%s\n", perm);
-			break;
-		case DEF_USER:
-			aclent_perms(tp->a_perm, perm);
-			(void) printf("default:user:%s:%s\n",
-			    pruname(tp->a_id), perm);
-			break;
-		case DEF_USER_OBJ:
-			aclent_perms(tp->a_perm, perm);
-			(void) printf("default:user::%s\n", perm);
-			break;
-		case DEF_GROUP:
-			aclent_perms(tp->a_perm, perm);
-			(void) printf("default:group:%s:%s\n",
-			    prgname(tp->a_id), perm);
-			break;
-		case DEF_GROUP_OBJ:
-			aclent_perms(tp->a_perm, perm);
-			(void) printf("default:group::%s\n", perm);
-			break;
-		case DEF_CLASS_OBJ:
-			aclent_perms(tp->a_perm, perm);
-			(void) printf("default:mask:%s\n", perm);
-			break;
-		case DEF_OTHER_OBJ:
-			aclent_perms(tp->a_perm, perm);
-			(void) printf("default:other:%s\n", perm);
-			break;
-		default:
-			(void) fprintf(stderr,
-			    gettext("unrecognized entry\n"));
-			break;
-		}
-	}
-}
-
-static void
-split_line(char *str, int cols)
-{
-	char *ptr;
-	int len;
-	int i;
-	int last_split;
-	char pad[11];
-	int pad_len;
-
-	len = strlen(str);
-	ptr = str;
-	(void) strcpy(pad, "");
-	pad_len = 0;
-
-	ptr = str;
-	last_split = 0;
-	for (i = 0; i != len; i++) {
-		if ((i + pad_len + 4) >= cols) {
-			(void) printf("%s%.*s\n", pad, last_split, ptr);
-			ptr = &ptr[last_split];
-			len = strlen(ptr);
-			i = 0;
-			pad_len = 4;
-			(void) strcpy(pad, "         ");
-		} else {
-			if (ptr[i] == '/' || ptr[i] == ':') {
-				last_split = i;
-			}
-		}
-	}
-	if (i == len) {
-		(void) printf("%s%s\n", pad, ptr);
-	}
-}
-
-static void
-ace_printacl(acl_t *aclp, int cols)
-{
-	int  slot = 0;
-	char *token;
-	char *acltext;
-
-	acltext = acl_totext(aclp);
-
-	if (acltext == NULL)
-		return;
-
-	token = strtok(acltext, ",");
-	if (token == NULL) {
-		free(acltext);
-		return;
-	}
-
-	do {
-		(void) printf("     %d:", slot++);
-		split_line(token, cols - 5);
-	} while (token = strtok(NULL, ","));
-	free(acltext);
-}
-
-/*
- * pretty print an ACL.
- * For aclent_t ACL's the format is
- * similar to the old format used by getfacl,
- * with the addition of adding a "slot" number
- * before each entry.
- *
- * for ace_t ACL's the cols variable will break up
- * the long lines into multiple lines and will also
- * print a "slot" number.
- */
-void
-acl_printacl(acl_t *aclp, int cols)
-{
-
-	switch (aclp->acl_type) {
-	case ACLENT_T:
-		aclent_printacl(aclp);
-		break;
-	case ACE_T:
-		ace_printacl(aclp, cols);
-		break;
-	}
-}
-
-
 /*
  * return text for an ACL error.
  */
@@ -1365,10 +1146,10 @@
 	switch (errnum) {
 	case EACL_GRP_ERROR:
 		return (dgettext(TEXT_DOMAIN,
-		    "There is more than one user group owner entry"));
+		    "There is more than one group or default group entry"));
 	case EACL_USER_ERROR:
 		return (dgettext(TEXT_DOMAIN,
-		    "There is more than one user owner entry"));
+		    "There is more than one user or default user entry"));
 	case EACL_OTHER_ERROR:
 		return (dgettext(TEXT_DOMAIN,
 		    "There is more than one other entry"));
@@ -1431,3 +1212,19 @@
 		return (dgettext(TEXT_DOMAIN, "Unknown error"));
 	}
 }
+
+extern int yyinteractive;
+
+/* PRINTFLIKE1 */
+void
+acl_error(const char *fmt, ...)
+{
+	va_list va;
+
+	if (yyinteractive == 0)
+		return;
+
+	va_start(va, fmt);
+	(void) vfprintf(stderr, fmt, va);
+	va_end(va);
+}
--- a/usr/src/lib/libsec/common/aclutils.h	Mon Feb 13 02:31:44 2006 -0800
+++ b/usr/src/lib/libsec/common/aclutils.h	Mon Feb 13 08:52:39 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -30,6 +30,11 @@
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 #include <sys/types.h>
+#include <strings.h>
+#include <locale.h>
+#include <ctype.h>
+#include <grp.h>
+#include <pwd.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -67,16 +72,41 @@
 };
 
 
+#define	PERM_TYPE_ACE		0x1	/* permissions are of ACE type */
+#define	PERM_TYPE_UNKNOWN	0x2	/* permission type not yet known */
+#define	PERM_TYPE_EMPTY		0x4	/* no permissions are specified */
+
+struct acl_perm_type {
+	int		perm_style;	/* type of perm style, see above */
+	char		*perm_str;	/* string value being returned */
+	uint32_t	perm_val;	/* numeric value being returned */
+};
+
+extern char *yybuf;
+extern acl_t *yyacl;
+
+extern int yyerror(const char *);
+extern int get_id(int entry_type, char *name, int *id);
+extern int ace_entry_type(int entry_type);
+extern int aclent_entry_type(int type, int owning, int *ret);
+extern int ace_perm_mask(struct acl_perm_type *, uint32_t *mask);
+extern int compute_aclent_perms(char *str, o_mode_t *mask);
+extern int compute_ace_inherit(char *str, uint32_t *imask);
 extern int acl_addentries(acl_t *, acl_t *, int);
 extern int acl_removeentries(acl_t *, acl_t *, int, int);
 extern int acl_modifyentries(acl_t *, acl_t *, int);
-extern void acl_printacl(acl_t *, int);
+extern void acl_printacl(acl_t *, int, int);
 extern char *acl_strerror(int);
 extern acl_t *acl_dup(acl_t *);
 extern int acl_type(acl_t *);
 extern int acl_cnt(acl_t *);
 extern int acl_flags(acl_t *);
 extern void *acl_data(acl_t *);
+extern void acl_error(const char *, ...);
+extern int acl_parse(const char *, acl_t **);
+extern int yyparse(void);
+extern void yyreset(void);
+extern acl_t *acl_alloc(enum acl_type);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/lib/libsec/spec/acl.spec	Mon Feb 13 02:31:44 2006 -0800
+++ b/usr/src/lib/libsec/spec/acl.spec	Mon Feb 13 08:52:39 2006 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
@@ -136,7 +136,7 @@
 
 function	acl_totext
 include		<sys/acl.h>
-declaration	char *acl_totext(acl_t *acl);
+declaration	char *acl_totext(acl_t *acl, int flags);
 version		SUNW_1.2
 exception	$return == 0
 end
@@ -167,7 +167,7 @@
 
 function	acl_printacl
 include		<sys/acl.h>
-declaration	void acl_printacl(acl_t *aclp, int cols);
+declaration	void acl_printacl(acl_t *aclp, int cols, int compact);
 version		SUNWprivate_1.1
 end
 
@@ -219,3 +219,15 @@
 declaration	void *acl_data(acl_t *);
 version		SUNWprivate_1.1
 end
+
+function	acl_error
+include		<aclutils.h>
+declaration	void acl_error(const char *, ...)
+version		SUNWprivate_1.1
+end
+
+function	acl_parse
+include		<aclutils.h>
+declaration	void acl_parse(char *textp, acl_t **);
+version		SUNWprivate_1.1
+end
--- a/usr/src/uts/common/sys/acl.h	Mon Feb 13 02:31:44 2006 -0800
+++ b/usr/src/uts/common/sys/acl.h	Mon Feb 13 08:52:39 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -126,6 +126,8 @@
     ACE_INHERIT_ONLY_ACE | \
     ACE_IDENTIFIER_GROUP)
 
+#define	ACE_TYPE_FLAGS	(ACE_OWNER|ACE_GROUP|ACE_EVERYONE|ACE_IDENTIFIER_GROUP)
+
 /* cmd args to acl(2) for aclent_t  */
 #define	GETACL			1
 #define	SETACL			2
@@ -167,6 +169,14 @@
  */
 #define	ACL_NO_TRIVIAL	0x2
 
+
+/*
+ * Flags to control acl_totext()
+ */
+
+#define	ACL_APPEND_ID	0x1 	/* append uid/gid to user/group entries */
+#define	ACL_COMPACT_FMT	0x2 	/* build ACL in ls -V format */
+
 /*
  * Legacy aclcheck errors for aclent_t ACLs
  */
@@ -210,7 +220,7 @@
 extern int facl_set(int, acl_t *acl);
 extern int acl_strip(const char *, uid_t, gid_t, mode_t);
 extern int acl_trivial(const char *);
-extern char *acl_totext(acl_t *);
+extern char *acl_totext(acl_t *, int);
 extern int acl_fromtext(const char *, acl_t **);
 extern int acl_check(acl_t *, int);