V10/cmd/uucp/uucp.c

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

/*	@(#)uucp.c	1.6
*/
#include "uucp.h"
VERSION(@(#)uucp.c	1.6);

/*
 * uucp
 * user id 
 * make a copy in spool directory
 */
int Copy = 0;
static int _Transfer = 0;
char Nuser[32];
char *Ropt = " ";
char Optns[10];
char Uopts[BUFSIZ];
char Grade = 'N';

char	Sfile[MAXFULLNAME];
#ifndef	V7
long ulimit();
#endif

main(argc, argv, envp)
char	*argv[];
char	**envp;
{
	int	ret;
	int	errors = 0;
	char	*fopt;
	char	sys1[MAXFULLNAME], sys2[MAXFULLNAME];
	char	fwd1[MAXFULLNAME], fwd2[MAXFULLNAME];
	char	file1[MAXFULLNAME], file2[MAXFULLNAME];
	short	jflag = 0;	/* -j flag  Jobid printout */

	void	split();
#ifndef V7
	long	limit, dummy;
	char	msg[100];
#endif V7


	/* this fails in some versions, but it doesn't hurt */
	Uid = getuid();
	Euid = geteuid();
	if (Uid == 0)
		(void) setuid(UUCPUID);

	/* choose LOGFILE */
	(void) strcpy(Logfile, LOGUUCP);

	Env = envp;
	fopt = NULL;
	(void) strcpy(Progname, "uucp");
	Pchar = 'U';
	*Uopts =  NULLCHAR;

	/*
	 * find name of local system
	 */
	uucpname(Myname);
	Optns[0] = '-';
	Optns[1] = 'd';
	Optns[2] = 'c';
	Optns[3] = Nuser[0] = Sfile[0] = NULLCHAR;

	/*
	 * find id of user who spawned command to 
	 * determine
	 */
	(void) guinfo(Uid, User);

	while ((ret = getopt(argc, argv, "Ccdfg:jmn:rx:")) != EOF) {
		switch (ret) {

		/*
		 * make a copy of the file in the spool
		 * directory.
		 */
		case 'C':
			Copy = 1;
			Optns[2] = 'C';
			break;

		/*
		 * not used (default)
		 */
		case 'c':
			break;

		/*
		 * not used (default)
		 */
		case 'd':
			break;
		case 'f':
			Optns[1] = 'f';
			break;

		/*
		 * set service grade
		 */
		case 'g':
			Grade = *optarg;
			break;

		case 'j':	/* job id */
			jflag = 1;
			break;

		/*
		 * send notification to local user
		 */
		case 'm':
			(void) strcat(Optns, "m");
			break;

		/*
		 * send notification to user on remote
		 * if no user specified do not send notification
		 */
		case 'n':
			(void) strcat(Optns, "n");
			(void) sprintf(Nuser, "%.8s", optarg);
			(void) sprintf(Uopts+strlen(Uopts), "-n%s ", Nuser);
			break;

		/*
		 * create JCL files but do not start uucico
		 */
		case 'r':
			Ropt = "-r";
			break;

		/*
		 * return status file
		 */

		/*
		 * turn on debugging
		 */
		case 'x':
			Debug = atoi(optarg);
			if (Debug <= 0)
				Debug = 1;
			break;

		default:
			/* getopt has already (stupidly) babbled */
			break;
		}
	}
	DEBUG(4, "\n\n** %s **\n", "START");
	gwd(Wrkdir);
	if (fopt) {
		if (*fopt != '/')
			(void) sprintf(Sfile, "%s/%s", Wrkdir, fopt);
		else
			(void) sprintf(Sfile, "%s", fopt);

	}
	/*
	 * work in WORKSPACE directory
	 */
	ret = chdir(WORKSPACE);
	if (ret != 0) {
		(void) fprintf(stderr, "No work directory - %s - get help\n",
		    WORKSPACE);
		cleanup(-12);
	}

	if (Nuser[0] == NULLCHAR)
		(void) strcpy(Nuser, User);
	(void) strcpy(Loginuser, User);
	DEBUG(4, "UID %d, ", Uid);
	DEBUG(4, "User %s\n", User);
	if (argc - optind < 2) {
		(void) fprintf(stderr, "usage uucp from ... to\n");
		cleanup(-2);
	}

	/*
	 * set up "to" system and file names
	 */

	split(argv[argc - 1], sys2, fwd2, file2);
	if (*sys2 != NULLCHAR) {
		if (versys(sys2, 0) != 0) {
			(void) fprintf(stderr, "bad system: %s\n", sys2);
			cleanup(-11);
		}
	}
	else
		(void) strcpy(sys2, Myname);

	(void) strncpy(Rmtname, sys2, MAXBASENAME);
	Rmtname[MAXBASENAME] = NULLCHAR;

	DEBUG(9, "sys2: %s, ", sys2);
	DEBUG(9, "fwd2: %s, ", fwd2);
	DEBUG(9, "file2: %s\n", file2);

	/*
	 * if there are more than 2 argsc, file2 is a directory
	 */
	if (argc - optind > 2)
		(void) strcat(file2, "/");

	/*
	 * do each from argument
	 */

	for ( ; optind < argc - 1; optind++) {
	    split(argv[optind], sys1, fwd1, file1);
	    if (*sys1 != NULLCHAR) {
		if (versys(sys1, 0) != 0) {
			(void) fprintf(stderr, "bad system: %s\n", sys1);
			cleanup(-11);
		}
	    }

	    /*  source files can have at most one ! */
	    if (*fwd1 != NULLCHAR) {
		/* syntax error */
	        (void) fprintf(stderr, "illegal  syntax %s\n", argv[optind]);
	        exit(2);
	    }

	    /*
	     * check for required remote expansion of file names -- generate
	     *	and execute a uux command
	     * e.g.
	     *		uucp   owl!~/dan/*   ~/dan/
	     *
	     * NOTE: The source file part must be full path name.
	     *  If ~ it will be expanded locally - it assumes the remote
	     *  names are the same.
	     */

	    if (*sys1 != NULLCHAR)
		if ((strchr(file1, '*') != NULL
		      || strchr(file1, '?') != NULL
		      || strchr(file1, '[') != NULL)) {
		        /* do a uux command */
		        if (ckexpf(file1) == FAIL)
			    exit(6);
		        ruux(sys1, sys1, file1, sys2, fwd2, file2);
		        continue;
		}

	    /*
	     * check for forwarding -- generate and execute a uux command
	     * e.g.
	     *		uucp uucp.c raven!owl!~/dan/
	     */

	    if (*fwd2 != NULLCHAR) {
	        ruux(sys2, sys1, file1, "", fwd2, file2);
	        continue;
	    }

	    /*
	     * check for both source and destination on other systems --
	     *  generate and execute a uux command
	     */

	    if (*sys1 != NULLCHAR )
		if ( (!EQUALS(Myname, sys1))
	    	  && *sys2 != NULLCHAR
	    	  && (!EQUALS(sys2, Myname)) ) {
		    ruux(sys2, sys1, file1, "", fwd2, file2);
	            continue;
	        }


	    if (*sys1 == NULLCHAR)
		(void) strcpy(sys1, Myname);
	    else {
		(void) strncpy(Rmtname, sys1, MAXBASENAME);
		Rmtname[MAXBASENAME] = NULLCHAR;
	    }

	    DEBUG(4, "sys1 - %s, ", sys1);
	    DEBUG(4, "file1 - %s, ", file1);
	    DEBUG(4, "Rmtname - %s\n", Rmtname);
	    if (copy(sys1, file1, sys2, file2))
	    	errors++;
	}

	/* move the work files to their proper places */
	commitall();

	/*
	 * do not spawn daemon if -r option specified
	 */
#ifndef	V7
	limit = ulimit(1, dummy);
#endif V7
	if (*Ropt != '-')
#ifndef	V7
		if (limit < MINULIMIT)  {
			(void) sprintf(msg,
			    "ULIMIT (%ld) < MINULIMIT (%ld)", limit, MINULIMIT);
			logent(msg, "Low-ULIMIT");
		}
		else
#endif
			xuucico(Rmtname);
	if (jflag)
	    printf("%s\n", Jobid);
	cleanup(errors);
}

/*
 * cleanup lock files before exiting
 */
cleanup(code)
register int	code;
{
	rmlock(CNULL);
	if (code != 0)
		wfabort();	/* this may be extreme -- abort all work */
	if (code < 0) {
	       (void) fprintf(stderr, "uucp failed completely (%d)\n", (-code));
		exit(-code);
	}
	else if (code > 0) {
		(void) fprintf(stderr, 
		"uucp failed partially: %d file(s) sent; %d error(s)\n",
		 _Transfer, code);
		exit(code);
	}
	exit(code);
}

/*
 * generate copy files for s1!f1 -> s2!f2
 *	Note: only one remote machine, other situations
 *	have been taken care of in main.
 * return:
 *	0	-> success
 * Non-zero     -> failure
 */

copy(s1, f1, s2, f2)
char *s1, *f1, *s2, *f2;
{
	FILE *cfp, *syscfile();
	struct stat stbuf, stbuf1;
	int type, statret;
	char dfile[NAMESIZE];
	char cfile[NAMESIZE];
	char file1[MAXFULLNAME], file2[MAXFULLNAME];
	char msg[BUFSIZ];

	type = 0;
	(void) strcpy(file1, f1);
	(void) strcpy(file2, f2);
	if (!EQUALS(s1, Myname))
		type = 1;
	if (!EQUALS(s2, Myname))
		type = 2;

	switch (type) {
	case 0:

		/*
		 * all work here
		 */
		DEBUG(4, "all work here %d\n", type);

		/*
		 * check access control permissions
		 */
		if (ckexpf(file1))
			 return(-6);
		if (ckexpf(file2))
			 return(-7);
		if (uidstat(file1, &stbuf) != 0) {
			(void) fprintf(stderr,
			    "can't get file status %s\n copy failed\n", file1);
			return(8);
		}
		statret = uidstat(file2, &stbuf1);
		if (statret == 0
		  && stbuf.st_ino == stbuf1.st_ino
		  && stbuf.st_dev == stbuf1.st_dev) {
			(void) fprintf(stderr,
			    "%s %s - same file; can't copy\n", file1, file2);
			return(5);
		}
		if (chkperm(file1, file2, strchr(Optns, 'd')) ) {
			(void) fprintf(stderr, "permission denied\n");
			cleanup(1);
		}
		if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
			(void) fprintf(stderr, "directory name illegal - %s\n",
			  file1);
			return(9);
		}
		/* see if I can read this file as read uid, gid */
		if ( !(stbuf.st_mode & ANYREAD)
		  && !(stbuf.st_uid == Uid && stbuf.st_mode & 0400)
		  && !(stbuf.st_gid == getgid() && stbuf.st_mode & 0040)
		  ) {
			(void) fprintf(stderr,
			    "uucp can't read (%s) mode (%o)\n",
			    file1, stbuf.st_mode);
			(void) fprintf(stderr, "use cp command\n");
			return(3);
		}
		if (statret == 0 && (stbuf1.st_mode & ANYWRITE) == 0) {
			(void) fprintf(stderr,
			    "can't write file (%s) mode (%o)\n",
			    file2, stbuf1.st_mode);
			return(4);
		}

		/*
		 * copy file locally
		 */
		DEBUG(2, "local copy:  uidxcp(%s, ", file1);
		DEBUG(2, "%s\n", file2);

		/* do copy as Uid, but the file will be owned by uucp */
		if (uidxcp(file1, file2) == FAIL) {
			(void) fprintf(stderr,
			    "can't copy file (%s) errno %d\n", file2, errno);
			return(5);
		}
		(void) chmod(file2, (int) (stbuf.st_mode | 0666) & 0777);
		return(0);
	case 1:

		/*
		 * receive file
		 */
		DEBUG(4, "receive file - %d\n", type);

		/*
		 * expand source and destination file names
		 * and check access permissions
		 */
		if (file1[0] != '~')
			if (ckexpf(file1))
				 return(6);
		if (ckexpf(file2))
			 return(7);

		/*
		 * insert JCL card in file
		 */
		cfp = syscfile(cfile, s1);
		(void) fprintf(cfp, 
	       	"R %s %s %s %s %s %o %s\n", file1, file2,
			User, Optns,
			*Sfile ? Sfile : "dummy",
			0777, Nuser);
		(void) fclose(cfp);
		(void) sprintf(msg, "%s!%s --> %s!%s", Rmtname, file1,
		    Myname, file2);
		logent(msg, "QUEUED");
		break;
	case 2:

		/*
		 * send file
		 */
		if (ckexpf(file1))
			 return(6);
		/* XQTDIR hook enables 3rd party uux requests (cough) */
		if (file2[0] != '~' && !EQUALS(Wrkdir, XQTDIR))
			if (ckexpf(file2))
				 return(7);
		DEBUG(4, "send file - %d\n", type);

		if (uidstat(file1, &stbuf) != 0) {
			(void) fprintf(stderr,
			    "can't get status for file %s\n", file1);
			return(8);
		}
		if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
			(void) fprintf(stderr,
			    "directory name illegal - %s\n", file1);
			return(9);
		}

		/*
		 * make a copy of file in spool directory
		 */
		if (Copy || !READANY(file1) ) {
			gename(DATAPRE, s2, Grade, dfile);

			if (uidxcp(file1, dfile))
			    return(5);

			(void) chmod(dfile, DFILEMODE);
			wfcommit(dfile, dfile, s2);
		} else {

			/*
			 * make a dummy D. name
			 * cntrl.c knows names < 6 chars are dummy D. files
			 */
			(void) strcpy(dfile, "D.0");
		}

		/*
		 * insert JCL card in file
		 */
		cfp = syscfile(cfile, s2);
		(void) fprintf(cfp, "S  %s %s %s %s %s %o %s %s\n",
		    file1, file2, User, Optns, dfile,
		    stbuf.st_mode & 0777, Nuser, Sfile);
		(void) fclose(cfp);
		(void) sprintf(msg, "%s!%s --> %s!%s", Myname, file1,
		    Rmtname, file2);
		logent(msg, "QUEUED");
		break;
	}
	_Transfer++;
	return(0);
}


