⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 getcap.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1992, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * Casey Leedom of Lawrence Livermore National Laboratory. * * 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. */#if defined(LIBC_SCCS) && !defined(lint)static char sccsid[] = "@(#)getcap.c	8.3 (Berkeley) 3/25/94";#endif /* LIBC_SCCS and not lint */#include <sys/types.h>#include <ctype.h>#include <db.h>#include <errno.h>	#include <fcntl.h>#include <limits.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#define	BFRAG		1024#define	BSIZE		1024#define	ESC		('[' & 037)	/* ASCII ESC */#define	MAX_RECURSION	32		/* maximum getent recursion */#define	SFRAG		100		/* cgetstr mallocs in SFRAG chunks */#define RECOK	(char)0#define TCERR	(char)1#define	SHADOW	(char)2static size_t	 topreclen;	/* toprec length */static char	*toprec;	/* Additional record specified by cgetset() */static int	 gottoprec;	/* Flag indicating retrieval of toprecord */static int	cdbget __P((DB *, char **, char *));static int 	getent __P((char **, u_int *, char **, int, char *, int, char *));static int	nfcmp __P((char *, char *));/* * Cgetset() allows the addition of a user specified buffer to be added * to the database array, in effect "pushing" the buffer on top of the * virtual database. 0 is returned on success, -1 on failure. */intcgetset(ent)	char *ent;{	if (ent == NULL) {		if (toprec)			free(toprec);                toprec = NULL;                topreclen = 0;                return (0);        }        topreclen = strlen(ent);        if ((toprec = malloc (topreclen + 1)) == NULL) {		errno = ENOMEM;                return (-1);	}	gottoprec = 0;        (void)strcpy(toprec, ent);        return (0);}/* * Cgetcap searches the capability record buf for the capability cap with * type `type'.  A pointer to the value of cap is returned on success, NULL * if the requested capability couldn't be found. * * Specifying a type of ':' means that nothing should follow cap (:cap:). * In this case a pointer to the terminating ':' or NUL will be returned if * cap is found. * * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator) * return NULL. */char *cgetcap(buf, cap, type)	char *buf, *cap;	int type;{	register char *bp, *cp;	bp = buf;	for (;;) {		/*		 * Skip past the current capability field - it's either the		 * name field if this is the first time through the loop, or		 * the remainder of a field whose name failed to match cap.		 */		for (;;)			if (*bp == '\0')				return (NULL);			else				if (*bp++ == ':')					break;		/*		 * Try to match (cap, type) in buf.		 */		for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++)			continue;		if (*cp != '\0')			continue;		if (*bp == '@')			return (NULL);		if (type == ':') {			if (*bp != '\0' && *bp != ':')				continue;			return(bp);		}		if (*bp != type)			continue;		bp++;		return (*bp == '@' ? NULL : bp);	}	/* NOTREACHED */}/* * Cgetent extracts the capability record name from the NULL terminated file * array db_array and returns a pointer to a malloc'd copy of it in buf. * Buf must be retained through all subsequent calls to cgetcap, cgetnum, * cgetflag, and cgetstr, but may then be free'd.  0 is returned on success, * -1 if the requested record couldn't be found, -2 if a system error was * encountered (couldn't open/read a file, etc.), and -3 if a potential * reference loop is detected. */intcgetent(buf, db_array, name)	char **buf, **db_array, *name;{	u_int dummy;	return (getent(buf, &dummy, db_array, -1, name, 0, NULL));}/* * Getent implements the functions of cgetent.  If fd is non-negative, * *db_array has already been opened and fd is the open file descriptor.  We * do this to save time and avoid using up file descriptors for tc= * recursions. * * Getent returns the same success/failure codes as cgetent.  On success, a * pointer to a malloc'ed capability record with all tc= capabilities fully * expanded and its length (not including trailing ASCII NUL) are left in * *cap and *len. * * Basic algorithm: *	+ Allocate memory incrementally as needed in chunks of size BFRAG *	  for capability buffer. *	+ Recurse for each tc=name and interpolate result.  Stop when all *	  names interpolated, a name can't be found, or depth exceeds *	  MAX_RECURSION. */static intgetent(cap, len, db_array, fd, name, depth, nfield)	char **cap, **db_array, *name, *nfield;	u_int *len;	int fd, depth;{	DB *capdbp;	DBT key, data;	register char *r_end, *rp, **db_p;	int myfd, eof, foundit, retval, clen;	char *record, *cbuf;	int tc_not_resolved;	char pbuf[_POSIX_PATH_MAX];		/*	 * Return with ``loop detected'' error if we've recursed more than	 * MAX_RECURSION times.	 */	if (depth > MAX_RECURSION)		return (-3);	/*	 * Check if we have a top record from cgetset().         */	if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) {		if ((record = malloc (topreclen + BFRAG)) == NULL) {			errno = ENOMEM;			return (-2);		}		(void)strcpy(record, toprec);		myfd = 0;		db_p = db_array;		rp = record + topreclen + 1;		r_end = rp + BFRAG;		goto tc_exp;	}	/*	 * Allocate first chunk of memory.	 */	if ((record = malloc(BFRAG)) == NULL) {		errno = ENOMEM;		return (-2);	}	r_end = record + BFRAG;	foundit = 0;	/*	 * Loop through database array until finding the record.	 */	for (db_p = db_array; *db_p != NULL; db_p++) {		eof = 0;		/*		 * Open database if not already open.		 */		if (fd >= 0) {			(void)lseek(fd, (off_t)0, L_SET);			myfd = 0;		} else {			(void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p);			if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0))			     != NULL) {				free(record);				retval = cdbget(capdbp, &record, name);				if (retval < 0) {					/* no record available */					(void)capdbp->close(capdbp);					return (retval);				}				/* save the data; close frees it */				clen = strlen(record);				cbuf = malloc(clen + 1);				memcpy(cbuf, record, clen + 1);				if (capdbp->close(capdbp) < 0) {					free(cbuf);					return (-2);				}				*len = clen;				*cap = cbuf;				return (retval);			} else {				fd = open(*db_p, O_RDONLY, 0);				if (fd < 0) {					/* No error on unfound file. */					if (errno == ENOENT)						continue;					free(record);					return (-2);				}				myfd = 1;			}		}		/*		 * Find the requested capability record ...		 */		{		char buf[BUFSIZ];		register char *b_end, *bp;		register int c;		/*		 * Loop invariants:		 *	There is always room for one more character in record.		 *	R_end always points just past end of record.		 *	Rp always points just past last character in record.		 *	B_end always points just past last character in buf.		 *	Bp always points at next character in buf.		 */		b_end = buf;		bp = buf;		for (;;) {			/*			 * Read in a line implementing (\, newline)			 * line continuation.			 */			rp = record;			for (;;) {				if (bp >= b_end) {					int n;							n = read(fd, buf, sizeof(buf));					if (n <= 0) {						if (myfd)							(void)close(fd);						if (n < 0) {							free(record);							return (-2);						} else {							fd = -1;							eof = 1;							break;						}					}					b_end = buf+n;					bp = buf;				}					c = *bp++;				if (c == '\n') {					if (rp > record && *(rp-1) == '\\') {						rp--;						continue;					} else						break;				}				*rp++ = c;				/*				 * Enforce loop invariant: if no room 				 * left in record buffer, try to get				 * some more.				 */				if (rp >= r_end) {					u_int pos;					size_t newsize;					pos = rp - record;					newsize = r_end - record + BFRAG;					record = realloc(record, newsize);					if (record == NULL) {						errno = ENOMEM;						if (myfd)							(void)close(fd);						return (-2);					}					r_end = record + newsize;					rp = record + pos;				}			}				/* loop invariant let's us do this */			*rp++ = '\0';			/*			 * If encountered eof check next file.			 */			if (eof)				break;							/*			 * Toss blank lines and comments.			 */			if (*record == '\0' || *record == '#')				continue;				/*			 * See if this is the record we want ...			 */			if (cgetmatch(record, name) == 0) {				if (nfield == NULL || !nfcmp(nfield, record)) {					foundit = 1;					break;	/* found it! */				}			}		}	}		if (foundit)			break;	}	if (!foundit)		return (-1);	/*	 * Got the capability record, but now we have to expand all tc=name	 * references in it ...	 */tc_exp:	{		register char *newicap, *s;		register int newilen;		u_int ilen;		int diff, iret, tclen;		char *icap, *scan, *tc, *tcstart, *tcend;		/*		 * Loop invariants:		 *	There is room for one more character in record.		 *	R_end points just past end of record.		 *	Rp points just past last character in record.		 *	Scan points at remainder of record that needs to be		 *	scanned for tc=name constructs.		 */		scan = record;		tc_not_resolved = 0;		for (;;) {			if ((tc = cgetcap(scan, "tc", '=')) == NULL)				break;			/*			 * Find end of tc=name and stomp on the trailing `:'			 * (if present) so we can use it to call ourselves.			 */			s = tc;			for (;;)				if (*s == '\0')					break;				else					if (*s++ == ':') {						*(s - 1) = '\0';						break;					}			tcstart = tc - 3;			tclen = s - tcstart;			tcend = s;			iret = getent(&icap, &ilen, db_p, fd, tc, depth+1, 				      NULL);			newicap = icap;		/* Put into a register. */			newilen = ilen;			if (iret != 0) {				/* an error */				if (iret < -1) {					if (myfd)						(void)close(fd);					free(record);					return (iret);				}				if (iret == 1)					tc_not_resolved = 1;				/* couldn't resolve tc */				if (iret == -1) {					*(s - 1) = ':';								scan = s - 1;					tc_not_resolved = 1;					continue;									}			}			/* not interested in name field of tc'ed record */			s = newicap;			for (;;)				if (*s == '\0')					break;				else					if (*s++ == ':')						break;			newilen -= s - newicap;			newicap = s;			/* make sure interpolated record is `:'-terminated */			s += newilen;			if (*(s-1) != ':') {				*s = ':';	/* overwrite NUL with : */				newilen++;			}			/*			 * Make sure there's enough room to insert the			 * new record.			 */			diff = newilen - tclen;			if (diff >= r_end - rp) {				u_int pos, tcpos, tcposend;				size_t newsize;				pos = rp - record;				newsize = r_end - record + diff + BFRAG;				tcpos = tcstart - record;				tcposend = tcend - record;				record = realloc(record, newsize);				if (record == NULL) {					errno = ENOMEM;					if (myfd)						(void)close(fd);					free(icap);					return (-2);				}				r_end = record + newsize;				rp = record + pos;				tcstart = record + tcpos;				tcend = record + tcposend;			}			/*			 * Insert tc'ed record into our record.			 */			s = tcstart + newilen;			bcopy(tcend, s, rp - tcend);			bcopy(newicap, tcstart, newilen);			rp += diff;			free(icap);			/*			 * Start scan on `:' so next cgetcap works properly			 * (cgetcap always skips first field).			 */			scan = s-1;		}		}	/*	 * Close file (if we opened it), give back any extra memory, and	 * return capability, length and success.	 */	if (myfd)		(void)close(fd);	*len = rp - record - 1;	/* don't count NUL */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -