--- old/usr/src/cmd/ssh/include/config.h	Mon Sep 30 20:00:44 2013
+++ new/usr/src/cmd/ssh/include/config.h	Mon Sep 30 20:00:43 2013
@@ -4,6 +4,7 @@
 
 /*
  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 Gary Mills
  */
 
 #ifndef	_CONFIG_H
@@ -379,10 +380,10 @@
 /* #undef BROKEN_SAVED_UIDS */
 
 /* Define if your system glob() function has the GLOB_ALTDIRFUNC extension */
-/* #undef GLOB_HAS_ALTDIRFUNC */
+#define	GLOB_HAS_ALTDIRFUNC	1
 
 /* Define if your system glob() function has gl_matchc options in glob_t */
-/* #undef GLOB_HAS_GL_MATCHC */
+#define	GLOB_HAS_GL_MATCHC	1
 
 /*
  * Define in your struct dirent expects you to allocate extra space for
--- old/usr/src/cmd/ssh/include/glob.h	Mon Sep 30 20:00:45 2013
+++ /dev/null	Mon Sep 30 15:01:59 2013
@@ -1,112 +0,0 @@
-/*	$OpenBSD: glob.h,v 1.7 2002/02/17 19:42:21 millert Exp $	*/
-/*	$NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $	*/
-
-#ifndef	_GLOB_H
-#define	_GLOB_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*
- * Copyright (c) 1989, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Guido van Rossum.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)glob.h	8.1 (Berkeley) 6/2/93
- */
-
-#if !defined(HAVE_GLOB_H) || !defined(GLOB_HAS_ALTDIRFUNC) || \
-    !defined(GLOB_HAS_GL_MATCHC)
-
-struct stat;
-typedef struct {
-	int gl_pathc;		/* Count of total paths so far. */
-	int gl_matchc;		/* Count of paths matching pattern. */
-	int gl_offs;		/* Reserved at beginning of gl_pathv. */
-	int gl_flags;		/* Copy of flags parameter to glob. */
-	char **gl_pathv;	/* List of paths matching pattern. */
-				/* Copy of errfunc parameter to glob. */
-	int (*gl_errfunc)(const char *, int);
-
-	/*
-	 * Alternate filesystem access methods for glob; replacement
-	 * versions of closedir(3), readdir(3), opendir(3), stat(2)
-	 * and lstat(2).
-	 */
-	void (*gl_closedir)(void *);
-	struct dirent *(*gl_readdir)(void *);	
-	void *(*gl_opendir)(const char *);
-	int (*gl_lstat)(const char *, struct stat *);
-	int (*gl_stat)(const char *, struct stat *);
-} glob_t;
-
-/* Flags */
-#define	GLOB_APPEND	0x0001	/* Append to output from previous call. */
-#define	GLOB_DOOFFS	0x0002	/* Use gl_offs. */
-#define	GLOB_ERR	0x0004	/* Return on error. */
-#define	GLOB_MARK	0x0008	/* Append / to matching directories. */
-#define	GLOB_NOCHECK	0x0010	/* Return pattern itself if nothing matches. */
-#define	GLOB_NOSORT	0x0020	/* Don't sort. */
-
-#define	GLOB_ALTDIRFUNC	0x0040	/* Use alternately specified directory funcs. */
-#define	GLOB_BRACE	0x0080	/* Expand braces ala csh. */
-#define	GLOB_MAGCHAR	0x0100	/* Pattern had globbing characters. */
-#define	GLOB_NOMAGIC	0x0200	/* GLOB_NOCHECK without magic chars (csh). */
-#define	GLOB_QUOTE	0x0400	/* Quote special chars with \. */
-#define	GLOB_TILDE	0x0800	/* Expand tilde names from the passwd file. */
-#define	GLOB_NOESCAPE	0x1000	/* Disable backslash escaping. */
-#define GLOB_LIMIT	0x2000	/* Limit pattern match output to ARG_MAX */
-
-/* Error values returned by glob(3) */
-#define	GLOB_NOSPACE	(-1)	/* Malloc call failed. */
-#define	GLOB_ABORTED	(-2)	/* Unignored error. */
-#define	GLOB_NOMATCH	(-3)	/* No match and GLOB_NOCHECK not set. */
-#define	GLOB_NOSYS	(-4)	/* Function not supported. */
-#define GLOB_ABEND	GLOB_ABORTED
-
-int	glob(const char *, int, int (*)(const char *, int), glob_t *);
-void	globfree(glob_t *);
-
-#endif /* !defined(HAVE_GLOB_H) || !defined(GLOB_HAS_ALTDIRFUNC)  ||
-	  !defined(GLOB_HAS_GL_MATCHC */
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _GLOB_H */
--- old/usr/src/head/glob.h	Mon Sep 30 20:00:45 2013
+++ new/usr/src/head/glob.h	Mon Sep 30 20:00:45 2013
@@ -19,22 +19,58 @@
  *
  * CDDL HEADER END
  */
+
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright 1985, 1992 by Mortice Kern Systems Inc.  All rights reserved.
  */
 
 /*
- * Copyright 1985, 1992 by Mortice Kern Systems Inc.  All rights reserved.
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)glob.h	8.1 (Berkeley) 6/2/93
  */
 
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ * Copyright (c) 2013 Gary Mills
+ */
+
 #ifndef	_GLOB_H
 #define	_GLOB_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/feature_tests.h>
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -41,16 +77,47 @@
 #endif
 
 typedef	struct	glob_t	{
-	size_t	gl_pathc;		/* Count of paths matched by pattern */
-	char	**gl_pathv;		/* List of matched pathnames */
-	size_t	gl_offs;		/* # of slots reserved in gl_pathv */
-	/* following are internal to the implementation */
-	char	**gl_pathp;		/* gl_pathv + gl_offs */
-	int	gl_pathn;		/* # of elements allocated */
+	/*
+	 * Members specified by POSIX
+	 */
+	size_t	gl_pathc;	/* Total count of paths matched by pattern */
+	char	**gl_pathv;	/* List of matched pathnames */
+	size_t	gl_offs;	/* # of slots reserved in gl_pathv */
+
+	/*
+	 * Internal-use members:
+	 *
+	 * NB: The next two members are carried in both the
+	 * libc backward compatibility wrapper functions and
+	 * the extended functions.
+	 */
+	char	**gl_pathp;	/* gl_pathv + gl_offs */
+	int	gl_pathn;	/* # of elements allocated */
+
+	/*
+	 * Non-POSIX extensions
+	 *
+	 * NB: The following members are not carried in
+	 * the libc backward compatibility wrapper functions.
+	 */
+	int	gl_matchc;	/* Count of paths matching pattern. */
+	int	gl_flags;	/* Copy of flags parameter to glob. */
+	struct	stat **gl_statv; /* Stat entries corresponding to gl_pathv */
+
+	/*
+	 * Alternate filesystem access methods for glob; replacement
+	 * versions of closedir(3), readdir(3), opendir(3), stat(2)
+	 * and lstat(2).
+	 */
+	void (*gl_closedir)(void *);
+	struct dirent *(*gl_readdir)(void *);
+	void *(*gl_opendir)(const char *);
+	int (*gl_lstat)(const char *, struct stat *);
+	int (*gl_stat)(const char *, struct stat *);
 }	glob_t;
 
 /*
- * "flags" argument to glob function.
+ * POSIX "flags" argument to glob function.
  */
 #define	GLOB_ERR	0x0001		/* Don't continue on directory error */
 #define	GLOB_MARK	0x0002		/* Mark directories with trailing / */
@@ -61,6 +128,21 @@
 #define	GLOB_NOESCAPE	0x0040		/* Backslashes do not quote M-chars */
 
 /*
+ * Non-POSIX "flags" argument to glob function, from OpenBSD.
+ */
+#if !defined(__XOPEN_OR_POSIX) || defined(__EXTENSIONS__)
+#define	GLOB_POSIX	0x007F	/* All POSIX flags */
+#define	GLOB_BRACE	0x0080	/* Expand braces ala csh. */
+#define	GLOB_MAGCHAR	0x0100	/* Pattern had globbing characters. */
+#define	GLOB_NOMAGIC	0x0200	/* GLOB_NOCHECK without magic chars (csh). */
+#define	GLOB_QUOTE	0x0400	/* Quote special chars with \. */
+#define	GLOB_TILDE	0x0800	/* Expand tilde names from the passwd file. */
+#define	GLOB_LIMIT	0x2000	/* Limit pattern match output to ARG_MAX */
+#define	GLOB_KEEPSTAT	0x4000	/* Retain stat data for paths in gl_statv. */
+#define	GLOB_ALTDIRFUNC	0x8000	/* Use alternately specified directory funcs. */
+#endif /* !defined(__XOPEN_OR_POSIX) || defined(__EXTENSIONS__) */
+
+/*
  * Error returns from "glob"
  */
 #define	GLOB_NOSYS	(-4)		/* function not supported (XPG4) */
@@ -67,16 +149,29 @@
 #define	GLOB_NOMATCH	(-3)		/* Pattern does not match */
 #define	GLOB_NOSPACE	(-2)		/* Not enough memory */
 #define	GLOB_ABORTED	(-1)		/* GLOB_ERR set or errfunc return!=0 */
+#define	GLOB_ABEND	GLOB_ABORTED	/* backward compatibility */
 
+#ifdef __PRAGMA_REDEFINE_EXTNAME
+#pragma	redefine_extname	glob	_glob_ext
+#pragma	redefine_extname	globfree	_globfree_ext
+#else /* __PRAGMA_REDEFINE_EXTNAME */
+#define	glob	_glob_ext
+#define	globfree	_globfree_ext
+#endif /* __PRAGMA_REDEFINE_EXTNAME */
+
 #if defined(__STDC__)
+
 extern int glob(const char *_RESTRICT_KYWD, int, int(*)(const char *, int),
 		glob_t *_RESTRICT_KYWD);
 extern void globfree(glob_t *);
-#else
+
+#else /* __STDC__ */
+
 extern int glob();
 extern void globfree();
-#endif
 
+#endif /* __STDC__ */
+
 #ifdef	__cplusplus
 }
 #endif
