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

⟦0135e4725⟧ TextFile

    Length: 13218 (0x33a2)
    Types: TextFile
    Names: »idistd2.c«

Derivation

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

TextFile

/* idistd2.c -- the non remote operations parts of the protocol */

/*
 * $Header: /f/osi/others/idist/RCS/idistd2.c,v 7.0 89/11/23 21:58:33 mrose Rel $
 *
 * Parts of the idist server which are not mixed up with remote
 * operations but depend on the defined types.
 *
 * Julian Onions <jpo@cs.nott.ac.uk>
 * Nottingham University Computer Science.
 *
 *
 * $Log:	idistd2.c,v $
 * Revision 7.0  89/11/23  21:58:33  mrose
 * Release 6.0
 * 
 */

#ifndef lint
static char *rcsid = "$Header: /f/osi/others/idist/RCS/idistd2.c,v 7.0 89/11/23 21:58:33 mrose Rel $";
#endif

#include "defs.h"
#include "Idist-types.h"

char	*tp, *stp[128];

extern	int catname;
extern	char	target[];
extern	FILE	*cfile;
extern	struct type_Idist_FileSpec *cfiletype;
extern	int oumask;
extern	char    utmpfile[];
extern	char    *tmpname;
extern	struct type_Idist_IA5List *ia5list;

static	char	*cannon ();
static	struct type_Idist_IA5List *str2ia5list ();
static	int compare ();
extern	struct type_Idist_FileSpec *makefs ();
extern	struct type_Idist_QueryResult *query ();
extern	struct type_Idist_FileList *do_listcdir ();

doexec (cmd)
char	*cmd;
{
	int fd[2], status, pid, i;
	char	buf[BUFSIZ];

	if (pipe(fd) < 0)
		return NOTOK;

	if ((pid = vfork ()) == 0) {
		/*
		 * Return everything the shell commands print.
		 */
		(void) close(0);
		(void) close(1);
		(void) close(2);
		(void) open("/dev/null", 0);
		(void) dup(fd[1]);
		(void) dup(fd[1]);
		(void) close(fd[0]);
		(void) close(fd[1]);
		execl("/bin/sh", "sh", "-c", cmd, 0);
		_exit(127);
	}
	if (pid == -1)
		return NOTOK;

	(void) close(fd[1]);

	while ((i = read(fd[0], buf, sizeof(buf))) > 0) {
		addtoia5 (buf, i);
	}

	while ((i = wait(&status)) != pid && i != -1)
		;
	if (i == -1)
		status = -1;
	(void) close(fd[0]);

	return OK;
}

do_symlink (fs)
struct type_Idist_FileSpec *fs;
{
	char	*new, old[BUFSIZ], *linkname;
	int	i;

	new = qb2str (fs -> filename);
	linkname = cannon (new);
	free (new);

	new = qb2str (fs -> linkname);
	(void) strcpy (old, new);
	free (new);

	
	if (symlink (old, linkname) < 0) {
		if (errno != ENOENT || chkparent (linkname) < 0 ||
		    symlink (old, linkname) < 0) {
			nadvise (linkname, "Can't symlink %s to", old);
			return NOTOK;
		}
	}

	if (bit_on (fs -> fileopts, bit_Idist_Options_compare)) {
		char	tbuf[BUFSIZ];

		if ((i = readlink (target, tbuf, BUFSIZ)) >= 0 &&
		    i == fs -> filesize &&
		    strncmp (old, tbuf, fs -> filesize) == 0) {
			(void) unlink (linkname);
			return OK;
		}
		if (bit_on (fs -> fileopts, bit_Idist_Options_verify)) {
			(void) unlink (linkname);
			note ("need to update: %s", target);
			return OK;
		}
	}

	if (rename (linkname, target) < 0) {
		nadvise (target, "can't rename %s to", linkname);
		(void) unlink (linkname);
		return NOTOK;
	}
	if (bit_on (fs -> fileopts, bit_Idist_Options_compare))
		note ("updated %s\n", target);
	return OK;
}

static	char	*cannon (name)
char	*name;
{
	static char	nname[BUFSIZ];
	char	*cp;
	extern	char	*tmpname;

	if (catname)
		(void) sprintf (tp, "/%s", name);
	if((cp = rindex (target, '/')) == NULL)
		(void) strcpy (nname, tmpname);
	else if (cp == target)
		(void) sprintf (nname, "/%s", tmpname);
	else {
		*cp = '\0';
		(void) sprintf (nname, "%s/%s", target, tmpname);
		*cp = '/';
	}
	return nname;
}

