Ultrix-3.1/src/cmd/decnet/dcp.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

#ifndef lint
static char *sccsid = "@(#)dcp.c	3.0	(ULTRIX-11)	4/21/86";
#endif

/*
 * dcp
 *
 * This Ultrix-11 version of dcp should try to emulate as closely
 * as possible the functionality of dcp in Ultrix-32.  
 * 
 * Ultrix-11 dcp does not support wild cards or local-to-local
 * file transfers.  Transfers from a local file to a remote 
 * directory result in a file named STDIN in the specified directory,
 * since the remote dcp has no idea what the file name is.
 */

#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <unistd.h>
#include <fcntl.h>

#define	BLEN	8192

int Aflag;
char	*rindex(), *sprintf();

main(ac, av)
	int ac;
	char **av;
{
	struct stat stb;
	int rc, i, argc;
	char **argv, *dummy[2], *flagp, flags[32];

	/*
	Create a fake arglist so that ps will not show such
	things as passwords, which decnet passes in clear text.
	 */
	argc = ac;
	argv = av;
	ac = 1;
	dummy[0] = argv[0];
	dummy[1] = 0;
	av = dummy;

	/*
	 * Process any switches.  Currently, only '-A' is enacted locally.
	 * In future other switches, such as '-v', should be 
	 * implemented.
	 */

	flagp = flags;
	argc--, argv++;
	while (argc > 0 && **argv == '-') {
		*flagp++ = '-';
		while (*(++(*argv))) switch (**argv) {
			case 'A':
				Aflag++;
			case 'i':
			case 'a':
			case 'P':
			case 'S':
			case 'v':
			case 'd':
				*flagp++ = **argv; /* append flags to flagp */
				break;
			default:
				goto usage;
		}
		argc--; argv++;
	}
	if (argc < 2) 
		goto usage;
	if (argc > 2) {
		if (((rc = stat(argv[argc-1], &stb)) < 0) || 
			((stb.st_mode&S_IFMT) != S_IFDIR)) {
/*
 * Having > 2 args and destination file not a directory means user wants
 * file1...fileN copied onto fileX .  Copy file1 onto fileX, then set Aflag
 * and copy the rest to fileX.  The result is the appended contents of file1 
 * through fileN in a file named fileX.  This is true whether or not fileX
 * previously existed.  However, if the '-A' flag was set by the user then 
 * the old contents of fileX will still be in the file, in front of the new 
 * stuff.  Contrary to the documentation, Ultrix-32 dcp allows the user to
 * use the '-A' switch even if fileX does not exist.  This version of dcp
 * will do the same in the name of compatibility.
 */
			rc = copy(*argv, argv[argc-1], flags);
			argc--; argv++;
			if (rc < 0)
				exit(rc);
			Aflag++;
			if (flags[0] == '\0') {
				flags[0] = '-';
				flags[1] = 'A';
			}
			else *flagp = 'A';
		}
		else if ((stb.st_mode&S_IFMT) != S_IFDIR)
			/* pre-existing--must be a directory */
			goto usage;			
	}
	rc = 0;
	for (i = 0; i < argc-1; i++)
		rc |= copy(argv[i], argv[argc-1], flags);
	exit(rc);
usage:
	fprintf(stderr,
		"Usage: dcp [-A][-P][-S][-v][-a][-d][-i] input output\n");
	exit(1);
}