--- old/usr/src/lib/libc/port/mapfile-vers	Mon Sep 30 20:00:46 2013
+++ new/usr/src/lib/libc/port/mapfile-vers	Mon Sep 30 20:00:46 2013
@@ -2724,6 +2724,8 @@
 	getvmusage;
 	__getwchar_xpg5;
 	__getwc_xpg5;
+	_glob_ext;
+	_globfree_ext;
 	gtty;
 	__idmap_flush_kcache;
 	__idmap_reg;
--- old/usr/src/lib/libc/port/regex/glob.c	Mon Sep 30 20:00:47 2013
+++ new/usr/src/lib/libc/port/regex/glob.c	Mon Sep 30 20:00:46 2013
@@ -1,299 +1,1340 @@
 /*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (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 (c) 2013 Gary Mills
  */
-
+/*	$OpenBSD: glob.c,v 1.39 2012/01/20 07:09:42 tedu Exp $ */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * This code is MKS code ported to Solaris originally with minimum
- * modifications so that upgrades from MKS would readily integrate.
- * The MKS basis for this modification was:
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
  *
- *	$Id: glob.c 1.31 1994/04/07 22:50:43 mark
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
  *
- * Additional modifications have been made to this code to make it
- * 64-bit clean.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 /*
- * glob, globfree -- POSIX.2 compatible file name expansion routines.
+ * glob(3) -- a superset of the one defined in POSIX 1003.2.
  *
- * Copyright 1985, 1991 by Mortice Kern Systems Inc.  All rights reserved.
+ * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
  *
- * Written by Eric Gisin.
+ * Optional extra services, controlled by flags not defined by POSIX:
+ *
+ * GLOB_QUOTE:
+ *	Escaping convention: \ inhibits any special meaning the following
+ *	character might have (except \ at end of string is retained).
+ * GLOB_MAGCHAR:
+ *	Set in gl_flags if pattern contained a globbing character.
+ * GLOB_NOMAGIC:
+ *	Same as GLOB_NOCHECK, but it will only append pattern if it did
+ *	not contain any magic characters.  [Used in csh style globbing]
+ * GLOB_ALTDIRFUNC:
+ *	Use alternately specified directory access functions.
+ * GLOB_TILDE:
+ *	expand ~user/foo to the /home/dir/of/user/foo
+ * GLOB_BRACE:
+ *	expand {1,2}{a,b} to 1a 1b 2a 2b
+ * gl_matchc:
+ *	Number of matches in the current invocation of glob.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#include "lint.h"
 
-#pragma	weak _glob = glob
-#pragma	weak _globfree = globfree
+#include <sys/param.h>
+#include <sys/stat.h>
 
-#include "lint.h"
-#include <stdio.h>
-#include <unistd.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <glob.h>
 #include <limits.h>
+#include <pwd.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <glob.h>
-#include <errno.h>
-#include <fnmatch.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
 
-#define	GLOB__CHECK	0x80	/* stat generated paths */
+/*
+ * This is the legacy glob_t prior to illumos enhancement 1097,
+ * used when old programs call the old libc glob functions.
+ * (New programs call the _glob_ext, _globfree_ext functions.)
+ * This struct should be considered "carved in stone".
+ */
+typedef	struct	old_glob_t	{
+	size_t	gl_pathc;		/* Count of paths matched by pattern */
+	char	**gl_pathv;		/* List of matched pathnames */
+	size_t	gl_offs;		/* # of slots reserved in gl_pathv */
+	/* following are internal to the implementation */
+	char	**gl_pathp;		/* gl_pathv + gl_offs */
+	int	gl_pathn;		/* # of elements allocated */
+}	old_glob_t;
 
-#define	INITIAL	8		/* initial pathv allocation */
-#define	NULLCPP	((char **)0)	/* Null char ** */
-#define	NAME_MAX	1024	/* something large */
+/*
+ * For old programs, the external names need to be the old names:
+ * glob() and globfree() .  We've redefined those already to
+ *  _glob_ext() and _globfree_ext() .  Now redefine old_glob()
+ * and old_globfree() to glob() and globfree() .
+ */
+#ifdef __PRAGMA_REDEFINE_EXTNAME
+#pragma	redefine_extname	old_glob	glob
+#pragma	redefine_extname	old_globfree	globfree
+#endif /* __PRAGMA_REDEFINE_EXTNAME */
 
-static int	globit(size_t, const char *, glob_t *, int,
-	int (*)(const char *, int), char **);
-static int	pstrcmp(const void *, const void *);
-static int	append(glob_t *, const char *);
+#define	DOLLAR		'$'
+#define	DOT		'.'
+#define	EOS		'\0'
+#define	LBRACKET	'['
+#define	NOT		'!'
+#define	QUESTION	'?'
+#define	QUOTE		'\\'
+#define	RANGE		'-'
+#define	RBRACKET	']'
+#define	SEP		'/'
+#define	STAR		'*'
+#define	TILDE		'~'
+#define	UNDERSCORE	'_'
+#define	LBRACE		'{'
+#define	RBRACE		'}'
+#define	SLASH		'/'
+#define	COMMA		','
+#define	COLON		':'
 
+#define	M_QUOTE		0x800000
+#define	M_PROTECT	0x400000
+
+typedef struct wcat {
+	wchar_t w_wc;
+	uint_t w_at;
+} wcat_t;
+
+#define	M_ALL		'*'	/* Plus M_QUOTE */
+#define	M_END		']'	/* Plus M_QUOTE */
+#define	M_NOT		'!'	/* Plus M_QUOTE */
+#define	M_ONE		'?'	/* Plus M_QUOTE */
+#define	M_RNG		'-'	/* Plus M_QUOTE */
+#define	M_SET		'['	/* Plus M_QUOTE */
+#define	M_CLASS		':'	/* Plus M_QUOTE */
+#define	ismeta(c)	(((c).w_at&M_QUOTE) != 0)
+
+#define	INITIAL			8	/* initial pathv allocation */
+
+#define	GLOB_LIMIT_MALLOC	65536
+#define	GLOB_LIMIT_STAT		2048
+#define	GLOB_LIMIT_READDIR	16384
+
+/* Limit of recursion during matching attempts. */
+#define	GLOB_LIMIT_RECUR	64
+
+struct glob_lim {
+	size_t	glim_malloc;
+	size_t	glim_stat;
+	size_t	glim_readdir;
+};
+
+struct glob_path_stat {
+	char		*gps_path;
+	struct stat	*gps_stat;
+};
+
+static int	 compare(const void *, const void *);
+static int	 compare_gps(const void *, const void *);
+static int	 g_Ctoc(const wcat_t *, char *, uint_t);
+static int	 g_lstat(wcat_t *, struct stat *, glob_t *);
+static DIR	*g_opendir(wcat_t *, glob_t *);
+static wcat_t	*g_strchr(const wcat_t *, wchar_t);
+static int	 g_stat(wcat_t *, struct stat *, glob_t *);
+static int	 glob0(const wcat_t *, glob_t *, struct glob_lim *,
+			int (*)(const char *, int));
+static int	 glob1(wcat_t *, wcat_t *, glob_t *, struct glob_lim *,
+			int (*)(const char *, int));
+static int	 glob2(wcat_t *, wcat_t *, wcat_t *, wcat_t *, wcat_t *,
+			wcat_t *, glob_t *, struct glob_lim *,
+			int (*)(const char *, int));
+static int	 glob3(wcat_t *, wcat_t *, wcat_t *, wcat_t *, wcat_t *,
+			wcat_t *, wcat_t *, glob_t *, struct glob_lim *,
+			int (*)(const char *, int));
+static int	 globextend(const wcat_t *, glob_t *, struct glob_lim *,
+		    struct stat *);
+static
+const wcat_t	*globtilde(const wcat_t *, wcat_t *, size_t, glob_t *);
+static int	 globexp1(const wcat_t *, glob_t *, struct glob_lim *,
+		    int (*)(const char *, int));
+static int	 globexp2(const wcat_t *, const wcat_t *, glob_t *,
+		    struct glob_lim *, int (*)(const char *, int));
+static int	 match(wcat_t *, wcat_t *, wcat_t *, int);
+
+static void
+qprintf(wcat_t *p)
+{
+	(void) p;	/* dtrace, debugger... */
+}
+
 /*
- * Free all space consumed by glob.
+ * Extended glob() function, selected by #pragma redefine_extname
+ * in glob.h with the external name _glob_ext() .
  */