/*
 *	syscfile(file, sys)
 *	char	*file, *sys;
 *
 *	get the cfile for system sys (creat if need be)
 *	return stream pointer
 *
 *	returns
 *		stream pointer to open cfile
 *		
 */

static FILE	*
syscfile(file, sys)
char	*file, *sys;
{
	FILE	*cfp;

	if (gtcfile(file, sys) == FAIL) {
		gename(CMDPRE, sys, Grade, file);
		ASSERT(access(file, 0) != 0, Fl_EXISTS, file, errno);
		cfp = fdopen(creat(file, CFILEMODE), "w");
		svcfile(file, sys);
	} else
		cfp = fopen(file, "a");
	/*  set Jobid -- C.jobid */
	(void) strncpy(Jobid, BASENAME(file, '.'), NAMESIZE);
	Jobid[NAMESIZE-1] = '\0';
	ASSERT(cfp != NULL, Ct_OPEN, file, errno);
	return(cfp);
}


/*
 * split - split the name into parts:
 * sys - system name
 * fwd - intermediate destinations
 * file - file part
 */

static
void
split(arg, sys, fwd, file)
char *arg, *sys, *fwd, *file;
{
    register char *cl, *cr, *n;
    *sys = *fwd = *file = NULLCHAR;
	
    for (n=arg ;; n=cl+1) {
	cl = strchr(n, '!');
	if ( cl == NULL) {
	    /* no ! in n */
	    (void) strcpy(file, n);
	    return;
	}

	if (PREFIX(Myname, n))
	    continue;

	cr = strrchr(n, '!');
	(void) strcpy(file, cr+1);
	(void) strncpy(sys, n, cl-n);
	sys[cl-n] = NULLCHAR;

	if (cr != cl) {
	    /*  more than one ! */
	    (void) strncpy(fwd, cl+1, cr-cl-1);
	    fwd[cr-cl-1] = NULLCHAR;
	}
	return;
    }
    /*NOTREACHED*/
}


