xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/glob.c (revision 7143:be301adcb4cf)
10Sstevel@tonic-gate /*
2*7143Sjk217608  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
70Sstevel@tonic-gate 
80Sstevel@tonic-gate /****************************************************************************
90Sstevel@tonic-gate   Copyright (c) 1999,2000,2001 WU-FTPD Development Group.
100Sstevel@tonic-gate   All rights reserved.
110Sstevel@tonic-gate 
120Sstevel@tonic-gate   Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
130Sstevel@tonic-gate     The Regents of the University of California.
140Sstevel@tonic-gate   Portions Copyright (c) 1993, 1994 Washington University in Saint Louis.
150Sstevel@tonic-gate   Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc.
160Sstevel@tonic-gate   Portions Copyright (c) 1989 Massachusetts Institute of Technology.
170Sstevel@tonic-gate   Portions Copyright (c) 1998 Sendmail, Inc.
180Sstevel@tonic-gate   Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P.  Allman.
190Sstevel@tonic-gate   Portions Copyright (c) 1997 by Stan Barber.
200Sstevel@tonic-gate   Portions Copyright (c) 1997 by Kent Landfield.
210Sstevel@tonic-gate   Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
220Sstevel@tonic-gate     Free Software Foundation, Inc.
230Sstevel@tonic-gate 
240Sstevel@tonic-gate   Use and distribution of this software and its source code are governed
250Sstevel@tonic-gate   by the terms and conditions of the WU-FTPD Software License ("LICENSE").
260Sstevel@tonic-gate 
270Sstevel@tonic-gate   If you did not receive a copy of the license, it may be obtained online
280Sstevel@tonic-gate   at http://www.wu-ftpd.org/license.html.
290Sstevel@tonic-gate 
300Sstevel@tonic-gate   $Id: glob.c,v 1.14.2.2 2001/11/29 17:01:38 wuftpd Exp $
310Sstevel@tonic-gate 
320Sstevel@tonic-gate ****************************************************************************/
330Sstevel@tonic-gate /*
340Sstevel@tonic-gate  * C-shell glob for random programs.
350Sstevel@tonic-gate  */
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include "config.h"
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #include <sys/param.h>
400Sstevel@tonic-gate #include <sys/stat.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #ifdef HAVE_DIRENT_H
430Sstevel@tonic-gate #include <dirent.h>
440Sstevel@tonic-gate #else
450Sstevel@tonic-gate #include <sys/dir.h>
460Sstevel@tonic-gate #endif
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #include <pwd.h>
490Sstevel@tonic-gate #include <errno.h>
500Sstevel@tonic-gate #include <stdio.h>
510Sstevel@tonic-gate #include <stdlib.h>
520Sstevel@tonic-gate #include <string.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #include "proto.h"
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #define	QUOTE 0200
570Sstevel@tonic-gate #define	TRIM 0177
580Sstevel@tonic-gate #define	eq(a,b)		(strcmp(a, b)==0)
590Sstevel@tonic-gate #define	GAVSIZ		(1024 * 8)
600Sstevel@tonic-gate #define	isdir(d)	((d.st_mode & S_IFMT) == S_IFDIR)
610Sstevel@tonic-gate 
620Sstevel@tonic-gate static char **gargv;		/* Pointer to the (stack) arglist */
630Sstevel@tonic-gate static char **agargv;
640Sstevel@tonic-gate static size_t agargv_size;
650Sstevel@tonic-gate static int gargc;		/* Number args in gargv */
660Sstevel@tonic-gate static size_t gnleft;
670Sstevel@tonic-gate static short gflag;
680Sstevel@tonic-gate static int tglob(register char);
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /* Prototypes */
710Sstevel@tonic-gate 
720Sstevel@tonic-gate static char *strend(register char *);
730Sstevel@tonic-gate static void addpath(char);
740Sstevel@tonic-gate static void ginit(char **);
750Sstevel@tonic-gate static void collect(register char *);
760Sstevel@tonic-gate static void acollect(register char *);
770Sstevel@tonic-gate static void sort(void);
780Sstevel@tonic-gate static void expand(char *);
790Sstevel@tonic-gate static void matchdir(char *);
800Sstevel@tonic-gate static int execbrc(char *, char *);
810Sstevel@tonic-gate static int match(char *, char *);
820Sstevel@tonic-gate static int amatch(char *, char *);
830Sstevel@tonic-gate static void Gcat(register char *, register char *);
840Sstevel@tonic-gate static void rscan(register char **, int (*f) (register char));
850Sstevel@tonic-gate static int tglob(register char c);
860Sstevel@tonic-gate static int gethdir(char *);
870Sstevel@tonic-gate 
880Sstevel@tonic-gate int letter(register char);
890Sstevel@tonic-gate int digit(register char);
900Sstevel@tonic-gate int any(register int, register char *);
910Sstevel@tonic-gate int blklen(register char **);
920Sstevel@tonic-gate char **blkcpy(char **, register char **);
930Sstevel@tonic-gate 
940Sstevel@tonic-gate char *globerr;
950Sstevel@tonic-gate char *home;
960Sstevel@tonic-gate extern int errno;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate static int globcnt;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate char *globchars = "`{[*?";
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static char *gpath, *gpathp, *lastgpathp;
1030Sstevel@tonic-gate static int globbed;
1040Sstevel@tonic-gate static char *entp;
1050Sstevel@tonic-gate static char **sortbas;
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate #ifdef OTHER_PASSWD
1080Sstevel@tonic-gate #include "getpwnam.h"
1090Sstevel@tonic-gate extern char _path_passwd[];
1100Sstevel@tonic-gate #endif
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate char **ftpglob(register char *v)
1130Sstevel@tonic-gate {
1140Sstevel@tonic-gate     char agpath[BUFSIZ];
1150Sstevel@tonic-gate     char *vv[2];
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate     if (agargv == NULL) {
1180Sstevel@tonic-gate 	agargv = (char **) malloc(GAVSIZ * sizeof (char *));
1190Sstevel@tonic-gate 	if (agargv == NULL) {
1200Sstevel@tonic-gate 	    fatal("Out of memory");
1210Sstevel@tonic-gate 	}
1220Sstevel@tonic-gate 	agargv_size = GAVSIZ;
1230Sstevel@tonic-gate     }
1240Sstevel@tonic-gate     fixpath(v);
1250Sstevel@tonic-gate     if (v[0] == '\0')
126*7143Sjk217608 	v = ".";
1270Sstevel@tonic-gate     else if ((strlen(v) > 1) && (v[strlen(v) - 1] == '/'))
1280Sstevel@tonic-gate 	v[strlen(v) - 1] = '\0';
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate     vv[0] = v;
1310Sstevel@tonic-gate     vv[1] = NULL;
1320Sstevel@tonic-gate     globerr = NULL;
1330Sstevel@tonic-gate     gflag = 0;
1340Sstevel@tonic-gate     rscan(vv, tglob);
1350Sstevel@tonic-gate     if (gflag == 0) {
1360Sstevel@tonic-gate 	vv[0] = strspl(v, "");
1370Sstevel@tonic-gate 	return (copyblk(vv));
1380Sstevel@tonic-gate     }
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate     globerr = NULL;
1410Sstevel@tonic-gate     gpath = agpath;
1420Sstevel@tonic-gate     gpathp = gpath;
1430Sstevel@tonic-gate     *gpathp = 0;
1440Sstevel@tonic-gate     lastgpathp = &gpath[sizeof agpath - 2];
1450Sstevel@tonic-gate     ginit(agargv);
1460Sstevel@tonic-gate     globcnt = 0;
1470Sstevel@tonic-gate     collect(v);
1480Sstevel@tonic-gate     if (globcnt == 0 && (gflag & 1)) {
1490Sstevel@tonic-gate 	blkfree(gargv), gargv = 0;
1500Sstevel@tonic-gate 	return (0);
1510Sstevel@tonic-gate     }
1520Sstevel@tonic-gate     else
1530Sstevel@tonic-gate 	return (gargv = copyblk(gargv));
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate static void ginit(char **agargv)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate     agargv[0] = 0;
1600Sstevel@tonic-gate     gargv = agargv;
1610Sstevel@tonic-gate     sortbas = agargv;
1620Sstevel@tonic-gate     gargc = 0;
1630Sstevel@tonic-gate     gnleft = NCARGS - 4;
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate static void collect(register char *as)
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate     if (eq(as, "{") || eq(as, "{}")) {
1690Sstevel@tonic-gate 	Gcat(as, "");
1700Sstevel@tonic-gate 	sort();
1710Sstevel@tonic-gate     }
1720Sstevel@tonic-gate     else
1730Sstevel@tonic-gate 	acollect(as);
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate static void acollect(register char *as)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate     register int ogargc = gargc;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate     gpathp = gpath;
1810Sstevel@tonic-gate     *gpathp = 0;
1820Sstevel@tonic-gate     globbed = 0;
1830Sstevel@tonic-gate     expand(as);
1840Sstevel@tonic-gate     if (gargc != ogargc)
1850Sstevel@tonic-gate 	sort();
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate static int
1890Sstevel@tonic-gate argcmp(const void *p1, const void *p2)
1900Sstevel@tonic-gate {
1910Sstevel@tonic-gate     char *s1 = *(char **) p1;
1920Sstevel@tonic-gate     char *s2 = *(char **) p2;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate     return (strcmp(s1, s2));
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate static void sort(void)
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate     char **Gvp = &gargv[gargc];
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate     if (!globerr)
2020Sstevel@tonic-gate 	qsort(sortbas, Gvp - sortbas, sizeof (*sortbas), argcmp);
2030Sstevel@tonic-gate     sortbas = Gvp;
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate static void expand(char *as)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate     register char *cs;
2090Sstevel@tonic-gate     register char *sgpathp, *oldcs;
2100Sstevel@tonic-gate     struct stat stb;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate     if (globerr)
2130Sstevel@tonic-gate 	return;
2140Sstevel@tonic-gate     sgpathp = gpathp;
2150Sstevel@tonic-gate     cs = as;
2160Sstevel@tonic-gate     if (*cs == '~' && gpathp == gpath) {
2170Sstevel@tonic-gate 	addpath('~');
2180Sstevel@tonic-gate 	for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
2190Sstevel@tonic-gate 	    addpath(*cs++);
2200Sstevel@tonic-gate 	if (!*cs || *cs == '/') {
2210Sstevel@tonic-gate 	    if (gpathp != gpath + 1) {
2220Sstevel@tonic-gate 		*gpathp = 0;
2230Sstevel@tonic-gate 		if (gethdir(gpath + 1))
2240Sstevel@tonic-gate 		    globerr = "Unknown user name after ~";
2250Sstevel@tonic-gate 		/* memmove used as strings overlap */
2260Sstevel@tonic-gate 		(void) memmove(gpath, gpath + 1, strlen(gpath + 1) + 1);
2270Sstevel@tonic-gate 	    }
2280Sstevel@tonic-gate 	    else
2290Sstevel@tonic-gate 		(void) strlcpy(gpath, home, BUFSIZ);
2300Sstevel@tonic-gate 	    gpathp = strend(gpath);
2310Sstevel@tonic-gate 	}
2320Sstevel@tonic-gate     }
2330Sstevel@tonic-gate     while (!any(*cs, globchars)) {
2340Sstevel@tonic-gate 	if (*cs == 0) {
2350Sstevel@tonic-gate 	    if (!globbed)
2360Sstevel@tonic-gate 		Gcat(gpath, "");
2370Sstevel@tonic-gate 	    else if (stat(gpath, &stb) >= 0) {
2380Sstevel@tonic-gate 		Gcat(gpath, "");
2390Sstevel@tonic-gate 		globcnt++;
2400Sstevel@tonic-gate 	    }
2410Sstevel@tonic-gate 	    goto endit;
2420Sstevel@tonic-gate 	}
2430Sstevel@tonic-gate 	addpath(*cs++);
2440Sstevel@tonic-gate     }
2450Sstevel@tonic-gate     oldcs = cs;
2460Sstevel@tonic-gate     while (cs > as && *cs != '/')
2470Sstevel@tonic-gate 	cs--, gpathp--;
2480Sstevel@tonic-gate     if (*cs == '/')
2490Sstevel@tonic-gate 	cs++, gpathp++;
2500Sstevel@tonic-gate     *gpathp = 0;
2510Sstevel@tonic-gate     if (*oldcs == '{') {
2520Sstevel@tonic-gate 	(void) execbrc(cs, ((char *) 0));
2530Sstevel@tonic-gate 	return;
2540Sstevel@tonic-gate     }
2550Sstevel@tonic-gate     matchdir(cs);
2560Sstevel@tonic-gate   endit:
2570Sstevel@tonic-gate     gpathp = sgpathp;
2580Sstevel@tonic-gate     *gpathp = 0;
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate static void matchdir(char *pattern)
2620Sstevel@tonic-gate {
2630Sstevel@tonic-gate     struct stat stb;
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate #ifdef HAVE_DIRENT_H
2660Sstevel@tonic-gate     register struct dirent *dp;
2670Sstevel@tonic-gate #else
2680Sstevel@tonic-gate     register struct direct *dp;
2690Sstevel@tonic-gate #endif
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate     DIR *dirp;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate     dirp = opendir(*gpath == '\0' ? "." : gpath);
2740Sstevel@tonic-gate     if (dirp == NULL) {
2750Sstevel@tonic-gate 	if (globbed)
2760Sstevel@tonic-gate 	    return;
2770Sstevel@tonic-gate 	goto patherr2;
2780Sstevel@tonic-gate     }
2790Sstevel@tonic-gate #ifdef HAVE_DIRFD
2800Sstevel@tonic-gate     if (fstat(dirfd(dirp), &stb) < 0)
2810Sstevel@tonic-gate #else /* HAVE_DIRFD */
2820Sstevel@tonic-gate     if (fstat(dirp->dd_fd, &stb) < 0)
2830Sstevel@tonic-gate #endif /* HAVE_DIRFD */
2840Sstevel@tonic-gate 	goto patherr1;
2850Sstevel@tonic-gate     if (!isdir(stb)) {
2860Sstevel@tonic-gate 	errno = ENOTDIR;
2870Sstevel@tonic-gate 	goto patherr1;
2880Sstevel@tonic-gate     }
2890Sstevel@tonic-gate     while (!globerr && ((dp = readdir(dirp)) != NULL)) {
2900Sstevel@tonic-gate 	if (dp->d_ino == 0)
2910Sstevel@tonic-gate 	    continue;
2920Sstevel@tonic-gate 	if (match(dp->d_name, pattern)) {
2930Sstevel@tonic-gate 	    Gcat(gpath, dp->d_name);
2940Sstevel@tonic-gate 	    globcnt++;
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate     }
2970Sstevel@tonic-gate     closedir(dirp);
2980Sstevel@tonic-gate     return;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate   patherr1:
3010Sstevel@tonic-gate     closedir(dirp);
3020Sstevel@tonic-gate   patherr2:
3030Sstevel@tonic-gate     globerr = "Bad directory components";
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate static int execbrc(char *p, char *s)
3070Sstevel@tonic-gate {
3080Sstevel@tonic-gate     char restbuf[BUFSIZ + 2];
3090Sstevel@tonic-gate     char *restbufend = &restbuf[sizeof(restbuf)];
3100Sstevel@tonic-gate     register char *pe, *pm, *pl;
3110Sstevel@tonic-gate     int brclev = 0;
3120Sstevel@tonic-gate     char *lm, savec, *sgpathp;
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate     for (lm = restbuf; *p != '{'; *lm++ = *p++) {
3150Sstevel@tonic-gate 	if (lm >= restbufend)
3160Sstevel@tonic-gate 	    return (0);
3170Sstevel@tonic-gate     }
3180Sstevel@tonic-gate     for (pe = ++p; *pe; pe++) {
3190Sstevel@tonic-gate 	switch (*pe) {
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	case '{':
3220Sstevel@tonic-gate 	    brclev++;
3230Sstevel@tonic-gate 	    continue;
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	case '}':
3260Sstevel@tonic-gate 	    if (brclev == 0)
3270Sstevel@tonic-gate 		goto pend;
3280Sstevel@tonic-gate 	    brclev--;
3290Sstevel@tonic-gate 	    continue;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	case '[':
3320Sstevel@tonic-gate 	    for (pe++; *pe && *pe != ']'; pe++)
3330Sstevel@tonic-gate 		continue;
3340Sstevel@tonic-gate 	    if (!*pe) {
3350Sstevel@tonic-gate 		globerr = "Missing ]";
3360Sstevel@tonic-gate 		return (0);
3370Sstevel@tonic-gate 	    }
3380Sstevel@tonic-gate 	    continue;
3390Sstevel@tonic-gate 	}
3400Sstevel@tonic-gate     }
3410Sstevel@tonic-gate   pend:
3420Sstevel@tonic-gate     if (brclev || !*pe) {
3430Sstevel@tonic-gate 	globerr = "Missing }";
3440Sstevel@tonic-gate 	return (0);
3450Sstevel@tonic-gate     }
3460Sstevel@tonic-gate     for (pl = pm = p; pm <= pe; pm++) {
3470Sstevel@tonic-gate 	switch (*pm & (QUOTE | TRIM)) {
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	case '{':
3500Sstevel@tonic-gate 	    brclev++;
3510Sstevel@tonic-gate 	    continue;
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	case '}':
3540Sstevel@tonic-gate 	    if (brclev) {
3550Sstevel@tonic-gate 		brclev--;
3560Sstevel@tonic-gate 		continue;
3570Sstevel@tonic-gate 	    }
3580Sstevel@tonic-gate 	    goto doit;
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	case ',' | QUOTE:
3610Sstevel@tonic-gate 	case ',':
3620Sstevel@tonic-gate 	    if (brclev)
3630Sstevel@tonic-gate 		continue;
3640Sstevel@tonic-gate 	  doit:
3650Sstevel@tonic-gate 	    savec = *pm;
3660Sstevel@tonic-gate 	    *pm = 0;
3670Sstevel@tonic-gate 	    if (lm + strlen(pl) + strlen(pe + 1) >= restbufend)
3680Sstevel@tonic-gate 		return (0);
3690Sstevel@tonic-gate 	    (void) strlcpy(lm, pl, restbufend - lm);
3700Sstevel@tonic-gate 	    (void) strlcat(restbuf, pe + 1, sizeof(restbuf));
3710Sstevel@tonic-gate 	    *pm = savec;
3720Sstevel@tonic-gate 	    if (s == 0) {
3730Sstevel@tonic-gate 		sgpathp = gpathp;
3740Sstevel@tonic-gate 		expand(restbuf);
3750Sstevel@tonic-gate 		gpathp = sgpathp;
3760Sstevel@tonic-gate 		*gpathp = 0;
3770Sstevel@tonic-gate 	    }
3780Sstevel@tonic-gate 	    else if (amatch(s, restbuf))
3790Sstevel@tonic-gate 		return (1);
3800Sstevel@tonic-gate 	    sort();
3810Sstevel@tonic-gate 	    pl = pm + 1;
3820Sstevel@tonic-gate 	    continue;
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	case '[':
3850Sstevel@tonic-gate 	    for (pm++; *pm && *pm != ']'; pm++)
3860Sstevel@tonic-gate 		continue;
3870Sstevel@tonic-gate 	    if (!*pm) {
3880Sstevel@tonic-gate 		globerr = "Missing ]";
3890Sstevel@tonic-gate 		return (0);
3900Sstevel@tonic-gate 	    }
3910Sstevel@tonic-gate 	    continue;
3920Sstevel@tonic-gate 	}
3930Sstevel@tonic-gate     }
3940Sstevel@tonic-gate     return (0);
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate static int match(char *s, char *p)
3980Sstevel@tonic-gate {
3990Sstevel@tonic-gate     register int c;
4000Sstevel@tonic-gate     register char *sentp;
4010Sstevel@tonic-gate     char sglobbed = globbed;
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate     if (*s == '.' && *p != '.')
4040Sstevel@tonic-gate 	return (0);
4050Sstevel@tonic-gate     sentp = entp;
4060Sstevel@tonic-gate     entp = s;
4070Sstevel@tonic-gate     c = amatch(s, p);
4080Sstevel@tonic-gate     entp = sentp;
4090Sstevel@tonic-gate     globbed = sglobbed;
4100Sstevel@tonic-gate     return (c);
4110Sstevel@tonic-gate }
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate static int amatch(char *s, char *p)
4140Sstevel@tonic-gate {
4150Sstevel@tonic-gate     register int scc;
4160Sstevel@tonic-gate     int ok, lc;
4170Sstevel@tonic-gate     char *sgpathp;
4180Sstevel@tonic-gate     struct stat stb;
4190Sstevel@tonic-gate     int c, cc;
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate     globbed = 1;
4220Sstevel@tonic-gate     for (;;) {
4230Sstevel@tonic-gate 	scc = *s++ & TRIM;
4240Sstevel@tonic-gate 	switch (c = *p++) {
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	case '{':
4270Sstevel@tonic-gate 	    return (execbrc(p - 1, s - 1));
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	case '[':
4300Sstevel@tonic-gate 	    ok = 0;
4310Sstevel@tonic-gate 	    lc = 077777;
4320Sstevel@tonic-gate 	    while ((cc = *p++)) {
4330Sstevel@tonic-gate 		if (cc == ']') {
4340Sstevel@tonic-gate 		    if (ok)
4350Sstevel@tonic-gate 			break;
4360Sstevel@tonic-gate 		    return (0);
4370Sstevel@tonic-gate 		}
4380Sstevel@tonic-gate 		if (cc == '-') {
4390Sstevel@tonic-gate 		    if (lc <= scc && scc <= *p++)
4400Sstevel@tonic-gate 			ok++;
4410Sstevel@tonic-gate 		}
4420Sstevel@tonic-gate 		else if (scc == (lc = cc))
4430Sstevel@tonic-gate 		    ok++;
4440Sstevel@tonic-gate 	    }
4450Sstevel@tonic-gate 	    if (cc == 0) {
4460Sstevel@tonic-gate 		globerr = "Missing ]";
4470Sstevel@tonic-gate 		return (0);
4480Sstevel@tonic-gate 	    }
4490Sstevel@tonic-gate 	    continue;
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	case '*':
4520Sstevel@tonic-gate 	    if (!*p)
4530Sstevel@tonic-gate 		return (1);
4540Sstevel@tonic-gate 	    if (*p == '/') {
4550Sstevel@tonic-gate 		p++;
4560Sstevel@tonic-gate 		goto slash;
4570Sstevel@tonic-gate 	    } else if (*p == '*') {
4580Sstevel@tonic-gate 		s--;
4590Sstevel@tonic-gate 		continue;
4600Sstevel@tonic-gate 	    }
4610Sstevel@tonic-gate 	    s--;
4620Sstevel@tonic-gate 	    do {
4630Sstevel@tonic-gate 		if (amatch(s, p))
4640Sstevel@tonic-gate 		    return (1);
4650Sstevel@tonic-gate 	    } while (*s++);
4660Sstevel@tonic-gate 	    return (0);
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	case 0:
4690Sstevel@tonic-gate 	    return (scc == 0);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	default:
4720Sstevel@tonic-gate 	    if (c != scc)
4730Sstevel@tonic-gate 		return (0);
4740Sstevel@tonic-gate 	    continue;
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	case '?':
4770Sstevel@tonic-gate 	    if (scc == 0)
4780Sstevel@tonic-gate 		return (0);
4790Sstevel@tonic-gate 	    continue;
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	case '/':
4820Sstevel@tonic-gate 	    if (scc)
4830Sstevel@tonic-gate 		return (0);
4840Sstevel@tonic-gate 	  slash:
4850Sstevel@tonic-gate 	    s = entp;
4860Sstevel@tonic-gate 	    sgpathp = gpathp;
4870Sstevel@tonic-gate 	    while (*s)
4880Sstevel@tonic-gate 		addpath(*s++);
4890Sstevel@tonic-gate 	    addpath('/');
4900Sstevel@tonic-gate 	    if (stat(gpath, &stb) == 0 && isdir(stb))
4910Sstevel@tonic-gate 		if (*p == 0) {
4920Sstevel@tonic-gate 		    Gcat(gpath, "");
4930Sstevel@tonic-gate 		    globcnt++;
4940Sstevel@tonic-gate 		}
4950Sstevel@tonic-gate 		else
4960Sstevel@tonic-gate 		    expand(p);
4970Sstevel@tonic-gate 	    gpathp = sgpathp;
4980Sstevel@tonic-gate 	    *gpathp = 0;
4990Sstevel@tonic-gate 	    return (0);
5000Sstevel@tonic-gate 	}
5010Sstevel@tonic-gate     }
5020Sstevel@tonic-gate }
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate static void Gcat(register char *s1, register char *s2)
5050Sstevel@tonic-gate {
5060Sstevel@tonic-gate     register size_t len = strlen(s1) + strlen(s2) + 1;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate     if (globerr)
5090Sstevel@tonic-gate 	return;
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate     if ((len + sizeof (char *)) >= gnleft) {
5120Sstevel@tonic-gate 	globerr = "Arguments too long";
5130Sstevel@tonic-gate 	return;
5140Sstevel@tonic-gate     }
5150Sstevel@tonic-gate     if (len > MAXPATHLEN) {
5160Sstevel@tonic-gate 	globerr = "Pathname too long";
5170Sstevel@tonic-gate 	return;
5180Sstevel@tonic-gate     }
5190Sstevel@tonic-gate     if (gargc >= agargv_size - 1) {
5200Sstevel@tonic-gate 	char **tmp;
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	tmp = (char **)realloc(agargv,
5230Sstevel@tonic-gate 		(agargv_size + GAVSIZ) * sizeof (char *));
5240Sstevel@tonic-gate 	if (tmp == NULL) {
5250Sstevel@tonic-gate 	    fatal("Out of memory");
5260Sstevel@tonic-gate 	} else {
5270Sstevel@tonic-gate 	    agargv = tmp;
5280Sstevel@tonic-gate 	    agargv_size += GAVSIZ;
5290Sstevel@tonic-gate 	}
5300Sstevel@tonic-gate 	gargv = agargv;
5310Sstevel@tonic-gate 	sortbas = agargv;
5320Sstevel@tonic-gate     }
5330Sstevel@tonic-gate     gargc++;
5340Sstevel@tonic-gate     gnleft -= len + sizeof (char *);
5350Sstevel@tonic-gate     gargv[gargc] = 0;
5360Sstevel@tonic-gate     gargv[gargc - 1] = strspl(s1, s2);
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate static void addpath(char c)
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate     if (gpathp >= lastgpathp)
5430Sstevel@tonic-gate 	globerr = "Pathname too long";
5440Sstevel@tonic-gate     else {
5450Sstevel@tonic-gate 	*gpathp++ = c;
5460Sstevel@tonic-gate 	*gpathp = 0;
5470Sstevel@tonic-gate     }
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate static void rscan(register char **t, int (*f) (register char))
5510Sstevel@tonic-gate {
5520Sstevel@tonic-gate     register char *p, c;
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate     while ((p = *t++)) {
5550Sstevel@tonic-gate 	if (*p == '~')
5560Sstevel@tonic-gate 	    gflag |= 2;
5570Sstevel@tonic-gate 	else if (eq(p, "{") || eq(p, "{}"))
5580Sstevel@tonic-gate 	    continue;
5590Sstevel@tonic-gate 	while ((c = *p++))
5600Sstevel@tonic-gate 	    (*f) (c);
5610Sstevel@tonic-gate     }
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate static int tglob(register char c)
5640Sstevel@tonic-gate {
5650Sstevel@tonic-gate     if (any(c, globchars))
5660Sstevel@tonic-gate 	gflag |= c == '{' ? 2 : 1;
5670Sstevel@tonic-gate     return (c);
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate int letter(register char c)
5710Sstevel@tonic-gate {
5720Sstevel@tonic-gate     return (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))
5730Sstevel@tonic-gate 	    || (c == '_'));
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate int digit(register char c)
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate     return (c >= '0' && c <= '9');
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate int any(register int c, register char *s)
5820Sstevel@tonic-gate {
5830Sstevel@tonic-gate     while (*s)
5840Sstevel@tonic-gate 	if (*s++ == c)
5850Sstevel@tonic-gate 	    return (1);
5860Sstevel@tonic-gate     return (0);
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate int blklen(register char **av)
5900Sstevel@tonic-gate {
5910Sstevel@tonic-gate     register int i = 0;
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate     while (*av++)
5940Sstevel@tonic-gate 	i++;
5950Sstevel@tonic-gate     return (i);
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate char **blkcpy(char **oav, register char **bv)
5990Sstevel@tonic-gate {
6000Sstevel@tonic-gate     register char **av = oav;
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate     while ((*av++ = *bv++))
6030Sstevel@tonic-gate 	continue;
6040Sstevel@tonic-gate     return (oav);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate void blkfree(char **av0)
6080Sstevel@tonic-gate {
6090Sstevel@tonic-gate     register char **av = av0;
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate     if (av) {
6120Sstevel@tonic-gate 	while (*av)
6130Sstevel@tonic-gate 	    free(*av++);
6140Sstevel@tonic-gate     }
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate char *strspl(register char *cp, register char *dp)
6180Sstevel@tonic-gate {
6190Sstevel@tonic-gate     int bufsize = strlen(cp) + strlen(dp) + 1;
6200Sstevel@tonic-gate     char *ep = malloc(bufsize);
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate     if (ep == NULL)
6230Sstevel@tonic-gate 	fatal("Out of memory");
6240Sstevel@tonic-gate     (void) strlcpy(ep, cp, bufsize);
6250Sstevel@tonic-gate     (void) strlcat(ep, dp, bufsize);
6260Sstevel@tonic-gate     return (ep);
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate char **copyblk(register char **v)
6300Sstevel@tonic-gate {
6310Sstevel@tonic-gate     register char **nv = (char **) malloc((unsigned) ((blklen(v) + 1) *
6320Sstevel@tonic-gate 						      sizeof(char **)));
6330Sstevel@tonic-gate     if (nv == (char **) 0)
6340Sstevel@tonic-gate 	fatal("Out of memory");
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate     return (blkcpy(nv, v));
6370Sstevel@tonic-gate }
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate static char *strend(register char *cp)
6400Sstevel@tonic-gate {
6410Sstevel@tonic-gate     while (*cp)
6420Sstevel@tonic-gate 	cp++;
6430Sstevel@tonic-gate     return (cp);
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate /*
6460Sstevel@tonic-gate  * Extract a home directory from the password file
6470Sstevel@tonic-gate  * The argument points to a buffer where the name of the
6480Sstevel@tonic-gate  * user whose home directory is sought is currently.
6490Sstevel@tonic-gate  * We write the home directory of the user back there.
6500Sstevel@tonic-gate  */
6510Sstevel@tonic-gate static int gethdir(char *home)
6520Sstevel@tonic-gate {
6530Sstevel@tonic-gate #ifdef OTHER_PASSWD
6540Sstevel@tonic-gate     register struct passwd *pp = bero_getpwnam(home, _path_passwd);
6550Sstevel@tonic-gate #else
6560Sstevel@tonic-gate     register struct passwd *pp = getpwnam(home);
6570Sstevel@tonic-gate #endif
6580Sstevel@tonic-gate     register char *root = NULL;
6590Sstevel@tonic-gate     if (!pp || home + strlen(pp->pw_dir) >= lastgpathp)
6600Sstevel@tonic-gate 	return (1);
6610Sstevel@tonic-gate     root = strstr(pp->pw_dir, "/./");
6620Sstevel@tonic-gate     (void) strlcpy(home, root ? (root + 2) : pp->pw_dir, lastgpathp - home);
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate     return (0);
6650Sstevel@tonic-gate }
666