-void
-globfree(glob_t *gp)
+int
+_glob_ext(const char *pattern, int flags, int (*errfunc)(const char *, int),
+    glob_t *pglob)
 {
-	size_t i;
+	const char *patnext;
+	int n;
+	size_t patlen;
+	wchar_t c;
+	wcat_t *bufnext, *bufend, patbuf[MAXPATHLEN];
+	struct glob_lim limit = { 0, 0, 0 };
 
-	if (gp->gl_pathv == 0)
-		return;
+	if ((patlen = strnlen(pattern, PATH_MAX)) == PATH_MAX)
+		return (GLOB_NOMATCH);
 
-	for (i = gp->gl_offs; i < gp->gl_offs + gp->gl_pathc; ++i)
-		free(gp->gl_pathv[i]);
-	free((void *)gp->gl_pathv);
+	patnext = pattern;
+	if (!(flags & GLOB_APPEND)) {
+		pglob->gl_pathc = 0;
+		pglob->gl_pathn = 0;
+		pglob->gl_pathv = NULL;
+		if ((flags & GLOB_KEEPSTAT) != 0)
+			pglob->gl_statv = NULL;
+		if (!(flags & GLOB_DOOFFS))
+			pglob->gl_offs = 0;
+	}
+	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
+	pglob->gl_matchc = 0;
 
-	gp->gl_pathc = 0;
-	gp->gl_pathv = NULLCPP;
+	if (pglob->gl_offs >= INT_MAX || pglob->gl_pathc >= INT_MAX ||
+	    pglob->gl_pathc >= INT_MAX - pglob->gl_offs - 1)
+		return (GLOB_NOSPACE);
+
+	bufnext = patbuf;
+	bufend = bufnext + MAXPATHLEN - 1;
+	patlen += 1;
+	if (flags & GLOB_NOESCAPE) {
+		while (bufnext < bufend) {
+			if ((n = mbtowc(&c, patnext, patlen)) > 0) {
+				patnext += n;
+				patlen -= n;
+				bufnext->w_at = 0;
+				(bufnext++)->w_wc = c;
+			} else if (n == 0) {
+				break;
+			} else {
+				return (GLOB_NOMATCH);
+			}
+		}
+	} else {
+		/* Protect the quoted characters. */
+		while (bufnext < bufend) {
+			if ((n = mbtowc(&c, patnext, patlen)) > 0) {
+				patnext += n;
+				patlen -= n;
+				if (c == QUOTE) {
+					n = mbtowc(&c, patnext, patlen);
+					if (n < 0)
+						return (GLOB_NOMATCH);
+					if (n > 0) {
+						patnext += n;
+						patlen -= n;
+					}
+					if (n == 0)
+						c = QUOTE;
+					bufnext->w_at = M_PROTECT;
+					(bufnext++)->w_wc = c;
+				} else {
+					bufnext->w_at = 0;
+					(bufnext++)->w_wc = c;
+				}
+			} else if (n == 0) {
+				break;
+			} else {
+				return (GLOB_NOMATCH);
+			}
+		}
+	}
+	bufnext->w_at = 0;
+	bufnext->w_wc = EOS;
+
+	if (flags & GLOB_BRACE)
+		return (globexp1(patbuf, pglob, &limit, errfunc));
+	else
+		return (glob0(patbuf, pglob, &limit, errfunc));
 }
 
 /*
- * Do filename expansion.
+ * Expand recursively a glob {} pattern. When there is no more expansion
+ * invoke the standard globbing routine to glob the rest of the magic
+ * characters
  */
-int
-glob(const char *pattern, int flags,
-	int (*errfn)(const char *, int), glob_t *gp)
+static int
+globexp1(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp,
+    int (*errfunc)(const char *, int))
 {
-	int rv;
-	size_t i;
-	size_t ipathc;
-	char	*path;
+	const wcat_t *ptr = pattern;
 
-	if ((flags & GLOB_DOOFFS) == 0)
-		gp->gl_offs = 0;
+	/* Protect a single {}, for find(1), like csh */
+	if (pattern[0].w_wc == LBRACE && pattern[1].w_wc == RBRACE &&
+	    pattern[2].w_wc == EOS)
+		return (glob0(pattern, pglob, limitp, errfunc));
 
-	if (!(flags & GLOB_APPEND)) {
-		gp->gl_pathc = 0;
-		gp->gl_pathn = gp->gl_offs + INITIAL;
-		gp->gl_pathv = (char **)malloc(sizeof (char *) * gp->gl_pathn);
+	if ((ptr = (const wcat_t *) g_strchr(ptr, LBRACE)) != NULL)
+		return (globexp2(ptr, pattern, pglob, limitp, errfunc));
 
-		if (gp->gl_pathv == NULLCPP)
-			return (GLOB_NOSPACE);
-		gp->gl_pathp = gp->gl_pathv + gp->gl_offs;
+	return (glob0(pattern, pglob, limitp, errfunc));
+}
 
-		for (i = 0; i < gp->gl_offs; ++i)
-			gp->gl_pathv[i] = NULL;
+
+/*
+ * Recursive brace globbing helper. Tries to expand a single brace.
+ * If it succeeds then it invokes globexp1 with the new pattern.
+ * If it fails then it tries to glob the rest of the pattern and returns.
+ */
+static int
+globexp2(const wcat_t *ptr, const wcat_t *pattern, glob_t *pglob,
+    struct glob_lim *limitp, int (*errfunc)(const char *, int))
+{
+	int	i, rv;
+	wcat_t   *lm, *ls;
+	const wcat_t *pe, *pm, *pl;
+	wcat_t    patbuf[MAXPATHLEN];
+
+	/* copy part up to the brace */
+	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
+		;
+	lm->w_at = 0;
+	lm->w_wc = EOS;
+	ls = lm;
+
+	/* Find the balanced brace */
+	for (i = 0, pe = ++ptr; pe->w_wc != EOS; pe++)
+		if (pe->w_wc == LBRACKET) {
+			/* Ignore everything between [] */
+			for (pm = pe++; pe->w_wc != RBRACKET &&
+			    pe->w_wc != EOS; pe++)
+				;
+			if (pe->w_wc == EOS) {
+				/*
+				 * We could not find a matching RBRACKET.
+				 * Ignore and just look for RBRACE
+				 */
+				pe = pm;
+			}
+		} else if (pe->w_wc == LBRACE) {
+			i++;
+		} else if (pe->w_wc == RBRACE) {
+			if (i == 0)
+				break;
+			i--;
+		}
+
+	/* Non matching braces; just glob the pattern */
+	if (i != 0 || pe->w_wc == EOS)
+		return (glob0(patbuf, pglob, limitp, errfunc));
+
+	for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
+		switch (pm->w_wc) {
+		case LBRACKET:
+			/* Ignore everything between [] */
+			for (pl = pm++; pm->w_wc != RBRACKET && pm->w_wc != EOS;
+			    pm++)
+				;
+			if (pm->w_wc == EOS) {
+				/*
+				 * We could not find a matching RBRACKET.
+				 * Ignore and just look for RBRACE
+				 */
+				pm = pl;
+			}
+			break;
+
+		case LBRACE:
+			i++;
+			break;
+
+		case RBRACE:
+			if (i) {
+				i--;
+				break;
+			}
+			/* FALLTHROUGH */
+		case COMMA:
+			if (i && pm->w_wc == COMMA)
+				break;
+			else {
+				/* Append the current string */
+				for (lm = ls; (pl < pm); *lm++ = *pl++)
+					;
+
+				/*
+				 * Append the rest of the pattern after the
+				 * closing brace
+				 */
+				for (pl = pe + 1;
+				    (*lm++ = *pl++).w_wc != EOS; /* */)
+					;
+
+				/* Expand the current pattern */
+				rv = globexp1(patbuf, pglob, limitp, errfunc);
+				if (rv && rv != GLOB_NOMATCH)
+					return (rv);
+
+				/* move after the comma, to the next string */
+				pl = pm + 1;
+			}
+			break;
+
+		default:
+			break;
+		}
 	}
+	return (0);
+}
 
-	if ((path = malloc(strlen(pattern)+1)) == NULL)
-		return (GLOB_NOSPACE);
 
-	ipathc = gp->gl_pathc;
-	rv = globit(0, pattern, gp, flags, errfn, &path);
 