/*
 * Check to see if parent directory exists and create one if not.
 */
chkparent(name)
	char *name;
{
	register char *cp;
	struct stat stb;

	cp = rindex(name, '/');
	if (cp == NULL || cp == name)
		return(0);
	*cp = '\0';
	if (lstat(name, &stb) < 0) {
		if (errno == ENOENT && chkparent(name) >= 0 &&
		    mkdir(name, 0777 & ~oumask) >= 0) {
			*cp = '/';
			return(0);
		}
	} else if (ISDIR(stb.st_mode)) {
		*cp = '/';
		return(0);
	}
	*cp = '/';
	return(-1);
}

do_rfile (fs)
struct type_Idist_FileSpec *fs;
{
	char	*name, *p;

	p = qb2str (fs -> filename);
	name = cannon (p);
	free (p);

	if ((cfile = fopen (name, "w")) == NULL) {
		if (errno != ENOENT || chkparent (name) < 0 ||
		    (cfile = fopen (name, "w")) == NULL) {
			nadvise (name, "Can't create file");
			return NOTOK;
		}
	}
	(void) fchmod (fileno (cfile), fs -> filemode);

	return OK;
}

do_hardlink (fs)
struct type_Idist_FileSpec *fs;
{
	char 	*new;
	char	*cp;
	char	old[BUFSIZ];
	struct stat stb;
	int	exists = 0;

	new = qb2str (fs -> filename);
	cp = qb2str (fs -> linkname);
	if (exptilde (old, cp) == NULL) {
		free (cp);
		free (new);
		return NOTOK;
	}
	free (cp);

	if (catname)
		(void) sprintf (tp, "/%s", new);
	free (new);

	if (lstat(target, &stb) == 0) {
		int mode = stb.st_mode & S_IFMT;
		if (mode != S_IFREG && mode != S_IFLNK) {
			nadvise (NULLCP, "%s: not a regular file",
				 host, target);
			return NOTOK;
		}
		exists = 1;
	}
	if (chkparent(target) < 0 ) {
		nadvise("chkparent", "%s (no parent)", target);
		return NOTOK;
	}
	if (exists && (unlink(target) < 0)) {
		nadvise ("unlink", "%s", target);
		return NOTOK;
	}
	if (link(old, target) < 0) {
		nadvise (old,  "can't link %s to", target);
		return NOTOK;
	}
	return OK;
}

do_direct (fs)
struct type_Idist_FileSpec *fs;
{
	char	*cp, *name;
	struct stat stb;

	cp = name = qb2str (fs -> filename);

	if (catname >= sizeof(stp)) {
		nadvise (NULLCP, "Too many directory levels");
		free (name);
		return NOTOK;
	}

	stp[catname] = tp;
	if (catname++) {
		*tp ++ = '/';
		while (*tp++ = *cp ++)
			;
		tp --;
	}
	
	if (bit_on (fs -> fileopts, bit_Idist_Options_verify)) {
		free (name);
		return OK;
	}

	if (lstat (target, &stb) == 0) {
		if ((stb.st_mode & S_IFMT) == S_IFDIR) {
			if ((stb.st_mode & 07777) == fs -> filemode) {
				free (name);
				return OK;
			}
			note ("%s remote node %o != local mode %o",
			      target, stb.st_mode & 07777, fs -> filemode);
			free (name);
			return OK;
		}
		errno = ENOTDIR;
	}
	else if (errno == ENOENT && (mkdir (target, fs -> filemode) == 0 ||
				     chkparent (target) == 0 &&
				     mkdir (target, fs -> filemode) == 0)) {
		char *owner = qb2str (fs -> fileowner);
		char *group = qb2str (fs -> filegroup);

		if (chog (target, owner, group, fs -> filemode) == 0) {
			free (owner);
			free (group);
			free (name);
			return OK;
		}
		free (owner);
		free (group);
	}
	free (name);
	nadvise (target, "Can't install directory");
	tp = stp[--catname];
	*tp = '\0';
	return NOTOK;
}

/*
 * Remove a file or directory (recursively) and send back an acknowledge
 * or an error message.
 */
