DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T i

⟦2711d2f34⟧ TextFile

    Length: 11495 (0x2ce7)
    Types: TextFile
    Names: »install.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z« 
        └─⟦de7628f85⟧ 
            └─⟦this⟧ »isode-6.0/others/idist/install.c« 

TextFile

/* install.c - installation of files on remote host */

/*
 * $Header: /f/osi/others/idist/RCS/install.c,v 7.0 89/11/23 21:58:34 mrose Rel $
 *
 * Installation of files on remote host - the routines here drive the
 * protocol for installation, comparision and deletion etc. The
 * protocol is basically similar to the original rdist, except it is
 * fully client/server in this model with the daemon only responding
 * to requests. In the old version, the two sides occasionally swapped
 * around for some operations. Parts of this file were originally in
 * the file server.c.
 *
 * Julian Onions <jpo@cs.nott.ac.uk>
 * Nottingham University Computer Science
 * 
 *
 * $Log:	install.c,v $
 * Revision 7.0  89/11/23  21:58:34  mrose
 * Release 6.0
 * 
 */

/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#ifndef lint
static char sccsid[] = "@(#)server.c	5.3 (Berkeley) 6/7/86";
static char rcsid[] = "$Header: /f/osi/others/idist/RCS/install.c,v 7.0 89/11/23 21:58:34 mrose Rel $";
#endif

#include "defs.h"
#include <sys/file.h>

struct	linkbuf *ihead;		/* list of files with more than one link */
char	target[BUFSIZ];		/* target/source directory name */
char	basename[BUFSIZ];	/* base of directory operations */
char	*tp;			/* pointer to end of target name */
char	*Tdest;			/* pointer to last T dest*/
int	catname;		/* cat name to target name */
char	*stp[128];		/* stack of saved tp's for directories */
int	oumask;			/* old umask for creating files */
char	tranbuf[1024*8];	/* 8K at a time... */

extern	FILE *lfp;		/* log file for mailing changes */

int	cleanup();
struct	linkbuf *savelink();
extern char *getstring ();

/*
 * 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).
 */
install(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 %s\n",
		       opts & VERIFY ? "verify":"install",
		       opts & WHOLE ? " -w" : "",
		       opts & YOUNGER ? " -y" : "",
		       opts & COMPARE ? " -b" : "",
		       opts & REMOVE ? " -R" : "",
		       opts & QUERYM ? " -Q" : "", src, dest);
		if (nflag)
			return;
	}

	rname = exptilde(target, src);
	if (rname == NULL)
		return;
	tp = target;
	(void) strcpy (basename, 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) {
		rname = target;
		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.
	 */
	if (initdir (destdir, dest) < 0)
		return;

	(void) 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.
 */
sendf(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;
	char	buf[BUFSIZ];
	static char uname[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) {
		advise (target, "Can't stat");
		return;
	}
	if ((u = update(rname, opts, &stb)) == 0) {
		if ((stb.st_mode & S_IFMT) == S_IFREG && stb.st_nlink > 1)
			(void) savelink(&stb, opts);
		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 \n", target);
			pw = NULL;
			(void) sprintf(uname, ":%d", 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);
			gr = NULL;
			(void) sprintf(group, ":%d", stb.st_gid);
		}
	if (u == 1) {
#ifdef UW
		if (opts & NOINSTALL) {
			log(lfp, "does not exist, did not install: %s\n", target);
			goto dospecial;
		}
#endif UW
		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) {
			advise (target, "Can't open directory");
			return;
		}
		if (transfer (stb.st_mode & S_IFMT, opts,
			      stb.st_mode & 07777, (off_t)0, (time_t)0,
			      protoname (), protogroup (),
			      rname, "") < 0) {
			closedir (d);
			return;
		}

		if (opts & REMOVE)
			(void) 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) {
				advise (NULLCP, "%s/%s name too long",
					target, dp->d_name);
				continue;
			}
			tp = otp;
			*tp++ = '/';
			cp = dp->d_name;
			while (*tp++ = *cp++)
				;
			tp--;
			sendf(dp->d_name, opts);
		}
		closedir(d);
		(void) terminate (S_IFDIR, OK);
		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, opts)) != NULL) {
				if (*lp -> target == 0)
					(void) strcpy (buf, lp -> pathname);
				else	(void) sprintf (buf, "%s/%s",
							lp -> target,
							lp -> pathname);
				(void) transfer ((unsigned short)0, opts,
						 (unsigned short)0, (off_t)0,
						 (time_t)0, "", "",
						 rname, buf);
				return;
			}
		}
		sizerr = (readlink(target, buf, BUFSIZ) != stb.st_size);
		if (debug)
			printf("readlink = %.*s\n", stb.st_size, buf);
		if (transfer (stb.st_mode & S_IFMT, opts, stb.st_mode & 07777,
			      stb.st_size, stb.st_mtime,
			      protoname (), protogroup (), rname,
			      buf) < 0)
			return;
		goto done;

	case S_IFREG:
		break;

	default:
		advise (NULLCP, "%s: not a file or directory", 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, opts)) != NULL) {
			if (*lp -> target == 0)
				(void) strcpy (buf, lp -> pathname);
			else	(void) sprintf (buf, "%s/%s",
						lp -> target,
						lp -> pathname);
			(void) transfer ((unsigned short)0, opts,
					 (unsigned short)0, (off_t)0,
					 (time_t)0, "", "",
					 rname, buf);
			return;
		}
	}

	if ((f = open(target, O_RDONLY, 0)) < 0) {
		advise (target, "Can't open file");
		return;
	}
	if ( transfer ((unsigned short)S_IFREG, opts, stb.st_mode & 07777,
		       stb.st_size,
		       stb.st_mtime, protoname (), protogroup (),
		       rname, "") < 0) {
		(void) close (f);
		return;
	}
	sizerr = 0;
	for (i = 0; i < stb.st_size; i += sizeof tranbuf) {
		int amt = sizeof tranbuf;
		if (i + amt > stb.st_size)
			amt = stb.st_size - i;
		if (sizerr == 0 && read(f, tranbuf, amt) != amt)
			sizerr = 1;
		if (tran_data (tranbuf, amt) == NOTOK)
			break;
	}
	(void) close(f);
	if (sizerr) {
		advise (NULLCP, "%s: file changed size", target);
		if (terminate (S_IFREG, NOTOK) < 0)
			return;
	} else {
		if (terminate (S_IFREG, OK) < 0)
			return;
	}