-	if (rv == GLOB_ABORTED) {
+/*
+ * expand tilde from the passwd file.
+ */
+static const wcat_t *
+globtilde(const wcat_t *pattern, wcat_t *patbuf, size_t patbuf_len,
+    glob_t *pglob)
+{
+	struct passwd *pwd;
+	char *h;
+	const wcat_t *p;
+	wcat_t *b, *eb, *q;
+	int n;
+	size_t lenh;
+	wchar_t c;
+
+	if (pattern->w_wc != TILDE || !(pglob->gl_flags & GLOB_TILDE))
+		return (pattern);
+
+	/* Copy up to the end of the string or / */
+	eb = &patbuf[patbuf_len - 1];
+	for (p = pattern + 1, q = patbuf;
+	    q < eb && p->w_wc != EOS && p->w_wc != SLASH; *q++ = *p++)
+		;
+
+	q->w_at = 0;
+	q->w_wc = EOS;
+
+	/* What to do if patbuf is full? */
+
+	if (patbuf[0].w_wc == EOS) {
 		/*
-		 * User's error function returned non-zero, or GLOB_ERR was
-		 * set, and we encountered a directory we couldn't search.
+		 * handle a plain ~ or ~/ by expanding $HOME
+		 * first and then trying the password file
 		 */
-		free(path);
-		return (GLOB_ABORTED);
+		if (issetugid() != 0)
+			return (pattern);
+		if ((h = getenv("HOME")) == NULL) {
+			if ((pwd = getpwuid(getuid())) == NULL)
+				return (pattern);
+			else
+				h = pwd->pw_dir;
+		}
+	} else {
+		/*
+		 * Expand a ~user
+		 */
+		if ((pwd = getpwnam((char *)patbuf)) == NULL)
+			return (pattern);
+		else
+			h = pwd->pw_dir;
 	}
 
-	i = gp->gl_pathc - ipathc;
-	if (i >= 1 && !(flags & GLOB_NOSORT)) {
-		qsort((char *)(gp->gl_pathp+ipathc), i, sizeof (char *),
-		    pstrcmp);
+	/* Copy the home directory */
+	lenh = strlen(h) + 1;
+	for (b = patbuf; b < eb && *h != EOS; b++) {
+		if ((n = mbtowc(&c, h, lenh)) > 0) {
+			h += n;
+			lenh -= n;
+			b->w_at = 0;
+			b->w_wc = c;
+		} else if (n < 0) {
+			return (pattern);
+		} else {
+			break;
+		}
 	}
-	if (i == 0) {
-		if (flags & GLOB_NOCHECK)
-			(void) append(gp, pattern);
-		else
-			rv = GLOB_NOMATCH;
-	}
-	gp->gl_pathp[gp->gl_pathc] = NULL;
-	free(path);
 
-	return (rv);
+	/* Append the rest of the pattern */
+	while (b < eb && (*b++ = *p++).w_wc != EOS)
+		;
+	b->w_at = 0;
+	b->w_wc = EOS;
+
+	return (patbuf);
 }
 
+static int
+g_charclass(const wcat_t **patternp, wcat_t **bufnextp)
+{
+	const wcat_t *pattern = *patternp + 1;
+	wcat_t *bufnext = *bufnextp;
+	const wcat_t *colon;
+	char cbuf[MB_LEN_MAX + 32];
+	wctype_t cc;
+	size_t len;
 
+	if ((colon = g_strchr(pattern, COLON)) == NULL ||
+	    colon[1].w_wc != RBRACKET)
+		return (1);	/* not a character class */
+
+	len = (size_t)(colon - pattern);
+	if (len + MB_LEN_MAX + 1 > sizeof (cbuf))
+		return (-1);	/* invalid character class */
+	{
+		wchar_t w;
+		const wcat_t *s1 = pattern;
+		char *s2 = cbuf;
+		size_t n = len;
+
+		/* Copy the string. */
+		while (n > 0) {
+			w = (s1++)->w_wc;
+			/* Character class names must be ASCII. */
+			if (iswascii(w)) {
+				n--;
+				*s2++ = w;
+			} else {
+				return (-1);	/* invalid character class */
+			}
+		}
+		*s2 = EOS;
+	}
+	if ((cc = wctype(cbuf)) == 0)
+		return (-1);	/* invalid character class */
+	bufnext->w_at = M_QUOTE;
+	(bufnext++)->w_wc = M_CLASS;
+	bufnext->w_at = 0;
+	(bufnext++)->w_wc = cc;
+	*bufnextp = bufnext;
+	*patternp += len + 3;
+
+	return (0);
+}
+
 /*
- * Recursive routine to match glob pattern, and walk directories.
+ * The main glob() routine: compiles the pattern (optionally processing
+ * quotes), calls glob1() to do the real pattern matching, and finally
+ * sorts the list (unless unsorted operation is requested).  Returns 0
+ * if things went well, nonzero if errors occurred.  It is not an error
+ * to find no matches.
  */
-int
-globit(size_t dend, const char *sp, glob_t *gp, int flags,
-	int (*errfn)(const char *, int), char **path)
+static int
+glob0(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp,
+    int (*errfunc)(const char *, int))
 {
-	size_t n;
-	size_t m;
-	ssize_t end = 0;	/* end of expanded directory */
-	char *pat = (char *)sp;	/* pattern component */
-	char *dp = (*path) + dend;
-	int expand = 0;		/* path has pattern */
-	char *cp;
-	struct stat64 sb;
-	DIR *dirp;
-	struct dirent64 *d;
-	int err;
+	const wcat_t *qpatnext;
+	int err, oldpathc;
+	wchar_t c;
+	int a;
+	wcat_t *bufnext, patbuf[MAXPATHLEN];
 
-	for (;;)
-		switch (*dp++ = *(unsigned char *)sp++) {
-		case '\0':	/* end of source path */
-			if (expand)
-				goto Expand;
-			else {
-				if (!(flags & GLOB_NOCHECK) ||
-				    flags & (GLOB__CHECK|GLOB_MARK))
-					if (stat64(*path, &sb) < 0) {
-						return (0);
+	qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
+	oldpathc = pglob->gl_pathc;
+	bufnext = patbuf;
+
+	/*
+	 * We don't need to check for buffer overflow any more.
+	 * The pattern has already been copied to an internal buffer.
+	 */
+	while ((a = qpatnext->w_at), (c = (qpatnext++)->w_wc) != EOS) {
+		switch (c) {
+		case LBRACKET:
+			if (a != 0) {
+				bufnext->w_at = a;
+				(bufnext++)->w_wc = c;
+				break;
+			}
+			a = qpatnext->w_at;
+			c = qpatnext->w_wc;
+			if (a == 0 && c == NOT)
+				++qpatnext;
+			if (qpatnext->w_wc == EOS ||
+			    g_strchr(qpatnext+1, RBRACKET) == NULL) {
+				bufnext->w_at = 0;
+				(bufnext++)->w_wc = LBRACKET;
+				if (a == 0 && c == NOT)
+					--qpatnext;
+				break;
+			}
+			bufnext->w_at = M_QUOTE;
+			(bufnext++)->w_wc = M_SET;
+			if (a == 0 && c == NOT) {
+				bufnext->w_at = M_QUOTE;
+				(bufnext++)->w_wc = M_NOT;
+			}
+			a = qpatnext->w_at;
+			c = (qpatnext++)->w_wc;
+			do {
+				if (a == 0 && c == LBRACKET &&
+				    qpatnext->w_wc == COLON) {
+					do {
+						err = g_charclass(&qpatnext,
+						    &bufnext);
+						if (err)
+							break;
+						a = qpatnext->w_at;
+						c = (qpatnext++)->w_wc;
+					} while (a == 0 && c == LBRACKET &&
+					    qpatnext->w_wc == COLON);
+					if (err == -1 &&
+					    !(pglob->gl_flags & GLOB_NOCHECK))
+						return (GLOB_NOMATCH);
+					if (a == 0 && c == RBRACKET)
+						break;
+				}
+				bufnext->w_at = a;
+				(bufnext++)->w_wc = c;
+				if (qpatnext->w_at == 0 &&
+				    qpatnext->w_wc == RANGE) {
+					a = qpatnext[1].w_at;
+					c = qpatnext[1].w_wc;
+					if (qpatnext[1].w_at != 0 ||
+					    qpatnext[1].w_wc != RBRACKET) {
+						bufnext->w_at = M_QUOTE;
+						(bufnext++)->w_wc = M_RNG;
+						bufnext->w_at = a;
+						(bufnext++)->w_wc = c;
+						qpatnext += 2;
 					}
-				if (flags & GLOB_MARK && S_ISDIR(sb.st_mode)) {
-					*dp = '\0';
-					*--dp = '/';
 				}
-				if (append(gp, *path) < 0) {
-					return (GLOB_NOSPACE);
-				}
-				return (0);
+				a = qpatnext->w_at;
+				c = (qpatnext++)->w_wc;
+			} while (a != 0 || c != RBRACKET);
+			pglob->gl_flags |= GLOB_MAGCHAR;
+			bufnext->w_at = M_QUOTE;
+			(bufnext++)->w_wc = M_END;
+			break;
+		case QUESTION:
+			if (a != 0) {
+				bufnext->w_at = a;
+				(bufnext++)->w_wc = c;
+				break;
 			}
-			/*NOTREACHED*/
-
-		case '*':
-		case '?':
-		case '[':
-		case '\\':
-			++expand;
+			pglob->gl_flags |= GLOB_MAGCHAR;
+			bufnext->w_at = M_QUOTE;
+			(bufnext++)->w_wc = M_ONE;
 			break;
-
-		case '/':
-			if (expand)
-				goto Expand;
-			end = dp - *path;
-			pat = (char *)sp;
+		case STAR:
+			if (a != 0) {
+				bufnext->w_at = a;
+				(bufnext++)->w_wc = c;
+				break;
+			}
+			pglob->gl_flags |= GLOB_MAGCHAR;
+			/*
+			 * collapse adjacent stars to one,
+			 * to avoid exponential behavior
+			 */
+			if (bufnext == patbuf ||
+			    bufnext[-1].w_at != M_QUOTE ||
+			    bufnext[-1].w_wc != M_ALL) {
+				bufnext->w_at = M_QUOTE;
+				(bufnext++)->w_wc = M_ALL;
+			}
 			break;
+		default:
+			bufnext->w_at = a;
+			(bufnext++)->w_wc = c;
+			break;
+		}
+	}
+	bufnext->w_at = 0;
+	bufnext->w_wc = EOS;
+	qprintf(patbuf);
 
-		Expand:
-			/* determine directory and open it */
-			(*path)[end] = '\0';
-			dirp = opendir(**path == '\0' ? "." : *path);
-			if (dirp == NULL) {
-				if (errfn != 0 && errfn(*path, errno) != 0 ||
-				    flags&GLOB_ERR) {
-					return (GLOB_ABORTED);
-				}
-				return (0);
+	if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, limitp, errfunc))
+	    != 0)
+		return (err);
+
+	/*
+	 * If there was no match we are going to append the pattern
+	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+	 * and the pattern did not contain any magic characters
+	 * GLOB_NOMAGIC is there just for compatibility with csh.
+	 */
+	if (pglob->gl_pathc == oldpathc) {
+		if ((pglob->gl_flags & GLOB_NOCHECK) ||
+		    ((pglob->gl_flags & GLOB_NOMAGIC) &&
+		    !(pglob->gl_flags & GLOB_MAGCHAR)))
+			return (globextend(pattern, pglob, limitp, NULL));
+		else
+			return (GLOB_NOMATCH);
+	}
+	if (!(pglob->gl_flags & GLOB_NOSORT)) {
+		if ((pglob->gl_flags & GLOB_KEEPSTAT)) {
+			/* Keep the paths and stat info synced during sort */
+			struct glob_path_stat *path_stat;
+			int i;
+			int n = pglob->gl_pathc - oldpathc;
+			int o = pglob->gl_offs + oldpathc;
+
+			if ((path_stat = calloc(n, sizeof (*path_stat))) ==
+			    NULL)
+				return (GLOB_NOSPACE);
+			for (i = 0; i < n; i++) {
+				path_stat[i].gps_path = pglob->gl_pathv[o + i];
+				path_stat[i].gps_stat = pglob->gl_statv[o + i];
 			}
+			qsort(path_stat, n, sizeof (*path_stat), compare_gps);
+			for (i = 0; i < n; i++) {
+				pglob->gl_pathv[o + i] = path_stat[i].gps_path;
+				pglob->gl_statv[o + i] = path_stat[i].gps_stat;
+			}
+			free(path_stat);
+		} else {
+			qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
+			    pglob->gl_pathc - oldpathc, sizeof (char *),
+			    compare);
+		}
+	}
+	return (0);
+}
 
-			/* extract pattern component */
-			n = sp - pat;
-			if ((cp = malloc(n)) == NULL) {
-				(void) closedir(dirp);
+static int
+compare(const void *p, const void *q)
+{
+	return (strcmp(*(char **)p, *(char **)q));
+}
+
+static int
+compare_gps(const void *_p, const void *_q)
+{
+	const struct glob_path_stat *p = (const struct glob_path_stat *)_p;
+	const struct glob_path_stat *q = (const struct glob_path_stat *)_q;
+
+	return (strcmp(p->gps_path, q->gps_path));
+}
+
+static int
+glob1(wcat_t *pattern, wcat_t *pattern_last, glob_t *pglob,
+    struct glob_lim *limitp, int (*errfunc)(const char *, int))
+{
+	wcat_t pathbuf[MAXPATHLEN];
+
+	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
+	if (pattern->w_wc == EOS)
+		return (0);
+	return (glob2(pathbuf, pathbuf+MAXPATHLEN-1,
+	    pathbuf, pathbuf+MAXPATHLEN-1,
+	    pattern, pattern_last, pglob, limitp, errfunc));
+}
+
+/*
+ * The functions glob2 and glob3 are mutually recursive; there is one level
+ * of recursion for each segment in the pattern that contains one or more
+ * meta characters.
+ */
+static int
+glob2(wcat_t *pathbuf, wcat_t *pathbuf_last, wcat_t *pathend,
+    wcat_t *pathend_last, wcat_t *pattern, wcat_t *pattern_last,
+    glob_t *pglob, struct glob_lim *limitp, int (*errfunc)(const char *, int))
+{
+	struct stat sb;
+	wcat_t *p, *q;
+	int anymeta;
+
+	/*
+	 * Loop over pattern segments until end of pattern or until
+	 * segment with meta character found.
+	 */
+	for (anymeta = 0; ; ) {
+		if (pattern->w_wc == EOS) {		/* End of pattern? */
+			pathend->w_at = 0;
+			pathend->w_wc = EOS;
+
+			if ((pglob->gl_flags & GLOB_LIMIT) &&
+			    limitp->glim_stat++ >= GLOB_LIMIT_STAT) {
+				errno = 0;
+				pathend->w_at = 0;
+				(pathend++)->w_wc = SEP;
+				pathend->w_at = 0;
+				pathend->w_wc = EOS;
 				return (GLOB_NOSPACE);
 			}
-			pat = memcpy(cp, pat, n);
-			pat[n-1] = '\0';
-			if (*--sp != '\0')
-				flags |= GLOB__CHECK;
+			if (g_lstat(pathbuf, &sb, pglob))
+				return (0);
 
-			/* expand path to max. expansion */
-			n = dp - *path;
-			*path = realloc(*path,
-			    strlen(*path) + NAME_MAX + strlen(sp) + 1);
-			if (*path == NULL) {
-				(void) closedir(dirp);
-				free(pat);
+			if (((pglob->gl_flags & GLOB_MARK) &&
+			    (pathend[-1].w_at != 0 ||
+			    pathend[-1].w_wc != SEP)) &&
+			    (S_ISDIR(sb.st_mode) ||
+			    (S_ISLNK(sb.st_mode) &&
+			    (g_stat(pathbuf, &sb, pglob) == 0) &&
+			    S_ISDIR(sb.st_mode)))) {
+				if (pathend+1 > pathend_last)
+					return (GLOB_NOSPACE);
+				pathend->w_at = 0;
+				(pathend++)->w_wc = SEP;
+				pathend->w_at = 0;
+				pathend->w_wc = EOS;
+			}
+			++pglob->gl_matchc;
+			return (globextend(pathbuf, pglob, limitp, &sb));
+		}
+
+		/* Find end of next segment, copy tentatively to pathend. */
+		q = pathend;
+		p = pattern;
+		while (p->w_wc != EOS && p->w_wc != SEP) {
+			if (ismeta(*p))
+				anymeta = 1;
+			if (q+1 > pathend_last)
 				return (GLOB_NOSPACE);
+			*q++ = *p++;
+		}
+
+		if (!anymeta) {		/* No expansion, do next segment. */
+			pathend = q;
+			pattern = p;
+			while (pattern->w_wc == SEP) {
+				if (pathend+1 > pathend_last)
+					return (GLOB_NOSPACE);
+				*pathend++ = *pattern++;
 			}
-			dp = (*path) + n;
+		} else  {
+			/* Need expansion, recurse. */
+			return (glob3(pathbuf, pathbuf_last, pathend,
+			    pathend_last, pattern, p, pattern_last,
+			    pglob, limitp, errfunc));
+		}
+	}
+	/* NOTREACHED */
+}
 
-			/* read directory and match entries */
-			err = 0;
-			while ((d = readdir64(dirp)) != NULL) {
-				cp = d->d_name;
-				if ((flags&GLOB_NOESCAPE)
-				    ? fnmatch(pat, cp, FNM_PERIOD|FNM_NOESCAPE)
-				    : fnmatch(pat, cp, FNM_PERIOD))
-					continue;
+static int
+glob3(wcat_t *pathbuf, wcat_t *pathbuf_last, wcat_t *pathend,
+    wcat_t *pathend_last, wcat_t *pattern, wcat_t *restpattern,
+    wcat_t *restpattern_last, glob_t *pglob, struct glob_lim *limitp,
+    int (*errfunc)(const char *, int))
+{
+	struct dirent *dp;
+	DIR *dirp;
+	int err;
+	char buf[MAXPATHLEN];
 
-				n = strlen(cp);
-				(void) memcpy((*path) + end, cp, n);
-				m = dp - *path;
-				err = globit(end+n, sp, gp, flags, errfn, path);
-				dp = (*path) + m;   /* globit can move path */
-				if (err != 0)
-					break;
+	/*
+	 * The readdirfunc declaration can't be prototyped, because it is
+	 * assigned, below, to two functions which are prototyped in glob.h
+	 * and dirent.h as taking pointers to differently typed opaque
+	 * structures.
+	 */
+	struct dirent *(*readdirfunc)(void *);
+
+	if (pathend > pathend_last)
+		return (GLOB_NOSPACE);
+	pathend->w_at = 0;
+	pathend->w_wc = EOS;
+	errno = 0;
+
+	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
+		/* TODO: don't call for ENOENT or ENOTDIR? */
+		if (errfunc) {
+			if (g_Ctoc(pathbuf, buf, sizeof (buf)))
+				return (GLOB_ABORTED);
+			if (errfunc(buf, errno) ||
+			    pglob->gl_flags & GLOB_ERR)
+				return (GLOB_ABORTED);
+		}
+		return (0);
+	}
+
+	err = 0;
+
+	/* Search directory for matching names. */
+	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+		readdirfunc = pglob->gl_readdir;
+	else
+		readdirfunc = (struct dirent *(*)(void *))readdir;
+	while ((dp = (*readdirfunc)(dirp))) {
+		char *sc;
+		wcat_t *dc;
+		int n;
+		int lensc;
+		wchar_t w;
+
+		if ((pglob->gl_flags & GLOB_LIMIT) &&
+		    limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) {
+			errno = 0;
+			pathend->w_at = 0;
+			(pathend++)->w_wc = SEP;
+			pathend->w_at = 0;
+			pathend->w_wc = EOS;
+			err = GLOB_NOSPACE;
+			break;
+		}
+
+		/* Initial DOT must be matched literally. */
+		if (dp->d_name[0] == DOT && pattern->w_wc != DOT)
+			continue;
+		dc = pathend;
+		sc = dp->d_name;
+		lensc = strlen(sc) + 1;
+		while (dc < pathend_last) {
+			if ((n = mbtowc(&w, sc, lensc)) <= 0) {
+				sc += 1;
+				lensc -= 1;
+				dc->w_at = 0;
+				dc->w_wc = EOS;
+			} else {
+				sc += n;
+				lensc -= n;
+				dc->w_at = 0;
+				dc->w_wc = w;
 			}
+			dc++;
+			if (n <= 0)
+				break;
+		}
+		if (dc >= pathend_last) {
+			dc->w_at = 0;
+			dc->w_wc = EOS;
+			err = GLOB_NOSPACE;
+			break;
+		}
+		if (n < 0) {
+			err = GLOB_NOMATCH;
+			break;
+		}
 
-			(void) closedir(dirp);
-			free(pat);
-			return (err);
+		if (!match(pathend, pattern, restpattern, GLOB_LIMIT_RECUR)) {
+			pathend->w_at = 0;
+			pathend->w_wc = EOS;
+			continue;
 		}
-		/* NOTREACHED */
+		err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
+		    restpattern, restpattern_last, pglob, limitp,
+		    errfunc);
+		if (err)
+			break;
+	}
+
+	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+		(*pglob->gl_closedir)(dirp);
+	else
+		(void) closedir(dirp);
+	return (err);
 }
 
+
 /*
- * Comparison routine for two name arguments, called by qsort.
+ * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
+ * add the new item, and update gl_pathc.  Avoids excessive reallocation
+ * by doubling the number of elements each time.  Uses gl_pathn to contain
+ * the number.
+ *
+ * Return 0 if new item added, error code if memory couldn't be allocated.
+ *
+ * Invariant of the glob_t structure:
+ *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
+ *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
  */
-int
-pstrcmp(const void *npp1, const void *npp2)
+static int
+globextend(const wcat_t *path, glob_t *pglob, struct glob_lim *limitp,
+    struct stat *sb)
 {
-	return (strcoll(*(char **)npp1, *(char **)npp2));
+	char **pathv;
+	ssize_t i;
+	size_t allocn, newn, len;
+	char *copy = NULL;
+	const wcat_t *p;
+	struct stat **statv;
+	char junk[MB_LEN_MAX];
+	int n;
+
+	allocn = pglob->gl_pathn;
+	newn = 2 + pglob->gl_pathc + pglob->gl_offs;
+
+	if (newn <= allocn) {
+		pathv = pglob->gl_pathv;
+		if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0)
+			statv = pglob->gl_statv;
+	} else {
+		if (allocn == 0)
+			allocn = pglob->gl_offs + INITIAL;
+		allocn *= 2;
+		if (pglob->gl_offs >= INT_MAX ||
+		    pglob->gl_pathc >= INT_MAX ||
+		    allocn >= INT_MAX ||
+		    SIZE_MAX / sizeof (*pathv) <= allocn ||
+		    SIZE_MAX / sizeof (*statv) <= allocn) {
+		nospace:
+			for (i = pglob->gl_offs; i < (ssize_t)(newn - 2);
+			    i++) {
+				if (pglob->gl_pathv && pglob->gl_pathv[i])
+					free(pglob->gl_pathv[i]);
+				if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
+				    pglob->gl_statv && pglob->gl_statv[i])
+					free(pglob->gl_statv[i]);
+			}
+			if (pglob->gl_pathv) {
+				free(pglob->gl_pathv);
+				pglob->gl_pathv = NULL;
+			}
+			if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
+			    pglob->gl_statv) {
+				free(pglob->gl_statv);
+				pglob->gl_statv = NULL;
+			}
+			return (GLOB_NOSPACE);
+		}
+		limitp->glim_malloc += allocn * sizeof (*pathv);
+		pathv = realloc(pglob->gl_pathv, allocn * sizeof (*pathv));
+		if (pathv == NULL)
+			goto nospace;
+		if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
+			limitp->glim_malloc += allocn * sizeof (*statv);
+			statv = realloc(pglob->gl_statv,
+			    allocn * sizeof (*statv));
+			if (statv == NULL)
+				goto nospace;
+		}
+	}
+	pglob->gl_pathn = allocn;
+
+	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
+		/* first time around -- clear initial gl_offs items */
+		pathv += pglob->gl_offs;
+		for (i = pglob->gl_offs; --i >= 0; )
+			*--pathv = NULL;
+	}
+	pglob->gl_pathv = pathv;
+
+	if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
+		if (pglob->gl_statv == NULL && pglob->gl_offs > 0) {
+			/* first time around -- clear initial gl_offs items */
+			statv += pglob->gl_offs;
+			for (i = pglob->gl_offs; --i >= 0; )
+				*--statv = NULL;
+		}
+		pglob->gl_statv = statv;
+		if (sb == NULL)
+			statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+		else {
+			limitp->glim_malloc += sizeof (**statv);
+			if ((statv[pglob->gl_offs + pglob->gl_pathc] =
+			    malloc(sizeof (**statv))) == NULL)
+				goto copy_error;
+			(void) memcpy(statv[pglob->gl_offs + pglob->gl_pathc],
+			    sb, sizeof (*sb));
+		}
+		statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL;
+	}
+
+	len = MB_LEN_MAX;
+	p = path;
+	while ((n = wctomb(junk, p->w_wc)) > 0) {
+		len += n;
+		if ((p++)->w_wc == EOS)
+			break;
+	}
+	if (n < 0)
+		return (GLOB_NOMATCH);
+
+	limitp->glim_malloc += len;
+	if ((copy = malloc(len)) != NULL) {
+		if (g_Ctoc(path, copy, len)) {
+			free(copy);
+			return (GLOB_NOSPACE);
+		}
+		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
+	}
+	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+
+	if ((pglob->gl_flags & GLOB_LIMIT) &&
+	    limitp->glim_malloc >= GLOB_LIMIT_MALLOC) {
+		errno = 0;
+		return (GLOB_NOSPACE);
+	}
+	copy_error:
+	return (copy == NULL ? GLOB_NOSPACE : 0);
 }
 