remove(str)
char	*str;
{
	DIR *d;
	struct direct *dp;
	struct stat stb;
	char	buf[BUFSIZ];
	int	result = OK;

	if (lstat (str, &stb) < 0) {
		nadvise (str, "Can't stat file");
		return NOTOK;
	}
	
	switch (stb.st_mode & S_IFMT) {
	case S_IFREG:
	case S_IFLNK:
		if (unlink(str) < 0) {
			nadvise (str, "Can't unlink");
			return NOTOK;
		}
		note ("removed: %s", str);
		return OK;

	case S_IFDIR:
		break;

	default:
		nadvise (NULLCP, "%s: not a plain file", target);
		return NOTOK;
	}

	if ((d = opendir(str)) == NULL) {
		nadvise (str, "Can't open directory");
		return NOTOK;
	}

	while (dp = readdir(d)) {
		if (strcmp(dp->d_name, ".") == 0 ||
		    strcmp(dp->d_name, "..") == 0)
			continue;
		(void) sprintf (buf, "%s/%s", str, dp -> d_name);
		result = remove(buf) == OK ? result : NOTOK;
	}
	closedir(d);
	if (rmdir(str) < 0) {
		nadvise (str, "Can't remove directory", str);
		return NOTOK;
	}
	note ("removed: %s", str);
	return result;
}


addtoia5 (str, len)
char	*str;
int	len;
{
	struct type_Idist_IA5List **ia5p;

	for (ia5p = &ia5list; *ia5p; ia5p = &(*ia5p) -> next)
		continue;

	*ia5p = str2ia5list (str, len);
}

struct type_Idist_QueryResult *query (str)
char	*str;
{
	struct type_Idist_QueryResult *qr;
	struct stat stb;

	qr = (struct type_Idist_QueryResult *) malloc (sizeof *qr);
	if (qr == NULL)
		adios ("memory", "out of");
	
	if (catname)
		(void) sprintf (tp, "/%s", str);

	if (lstat (target, &stb) < 0) {
		if (errno == ENOENT) {
			qr -> offset = type_Idist_QueryResult_doesntExist;
		}
		else {
			nadvise ("failed", "lstat");
			free ((	char *) qr);
			qr = NULL;
		}
		*tp = '\0';
		return qr;
	}
	qr -> offset = type_Idist_QueryResult_doesExist;
	switch (stb.st_mode & S_IFMT) {
	    case S_IFREG:
	    case S_IFDIR:
	    case S_IFLNK:
		qr -> un.doesExist = makefs (stb.st_mode & S_IFMT, 0,
					     stb.st_mode & 07777, stb.st_size,
					     stb.st_mtime, "", "", str, "");
		break;

	    default:
		nadvise (NULLCP, "%s: not a file or directory", str);
		free ((char *)qr);
		qr = NULL;
	}
	*tp = '\0';
	return qr;
}

static struct type_Idist_IA5List *str2ia5list (s, len)
char   *s;
int	len;
{
	register struct type_Idist_IA5List *ia5;

	if ((ia5 = (struct type_Idist_IA5List  *) calloc (1, sizeof *ia5))
	    == NULL)
		return NULL;

	if ((ia5 -> IA5String = str2qb (s, len, 1)) == NULL) {
		free ((char *) ia5);
		return NULL;
	}

	return ia5;
}

struct type_Idist_FileList *do_listcdir ()
{
	DIR	*d;
	register struct direct *dp;
	struct type_Idist_FileList *base, **flp;
	char	buf[BUFSIZ];
	struct stat stb;

	base = NULL;
	flp = &base;
	
	if ((d = opendir (target)) == NULL) {
		nadvise (target, "Can't open directory");
		return NULL;
	}

	while (dp = readdir (d)) {
		if (strcmp (dp -> d_name, ".") == 0 ||
		    strcmp (dp -> d_name, "..") == 0)
			continue;
		(void) sprintf (buf, "%s/%s", target, dp -> d_name);
		if (lstat (buf, &stb) < 0) {
			nadvise (buf, "Can't stat");
			continue;
		}
		switch (stb.st_mode & S_IFMT) {
		    case S_IFDIR:
		    case S_IFLNK:
		    case S_IFREG:
			break;
		    default:	/* skip sockets, fifos et al... */
			continue;
		}
		if ((*flp = (struct type_Idist_FileList *)
		     malloc (sizeof **flp)) == NULL)
			adios ("memory", "out of");

		(*flp) -> FileSpec = makefs (stb.st_mode & S_IFMT, 0,
					     stb.st_mode & 07777, stb.st_size,
					     stb.st_mtime, "", "",
					     dp->d_name, "");
		(*flp) -> next = NULL;
		flp = &(*flp) -> next;
	}
	closedir (d);
	return base;
}