done:
	if (opts & COMPARE)
		return;
dospecial:
	for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
		if (sc->sc_type != SPECIAL)
			continue;
#ifdef UW
		if (opts & NOINSTALL)  /* don't do specials associated with
					  non-installation notices */
			continue;
#endif UW
		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, "FILE=%s;export FILE;%s",
			       target, sc->sc_name);
		(void) runspecial (buf);
		
	}
}

struct linkbuf *
savelink(sp, opts)
struct stat *sp;
int	opts;
{
	struct linkbuf *lp;
	extern	char *makestr ();

	for (lp = ihead; lp != NULL; lp = lp->nextp)
		if (lp->inum == sp->st_ino && lp->devnum == sp->st_dev) {
			lp->count--;
			return(lp);
		}
	lp = (struct linkbuf *) malloc(sizeof(*lp));
	if (lp == NULL)
		log(lfp, "out of memory, link information lost\n");
	else {
		lp->nextp = ihead;
		ihead = lp;
		lp->inum = sp->st_ino;
		lp->devnum = sp->st_dev;
		lp->count = sp->st_nlink - 1;
		if (opts & WHOLE)
			lp->pathname = makestr (target);
		else {
			if (strncmp (target, basename, strlen(basename)) == 0)
				lp -> pathname = makestr (target +
							  strlen(basename) + 1);
			else
				lp -> pathname = makestr (target);
		}
				
		if (Tdest)
			lp->target = makestr (Tdest);
		else
			*lp->target = 0;
	}
	return(NULL);
}

update(rname, opts, sp)
	char *rname;
	int opts;
	struct stat *sp;
{
	off_t size;
	time_t mtime;
	unsigned short mode;
	int	retval;

	if (debug) 
		printf("update(%s, %x, %x)\n", rname, opts, sp);

	/*
	 * Check to see if the file exists on the remote machine.
	 */
	switch (retval = rquery (rname, &mtime, &size, &mode)) {
	    case DONE:  /* file doesn't exist so install it */
		if ((opts & QUERYM) && !query ("Install",
					       (sp ->st_mode & S_IFMT),
					       NULLCP))
			return 0;
		return(1);

	    case NOTOK:	/* something went wrong! */
		nerrs++;
		return(0);

	    case OK:
		break;

	    default:
		advise (NULLCP, "update: unexpected response %d", retval);
		return(0);
	}

	if (mode == S_IFDIR)
		return (2);

	if (opts & COMPARE) {
		if ((opts & QUERYM) && !query ("Compare and update", mode, NULLCP))
			return 0;
		return(3);
	}

	/*
	 * File needs to be updated?
	 */
	if (opts & YOUNGER) {
		if (sp->st_mtime == mtime)
			return(0);
		if (sp->st_mtime < mtime) {
			log(lfp, "Warning: %s: remote copy is newer\n", target);
			return(0);
		}
	} else if (sp->st_mtime == mtime && sp->st_size == size)
		return(0);
	if ((opts & QUERYM) && !query ("Update",
				       sp -> st_mode & S_IFMT, NULLCP))
		return 0;
	return(2);
}



/*VARARGS2*/
log(fp, fmt, a1, a2, a3)
	FILE *fp;
	char *fmt;
	int a1, a2, a3;
{
	/* Print changes locally if not quiet mode */
	if (!qflag)
		printf(fmt, a1, a2, a3);

	/* Save changes (for mailing) if really updating files */
	if (!(options & VERIFY) && fp != NULL)
		fprintf(fp, fmt, a1, a2, a3);
}

/*
 * Remove temporary files and do any cleanup operations before exiting.
 */
cleanup()
{
	(void) unlink(utmpfile);
	exit(1);
}

query (mess, mode, name)
int	mode;
char	*mess, *name;
{
	char	buf[BUFSIZ];
	char	*cp;

	switch (mode) {
	    case S_IFDIR:
		cp = "directory";
		break;
	    case 0:
	    case S_IFREG:
		cp = "file";
		break;
	    case S_IFLNK:
		cp = "symbolic link";
		break;
	    default:
		cp = "unknown file type";
		break;
	}

	(void) sprintf (buf, "%s %s %s? ", mess, cp,
			name == NULLCP ? target : name);
	for (;;) {
		cp = getstring (buf);
		if (cp == NULLCP)
			continue;
		if (*cp == 'y' || *cp == 'Y' || *cp == 'n' || *cp == 'N')
			break;
	}
	
	if (*cp == 'y' || *cp == 'Y')
		return 1;
	return 0;
}