xref: /freebsd/lib/libc/gen/glob-compat11.c (revision dc36d6f9bb1753f3808552f3afd30eda9a7b206a)
169921123SKonstantin Belousov /*
269921123SKonstantin Belousov  * Copyright (c) 1989, 1993
369921123SKonstantin Belousov  *	The Regents of the University of California.  All rights reserved.
469921123SKonstantin Belousov  *
569921123SKonstantin Belousov  * This code is derived from software contributed to Berkeley by
669921123SKonstantin Belousov  * Guido van Rossum.
769921123SKonstantin Belousov  *
869921123SKonstantin Belousov  * Copyright (c) 2011 The FreeBSD Foundation
969921123SKonstantin Belousov  * All rights reserved.
1069921123SKonstantin Belousov  * Portions of this software were developed by David Chisnall
1169921123SKonstantin Belousov  * under sponsorship from the FreeBSD Foundation.
1269921123SKonstantin Belousov  *
1369921123SKonstantin Belousov  * Redistribution and use in source and binary forms, with or without
1469921123SKonstantin Belousov  * modification, are permitted provided that the following conditions
1569921123SKonstantin Belousov  * are met:
1669921123SKonstantin Belousov  * 1. Redistributions of source code must retain the above copyright
1769921123SKonstantin Belousov  *    notice, this list of conditions and the following disclaimer.
1869921123SKonstantin Belousov  * 2. Redistributions in binary form must reproduce the above copyright
1969921123SKonstantin Belousov  *    notice, this list of conditions and the following disclaimer in the
2069921123SKonstantin Belousov  *    documentation and/or other materials provided with the distribution.
2169921123SKonstantin Belousov  * 3. Neither the name of the University nor the names of its contributors
2269921123SKonstantin Belousov  *    may be used to endorse or promote products derived from this software
2369921123SKonstantin Belousov  *    without specific prior written permission.
2469921123SKonstantin Belousov  *
2569921123SKonstantin Belousov  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2669921123SKonstantin Belousov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2769921123SKonstantin Belousov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2869921123SKonstantin Belousov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2969921123SKonstantin Belousov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3069921123SKonstantin Belousov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3169921123SKonstantin Belousov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3269921123SKonstantin Belousov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3369921123SKonstantin Belousov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3469921123SKonstantin Belousov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3569921123SKonstantin Belousov  * SUCH DAMAGE.
36c1920558SJohn Baldwin  * From: FreeBSD: head/lib/libc/gen/glob.c 317913 2017-05-07 19:52:56Z jilles
3769921123SKonstantin Belousov  */
3869921123SKonstantin Belousov 
3969921123SKonstantin Belousov #include <sys/param.h>
4069921123SKonstantin Belousov #define	_WANT_FREEBSD11_STAT
4169921123SKonstantin Belousov #include <sys/stat.h>
4269921123SKonstantin Belousov 
4369921123SKonstantin Belousov #include <ctype.h>
4469921123SKonstantin Belousov #define	_WANT_FREEBSD11_DIRENT
4569921123SKonstantin Belousov #include <dirent.h>
4669921123SKonstantin Belousov #include <errno.h>
4769921123SKonstantin Belousov #include <glob.h>
4869921123SKonstantin Belousov #include <limits.h>
4969921123SKonstantin Belousov #include <pwd.h>
5069921123SKonstantin Belousov #include <stdint.h>
5169921123SKonstantin Belousov #include <stdio.h>
5269921123SKonstantin Belousov #include <stdlib.h>
5369921123SKonstantin Belousov #include <string.h>
5469921123SKonstantin Belousov #include <unistd.h>
5569921123SKonstantin Belousov #include <wchar.h>
5669921123SKonstantin Belousov 
5769921123SKonstantin Belousov #include "collate.h"
5869921123SKonstantin Belousov #include "gen-compat.h"
5969921123SKonstantin Belousov #include "glob-compat11.h"
6069921123SKonstantin Belousov 
6169921123SKonstantin Belousov /*
6269921123SKonstantin Belousov  * glob(3) expansion limits. Stop the expansion if any of these limits
6369921123SKonstantin Belousov  * is reached. This caps the runtime in the face of DoS attacks. See
6469921123SKonstantin Belousov  * also CVE-2010-2632
6569921123SKonstantin Belousov  */
6669921123SKonstantin Belousov #define	GLOB_LIMIT_BRACE	128	/* number of brace calls */
6769921123SKonstantin Belousov #define	GLOB_LIMIT_PATH		65536	/* number of path elements */
6869921123SKonstantin Belousov #define	GLOB_LIMIT_READDIR	16384	/* number of readdirs */
6969921123SKonstantin Belousov #define	GLOB_LIMIT_STAT		1024	/* number of stat system calls */
7069921123SKonstantin Belousov #define	GLOB_LIMIT_STRING	ARG_MAX	/* maximum total size for paths */
7169921123SKonstantin Belousov 
7269921123SKonstantin Belousov struct glob_limit {
7369921123SKonstantin Belousov 	size_t	l_brace_cnt;
7469921123SKonstantin Belousov 	size_t	l_path_lim;
7569921123SKonstantin Belousov 	size_t	l_readdir_cnt;
7669921123SKonstantin Belousov 	size_t	l_stat_cnt;
7769921123SKonstantin Belousov 	size_t	l_string_cnt;
7869921123SKonstantin Belousov };
7969921123SKonstantin Belousov 
8069921123SKonstantin Belousov #define	DOT		L'.'
8169921123SKonstantin Belousov #define	EOS		L'\0'
8269921123SKonstantin Belousov #define	LBRACKET	L'['
8369921123SKonstantin Belousov #define	NOT		L'!'
8469921123SKonstantin Belousov #define	QUESTION	L'?'
8569921123SKonstantin Belousov #define	QUOTE		L'\\'
8669921123SKonstantin Belousov #define	RANGE		L'-'
8769921123SKonstantin Belousov #define	RBRACKET	L']'
8869921123SKonstantin Belousov #define	SEP		L'/'
8969921123SKonstantin Belousov #define	STAR		L'*'
9069921123SKonstantin Belousov #define	TILDE		L'~'
9169921123SKonstantin Belousov #define	LBRACE		L'{'
9269921123SKonstantin Belousov #define	RBRACE		L'}'
9369921123SKonstantin Belousov #define	COMMA		L','
9469921123SKonstantin Belousov 
9569921123SKonstantin Belousov #define	M_QUOTE		0x8000000000ULL
9669921123SKonstantin Belousov #define	M_PROTECT	0x4000000000ULL
9769921123SKonstantin Belousov #define	M_MASK		0xffffffffffULL
9869921123SKonstantin Belousov #define	M_CHAR		0x00ffffffffULL
9969921123SKonstantin Belousov 
10069921123SKonstantin Belousov typedef uint_fast64_t Char;
10169921123SKonstantin Belousov 
10269921123SKonstantin Belousov #define	CHAR(c)		((Char)((c)&M_CHAR))
10369921123SKonstantin Belousov #define	META(c)		((Char)((c)|M_QUOTE))
10469921123SKonstantin Belousov #define	UNPROT(c)	((c) & ~M_PROTECT)
10569921123SKonstantin Belousov #define	M_ALL		META(L'*')
10669921123SKonstantin Belousov #define	M_END		META(L']')
10769921123SKonstantin Belousov #define	M_NOT		META(L'!')
10869921123SKonstantin Belousov #define	M_ONE		META(L'?')
10969921123SKonstantin Belousov #define	M_RNG		META(L'-')
11069921123SKonstantin Belousov #define	M_SET		META(L'[')
11169921123SKonstantin Belousov #define	ismeta(c)	(((c)&M_QUOTE) != 0)
11269921123SKonstantin Belousov #ifdef DEBUG
11369921123SKonstantin Belousov #define	isprot(c)	(((c)&M_PROTECT) != 0)
11469921123SKonstantin Belousov #endif
11569921123SKonstantin Belousov 
11669921123SKonstantin Belousov static int	 compare(const void *, const void *);
11769921123SKonstantin Belousov static int	 g_Ctoc(const Char *, char *, size_t);
11869921123SKonstantin Belousov static int	 g_lstat(Char *, struct freebsd11_stat *, glob11_t *);
11969921123SKonstantin Belousov static DIR	*g_opendir(Char *, glob11_t *);
12069921123SKonstantin Belousov static const Char *g_strchr(const Char *, wchar_t);
12169921123SKonstantin Belousov #ifdef notdef
12269921123SKonstantin Belousov static Char	*g_strcat(Char *, const Char *);
12369921123SKonstantin Belousov #endif
12469921123SKonstantin Belousov static int	 g_stat(Char *, struct freebsd11_stat *, glob11_t *);
12569921123SKonstantin Belousov static int	 glob0(const Char *, glob11_t *, struct glob_limit *,
12669921123SKonstantin Belousov     const char *);
12769921123SKonstantin Belousov static int	 glob1(Char *, glob11_t *, struct glob_limit *);
12869921123SKonstantin Belousov static int	 glob2(Char *, Char *, Char *, Char *, glob11_t *,
12969921123SKonstantin Belousov     struct glob_limit *);
13069921123SKonstantin Belousov static int	 glob3(Char *, Char *, Char *, Char *, Char *, glob11_t *,
13169921123SKonstantin Belousov     struct glob_limit *);
13269921123SKonstantin Belousov static int	 globextend(const Char *, glob11_t *, struct glob_limit *,
13369921123SKonstantin Belousov     const char *);
13469921123SKonstantin Belousov static const Char *
13569921123SKonstantin Belousov 		 globtilde(const Char *, Char *, size_t, glob11_t *);
13669921123SKonstantin Belousov static int	 globexp0(const Char *, glob11_t *, struct glob_limit *,
13769921123SKonstantin Belousov     const char *);
13869921123SKonstantin Belousov static int	 globexp1(const Char *, glob11_t *, struct glob_limit *);
13969921123SKonstantin Belousov static int	 globexp2(const Char *, const Char *, glob11_t *,
14069921123SKonstantin Belousov     struct glob_limit *);
14169921123SKonstantin Belousov static int	 globfinal(glob11_t *, struct glob_limit *, size_t,
14269921123SKonstantin Belousov     const char *);
14369921123SKonstantin Belousov static int	 match(Char *, Char *, Char *);
14469921123SKonstantin Belousov static int	 err_nomatch(glob11_t *, struct glob_limit *, const char *);
14569921123SKonstantin Belousov static int	 err_aborted(glob11_t *, int, char *);
14669921123SKonstantin Belousov #ifdef DEBUG
14769921123SKonstantin Belousov static void	 qprintf(const char *, Char *);
14869921123SKonstantin Belousov #endif
14969921123SKonstantin Belousov 
15069921123SKonstantin Belousov int
freebsd11_glob(const char * __restrict pattern,int flags,int (* errfunc)(const char *,int),glob11_t * __restrict pglob)15169921123SKonstantin Belousov freebsd11_glob(const char * __restrict pattern, int flags,
15269921123SKonstantin Belousov 	 int (*errfunc)(const char *, int), glob11_t * __restrict pglob)
15369921123SKonstantin Belousov {
15469921123SKonstantin Belousov 	struct glob_limit limit = { 0, 0, 0, 0, 0 };
15569921123SKonstantin Belousov 	const char *patnext;
15669921123SKonstantin Belousov 	Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot;
15769921123SKonstantin Belousov 	mbstate_t mbs;
15869921123SKonstantin Belousov 	wchar_t wc;
15969921123SKonstantin Belousov 	size_t clen;
16069921123SKonstantin Belousov 	int too_long;
16169921123SKonstantin Belousov 
16269921123SKonstantin Belousov 	patnext = pattern;
16369921123SKonstantin Belousov 	if (!(flags & GLOB_APPEND)) {
16469921123SKonstantin Belousov 		pglob->gl_pathc = 0;
16569921123SKonstantin Belousov 		pglob->gl_pathv = NULL;
16669921123SKonstantin Belousov 		if (!(flags & GLOB_DOOFFS))
16769921123SKonstantin Belousov 			pglob->gl_offs = 0;
16869921123SKonstantin Belousov 	}
16969921123SKonstantin Belousov 	if (flags & GLOB_LIMIT) {
17069921123SKonstantin Belousov 		limit.l_path_lim = pglob->gl_matchc;
17169921123SKonstantin Belousov 		if (limit.l_path_lim == 0)
17269921123SKonstantin Belousov 			limit.l_path_lim = GLOB_LIMIT_PATH;
17369921123SKonstantin Belousov 	}
17469921123SKonstantin Belousov 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
17569921123SKonstantin Belousov 	pglob->gl_errfunc = errfunc;
17669921123SKonstantin Belousov 	pglob->gl_matchc = 0;
17769921123SKonstantin Belousov 
17869921123SKonstantin Belousov 	bufnext = patbuf;
17969921123SKonstantin Belousov 	bufend = bufnext + MAXPATHLEN - 1;
18069921123SKonstantin Belousov 	too_long = 1;
18169921123SKonstantin Belousov 	if (flags & GLOB_NOESCAPE) {
18269921123SKonstantin Belousov 		memset(&mbs, 0, sizeof(mbs));
18369921123SKonstantin Belousov 		while (bufnext <= bufend) {
18469921123SKonstantin Belousov 			clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
18569921123SKonstantin Belousov 			if (clen == (size_t)-1 || clen == (size_t)-2)
18669921123SKonstantin Belousov 				return (err_nomatch(pglob, &limit, pattern));
18769921123SKonstantin Belousov 			else if (clen == 0) {
18869921123SKonstantin Belousov 				too_long = 0;
18969921123SKonstantin Belousov 				break;
19069921123SKonstantin Belousov 			}
19169921123SKonstantin Belousov 			*bufnext++ = wc;
19269921123SKonstantin Belousov 			patnext += clen;
19369921123SKonstantin Belousov 		}
19469921123SKonstantin Belousov 	} else {
19569921123SKonstantin Belousov 		/* Protect the quoted characters. */
19669921123SKonstantin Belousov 		memset(&mbs, 0, sizeof(mbs));
19769921123SKonstantin Belousov 		while (bufnext <= bufend) {
19869921123SKonstantin Belousov 			if (*patnext == '\\') {
19969921123SKonstantin Belousov 				if (*++patnext == '\0') {
20069921123SKonstantin Belousov 					*bufnext++ = QUOTE;
20169921123SKonstantin Belousov 					continue;
20269921123SKonstantin Belousov 				}
20369921123SKonstantin Belousov 				prot = M_PROTECT;
20469921123SKonstantin Belousov 			} else
20569921123SKonstantin Belousov 				prot = 0;
20669921123SKonstantin Belousov 			clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
20769921123SKonstantin Belousov 			if (clen == (size_t)-1 || clen == (size_t)-2)
20869921123SKonstantin Belousov 				return (err_nomatch(pglob, &limit, pattern));
20969921123SKonstantin Belousov 			else if (clen == 0) {
21069921123SKonstantin Belousov 				too_long = 0;
21169921123SKonstantin Belousov 				break;
21269921123SKonstantin Belousov 			}
21369921123SKonstantin Belousov 			*bufnext++ = wc | prot;
21469921123SKonstantin Belousov 			patnext += clen;
21569921123SKonstantin Belousov 		}
21669921123SKonstantin Belousov 	}
21769921123SKonstantin Belousov 	if (too_long)
21869921123SKonstantin Belousov 		return (err_nomatch(pglob, &limit, pattern));
21969921123SKonstantin Belousov 	*bufnext = EOS;
22069921123SKonstantin Belousov 
22169921123SKonstantin Belousov 	if (flags & GLOB_BRACE)
22269921123SKonstantin Belousov 	    return (globexp0(patbuf, pglob, &limit, pattern));
22369921123SKonstantin Belousov 	else
22469921123SKonstantin Belousov 	    return (glob0(patbuf, pglob, &limit, pattern));
22569921123SKonstantin Belousov }
22669921123SKonstantin Belousov 
22769921123SKonstantin Belousov static int
globexp0(const Char * pattern,glob11_t * pglob,struct glob_limit * limit,const char * origpat)22869921123SKonstantin Belousov globexp0(const Char *pattern, glob11_t *pglob, struct glob_limit *limit,
22969921123SKonstantin Belousov     const char *origpat) {
23069921123SKonstantin Belousov 	int rv;
23169921123SKonstantin Belousov 	size_t oldpathc;
23269921123SKonstantin Belousov 
23369921123SKonstantin Belousov 	/* Protect a single {}, for find(1), like csh */
23469921123SKonstantin Belousov 	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) {
23569921123SKonstantin Belousov 		if ((pglob->gl_flags & GLOB_LIMIT) &&
23669921123SKonstantin Belousov 		    limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
23769921123SKonstantin Belousov 			errno = E2BIG;
23869921123SKonstantin Belousov 			return (GLOB_NOSPACE);
23969921123SKonstantin Belousov 		}
24069921123SKonstantin Belousov 		return (glob0(pattern, pglob, limit, origpat));
24169921123SKonstantin Belousov 	}
24269921123SKonstantin Belousov 
24369921123SKonstantin Belousov 	oldpathc = pglob->gl_pathc;
24469921123SKonstantin Belousov 
24569921123SKonstantin Belousov 	if ((rv = globexp1(pattern, pglob, limit)) != 0)
24669921123SKonstantin Belousov 		return rv;
24769921123SKonstantin Belousov 
24869921123SKonstantin Belousov 	return (globfinal(pglob, limit, oldpathc, origpat));
24969921123SKonstantin Belousov }
25069921123SKonstantin Belousov 
25169921123SKonstantin Belousov /*
25269921123SKonstantin Belousov  * Expand recursively a glob {} pattern. When there is no more expansion
25369921123SKonstantin Belousov  * invoke the standard globbing routine to glob the rest of the magic
25469921123SKonstantin Belousov  * characters
25569921123SKonstantin Belousov  */
25669921123SKonstantin Belousov static int
globexp1(const Char * pattern,glob11_t * pglob,struct glob_limit * limit)25769921123SKonstantin Belousov globexp1(const Char *pattern, glob11_t *pglob, struct glob_limit *limit)
25869921123SKonstantin Belousov {
25969921123SKonstantin Belousov 	const Char* ptr;
26069921123SKonstantin Belousov 
26169921123SKonstantin Belousov 	if ((ptr = g_strchr(pattern, LBRACE)) != NULL) {
26269921123SKonstantin Belousov 		if ((pglob->gl_flags & GLOB_LIMIT) &&
26369921123SKonstantin Belousov 		    limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
26469921123SKonstantin Belousov 			errno = E2BIG;
26569921123SKonstantin Belousov 			return (GLOB_NOSPACE);
26669921123SKonstantin Belousov 		}
26769921123SKonstantin Belousov 		return (globexp2(ptr, pattern, pglob, limit));
26869921123SKonstantin Belousov 	}
26969921123SKonstantin Belousov 
27069921123SKonstantin Belousov 	return (glob0(pattern, pglob, limit, NULL));
27169921123SKonstantin Belousov }
27269921123SKonstantin Belousov 
27369921123SKonstantin Belousov 
27469921123SKonstantin Belousov /*
27569921123SKonstantin Belousov  * Recursive brace globbing helper. Tries to expand a single brace.
27669921123SKonstantin Belousov  * If it succeeds then it invokes globexp1 with the new pattern.
27769921123SKonstantin Belousov  * If it fails then it tries to glob the rest of the pattern and returns.
27869921123SKonstantin Belousov  */
27969921123SKonstantin Belousov static int
globexp2(const Char * ptr,const Char * pattern,glob11_t * pglob,struct glob_limit * limit)28069921123SKonstantin Belousov globexp2(const Char *ptr, const Char *pattern, glob11_t *pglob,
28169921123SKonstantin Belousov     struct glob_limit *limit)
28269921123SKonstantin Belousov {
28369921123SKonstantin Belousov 	int     i, rv;
28469921123SKonstantin Belousov 	Char   *lm, *ls;
28569921123SKonstantin Belousov 	const Char *pe, *pm, *pm1, *pl;
28669921123SKonstantin Belousov 	Char    patbuf[MAXPATHLEN];
28769921123SKonstantin Belousov 
28869921123SKonstantin Belousov 	/* copy part up to the brace */
28969921123SKonstantin Belousov 	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
29069921123SKonstantin Belousov 		continue;
29169921123SKonstantin Belousov 	*lm = EOS;
29269921123SKonstantin Belousov 	ls = lm;
29369921123SKonstantin Belousov 
29469921123SKonstantin Belousov 	/* Find the balanced brace */
29569921123SKonstantin Belousov 	for (i = 0, pe = ++ptr; *pe != EOS; pe++)
29669921123SKonstantin Belousov 		if (*pe == LBRACKET) {
29769921123SKonstantin Belousov 			/* Ignore everything between [] */
29869921123SKonstantin Belousov 			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
29969921123SKonstantin Belousov 				continue;
30069921123SKonstantin Belousov 			if (*pe == EOS) {
30169921123SKonstantin Belousov 				/*
30269921123SKonstantin Belousov 				 * We could not find a matching RBRACKET.
30369921123SKonstantin Belousov 				 * Ignore and just look for RBRACE
30469921123SKonstantin Belousov 				 */
30569921123SKonstantin Belousov 				pe = pm;
30669921123SKonstantin Belousov 			}
30769921123SKonstantin Belousov 		}
30869921123SKonstantin Belousov 		else if (*pe == LBRACE)
30969921123SKonstantin Belousov 			i++;
31069921123SKonstantin Belousov 		else if (*pe == RBRACE) {
31169921123SKonstantin Belousov 			if (i == 0)
31269921123SKonstantin Belousov 				break;
31369921123SKonstantin Belousov 			i--;
31469921123SKonstantin Belousov 		}
31569921123SKonstantin Belousov 
31669921123SKonstantin Belousov 	/* Non matching braces; just glob the pattern */
31769921123SKonstantin Belousov 	if (i != 0 || *pe == EOS)
31869921123SKonstantin Belousov 		return (glob0(pattern, pglob, limit, NULL));
31969921123SKonstantin Belousov 
32069921123SKonstantin Belousov 	for (i = 0, pl = pm = ptr; pm <= pe; pm++)
32169921123SKonstantin Belousov 		switch (*pm) {
32269921123SKonstantin Belousov 		case LBRACKET:
32369921123SKonstantin Belousov 			/* Ignore everything between [] */
32469921123SKonstantin Belousov 			for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++)
32569921123SKonstantin Belousov 				continue;
32669921123SKonstantin Belousov 			if (*pm == EOS) {
32769921123SKonstantin Belousov 				/*
32869921123SKonstantin Belousov 				 * We could not find a matching RBRACKET.
32969921123SKonstantin Belousov 				 * Ignore and just look for RBRACE
33069921123SKonstantin Belousov 				 */
33169921123SKonstantin Belousov 				pm = pm1;
33269921123SKonstantin Belousov 			}
33369921123SKonstantin Belousov 			break;
33469921123SKonstantin Belousov 
33569921123SKonstantin Belousov 		case LBRACE:
33669921123SKonstantin Belousov 			i++;
33769921123SKonstantin Belousov 			break;
33869921123SKonstantin Belousov 
33969921123SKonstantin Belousov 		case RBRACE:
34069921123SKonstantin Belousov 			if (i) {
34169921123SKonstantin Belousov 			    i--;
34269921123SKonstantin Belousov 			    break;
34369921123SKonstantin Belousov 			}
34469921123SKonstantin Belousov 			/* FALLTHROUGH */
34569921123SKonstantin Belousov 		case COMMA:
34669921123SKonstantin Belousov 			if (i && *pm == COMMA)
34769921123SKonstantin Belousov 				break;
34869921123SKonstantin Belousov 			else {
34969921123SKonstantin Belousov 				/* Append the current string */
35069921123SKonstantin Belousov 				for (lm = ls; (pl < pm); *lm++ = *pl++)
35169921123SKonstantin Belousov 					continue;
35269921123SKonstantin Belousov 				/*
35369921123SKonstantin Belousov 				 * Append the rest of the pattern after the
35469921123SKonstantin Belousov 				 * closing brace
35569921123SKonstantin Belousov 				 */
35669921123SKonstantin Belousov 				for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
35769921123SKonstantin Belousov 					continue;
35869921123SKonstantin Belousov 
35969921123SKonstantin Belousov 				/* Expand the current pattern */
36069921123SKonstantin Belousov #ifdef DEBUG
36169921123SKonstantin Belousov 				qprintf("globexp2:", patbuf);
36269921123SKonstantin Belousov #endif
36369921123SKonstantin Belousov 				rv = globexp1(patbuf, pglob, limit);
36469921123SKonstantin Belousov 				if (rv)
36569921123SKonstantin Belousov 					return (rv);
36669921123SKonstantin Belousov 
36769921123SKonstantin Belousov 				/* move after the comma, to the next string */
36869921123SKonstantin Belousov 				pl = pm + 1;
36969921123SKonstantin Belousov 			}
37069921123SKonstantin Belousov 			break;
37169921123SKonstantin Belousov 
37269921123SKonstantin Belousov 		default:
37369921123SKonstantin Belousov 			break;
37469921123SKonstantin Belousov 		}
37569921123SKonstantin Belousov 	return (0);
37669921123SKonstantin Belousov }
37769921123SKonstantin Belousov 
37869921123SKonstantin Belousov 
37969921123SKonstantin Belousov 
38069921123SKonstantin Belousov /*
38169921123SKonstantin Belousov  * expand tilde from the passwd file.
38269921123SKonstantin Belousov  */
38369921123SKonstantin Belousov static const Char *
globtilde(const Char * pattern,Char * patbuf,size_t patbuf_len,glob11_t * pglob)38469921123SKonstantin Belousov globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob11_t *pglob)
38569921123SKonstantin Belousov {
38669921123SKonstantin Belousov 	struct passwd *pwd;
38769921123SKonstantin Belousov 	char *h, *sc;
38869921123SKonstantin Belousov 	const Char *p;
38969921123SKonstantin Belousov 	Char *b, *eb;
39069921123SKonstantin Belousov 	wchar_t wc;
39169921123SKonstantin Belousov 	wchar_t wbuf[MAXPATHLEN];
39269921123SKonstantin Belousov 	wchar_t *wbufend, *dc;
39369921123SKonstantin Belousov 	size_t clen;
39469921123SKonstantin Belousov 	mbstate_t mbs;
39569921123SKonstantin Belousov 	int too_long;
39669921123SKonstantin Belousov 
39769921123SKonstantin Belousov 	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
39869921123SKonstantin Belousov 		return (pattern);
39969921123SKonstantin Belousov 
40069921123SKonstantin Belousov 	/*
40169921123SKonstantin Belousov 	 * Copy up to the end of the string or /
40269921123SKonstantin Belousov 	 */
40369921123SKonstantin Belousov 	eb = &patbuf[patbuf_len - 1];
40469921123SKonstantin Belousov 	for (p = pattern + 1, b = patbuf;
40569921123SKonstantin Belousov 	    b < eb && *p != EOS && UNPROT(*p) != SEP; *b++ = *p++)
40669921123SKonstantin Belousov 		continue;
40769921123SKonstantin Belousov 
40869921123SKonstantin Belousov 	if (*p != EOS && UNPROT(*p) != SEP)
40969921123SKonstantin Belousov 		return (NULL);
41069921123SKonstantin Belousov 
41169921123SKonstantin Belousov 	*b = EOS;
41269921123SKonstantin Belousov 	h = NULL;
41369921123SKonstantin Belousov 
41469921123SKonstantin Belousov 	if (patbuf[0] == EOS) {
41569921123SKonstantin Belousov 		/*
41669921123SKonstantin Belousov 		 * handle a plain ~ or ~/ by expanding $HOME first (iff
41769921123SKonstantin Belousov 		 * we're not running setuid or setgid) and then trying
41869921123SKonstantin Belousov 		 * the password file
41969921123SKonstantin Belousov 		 */
420*68ca8363SMark Johnston 		if ((h = secure_getenv("HOME")) == NULL) {
42169921123SKonstantin Belousov 			if (((h = getlogin()) != NULL &&
42269921123SKonstantin Belousov 			     (pwd = getpwnam(h)) != NULL) ||
42369921123SKonstantin Belousov 			    (pwd = getpwuid(getuid())) != NULL)
42469921123SKonstantin Belousov 				h = pwd->pw_dir;
42569921123SKonstantin Belousov 			else
42669921123SKonstantin Belousov 				return (pattern);
42769921123SKonstantin Belousov 		}
42869921123SKonstantin Belousov 	}
42969921123SKonstantin Belousov 	else {
43069921123SKonstantin Belousov 		/*
43169921123SKonstantin Belousov 		 * Expand a ~user
43269921123SKonstantin Belousov 		 */
43369921123SKonstantin Belousov 		if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf)))
43469921123SKonstantin Belousov 			return (NULL);
43569921123SKonstantin Belousov 		if ((pwd = getpwnam((char *)wbuf)) == NULL)
43669921123SKonstantin Belousov 			return (pattern);
43769921123SKonstantin Belousov 		else
43869921123SKonstantin Belousov 			h = pwd->pw_dir;
43969921123SKonstantin Belousov 	}
44069921123SKonstantin Belousov 
44169921123SKonstantin Belousov 	/* Copy the home directory */
44269921123SKonstantin Belousov 	dc = wbuf;
44369921123SKonstantin Belousov 	sc = h;
44469921123SKonstantin Belousov 	wbufend = wbuf + MAXPATHLEN - 1;
44569921123SKonstantin Belousov 	too_long = 1;
44669921123SKonstantin Belousov 	memset(&mbs, 0, sizeof(mbs));
44769921123SKonstantin Belousov 	while (dc <= wbufend) {
44869921123SKonstantin Belousov 		clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
44969921123SKonstantin Belousov 		if (clen == (size_t)-1 || clen == (size_t)-2) {
45069921123SKonstantin Belousov 			/* XXX See initial comment #2. */
45169921123SKonstantin Belousov 			wc = (unsigned char)*sc;
45269921123SKonstantin Belousov 			clen = 1;
45369921123SKonstantin Belousov 			memset(&mbs, 0, sizeof(mbs));
45469921123SKonstantin Belousov 		}
45569921123SKonstantin Belousov 		if ((*dc++ = wc) == EOS) {
45669921123SKonstantin Belousov 			too_long = 0;
45769921123SKonstantin Belousov 			break;
45869921123SKonstantin Belousov 		}
45969921123SKonstantin Belousov 		sc += clen;
46069921123SKonstantin Belousov 	}
46169921123SKonstantin Belousov 	if (too_long)
46269921123SKonstantin Belousov 		return (NULL);
46369921123SKonstantin Belousov 
46469921123SKonstantin Belousov 	dc = wbuf;
46569921123SKonstantin Belousov 	for (b = patbuf; b < eb && *dc != EOS; *b++ = *dc++ | M_PROTECT)
46669921123SKonstantin Belousov 		continue;
46769921123SKonstantin Belousov 	if (*dc != EOS)
46869921123SKonstantin Belousov 		return (NULL);
46969921123SKonstantin Belousov 
47069921123SKonstantin Belousov 	/* Append the rest of the pattern */
47169921123SKonstantin Belousov 	if (*p != EOS) {
47269921123SKonstantin Belousov 		too_long = 1;
47369921123SKonstantin Belousov 		while (b <= eb) {
47469921123SKonstantin Belousov 			if ((*b++ = *p++) == EOS) {
47569921123SKonstantin Belousov 				too_long = 0;
47669921123SKonstantin Belousov 				break;
47769921123SKonstantin Belousov 			}
47869921123SKonstantin Belousov 		}
47969921123SKonstantin Belousov 		if (too_long)
48069921123SKonstantin Belousov 			return (NULL);
48169921123SKonstantin Belousov 	} else
48269921123SKonstantin Belousov 		*b = EOS;
48369921123SKonstantin Belousov 
48469921123SKonstantin Belousov 	return (patbuf);
48569921123SKonstantin Belousov }
48669921123SKonstantin Belousov 
48769921123SKonstantin Belousov 
48869921123SKonstantin Belousov /*
48969921123SKonstantin Belousov  * The main glob() routine: compiles the pattern (optionally processing
49069921123SKonstantin Belousov  * quotes), calls glob1() to do the real pattern matching, and finally
49169921123SKonstantin Belousov  * sorts the list (unless unsorted operation is requested).  Returns 0
49269921123SKonstantin Belousov  * if things went well, nonzero if errors occurred.
49369921123SKonstantin Belousov  */
49469921123SKonstantin Belousov static int
glob0(const Char * pattern,glob11_t * pglob,struct glob_limit * limit,const char * origpat)49569921123SKonstantin Belousov glob0(const Char *pattern, glob11_t *pglob, struct glob_limit *limit,
49669921123SKonstantin Belousov     const char *origpat) {
49769921123SKonstantin Belousov 	const Char *qpatnext;
49869921123SKonstantin Belousov 	int err;
49969921123SKonstantin Belousov 	size_t oldpathc;
50069921123SKonstantin Belousov 	Char *bufnext, c, patbuf[MAXPATHLEN];
50169921123SKonstantin Belousov 
50269921123SKonstantin Belousov 	qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
50369921123SKonstantin Belousov 	if (qpatnext == NULL) {
50469921123SKonstantin Belousov 		errno = E2BIG;
50569921123SKonstantin Belousov 		return (GLOB_NOSPACE);
50669921123SKonstantin Belousov 	}
50769921123SKonstantin Belousov 	oldpathc = pglob->gl_pathc;
50869921123SKonstantin Belousov 	bufnext = patbuf;
50969921123SKonstantin Belousov 
51069921123SKonstantin Belousov 	/* We don't need to check for buffer overflow any more. */
51169921123SKonstantin Belousov 	while ((c = *qpatnext++) != EOS) {
51269921123SKonstantin Belousov 		switch (c) {
51369921123SKonstantin Belousov 		case LBRACKET:
51469921123SKonstantin Belousov 			c = *qpatnext;
51569921123SKonstantin Belousov 			if (c == NOT)
51669921123SKonstantin Belousov 				++qpatnext;
51769921123SKonstantin Belousov 			if (*qpatnext == EOS ||
51869921123SKonstantin Belousov 			    g_strchr(qpatnext+1, RBRACKET) == NULL) {
51969921123SKonstantin Belousov 				*bufnext++ = LBRACKET;
52069921123SKonstantin Belousov 				if (c == NOT)
52169921123SKonstantin Belousov 					--qpatnext;
52269921123SKonstantin Belousov 				break;
52369921123SKonstantin Belousov 			}
52469921123SKonstantin Belousov 			*bufnext++ = M_SET;
52569921123SKonstantin Belousov 			if (c == NOT)
52669921123SKonstantin Belousov 				*bufnext++ = M_NOT;
52769921123SKonstantin Belousov 			c = *qpatnext++;
52869921123SKonstantin Belousov 			do {
52969921123SKonstantin Belousov 				*bufnext++ = CHAR(c);
53069921123SKonstantin Belousov 				if (*qpatnext == RANGE &&
53169921123SKonstantin Belousov 				    (c = qpatnext[1]) != RBRACKET) {
53269921123SKonstantin Belousov 					*bufnext++ = M_RNG;
53369921123SKonstantin Belousov 					*bufnext++ = CHAR(c);
53469921123SKonstantin Belousov 					qpatnext += 2;
53569921123SKonstantin Belousov 				}
53669921123SKonstantin Belousov 			} while ((c = *qpatnext++) != RBRACKET);
53769921123SKonstantin Belousov 			pglob->gl_flags |= GLOB_MAGCHAR;
53869921123SKonstantin Belousov 			*bufnext++ = M_END;
53969921123SKonstantin Belousov 			break;
54069921123SKonstantin Belousov 		case QUESTION:
54169921123SKonstantin Belousov 			pglob->gl_flags |= GLOB_MAGCHAR;
54269921123SKonstantin Belousov 			*bufnext++ = M_ONE;
54369921123SKonstantin Belousov 			break;
54469921123SKonstantin Belousov 		case STAR:
54569921123SKonstantin Belousov 			pglob->gl_flags |= GLOB_MAGCHAR;
54669921123SKonstantin Belousov 			/* collapse adjacent stars to one,
54769921123SKonstantin Belousov 			 * to avoid exponential behavior
54869921123SKonstantin Belousov 			 */
54969921123SKonstantin Belousov 			if (bufnext == patbuf || bufnext[-1] != M_ALL)
55069921123SKonstantin Belousov 			    *bufnext++ = M_ALL;
55169921123SKonstantin Belousov 			break;
55269921123SKonstantin Belousov 		default:
55369921123SKonstantin Belousov 			*bufnext++ = CHAR(c);
55469921123SKonstantin Belousov 			break;
55569921123SKonstantin Belousov 		}
55669921123SKonstantin Belousov 	}
55769921123SKonstantin Belousov 	*bufnext = EOS;
55869921123SKonstantin Belousov #ifdef DEBUG
55969921123SKonstantin Belousov 	qprintf("glob0:", patbuf);
56069921123SKonstantin Belousov #endif
56169921123SKonstantin Belousov 
56269921123SKonstantin Belousov 	if ((err = glob1(patbuf, pglob, limit)) != 0)
56369921123SKonstantin Belousov 		return(err);
56469921123SKonstantin Belousov 
56569921123SKonstantin Belousov 	if (origpat != NULL)
56669921123SKonstantin Belousov 		return (globfinal(pglob, limit, oldpathc, origpat));
56769921123SKonstantin Belousov 
56869921123SKonstantin Belousov 	return (0);
56969921123SKonstantin Belousov }
57069921123SKonstantin Belousov 
57169921123SKonstantin Belousov static int
globfinal(glob11_t * pglob,struct glob_limit * limit,size_t oldpathc,const char * origpat)57269921123SKonstantin Belousov globfinal(glob11_t *pglob, struct glob_limit *limit, size_t oldpathc,
57369921123SKonstantin Belousov     const char *origpat) {
57469921123SKonstantin Belousov 	if (pglob->gl_pathc == oldpathc)
57569921123SKonstantin Belousov 		return (err_nomatch(pglob, limit, origpat));
57669921123SKonstantin Belousov 
57769921123SKonstantin Belousov 	if (!(pglob->gl_flags & GLOB_NOSORT))
57869921123SKonstantin Belousov 		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
57969921123SKonstantin Belousov 		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
58069921123SKonstantin Belousov 
58169921123SKonstantin Belousov 	return (0);
58269921123SKonstantin Belousov }
58369921123SKonstantin Belousov 
58469921123SKonstantin Belousov static int
compare(const void * p,const void * q)58569921123SKonstantin Belousov compare(const void *p, const void *q)
58669921123SKonstantin Belousov {
58769921123SKonstantin Belousov 	return (strcoll(*(char **)p, *(char **)q));
58869921123SKonstantin Belousov }
58969921123SKonstantin Belousov 
59069921123SKonstantin Belousov static int
glob1(Char * pattern,glob11_t * pglob,struct glob_limit * limit)59169921123SKonstantin Belousov glob1(Char *pattern, glob11_t *pglob, struct glob_limit *limit)
59269921123SKonstantin Belousov {
59369921123SKonstantin Belousov 	Char pathbuf[MAXPATHLEN];
59469921123SKonstantin Belousov 
59569921123SKonstantin Belousov 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
59669921123SKonstantin Belousov 	if (*pattern == EOS)
59769921123SKonstantin Belousov 		return (0);
59869921123SKonstantin Belousov 	return (glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
59969921123SKonstantin Belousov 	    pattern, pglob, limit));
60069921123SKonstantin Belousov }
60169921123SKonstantin Belousov 
60269921123SKonstantin Belousov /*
60369921123SKonstantin Belousov  * The functions glob2 and glob3 are mutually recursive; there is one level
60469921123SKonstantin Belousov  * of recursion for each segment in the pattern that contains one or more
60569921123SKonstantin Belousov  * meta characters.
60669921123SKonstantin Belousov  */
60769921123SKonstantin Belousov static int
glob2(Char * pathbuf,Char * pathend,Char * pathend_last,Char * pattern,glob11_t * pglob,struct glob_limit * limit)60869921123SKonstantin Belousov glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern,
60969921123SKonstantin Belousov       glob11_t *pglob, struct glob_limit *limit)
61069921123SKonstantin Belousov {
61169921123SKonstantin Belousov 	struct freebsd11_stat sb;
61269921123SKonstantin Belousov 	Char *p, *q;
61369921123SKonstantin Belousov 	int anymeta;
61469921123SKonstantin Belousov 
61569921123SKonstantin Belousov 	/*
61669921123SKonstantin Belousov 	 * Loop over pattern segments until end of pattern or until
61769921123SKonstantin Belousov 	 * segment with meta character found.
61869921123SKonstantin Belousov 	 */
61969921123SKonstantin Belousov 	for (anymeta = 0;;) {
62069921123SKonstantin Belousov 		if (*pattern == EOS) {		/* End of pattern? */
62169921123SKonstantin Belousov 			*pathend = EOS;
62269921123SKonstantin Belousov 			if (g_lstat(pathbuf, &sb, pglob))
62369921123SKonstantin Belousov 				return (0);
62469921123SKonstantin Belousov 
62569921123SKonstantin Belousov 			if ((pglob->gl_flags & GLOB_LIMIT) &&
62669921123SKonstantin Belousov 			    limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) {
62769921123SKonstantin Belousov 				errno = E2BIG;
62869921123SKonstantin Belousov 				return (GLOB_NOSPACE);
62969921123SKonstantin Belousov 			}
63069921123SKonstantin Belousov 			if ((pglob->gl_flags & GLOB_MARK) &&
63169921123SKonstantin Belousov 			    UNPROT(pathend[-1]) != SEP &&
63269921123SKonstantin Belousov 			    (S_ISDIR(sb.st_mode) ||
63369921123SKonstantin Belousov 			    (S_ISLNK(sb.st_mode) &&
63469921123SKonstantin Belousov 			    g_stat(pathbuf, &sb, pglob) == 0 &&
63569921123SKonstantin Belousov 			    S_ISDIR(sb.st_mode)))) {
63669921123SKonstantin Belousov 				if (pathend + 1 > pathend_last) {
63769921123SKonstantin Belousov 					errno = E2BIG;
63869921123SKonstantin Belousov 					return (GLOB_NOSPACE);
63969921123SKonstantin Belousov 				}
64069921123SKonstantin Belousov 				*pathend++ = SEP;
64169921123SKonstantin Belousov 				*pathend = EOS;
64269921123SKonstantin Belousov 			}
64369921123SKonstantin Belousov 			++pglob->gl_matchc;
64469921123SKonstantin Belousov 			return (globextend(pathbuf, pglob, limit, NULL));
64569921123SKonstantin Belousov 		}
64669921123SKonstantin Belousov 
64769921123SKonstantin Belousov 		/* Find end of next segment, copy tentatively to pathend. */
64869921123SKonstantin Belousov 		q = pathend;
64969921123SKonstantin Belousov 		p = pattern;
65069921123SKonstantin Belousov 		while (*p != EOS && UNPROT(*p) != SEP) {
65169921123SKonstantin Belousov 			if (ismeta(*p))
65269921123SKonstantin Belousov 				anymeta = 1;
65369921123SKonstantin Belousov 			if (q + 1 > pathend_last) {
65469921123SKonstantin Belousov 				errno = E2BIG;
65569921123SKonstantin Belousov 				return (GLOB_NOSPACE);
65669921123SKonstantin Belousov 			}
65769921123SKonstantin Belousov 			*q++ = *p++;
65869921123SKonstantin Belousov 		}
65969921123SKonstantin Belousov 
66069921123SKonstantin Belousov 		if (!anymeta) {		/* No expansion, do next segment. */
66169921123SKonstantin Belousov 			pathend = q;
66269921123SKonstantin Belousov 			pattern = p;
66369921123SKonstantin Belousov 			while (UNPROT(*pattern) == SEP) {
66469921123SKonstantin Belousov 				if (pathend + 1 > pathend_last) {
66569921123SKonstantin Belousov 					errno = E2BIG;
66669921123SKonstantin Belousov 					return (GLOB_NOSPACE);
66769921123SKonstantin Belousov 				}
66869921123SKonstantin Belousov 				*pathend++ = *pattern++;
66969921123SKonstantin Belousov 			}
67069921123SKonstantin Belousov 		} else			/* Need expansion, recurse. */
67169921123SKonstantin Belousov 			return (glob3(pathbuf, pathend, pathend_last, pattern,
67269921123SKonstantin Belousov 			    p, pglob, limit));
67369921123SKonstantin Belousov 	}
67469921123SKonstantin Belousov 	/* NOTREACHED */
67569921123SKonstantin Belousov }
67669921123SKonstantin Belousov 
67769921123SKonstantin Belousov static int
glob3(Char * pathbuf,Char * pathend,Char * pathend_last,Char * pattern,Char * restpattern,glob11_t * pglob,struct glob_limit * limit)67869921123SKonstantin Belousov glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
67969921123SKonstantin Belousov       Char *pattern, Char *restpattern,
68069921123SKonstantin Belousov       glob11_t *pglob, struct glob_limit *limit)
68169921123SKonstantin Belousov {
68269921123SKonstantin Belousov 	struct freebsd11_dirent *dp;
68369921123SKonstantin Belousov 	DIR *dirp;
68469921123SKonstantin Belousov 	int err, too_long, saverrno, saverrno2;
68569921123SKonstantin Belousov 	char buf[MAXPATHLEN + MB_LEN_MAX - 1];
68669921123SKonstantin Belousov 
68769921123SKonstantin Belousov 	struct freebsd11_dirent *(*readdirfunc)(DIR *);
68869921123SKonstantin Belousov 
68969921123SKonstantin Belousov 	if (pathend > pathend_last) {
69069921123SKonstantin Belousov 		errno = E2BIG;
69169921123SKonstantin Belousov 		return (GLOB_NOSPACE);
69269921123SKonstantin Belousov 	}
69369921123SKonstantin Belousov 	*pathend = EOS;
69469921123SKonstantin Belousov 	if (pglob->gl_errfunc != NULL &&
69569921123SKonstantin Belousov 	    g_Ctoc(pathbuf, buf, sizeof(buf))) {
69669921123SKonstantin Belousov 		errno = E2BIG;
69769921123SKonstantin Belousov 		return (GLOB_NOSPACE);
69869921123SKonstantin Belousov 	}
69969921123SKonstantin Belousov 
70069921123SKonstantin Belousov 	saverrno = errno;
70169921123SKonstantin Belousov 	errno = 0;
70269921123SKonstantin Belousov 	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
70369921123SKonstantin Belousov 		if (errno == ENOENT || errno == ENOTDIR)
70469921123SKonstantin Belousov 			return (0);
70569921123SKonstantin Belousov 		err = err_aborted(pglob, errno, buf);
70669921123SKonstantin Belousov 		if (errno == 0)
70769921123SKonstantin Belousov 			errno = saverrno;
70869921123SKonstantin Belousov 		return (err);
70969921123SKonstantin Belousov 	}
71069921123SKonstantin Belousov 
71169921123SKonstantin Belousov 	err = 0;
71269921123SKonstantin Belousov 
71369921123SKonstantin Belousov 	/* pglob->gl_readdir takes a void *, fix this manually */
71469921123SKonstantin Belousov 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
71569921123SKonstantin Belousov 		readdirfunc =
71669921123SKonstantin Belousov 		    (struct freebsd11_dirent *(*)(DIR *))pglob->gl_readdir;
71769921123SKonstantin Belousov 	else
71869921123SKonstantin Belousov 		readdirfunc = freebsd11_readdir;
71969921123SKonstantin Belousov 
72069921123SKonstantin Belousov 	errno = 0;
72169921123SKonstantin Belousov 	/* Search directory for matching names. */
72269921123SKonstantin Belousov 	while ((dp = (*readdirfunc)(dirp)) != NULL) {
72369921123SKonstantin Belousov 		char *sc;
72469921123SKonstantin Belousov 		Char *dc;
72569921123SKonstantin Belousov 		wchar_t wc;
72669921123SKonstantin Belousov 		size_t clen;
72769921123SKonstantin Belousov 		mbstate_t mbs;
72869921123SKonstantin Belousov 
72969921123SKonstantin Belousov 		if ((pglob->gl_flags & GLOB_LIMIT) &&
73069921123SKonstantin Belousov 		    limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) {
73169921123SKonstantin Belousov 			errno = E2BIG;
73269921123SKonstantin Belousov 			err = GLOB_NOSPACE;
73369921123SKonstantin Belousov 			break;
73469921123SKonstantin Belousov 		}
73569921123SKonstantin Belousov 
73669921123SKonstantin Belousov 		/* Initial DOT must be matched literally. */
73769921123SKonstantin Belousov 		if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) {
73869921123SKonstantin Belousov 			errno = 0;
73969921123SKonstantin Belousov 			continue;
74069921123SKonstantin Belousov 		}
74169921123SKonstantin Belousov 		memset(&mbs, 0, sizeof(mbs));
74269921123SKonstantin Belousov 		dc = pathend;
74369921123SKonstantin Belousov 		sc = dp->d_name;
74469921123SKonstantin Belousov 		too_long = 1;
74569921123SKonstantin Belousov 		while (dc <= pathend_last) {
74669921123SKonstantin Belousov 			clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
74769921123SKonstantin Belousov 			if (clen == (size_t)-1 || clen == (size_t)-2) {
74869921123SKonstantin Belousov 				/* XXX See initial comment #2. */
74969921123SKonstantin Belousov 				wc = (unsigned char)*sc;
75069921123SKonstantin Belousov 				clen = 1;
75169921123SKonstantin Belousov 				memset(&mbs, 0, sizeof(mbs));
75269921123SKonstantin Belousov 			}
75369921123SKonstantin Belousov 			if ((*dc++ = wc) == EOS) {
75469921123SKonstantin Belousov 				too_long = 0;
75569921123SKonstantin Belousov 				break;
75669921123SKonstantin Belousov 			}
75769921123SKonstantin Belousov 			sc += clen;
75869921123SKonstantin Belousov 		}
75969921123SKonstantin Belousov 		if (too_long && (err = err_aborted(pglob, ENAMETOOLONG,
76069921123SKonstantin Belousov 		    buf))) {
76169921123SKonstantin Belousov 			errno = ENAMETOOLONG;
76269921123SKonstantin Belousov 			break;
76369921123SKonstantin Belousov 		}
76469921123SKonstantin Belousov 		if (too_long || !match(pathend, pattern, restpattern)) {
76569921123SKonstantin Belousov 			*pathend = EOS;
76669921123SKonstantin Belousov 			errno = 0;
76769921123SKonstantin Belousov 			continue;
76869921123SKonstantin Belousov 		}
76969921123SKonstantin Belousov 		if (errno == 0)
77069921123SKonstantin Belousov 			errno = saverrno;
77169921123SKonstantin Belousov 		err = glob2(pathbuf, --dc, pathend_last, restpattern,
77269921123SKonstantin Belousov 		    pglob, limit);
77369921123SKonstantin Belousov 		if (err)
77469921123SKonstantin Belousov 			break;
77569921123SKonstantin Belousov 		errno = 0;
77669921123SKonstantin Belousov 	}
77769921123SKonstantin Belousov 
77869921123SKonstantin Belousov 	saverrno2 = errno;
77969921123SKonstantin Belousov 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
78069921123SKonstantin Belousov 		(*pglob->gl_closedir)(dirp);
78169921123SKonstantin Belousov 	else
78269921123SKonstantin Belousov 		closedir(dirp);
78369921123SKonstantin Belousov 	errno = saverrno2;
78469921123SKonstantin Belousov 
78569921123SKonstantin Belousov 	if (err)
78669921123SKonstantin Belousov 		return (err);
78769921123SKonstantin Belousov 
78869921123SKonstantin Belousov 	if (dp == NULL && errno != 0 &&
78969921123SKonstantin Belousov 	    (err = err_aborted(pglob, errno, buf)))
79069921123SKonstantin Belousov 		return (err);
79169921123SKonstantin Belousov 
79269921123SKonstantin Belousov 	if (errno == 0)
79369921123SKonstantin Belousov 		errno = saverrno;
79469921123SKonstantin Belousov 	return (0);
79569921123SKonstantin Belousov }
79669921123SKonstantin Belousov 
79769921123SKonstantin Belousov 
79869921123SKonstantin Belousov /*
79969921123SKonstantin Belousov  * Extend the gl_pathv member of a glob11_t structure to accommodate a new item,
80069921123SKonstantin Belousov  * add the new item, and update gl_pathc.
80169921123SKonstantin Belousov  *
80269921123SKonstantin Belousov  * This assumes the BSD realloc, which only copies the block when its size
80369921123SKonstantin Belousov  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
80469921123SKonstantin Belousov  * behavior.
80569921123SKonstantin Belousov  *
80669921123SKonstantin Belousov  * Return 0 if new item added, error code if memory couldn't be allocated.
80769921123SKonstantin Belousov  *
80869921123SKonstantin Belousov  * Invariant of the glob11_t structure:
80969921123SKonstantin Belousov  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
81069921123SKonstantin Belousov  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
81169921123SKonstantin Belousov  */
81269921123SKonstantin Belousov static int
globextend(const Char * path,glob11_t * pglob,struct glob_limit * limit,const char * origpat)81369921123SKonstantin Belousov globextend(const Char *path, glob11_t *pglob, struct glob_limit *limit,
81469921123SKonstantin Belousov     const char *origpat)
81569921123SKonstantin Belousov {
81669921123SKonstantin Belousov 	char **pathv;
81769921123SKonstantin Belousov 	size_t i, newn, len;
81869921123SKonstantin Belousov 	char *copy;
81969921123SKonstantin Belousov 	const Char *p;
82069921123SKonstantin Belousov 
82169921123SKonstantin Belousov 	if ((pglob->gl_flags & GLOB_LIMIT) &&
82269921123SKonstantin Belousov 	    pglob->gl_matchc > limit->l_path_lim) {
82369921123SKonstantin Belousov 		errno = E2BIG;
82469921123SKonstantin Belousov 		return (GLOB_NOSPACE);
82569921123SKonstantin Belousov 	}
82669921123SKonstantin Belousov 
82769921123SKonstantin Belousov 	newn = 2 + pglob->gl_pathc + pglob->gl_offs;
82869921123SKonstantin Belousov 	/* reallocarray(NULL, newn, size) is equivalent to malloc(newn*size). */
82969921123SKonstantin Belousov 	pathv = reallocarray(pglob->gl_pathv, newn, sizeof(*pathv));
83069921123SKonstantin Belousov 	if (pathv == NULL)
83169921123SKonstantin Belousov 		return (GLOB_NOSPACE);
83269921123SKonstantin Belousov 
83369921123SKonstantin Belousov 	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
83469921123SKonstantin Belousov 		/* first time around -- clear initial gl_offs items */
83569921123SKonstantin Belousov 		pathv += pglob->gl_offs;
83669921123SKonstantin Belousov 		for (i = pglob->gl_offs + 1; --i > 0; )
83769921123SKonstantin Belousov 			*--pathv = NULL;
83869921123SKonstantin Belousov 	}
83969921123SKonstantin Belousov 	pglob->gl_pathv = pathv;
84069921123SKonstantin Belousov 
84169921123SKonstantin Belousov 	if (origpat != NULL)
84269921123SKonstantin Belousov 		copy = strdup(origpat);
84369921123SKonstantin Belousov 	else {
84469921123SKonstantin Belousov 		for (p = path; *p++ != EOS;)
84569921123SKonstantin Belousov 			continue;
84669921123SKonstantin Belousov 		len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */
84769921123SKonstantin Belousov 		if ((copy = malloc(len)) != NULL) {
84869921123SKonstantin Belousov 			if (g_Ctoc(path, copy, len)) {
84969921123SKonstantin Belousov 				free(copy);
85069921123SKonstantin Belousov 				errno = E2BIG;
85169921123SKonstantin Belousov 				return (GLOB_NOSPACE);
85269921123SKonstantin Belousov 			}
85369921123SKonstantin Belousov 		}
85469921123SKonstantin Belousov 	}
85569921123SKonstantin Belousov 	if (copy != NULL) {
85669921123SKonstantin Belousov 		limit->l_string_cnt += strlen(copy) + 1;
85769921123SKonstantin Belousov 		if ((pglob->gl_flags & GLOB_LIMIT) &&
85869921123SKonstantin Belousov 		    limit->l_string_cnt >= GLOB_LIMIT_STRING) {
85969921123SKonstantin Belousov 			free(copy);
86069921123SKonstantin Belousov 			errno = E2BIG;
86169921123SKonstantin Belousov 			return (GLOB_NOSPACE);
86269921123SKonstantin Belousov 		}
86369921123SKonstantin Belousov 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
86469921123SKonstantin Belousov 	}
86569921123SKonstantin Belousov 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
86669921123SKonstantin Belousov 	return (copy == NULL ? GLOB_NOSPACE : 0);
86769921123SKonstantin Belousov }
86869921123SKonstantin Belousov 
86969921123SKonstantin Belousov /*
87069921123SKonstantin Belousov  * pattern matching function for filenames.
87169921123SKonstantin Belousov  */
87269921123SKonstantin Belousov static int
match(Char * name,Char * pat,Char * patend)87369921123SKonstantin Belousov match(Char *name, Char *pat, Char *patend)
87469921123SKonstantin Belousov {
87569921123SKonstantin Belousov 	int ok, negate_range;
87669921123SKonstantin Belousov 	Char c, k, *nextp, *nextn;
87769921123SKonstantin Belousov 	struct xlocale_collate *table =
87869921123SKonstantin Belousov 		(struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
87969921123SKonstantin Belousov 
88069921123SKonstantin Belousov 	nextn = NULL;
88169921123SKonstantin Belousov 	nextp = NULL;
88269921123SKonstantin Belousov 
88369921123SKonstantin Belousov 	while (1) {
88469921123SKonstantin Belousov 		while (pat < patend) {
88569921123SKonstantin Belousov 			c = *pat++;
88669921123SKonstantin Belousov 			switch (c & M_MASK) {
88769921123SKonstantin Belousov 			case M_ALL:
88869921123SKonstantin Belousov 				if (pat == patend)
88969921123SKonstantin Belousov 					return (1);
89069921123SKonstantin Belousov 				if (*name == EOS)
89169921123SKonstantin Belousov 					return (0);
89269921123SKonstantin Belousov 				nextn = name + 1;
89369921123SKonstantin Belousov 				nextp = pat - 1;
89469921123SKonstantin Belousov 				break;
89569921123SKonstantin Belousov 			case M_ONE:
89669921123SKonstantin Belousov 				if (*name++ == EOS)
89769921123SKonstantin Belousov 					goto fail;
89869921123SKonstantin Belousov 				break;
89969921123SKonstantin Belousov 			case M_SET:
90069921123SKonstantin Belousov 				ok = 0;
90169921123SKonstantin Belousov 				if ((k = *name++) == EOS)
90269921123SKonstantin Belousov 					goto fail;
90369921123SKonstantin Belousov 				negate_range = ((*pat & M_MASK) == M_NOT);
90469921123SKonstantin Belousov 				if (negate_range != 0)
90569921123SKonstantin Belousov 					++pat;
90669921123SKonstantin Belousov 				while (((c = *pat++) & M_MASK) != M_END)
90769921123SKonstantin Belousov 					if ((*pat & M_MASK) == M_RNG) {
90869921123SKonstantin Belousov 						if (table->__collate_load_error ?
90969921123SKonstantin Belousov 						    CHAR(c) <= CHAR(k) &&
91069921123SKonstantin Belousov 						    CHAR(k) <= CHAR(pat[1]) :
91169921123SKonstantin Belousov 						    __wcollate_range_cmp(CHAR(c),
91269921123SKonstantin Belousov 						    CHAR(k)) <= 0 &&
91369921123SKonstantin Belousov 						    __wcollate_range_cmp(CHAR(k),
91469921123SKonstantin Belousov 						    CHAR(pat[1])) <= 0)
91569921123SKonstantin Belousov 							ok = 1;
91669921123SKonstantin Belousov 						pat += 2;
91769921123SKonstantin Belousov 					} else if (c == k)
91869921123SKonstantin Belousov 						ok = 1;
91969921123SKonstantin Belousov 				if (ok == negate_range)
92069921123SKonstantin Belousov 					goto fail;
92169921123SKonstantin Belousov 				break;
92269921123SKonstantin Belousov 			default:
92369921123SKonstantin Belousov 				if (*name++ != c)
92469921123SKonstantin Belousov 					goto fail;
92569921123SKonstantin Belousov 				break;
92669921123SKonstantin Belousov 			}
92769921123SKonstantin Belousov 		}
92869921123SKonstantin Belousov 		if (*name == EOS)
92969921123SKonstantin Belousov 			return (1);
93069921123SKonstantin Belousov 
93169921123SKonstantin Belousov 	fail:
93269921123SKonstantin Belousov 		if (nextn == NULL)
93369921123SKonstantin Belousov 			break;
93469921123SKonstantin Belousov 		pat = nextp;
93569921123SKonstantin Belousov 		name = nextn;
93669921123SKonstantin Belousov 	}
93769921123SKonstantin Belousov 	return (0);
93869921123SKonstantin Belousov }
93969921123SKonstantin Belousov 
94069921123SKonstantin Belousov /* Free allocated data belonging to a glob11_t structure. */
94169921123SKonstantin Belousov void
freebsd11_globfree(glob11_t * pglob)94269921123SKonstantin Belousov freebsd11_globfree(glob11_t *pglob)
94369921123SKonstantin Belousov {
94469921123SKonstantin Belousov 	size_t i;
94569921123SKonstantin Belousov 	char **pp;
94669921123SKonstantin Belousov 
94769921123SKonstantin Belousov 	if (pglob->gl_pathv != NULL) {
94869921123SKonstantin Belousov 		pp = pglob->gl_pathv + pglob->gl_offs;
94969921123SKonstantin Belousov 		for (i = pglob->gl_pathc; i--; ++pp)
95069921123SKonstantin Belousov 			if (*pp)
95169921123SKonstantin Belousov 				free(*pp);
95269921123SKonstantin Belousov 		free(pglob->gl_pathv);
95369921123SKonstantin Belousov 		pglob->gl_pathv = NULL;
95469921123SKonstantin Belousov 	}
95569921123SKonstantin Belousov }
95669921123SKonstantin Belousov 
95769921123SKonstantin Belousov static DIR *
g_opendir(Char * str,glob11_t * pglob)95869921123SKonstantin Belousov g_opendir(Char *str, glob11_t *pglob)
95969921123SKonstantin Belousov {
96069921123SKonstantin Belousov 	char buf[MAXPATHLEN + MB_LEN_MAX - 1];
96169921123SKonstantin Belousov 
96269921123SKonstantin Belousov 	if (*str == EOS)
96369921123SKonstantin Belousov 		strcpy(buf, ".");
96469921123SKonstantin Belousov 	else {
96569921123SKonstantin Belousov 		if (g_Ctoc(str, buf, sizeof(buf))) {
96669921123SKonstantin Belousov 			errno = ENAMETOOLONG;
96769921123SKonstantin Belousov 			return (NULL);
96869921123SKonstantin Belousov 		}
96969921123SKonstantin Belousov 	}
97069921123SKonstantin Belousov 
97169921123SKonstantin Belousov 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
97269921123SKonstantin Belousov 		return ((*pglob->gl_opendir)(buf));
97369921123SKonstantin Belousov 
97469921123SKonstantin Belousov 	return (opendir(buf));
97569921123SKonstantin Belousov }
97669921123SKonstantin Belousov 
97769921123SKonstantin Belousov static int
g_lstat(Char * fn,struct freebsd11_stat * sb,glob11_t * pglob)97869921123SKonstantin Belousov g_lstat(Char *fn, struct freebsd11_stat *sb, glob11_t *pglob)
97969921123SKonstantin Belousov {
98069921123SKonstantin Belousov 	char buf[MAXPATHLEN + MB_LEN_MAX - 1];
98169921123SKonstantin Belousov 
98269921123SKonstantin Belousov 	if (g_Ctoc(fn, buf, sizeof(buf))) {
98369921123SKonstantin Belousov 		errno = ENAMETOOLONG;
98469921123SKonstantin Belousov 		return (-1);
98569921123SKonstantin Belousov 	}
98669921123SKonstantin Belousov 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
98769921123SKonstantin Belousov 		return((*pglob->gl_lstat)(buf, sb));
98869921123SKonstantin Belousov 	return (freebsd11_lstat(buf, sb));
98969921123SKonstantin Belousov }
99069921123SKonstantin Belousov 
99169921123SKonstantin Belousov static int
g_stat(Char * fn,struct freebsd11_stat * sb,glob11_t * pglob)99269921123SKonstantin Belousov g_stat(Char *fn, struct freebsd11_stat *sb, glob11_t *pglob)
99369921123SKonstantin Belousov {
99469921123SKonstantin Belousov 	char buf[MAXPATHLEN + MB_LEN_MAX - 1];
99569921123SKonstantin Belousov 
99669921123SKonstantin Belousov 	if (g_Ctoc(fn, buf, sizeof(buf))) {
99769921123SKonstantin Belousov 		errno = ENAMETOOLONG;
99869921123SKonstantin Belousov 		return (-1);
99969921123SKonstantin Belousov 	}
100069921123SKonstantin Belousov 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
100169921123SKonstantin Belousov 		return ((*pglob->gl_stat)(buf, sb));
100269921123SKonstantin Belousov 	return (freebsd11_stat(buf, sb));
100369921123SKonstantin Belousov }
100469921123SKonstantin Belousov 
100569921123SKonstantin Belousov static const Char *
g_strchr(const Char * str,wchar_t ch)100669921123SKonstantin Belousov g_strchr(const Char *str, wchar_t ch)
100769921123SKonstantin Belousov {
100869921123SKonstantin Belousov 
100969921123SKonstantin Belousov 	do {
101069921123SKonstantin Belousov 		if (*str == ch)
101169921123SKonstantin Belousov 			return (str);
101269921123SKonstantin Belousov 	} while (*str++);
101369921123SKonstantin Belousov 	return (NULL);
101469921123SKonstantin Belousov }
101569921123SKonstantin Belousov 
101669921123SKonstantin Belousov static int
g_Ctoc(const Char * str,char * buf,size_t len)101769921123SKonstantin Belousov g_Ctoc(const Char *str, char *buf, size_t len)
101869921123SKonstantin Belousov {
101969921123SKonstantin Belousov 	mbstate_t mbs;
102069921123SKonstantin Belousov 	size_t clen;
102169921123SKonstantin Belousov 
102269921123SKonstantin Belousov 	memset(&mbs, 0, sizeof(mbs));
102369921123SKonstantin Belousov 	while (len >= MB_CUR_MAX) {
102469921123SKonstantin Belousov 		clen = wcrtomb(buf, CHAR(*str), &mbs);
102569921123SKonstantin Belousov 		if (clen == (size_t)-1) {
102669921123SKonstantin Belousov 			/* XXX See initial comment #2. */
102769921123SKonstantin Belousov 			*buf = (char)CHAR(*str);
102869921123SKonstantin Belousov 			clen = 1;
102969921123SKonstantin Belousov 			memset(&mbs, 0, sizeof(mbs));
103069921123SKonstantin Belousov 		}
103169921123SKonstantin Belousov 		if (CHAR(*str) == EOS)
103269921123SKonstantin Belousov 			return (0);
103369921123SKonstantin Belousov 		str++;
103469921123SKonstantin Belousov 		buf += clen;
103569921123SKonstantin Belousov 		len -= clen;
103669921123SKonstantin Belousov 	}
103769921123SKonstantin Belousov 	return (1);
103869921123SKonstantin Belousov }
103969921123SKonstantin Belousov 
104069921123SKonstantin Belousov static int
err_nomatch(glob11_t * pglob,struct glob_limit * limit,const char * origpat)104169921123SKonstantin Belousov err_nomatch(glob11_t *pglob, struct glob_limit *limit, const char *origpat) {
104269921123SKonstantin Belousov 	/*
104369921123SKonstantin Belousov 	 * If there was no match we are going to append the origpat
104469921123SKonstantin Belousov 	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
104569921123SKonstantin Belousov 	 * and the origpat did not contain any magic characters
104669921123SKonstantin Belousov 	 * GLOB_NOMAGIC is there just for compatibility with csh.
104769921123SKonstantin Belousov 	 */
104869921123SKonstantin Belousov 	if ((pglob->gl_flags & GLOB_NOCHECK) ||
104969921123SKonstantin Belousov 	    ((pglob->gl_flags & GLOB_NOMAGIC) &&
105069921123SKonstantin Belousov 	    !(pglob->gl_flags & GLOB_MAGCHAR)))
105169921123SKonstantin Belousov 		return (globextend(NULL, pglob, limit, origpat));
105269921123SKonstantin Belousov 	return (GLOB_NOMATCH);
105369921123SKonstantin Belousov }
105469921123SKonstantin Belousov 
105569921123SKonstantin Belousov static int
err_aborted(glob11_t * pglob,int err,char * buf)105669921123SKonstantin Belousov err_aborted(glob11_t *pglob, int err, char *buf) {
105769921123SKonstantin Belousov 	if ((pglob->gl_errfunc != NULL && pglob->gl_errfunc(buf, err)) ||
105869921123SKonstantin Belousov 	    (pglob->gl_flags & GLOB_ERR))
105969921123SKonstantin Belousov 		return (GLOB_ABORTED);
106069921123SKonstantin Belousov 	return (0);
106169921123SKonstantin Belousov }
106269921123SKonstantin Belousov 
106369921123SKonstantin Belousov #ifdef DEBUG
106469921123SKonstantin Belousov static void
qprintf(const char * str,Char * s)106569921123SKonstantin Belousov qprintf(const char *str, Char *s)
106669921123SKonstantin Belousov {
106769921123SKonstantin Belousov 	Char *p;
106869921123SKonstantin Belousov 
106969921123SKonstantin Belousov 	(void)printf("%s\n", str);
107069921123SKonstantin Belousov 	if (s != NULL) {
107169921123SKonstantin Belousov 		for (p = s; *p != EOS; p++)
107269921123SKonstantin Belousov 			(void)printf("%c", (char)CHAR(*p));
107369921123SKonstantin Belousov 		(void)printf("\n");
107469921123SKonstantin Belousov 		for (p = s; *p != EOS; p++)
107569921123SKonstantin Belousov 			(void)printf("%c", (isprot(*p) ? '\\' : ' '));
107669921123SKonstantin Belousov 		(void)printf("\n");
107769921123SKonstantin Belousov 		for (p = s; *p != EOS; p++)
107869921123SKonstantin Belousov 			(void)printf("%c", (ismeta(*p) ? '_' : ' '));
107969921123SKonstantin Belousov 		(void)printf("\n");
108069921123SKonstantin Belousov 	}
108169921123SKonstantin Belousov }
108269921123SKonstantin Belousov #endif
108369921123SKonstantin Belousov 
108469921123SKonstantin Belousov __sym_compat(glob, freebsd11_glob, FBSD_1.0);
108569921123SKonstantin Belousov __sym_compat(globfree, freebsd11_globfree, FBSD_1.0);
1086