fixup ()
{
	struct timeval tvp[2];
	char	*new, *p;
	char	*owner, *group;
	long	convtime ();

	p = qb2str (cfiletype -> filename);
	new = cannon (p);
	free (p);
	
	if (bit_on (cfiletype -> fileopts, bit_Idist_Options_compare)) {
		if (compare (target, new) == OK) {
			(void) unlink (new);
			return OK;
		}
		if (bit_on (cfiletype -> fileopts, bit_Idist_Options_verify)) {
			(void) unlink (new);
			note ("need to update: %s", target);
			return OK;
		}
	}

	tvp[1].tv_sec =
		tvp[0].tv_sec =
			convtime (cfiletype -> filemtime);
	tvp[0].tv_usec = tvp[1].tv_usec = 0;
	if (utimes (new, tvp) < 0)
		nadvise (new, "utimes failed on");

	owner = qb2str (cfiletype -> fileowner);
	group = qb2str (cfiletype -> filegroup);

	if (chog (new, owner, group, cfiletype -> filemode) < 0) {
		free (owner);
		free (group);
		(void) unlink (new);
		return NOTOK;
	}
	free (owner);
	free (group);
	
	if (rename (new, target) < 0) {
		nadvise (target, "Can't rename %s to", new);
		return NOTOK;
	}
	if (bit_on (cfiletype -> fileopts, bit_Idist_Options_compare))
		note ("updated %s", target);
	free_Idist_FileSpec (cfiletype);
	cfiletype = NULL;
	return OK;
}

static int	compare (f1, f2)
char	*f1, *f2;
{
	FILE	*fp1, *fp2;
	char	buf1[BUFSIZ], buf2[BUFSIZ];	/* these two had
						   better be identical */
	int	n1, n2;

	if ((fp1 = fopen (f1, "r")) == NULL) {
		nadvise (f1, "Can't reopen file");
		return NOTOK;
	}
	if ((fp2 = fopen (f2, "r")) == NULL) {
		nadvise (f2, "Can't reopend file");
		(void) fclose (fp1);
		return NOTOK;
	}
	for (;;) {
		n1 = fread (buf1, sizeof buf1[0], sizeof buf1, fp1);
		n2 = fread (buf2, sizeof buf2[0], sizeof buf2, fp2);
		if (n1 != n2 || n1 == 0)
			break;
		if (bcmp (buf1, buf2, n1) != 0)
			break;
	}

	(void) fclose (fp1);
	(void) fclose (fp2);
	return n1 == 0 ? OK : NOTOK;
}


/*
 * Change owner, group and mode of file.
 */
chog(file, owner, group, mode)
	char *file, *owner, *group;
	int mode;
{
	register int i;
	int uid, gid;
	extern char user[];
	extern int userid;

	uid = userid;
	if (userid == 0) {
		if (*owner == ':') {
			uid = atoi(owner + 1);
		} else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) {
			if ((pw = getpwnam(owner)) == NULL) {
				if (mode & 04000) {
					note("%s: unknown login name, clearing setuid",
						host, owner);
					mode &= ~04000;
					uid = 0;
				}
			} else
				uid = pw->pw_uid;
		} else
			uid = pw->pw_uid;
		if (*group == ':') {
			gid = atoi(group + 1);
			goto ok;
		}
	} else if ((mode & 04000) && strcmp(user, owner) != 0)
		mode &= ~04000;
	gid = -1;
	if (gr == NULL || strcmp(group, gr->gr_name) != 0) {
		if ((*group == ':' && (getgrgid(gid = atoi(group + 1)) == NULL))
		   || ((gr = getgrnam(group)) == NULL)) {
			if (mode & 02000) {
				note("%s: unknown group", group);
				mode &= ~02000;
			}
		} else
			gid = gr->gr_gid;
	} else
		gid = gr->gr_gid;
	if (userid && gid >= 0) {
		if (gr) for (i = 0; gr->gr_mem[i] != NULL; i++)
			if (!(strcmp(user, gr->gr_mem[i])))
				goto ok;
		mode &= ~02000;
		gid = -1;
	}
ok:
	if (userid == 0 && chown(file, uid, gid) < 0 )
		nadvise (file, "chown failed on");
	if ((mode & 06000) && chmod(file, mode) < 0) {
		nadvise (file, "chmod to 0%o failed on", mode);
	}
	return(0);
}

cleanup ()
{
	char	*p, *temp;

	if (cfiletype) {
		p = qb2str (cfiletype -> filename);
		temp = cannon (p);
		(void) unlink (temp);
	}
}