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

📄 server.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 1983, 1993 *	The Regents of the University of California.  All rights reserved. * * 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. */#ifndef lintstatic char sccsid[] = "@(#)server.c	8.1 (Berkeley) 6/9/93";#endif /* not lint */#include <sys/wait.h>#include "defs.h"#define	ack() 	(void) write(rem, "\0\n", 2)#define	err() 	(void) write(rem, "\1\n", 2)struct	linkbuf *ihead;		/* list of files with more than one link */char	buf[BUFSIZ];		/* general purpose buffer */char	target[BUFSIZ];		/* target/source directory name */char	*tp;			/* pointer to end of target name */char	*Tdest;			/* pointer to last T dest*/int	catname;		/* cat name to target name */char	*stp[32];		/* stack of saved tp's for directories */int	oumask;			/* old umask for creating files */extern	FILE *lfp;		/* log file for mailing changes */static int	chkparent __P((char *));static void	clean __P((char *));static void	comment __P((char *));static void	dospecial __P((char *));static int	fchog __P((int, char *, char *, char *, int));static void	hardlink __P((char *));static void	note __P((const char *, ...));static void	query __P((char *));static void	recvf __P((char *, int));static void	removeit __P((struct stat *));static int	response __P((void));static void	rmchk __P((int));static struct linkbuf *		    savelink __P((struct stat *));static void	sendf __P((char *, int));static int	update __P((char *, int, struct stat *));/* * Server routine to read requests and process them. * Commands are: *	Tname	- Transmit file if out of date *	Vname	- Verify if file out of date or not *	Qname	- Query if file exists. Return mtime & size if it does. */voidserver(){	char cmdbuf[BUFSIZ];	register char *cp;	signal(SIGHUP, cleanup);	signal(SIGINT, cleanup);	signal(SIGQUIT, cleanup);	signal(SIGTERM, cleanup);	signal(SIGPIPE, cleanup);	rem = 0;	oumask = umask(0);	(void) sprintf(buf, "V%d\n", VERSION);	(void) write(rem, buf, strlen(buf));	for (;;) {		cp = cmdbuf;		if (read(rem, cp, 1) <= 0)			return;		if (*cp++ == '\n') {			error("server: expected control record\n");			continue;		}		do {			if (read(rem, cp, 1) != 1)				cleanup(0);		} while (*cp++ != '\n' && cp < &cmdbuf[BUFSIZ]);		*--cp = '\0';		cp = cmdbuf;		switch (*cp++) {		case 'T':  /* init target file/directory name */			catname = 1;	/* target should be directory */			goto dotarget;		case 't':  /* init target file/directory name */			catname = 0;		dotarget:			if (exptilde(target, cp) == NULL)				continue;			tp = target;			while (*tp)				tp++;			ack();			continue;		case 'R':  /* Transfer a regular file. */			recvf(cp, S_IFREG);			continue;		case 'D':  /* Transfer a directory. */			recvf(cp, S_IFDIR);			continue;		case 'K':  /* Transfer symbolic link. */			recvf(cp, S_IFLNK);			continue;		case 'k':  /* Transfer hard link. */			hardlink(cp);			continue;		case 'E':  /* End. (of directory) */			*tp = '\0';			if (catname <= 0) {				error("server: too many 'E's\n");				continue;			}			tp = stp[--catname];			*tp = '\0';			ack();			continue;		case 'C':  /* Clean. Cleanup a directory */			clean(cp);			continue;		case 'Q':  /* Query. Does the file/directory exist? */			query(cp);			continue;		case 'S':  /* Special. Execute commands */			dospecial(cp);			continue;#ifdef notdef		/*		 * These entries are reserved but not currently used.		 * The intent is to allow remote hosts to have master copies.		 * Currently, only the host rdist runs on can have masters.		 */		case 'X':  /* start a new list of files to exclude */			except = bp = NULL;		case 'x':  /* add name to list of files to exclude */			if (*cp == '\0') {				ack();				continue;			}			if (*cp == '~') {				if (exptilde(buf, cp) == NULL)					continue;				cp = buf;			}			if (bp == NULL)				except = bp = expand(makeblock(NAME, cp), E_VARS);			else				bp->b_next = expand(makeblock(NAME, cp), E_VARS);			while (bp->b_next != NULL)				bp = bp->b_next;			ack();			continue;		case 'I':  /* Install. Transfer file if out of date. */			opts = 0;			while (*cp >= '0' && *cp <= '7')				opts = (opts << 3) | (*cp++ - '0');			if (*cp++ != ' ') {				error("server: options not delimited\n");				return;			}			install(cp, opts);			continue;		case 'L':  /* Log. save message in log file */			log(lfp, cp);			continue;#endif		case '\1':			nerrs++;			continue;		case '\2':			return;		default:			error("server: unknown command '%s'\n", cp);		case '\0':			continue;		}	}}/* * Update the file(s) if they are different. * destdir = 1 if destination should be a directory * (i.e., more than one source is being copied to the same destination). */voidinstall(src, dest, destdir, opts)	char *src, *dest;	int destdir, opts;{	char *rname;	char destcopy[BUFSIZ];	if (dest == NULL) {		opts &= ~WHOLE; /* WHOLE mode only useful if renaming */		dest = src;	}	if (nflag || debug) {		printf("%s%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install",			opts & WHOLE ? " -w" : "",			opts & YOUNGER ? " -y" : "",			opts & COMPARE ? " -b" : "",			opts & REMOVE ? " -R" : "", src, dest);		if (nflag)			return;	}	rname = exptilde(target, src);	if (rname == NULL)		return;	tp = target;	while (*tp)		tp++;	/*	 * If we are renaming a directory and we want to preserve	 * the directory heirarchy (-w), we must strip off the leading	 * directory name and preserve the rest.	 */	if (opts & WHOLE) {		while (*rname == '/')			rname++;		destdir = 1;	} else {		rname = rindex(target, '/');		if (rname == NULL)			rname = target;		else			rname++;	}	if (debug)		printf("target = %s, rname = %s\n", target, rname);	/*	 * Pass the destination file/directory name to remote.	 */	(void) sprintf(buf, "%c%s\n", destdir ? 'T' : 't', dest);	if (debug)		printf("buf = %s", buf);	(void) write(rem, buf, strlen(buf));	if (response() < 0)		return;	if (destdir) {		strcpy(destcopy, dest);		Tdest = destcopy;	}	sendf(rname, opts);	Tdest = 0;}#define protoname() (pw ? pw->pw_name : user)#define protogroup() (gr ? gr->gr_name : group)/* * Transfer the file or directory in target[]. * rname is the name of the file on the remote host. */static voidsendf(rname, opts)	char *rname;	int opts;{	register struct subcmd *sc;	struct stat stb;	int sizerr, f, u, len;	off_t i;	DIR *d;	struct direct *dp;	char *otp, *cp;	extern struct subcmd *subcmds;	static char user[15], group[15];	if (debug)		printf("sendf(%s, %x)\n", rname, opts);	if (except(target))		return;	if ((opts & FOLLOW ? stat(target, &stb) : lstat(target, &stb)) < 0) {		error("%s: %s\n", target, strerror(errno));		return;	}	if ((u = update(rname, opts, &stb)) == 0) {		if ((stb.st_mode & S_IFMT) == S_IFREG && stb.st_nlink > 1)			(void) savelink(&stb);		return;	}	if (pw == NULL || pw->pw_uid != stb.st_uid)		if ((pw = getpwuid(stb.st_uid)) == NULL) {			log(lfp, "%s: no password entry for uid %d \n",				target, stb.st_uid);			pw = NULL;			(void)sprintf(user, ":%lu", stb.st_uid);		}	if (gr == NULL || gr->gr_gid != stb.st_gid)		if ((gr = getgrgid(stb.st_gid)) == NULL) {			log(lfp, "%s: no name for group %d\n",				target, stb.st_gid);			gr = NULL;			(void)sprintf(group, ":%lu", stb.st_gid);		}	if (u == 1) {		if (opts & VERIFY) {			log(lfp, "need to install: %s\n", target);			goto dospecial;		}		log(lfp, "installing: %s\n", target);		opts &= ~(COMPARE|REMOVE);	}	switch (stb.st_mode & S_IFMT) {	case S_IFDIR:		if ((d = opendir(target)) == NULL) {			error("%s: %s\n", target, strerror(errno));			return;		}		(void) sprintf(buf, "D%o %04o 0 0 %s %s %s\n", opts,			stb.st_mode & 07777, protoname(), protogroup(), rname);		if (debug)			printf("buf = %s", buf);		(void) write(rem, buf, strlen(buf));		if (response() < 0) {			closedir(d);			return;		}		if (opts & REMOVE)			rmchk(opts);		otp = tp;		len = tp - target;		while (dp = readdir(d)) {			if (!strcmp(dp->d_name, ".") ||			    !strcmp(dp->d_name, ".."))				continue;			if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {				error("%s/%s: Name too long\n", target,					dp->d_name);				continue;			}			tp = otp;			*tp++ = '/';			cp = dp->d_name;			while (*tp++ = *cp++)				;			tp--;			sendf(dp->d_name, opts);		}		closedir(d);		(void) write(rem, "E\n", 2);		(void) response();		tp = otp;		*tp = '\0';		return;	case S_IFLNK:		if (u != 1)			opts |= COMPARE;		if (stb.st_nlink > 1) {			struct linkbuf *lp;			if ((lp = savelink(&stb)) != NULL) {				/* install link */				if (*lp->target == 0)				(void) sprintf(buf, "k%o %s %s\n", opts,					lp->pathname, rname);				else				(void) sprintf(buf, "k%o %s/%s %s\n", opts,					lp->target, lp->pathname, rname);				if (debug)					printf("buf = %s", buf);				(void) write(rem, buf, strlen(buf));				(void) response();				return;			}		}		(void) sprintf(buf, "K%o %o %qd %ld %s %s %s\n", opts,			stb.st_mode & 07777, stb.st_size, stb.st_mtime,			protoname(), protogroup(), rname);		if (debug)			printf("buf = %s", buf);		(void) write(rem, buf, strlen(buf));		if (response() < 0)			return;		sizerr = (readlink(target, buf, BUFSIZ) != stb.st_size);		(void) write(rem, buf, stb.st_size);		if (debug)			printf("readlink = %.*s\n", (int)stb.st_size, buf);		goto done;	case S_IFREG:		break;	default:		error("%s: not a file or directory\n", target);		return;	}	if (u == 2) {		if (opts & VERIFY) {			log(lfp, "need to update: %s\n", target);			goto dospecial;		}		log(lfp, "updating: %s\n", target);	}	if (stb.st_nlink > 1) {		struct linkbuf *lp;		if ((lp = savelink(&stb)) != NULL) {			/* install link */			if (*lp->target == 0)			(void) sprintf(buf, "k%o %s %s\n", opts,				lp->pathname, rname);			else			(void) sprintf(buf, "k%o %s/%s %s\n", opts,				lp->target, lp->pathname, rname);			if (debug)				printf("buf = %s", buf);			(void) write(rem, buf, strlen(buf));			(void) response();			return;		}	}	if ((f = open(target, O_RDONLY, 0)) < 0) {		error("%s: %s\n", target, strerror(errno));		return;	}	(void) sprintf(buf, "R%o %o %qd %ld %s %s %s\n", opts,		stb.st_mode & 07777, stb.st_size, stb.st_mtime,		protoname(), protogroup(), rname);	if (debug)		printf("buf = %s", buf);	(void) write(rem, buf, strlen(buf));	if (response() < 0) {		(void) close(f);		return;	}	sizerr = 0;	for (i = 0; i < stb.st_size; i += BUFSIZ) {		int amt = BUFSIZ;		if (i + amt > stb.st_size)			amt = stb.st_size - i;		if (sizerr == 0 && read(f, buf, amt) != amt)			sizerr = 1;		(void) write(rem, buf, amt);	}	(void) close(f);done:	if (sizerr) {		error("%s: file changed size\n", target);		err();	} else		ack();	f = response();	if (f < 0 || f == 0 && (opts & COMPARE))		return;dospecial:	for (sc = subcmds; sc != NULL; sc = sc->sc_next) {		if (sc->sc_type != SPECIAL)			continue;		if (sc->sc_args != NULL && !inlist(sc->sc_args, target))			continue;		log(lfp, "special \"%s\"\n", sc->sc_name);		if (opts & VERIFY)			continue;		(void) sprintf(buf, "SFILE=%s;%s\n", target, sc->sc_name);		if (debug)			printf("buf = %s", buf);		(void) write(rem, buf, strlen(buf));		while (response() > 0)			;	}}static struct linkbuf *savelink(stp)	struct stat *stp;{	struct linkbuf *lp;	for (lp = ihead; lp != NULL; lp = lp->nextp)		if (lp->inum == stp->st_ino && lp->devnum == stp->st_dev) {			lp->count--;			return(lp);		}	lp = (struct linkbuf *) malloc(sizeof(*lp));

⌨️ 快捷键说明

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