+
 /*
- * Add a new matched filename to the glob_t structure, increasing the
- * size of that array, as required.
+ * pattern matching function for filenames.  Each occurrence of the *
+ * pattern causes a recursion level.
  */
-int
-append(glob_t *gp, const char *str)
+static int
+match(wcat_t *name, wcat_t *pat, wcat_t *patend, int recur)
 {
-	char *cp;
+	int ok, negate_range;
+	wcat_t c, k;
 
-	if ((cp = malloc(strlen(str)+1)) == NULL)
-		return (GLOB_NOSPACE);
-	gp->gl_pathp[gp->gl_pathc++] = strcpy(cp, str);
+	if (recur-- == 0)
+		return (1);
 
-	if ((gp->gl_pathc + gp->gl_offs) >= gp->gl_pathn) {
-		gp->gl_pathn *= 2;
-		gp->gl_pathv = (char **)realloc((void *)gp->gl_pathv,
-		    gp->gl_pathn * sizeof (char *));
-		if (gp->gl_pathv == NULLCPP)
-			return (GLOB_NOSPACE);
-		gp->gl_pathp = gp->gl_pathv + gp->gl_offs;
+	while (pat < patend) {
+		c = *pat++;
+		switch (c.w_wc) {
+		case M_ALL:
+			if (c.w_at != M_QUOTE) {
+				k = *name++;
+				if (k.w_at != c.w_at || k.w_wc != c.w_wc)
+					return (0);
+				break;
+			}
+			while (pat < patend && pat->w_at == M_QUOTE &&
+			    pat->w_wc == M_ALL)
+				pat++;	/* eat consecutive '*' */
+			if (pat == patend)
+				return (1);
+			do {
+				if (match(name, pat, patend, recur))
+					return (1);
+			} while ((name++)->w_wc != EOS);
+			return (0);
+		case M_ONE:
+			if (c.w_at != M_QUOTE) {
+				k = *name++;
+				if (k.w_at != c.w_at || k.w_wc != c.w_wc)
+					return (0);
+				break;
+			}
+			if ((name++)->w_wc == EOS)
+				return (0);
+			break;
+		case M_SET:
+			if (c.w_at != M_QUOTE) {
+				k = *name++;
+				if (k.w_at != c.w_at || k.w_wc != c.w_wc)
+					return (0);
+				break;
+			}
+			ok = 0;
+			if ((k = *name++).w_wc == EOS)
+				return (0);
+			if ((negate_range = (pat->w_at == M_QUOTE &&
+			    pat->w_wc == M_NOT)) != 0)
+				++pat;
+			while (((c = *pat++).w_at != M_QUOTE) ||
+			    c.w_wc != M_END) {
+				if (c.w_at == M_QUOTE && c.w_wc == M_CLASS) {
+					wcat_t cc;
+
+					cc.w_at = pat->w_at;
+					cc.w_wc = pat->w_wc;
+					if (iswctype(k.w_wc, cc.w_wc))
+						ok = 1;
+					++pat;
+				}
+				if (pat->w_at == M_QUOTE &&
+				    pat->w_wc == M_RNG) {
+					if (c.w_wc <= k.w_wc &&
+					    k.w_wc <= pat[1].w_wc)
+						ok = 1;
+					pat += 2;
+				} else if (c.w_wc == k.w_wc)
+					ok = 1;
+			}
+			if (ok == negate_range)
+				return (0);
+			break;
+		default:
+			k = *name++;
+			if (k.w_at != c.w_at || k.w_wc != c.w_wc)
+				return (0);
+			break;
+		}
 	}
-	return (0);
+	return (name->w_wc == EOS);
 }
+
+/*
+ * Extended globfree() function, selected by #pragma redefine_extname
+ * in glob.h with the external name _globfree_ext() .
+ */
+void
+_globfree_ext(glob_t *pglob)
+{
+	int i;
+	char **pp;
+
+	if (pglob->gl_pathv != NULL) {
+		pp = pglob->gl_pathv + pglob->gl_offs;
+		for (i = pglob->gl_pathc; i--; ++pp)
+			if (*pp)
+				free(*pp);
+		free(pglob->gl_pathv);
+		pglob->gl_pathv = NULL;
+	}
+	if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
+	    pglob->gl_statv != NULL) {
+		for (i = 0; i < pglob->gl_pathc; i++) {
+			if (pglob->gl_statv[i] != NULL)
+				free(pglob->gl_statv[i]);
+		}
+		free(pglob->gl_statv);
+		pglob->gl_statv = NULL;
+	}
+}
+
+static DIR *
+g_opendir(wcat_t *str, glob_t *pglob)
+{
+	char buf[MAXPATHLEN];
+
+	if (str->w_wc == EOS)
+		(void) strlcpy(buf, ".", sizeof (buf));
+	else {
+		if (g_Ctoc(str, buf, sizeof (buf)))
+			return (NULL);
+	}
+
+	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+		return ((*pglob->gl_opendir)(buf));
+
+	return (opendir(buf));
+}
+
+static int
+g_lstat(wcat_t *fn, struct stat *sb, glob_t *pglob)
+{
+	char buf[MAXPATHLEN];
+
+	if (g_Ctoc(fn, buf, sizeof (buf)))
+		return (-1);
+	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+		return ((*pglob->gl_lstat)(buf, sb));
+	return (lstat(buf, sb));
+}
+
+static int
+g_stat(wcat_t *fn, struct stat *sb, glob_t *pglob)
+{
+	char buf[MAXPATHLEN];
+
+	if (g_Ctoc(fn, buf, sizeof (buf)))
+		return (-1);
+	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+		return ((*pglob->gl_stat)(buf, sb));
+	return (stat(buf, sb));
+}
+
+static wcat_t *
+g_strchr(const wcat_t *str, wchar_t ch)
+{
+	do {
+		if (str->w_at == 0 && str->w_wc == ch)
+			return ((wcat_t *)str);
+	} while ((str++)->w_wc != EOS);
+	return (NULL);
+}
+
+static int
+g_Ctoc(const wcat_t *str, char *buf, uint_t len)
+{
+	int n;
+	wchar_t w;
+
+	while (len >= MB_LEN_MAX) {
+		w = (str++)->w_wc;
+		if ((n = wctomb(buf, w)) > 0) {
+			len -= n;
+			buf += n;
+		}
+		if (n < 0)
+			break;
+		if (w == EOS)
+			return (0);
+	}
+	return (1);
+}
+
+/* glob() function with legacy glob structure */
+int
+old_glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
+    old_glob_t *pglob)
+{
+
+	glob_t gl;
+	int rv;
+
+	flags &= GLOB_POSIX;
+
+	(void) memset(&gl, 0, sizeof (gl));
+
+	/*
+	 * Copy all the members, old to new.  There's
+	 * really no point in micro-optimizing the copying.
+	 * Other members are set to zero.
+	 */
+	gl.gl_pathc = pglob->gl_pathc;
+	gl.gl_pathv = pglob->gl_pathv;
+	gl.gl_offs = pglob->gl_offs;
+	gl.gl_pathp = pglob->gl_pathp;
+	gl.gl_pathn = pglob->gl_pathn;
+
+	rv = _glob_ext(pattern, flags, errfunc, &gl);
+
+	/*
+	 * Copy all the members, new to old.  There's
+	 * really no point in micro-optimizing the copying.
+	 */
+	pglob->gl_pathc = gl.gl_pathc;
+	pglob->gl_pathv = gl.gl_pathv;
+	pglob->gl_offs = gl.gl_offs;
+	pglob->gl_pathp = gl.gl_pathp;
+	pglob->gl_pathn = gl.gl_pathn;
+
+	return (rv);
+}
+
+/* globfree() function with legacy glob structure */
+void
+old_globfree(old_glob_t *pglob)
+{
+	glob_t gl;
+
+	(void) memset(&gl, 0, sizeof (gl));
+
+	/*
+	 * Copy all the members, old to new.  There's
+	 * really no point in micro-optimizing the copying.
+	 * Other members are set to zero.
+	 */
+	gl.gl_pathc = pglob->gl_pathc;
+	gl.gl_pathv = pglob->gl_pathv;
+	gl.gl_offs = pglob->gl_offs;
+	gl.gl_pathp = pglob->gl_pathp;
+	gl.gl_pathn = pglob->gl_pathn;
+
+	_globfree_ext(&gl);
+
+	/*
+	 * Copy all the members, new to old.  There's
+	 * really no point in micro-optimizing the copying.
+	 */
+	pglob->gl_pathc = gl.gl_pathc;
+	pglob->gl_pathv = gl.gl_pathv;
+	pglob->gl_offs = gl.gl_offs;
+	pglob->gl_pathp = gl.gl_pathp;
+	pglob->gl_pathn = gl.gl_pathn;
+
+}
+
+/* End */
--- old/usr/src/man/man3c/glob.3c	Mon Sep 30 20:00:48 2013
+++ new/usr/src/man/man3c/glob.3c	Mon Sep 30 20:00:47 2013
@@ -1,8 +1,42 @@
 '\" te
-.\" Copyright (c) 1992, X/Open Company Limited. All Rights Reserved.  Portions Copyright (c) 2003, Sun Microsystems, Inc.  All Rights Reserved.
+.\" Copyright (c) 1992, X/Open Company Limited. All Rights Reserved.
+.\" Portions Copyright (c) 2003, Sun Microsystems, Inc.  All Rights Reserved.
+.\" Portions Copyright (c) 2013, Gary Mills
 .\" Sun Microsystems, Inc. gratefully acknowledges The Open Group for permission to reproduce portions of its copyrighted documentation. Original documentation from The Open Group can be obtained online at
 .\" http://www.opengroup.org/bookstore/.
 .\" The Institute of Electrical and Electronics Engineers and The Open Group, have given us permission to reprint portions of their documentation. In the following statement, the phrase "this text" refers to portions of the system documentation. Portions of this text are reprinted and reproduced in electronic form in the Sun OS Reference Manual, from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between these versions and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html.
+.\"
+.\" $OpenBSD: glob.3,v 1.30 2012/01/20 07:09:42 tedu Exp $
+.\"
+.\" Copyright (c) 1989, 1991, 1993, 1994
+.\" The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Guido van Rossum.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
 .\"  This notice shall appear on any product containing this material.
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (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.
@@ -58,12 +92,12 @@
 .sp
 .in +2
 .nf
-size_t   gl_pathc;     /* count of paths matched by */
+size_t   gl_pathc;     /* Total count of paths matched by */
                        /* pattern */
-char     **gl_pathv;   /* pointer to list of matched */
-                       /* path names */
-size_t   gl_offs;      /* slots to reserve at beginning */
-                       /* of gl_pathv */
+char     **gl_pathv;   /* List of matched path names */
+size_t   gl_offs;      /* # of slots reserved in gl_pathv */
+int      gl_matchc;    /* Count of paths matching pattern. */
+int      gl_flags;     /* Copy of flags parameter to glob. */
 .fi
 .in -2
 
@@ -164,6 +198,116 @@
 .RE
 
 .sp
+.ne 2
+.na
+\fB\fBGLOB_ALTDIRFUNC\fR\fR
+.ad
+.RS 17n
+The following additional fields in the \fIpglob\fR structure
+have been initialized with alternate functions for
+\fBglob()\fR to use to open, read, and close directories and
+to get stat information on names found in those directories:
+.sp
+.nf
+void *(*gl_opendir)(const char *);
+struct dirent *(*gl_readdir)(void *);
+void (*gl_closedir)(void *);
+int (*gl_lstat)(const char *, struct stat *);
+int (*gl_stat)(const char *, struct stat *);
+.fi
+.sp
+This extension is provided to allow programs such as
+\fBufsrestore\fR(1M) to provide globbing from directories stored
+on tape.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBGLOB_BRACE\fR\fR
+.ad
+.RS 17n
+Pre-process the pattern string to expand `{pat,pat,...}'
+strings like \fBcsh\fR(1).  The pattern `{}' is left unexpanded
+for historical reasons.  (\fBcsh\fR(1) does the same thing
+to ease typing of \fBfind\fR(1) patterns.)
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBGLOB_MAGCHAR\fR\fR
+.ad
+.RS 17n
+Set by the \fBglob()\fR function if the pattern included globbing
+characters.  See the description of the usage of
+the \fBgl_matchc\fR structure member for more details.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBGLOB_NOMAGIC\fR\fR
+.ad
+.RS 17n
+Is the same as \fBGLOB_NOCHECK\fR but it only appends the
+pattern if it does not contain any of the special characters
+`*', `?', or `['.  \fBGLOB_NOMAGIC\fR is provided to
+simplify implementing the historic \fBcsh\fR(1) globbing behavior
+and should probably not be used anywhere else.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBGLOB_QUOTE\fR\fR
+.ad
+.RS 17n
+This option has no effect and is included for backwards
+compatibility with older sources.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBGLOB_TILDE\fR\fR
+.ad
+.RS 17n
+Expand patterns that start with `~' to user name home
+directories.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBGLOB_LIMIT\fR\fR
+.ad
+.RS 17n
+Limit the amount of memory used by matches to \fIARG_MAX\fR.
+This option should be set for programs that can be coerced
+to a denial of service attack via patterns that
+expand to a very large number of matches, such as a long
+string of `*/../*/..'.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBGLOB_KEEPSTAT\fR\fR
+.ad
+.RS 17n
+Retain a copy of the \fBstat\fR(2) information retrieved for
+matching paths in the gl_statv array:
+.sp
+.nf
+struct stat **gl_statv;
+.fi
+.sp
+This option may be used to avoid \fBlstat\fR(2) lookups in
+cases where they are expensive.
+.RE
+
+.sp
 .LP
 The \fBGLOB_APPEND\fR flag can be used to append a new set of path names to
 those found in a previous call to \fBglob()\fR. The following rules apply when
@@ -237,76 +381,124 @@
 (Other values may be used to report other errors not explicitly documented for
 those functions.)
 .RE
+
 .sp
 .LP
-The following constants are defined as error return values for \fBglob()\fR:
+If \fB(\fR\fI*errfunc\fR\fB)\fR is called and returns non-zero, or if the
+\fBGLOB_ERR\fR flag is set in \fIflags\fR, \fBglob()\fR stops the scan and
+returns \fBGLOB_ABORTED\fR after setting \fIgl_pathc\fR and \fIgl_pathv\fR in
+\fIpglob\fR to reflect the paths already scanned. If \fBGLOB_ERR\fR is not set
+and either \fIerrfunc\fR is a \fINULL\fR pointer or
+\fB(\fR\fI*errfunc\fR\fB)\fR returns 0, the error is ignored.
+.SH RETURN VALUES
 .sp
+.LP
+On successful completion, \fBglob()\fR returns zero.
+In addition the fields of pglob contain the values described below:
+
+.sp
 .ne 2
 .na
-\fB\fBGLOB_ABORTED\fR\fR
+\fB\fBgl_pathc\fR\fR
 .ad
 .RS 16n
-The scan was stopped because \fBGLOB_ERR\fR was set or
-\fB(\fR\fI*errfunc\fR\fB)\fR returned non-zero.
+Contains the total number of matched pathnames so far.
+This includes other matches from previous invocations of
+\fBglob()\fR if \fBGLOB_APPEND\fR was specified.
 .RE
 
 .sp
 .ne 2
 .na
-\fB\fBGLOB_NOMATCH\fR\fR
+\fB\fBgl_matchc\fR\fR
 .ad
 .RS 16n
-The pattern does not match any existing path name, and \fBGLOB_NOCHECK\fR was
-not set in flags.
+Contains the number of matched pathnames in the current
+invocation of \fBglob()\fR.
 .RE
 
 .sp
 .ne 2
 .na
-\fB\fBGLOG_NOSPACE\fR\fR
+\fB\fBgl_flags\fR\fR
 .ad
 .RS 16n
-An attempt to allocate memory failed.
+Contains a copy of the flags parameter with the bit
+\fBGLOB_MAGCHAR\fR set if pattern contained any of the special
+characters `*', `?', or `[', cleared if not.
 .RE
 
 .sp
-.LP
-If \fB(\fR\fI*errfunc\fR\fB)\fR is called and returns non-zero, or if the
-\fBGLOB_ERR\fR flag is set in \fIflags\fR, \fBglob()\fR stops the scan and
-returns \fBGLOB_ABORTED\fR after setting \fIgl_pathc\fR and \fIgl_pathv\fR in
-\fIpglob\fR to reflect the paths already scanned. If \fBGLOB_ERR\fR is not set
-and either \fIerrfunc\fR is a \fINULL\fR pointer or
-\fB(\fR\fI*errfunc\fR\fB)\fR returns 0, the error is ignored.
-.SH RETURN VALUES
+.ne 2
+.na
+\fB\fBgl_pathv\fR\fR
+.ad
+.RS 16n
+Contains a pointer to a null-terminated list of matched
+pathnames.  However, if \fBgl_pathc\fR is zero, the contents of
+\fBgl_pathv\fR are undefined.
+.RE
+
 .sp
+.ne 2
+.na
+\fB\fBgl_statv\fR\fR
+.ad
+.RS 16n
+If the \fBGLOB_KEEPSTAT\fR flag was set, \fBgl_statv\fR contains a
+pointer to a null-terminated list of matched \fBstat\fR(2)
+objects corresponding to the paths in \fBgl_pathc\fR.
+.RE
+
+.sp
 .LP
-The following values are returned by \fBglob()\fR:
+If \fBglob()\fR terminates due to an error, it sets \fBerrno\fR and
+returns one of the following non-zero constants. defined in <\fBglob.h\fR>:
+
 .sp
 .ne 2
 .na
-\fB\fB0\fR\fR
+\fB\fBGLOB_ABORTED\fR\fR
 .ad
-.RS 12n
-Successful completion. The argument \fIpglob\(mi>\fR\fBgl_pathc\fR returns the
-number of matched path names and the argument \fIpglob\(mi>\fR\fBgl_pathv\fR
-contains a pointer to a null-terminated list of matched and sorted path names.
-However, if \fIpglob\(mi>\fR\fBgl_pathc\fR is 0, the content of
-\fIpglob\(mi>\fR\fBgl_pathv\fR is undefined.
+.RS 16n
+The scan was stopped because \fBGLOB_ERR\fR was set or
+\fB(\fR\fI*errfunc\fR\fB)\fR returned non-zero.
 .RE
 
 .sp
 .ne 2
 .na
-\fB\fBnon-zero\fR\fR
+\fB\fBGLOB_NOMATCH\fR\fR
 .ad
-.RS 12n
-An error has occurred. Non-zero constants are defined in <\fBglob.h\fR>. The
-arguments \fIpglob\(mi>\fR\fBgl_pathc\fR and \fIpglob\(mi>\fR\fBgl_pathv\fR are
-still set as defined above.
+.RS 16n
+The pattern does not match any existing path name, and \fBGLOB_NOCHECK\fR was
+not set in flags.
 .RE
 
 .sp
+.ne 2
+.na
+\fB\fBGLOB_NOSPACE\fR\fR
+.ad
+.RS 16n
+An attempt to allocate memory failed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBGLOB_NOSYS\fR\fR
+.ad
+.RS 16n
+The requested function is not supported by this version of
+\fBglob()\fR.
+.RE
+
 .LP
+The arguments \fIpglob\(mi>\fR\fBgl_pathc\fR and \fIpglob\(mi>\fR\fBgl_pathv\fR are still set as
+specified above.
+.sp
+.LP
 The \fBglobfree()\fR function returns no value.
 .SH USAGE
 .sp