copy(from, to, flags)
	char *from, *to, flags[32];
{
#include "dgate.h"

	char *last, buf[BLEN];
	char gate_way[64], gate_acct[64], *p1, *p2, *bp;
	char *remorig, *remdest;
	int rc;
	struct stat stfrom, stto;
	int output, input;

	char *arglist[80];
	char **argp;

	/* is target a directory? */
	if (stat(to, &stto) ==0 &&
	   (stto.st_mode&S_IFMT) == S_IFDIR) {
		p1 = from;
		p2 = to;
		bp = buf;
		while(*bp++ = *p2++)
			;
		bp[-1] = '/';
		p2 = bp;
		while(*bp = *p1++)
			if (*bp++ == '/')
				bp = p2;
		to = buf;
	}

	getgateway(gate_way, gate_acct);
	argp = arglist;
	*argp++ = RSH;
	*argp++ = gate_way;
	*argp++ = "-l";
	*argp++ = gate_acct;
	*argp++ = DCP;
	*argp++ = flags;

	remorig = remotename(from);
	remdest = remotename(to);

	if (remorig) {
		if (remdest) { /* remote to remote copy */
			*argp++ = from;
			*argp++ = to;
			*argp = 0;
			rshfork(stdin, stdout, arglist);
		}
		else {
			/*
			 * Remote to local copy:  set destination name to
			 * stdin, open the file locally, then fork and run 
			 * the cmd.
		 	 */
			*argp++ = from;
			*argp++ = "-";
			*argp = 0;
			if ((rc = strcmp(to, "-")) == 0)
				output = stdout;
			else 	{
				/* Check to see if destination file exists.
				 * If so, check if the append option was
				 * specified or if destination is a directory.
				 */

				if ((rc=stat(to, &stto)) < 0) {
					/* create new file */
					if (errno != ENOENT) {
						perror("dcp");
						exit(1);
						}
					setreuid(geteuid(), getuid());
					output = creat(to, 0666);
					setreuid(geteuid(), getuid());
					if (output < 0) {
						perror(to);
						exit(1);
					}
				} 
				else if (((stto.st_mode&S_IFMT) != 
						S_IFDIR) && (Aflag)) {
					/* file exists and user wants to 
					 * append to it.
					 */
					setreuid(geteuid(), getuid());
					output = open(to,O_WRONLY|O_APPEND);
					setreuid(geteuid(), getuid());
					if (output < 0) {
						perror(to);
						exit(1);
					}
				} 

			/* Check to see if file has write access.  */

				else 	{
					if ((rc = access(to, W_OK)) < 0) {
						perror(to);
						exit(1);
					}
					setreuid(geteuid(), getuid());
					output = open(to,O_WRONLY);
					setreuid(geteuid(), getuid());
					if (output < 0) {
						perror(to);
						exit(1);
					}
				}
			}
			rshfork(stdin, output, arglist);
		}
	}
	else if (remdest) {
			/*
			 * Local to remote copy:  set source name to stdin,
			 * open the file locally, then fork and run the cmd.
		 	 */
			*argp++ = "-";
			*argp++ = to;
			*argp = 0;
			if (strcmp(from, "-") != 0) {
				setreuid(geteuid(), getuid());
				input = open(from, 0);
				setreuid(geteuid(), getuid());
				if (input < 0) {
					perror(from);
					return(1);
				}
				rshfork(input, stdout, arglist);
				close(input);
			} else
				rshfork(stdin, stdout, arglist);
			return(0);
		}
		else {
			 /* local to local copy not allowed at present */
			fprintf(stderr, 
				"Local to local copies not supported.  Use cp.\n");
			exit(1);
		}

}


remotename(cp)
register char *cp;
{
	/*
	 * Determine whether a name is local or remote.  This
	 * is done by looking for a "::" in the path name, which
	 * should indicate a remote name.
	 */
	while (*cp)
		if (*cp++ == ':')
			if (*cp == ':')
				return(1);
	return(0);
}


rshfork(ifd, ofd, arglist)
int ifd, ofd; 
char **arglist;
{
	int pid, child, status, fail = 0;

	/*
	 * Fork off a sub-shell.  If the fork fails, sleep
	 * and then try again.  Try up to 5 times before
	 * we give up.
	 */
	while ((pid = fork()) < 0) {
		if (++fail > 5) {
			perror("fork");
			return;
		}
		sleep(2);
	}
	if (pid) {
		/* parent waits for the child */
		while ((child = wait(&status)) >= 0)
			if (child == pid)
				break;
		return;
	} else {
		/*
		 * Child dups ifd to stdin, ofd to
		 * stdout, and executes rsh command.
		 */
		if (ifd > 0) {
			dup2(ifd, 0);
			close(ifd);
		}
		if (ofd > 1) {
			dup2(ofd, 1);
			close(ofd);
		}
		execv(RSH, arglist);
		perror(RSH);
		exit(1);
	}
}