/*
 * generate and execute a uux command
 */

ruux(rmt, sys1, file1, sys2, fwd2, file2)
char *rmt, *sys1, *file1, *sys2, *fwd2, *file2;
{
    char cmd[BUFSIZ];

    if (*Uopts != NULLCHAR)
	(void) sprintf(cmd, "uux -C %s %s!uucp -C \\(%s\\) ", Ropt, rmt, Uopts);
    else
	(void) sprintf(cmd, "uux -C %s %s!uucp -C ", Ropt, rmt);

    if (*sys1 == NULLCHAR || EQUALS(sys1, Myname)) {
        if (ckexpf(file1))
  	    exit(6);
	(void) sprintf(cmd+strlen(cmd), " %s!%s ", sys1, file1);
    }
    else
	if (!EQUALS(rmt, sys1))
	    (void) sprintf(cmd+strlen(cmd), " \\(%s!%s\\) ", sys1, file1);
	else
	    (void) sprintf(cmd+strlen(cmd), " \\(%s\\) ", file1);

    if (*fwd2 != NULLCHAR) {
	if (*sys2 != NULLCHAR)
	    (void) sprintf(cmd+strlen(cmd),
		" \\(%s!%s!%s\\) ", sys2, fwd2, file2);
	else
	    (void) sprintf(cmd+strlen(cmd), " \\(%s!%s\\) ", fwd2, file2);
    }
    else {
	if (*sys2 == NULLCHAR || EQUALS(sys2, Myname))
	    if (ckexpf(file2))
		exit(7);
	(void) sprintf(cmd+strlen(cmd), " \\(%s!%s\\) ", sys2, file2);
    }

    DEBUG(2, "cmd: %s\n", cmd);
    logent(cmd, "QUEUED");
    system(cmd);
    return;
}