Home | History | Annotate | Download | only in bnu
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     28 /*	  All Rights Reserved  	*/
     29 
     30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     31 
     32 #include "uucp.h"
     33 
     34 /*
     35  * uucp
     36  * user id
     37  * make a copy in spool directory
     38  */
     39 int Copy = 0;
     40 static int _Transfer = 0;
     41 char Nuser[32];
     42 char *Ropt = " ";
     43 char Optns[10];
     44 char Uopts[BUFSIZ];
     45 char Xopts[BUFSIZ];
     46 char Sgrade[NAMESIZE];
     47 int Mail = 0;
     48 int Notify = 0;
     49 
     50 void cleanup(), ruux(), usage();
     51 int eaccess(), guinfo(), vergrd(), gwd(), ckexpf(), uidstat(), uidxcp(),
     52 	copy(), gtcfile();
     53 void commitall(), wfabort(), mailst(), gename(), svcfile();
     54 
     55 char	Sfile[MAXFULLNAME];
     56 
     57 int
     58 main(argc, argv, envp)
     59 int argc;
     60 char *argv[];
     61 char	**envp;
     62 {
     63 	char *jid();
     64 	int	ret;
     65 	int	errors = 0;
     66 	char	*fopt, *sys2p;
     67 	char	sys1[MAXFULLNAME], sys2[MAXFULLNAME];
     68 	char	fwd1[MAXFULLNAME], fwd2[MAXFULLNAME];
     69 	char	file1[MAXFULLNAME], file2[MAXFULLNAME];
     70 	short	jflag = 0;	/* -j flag  Jobid printout */
     71 	extern int	split();
     72 
     73 
     74 	/* Set locale environment variables local definitions */
     75 	(void) setlocale(LC_ALL, "");
     76 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
     77 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it wasn't */
     78 #endif
     79 	(void) textdomain(TEXT_DOMAIN);
     80 
     81 	/* this fails in some versions, but it doesn't hurt */
     82 	Uid = getuid();
     83 	Euid = geteuid();
     84 	if (Uid == 0)
     85 		(void) setuid(UUCPUID);
     86 
     87 	/* choose LOGFILE */
     88 	(void) strcpy(Logfile, LOGUUCP);
     89 
     90 	Env = envp;
     91 	fopt = NULL;
     92 	(void) strcpy(Progname, "uucp");
     93 	Pchar = 'U';
     94 	*Uopts = NULLCHAR;
     95 	*Xopts = NULLCHAR;
     96 	*Sgrade = NULLCHAR;
     97 
     98 	if (eaccess(GRADES, 0) != -1) {
     99 		Grade = 'A';
    100 		Sgrades = TRUE;
    101 		sprintf(Sgrade, "%s", "default");
    102 	}
    103 
    104 	/*
    105 	 * find name of local system
    106 	 */
    107 	uucpname(Myname);
    108 	Optns[0] = '-';
    109 	Optns[1] = 'd';
    110 	Optns[2] = 'c';
    111 	Optns[3] = Nuser[0] = Sfile[0] = NULLCHAR;
    112 
    113 	/*
    114 	 * find id of user who spawned command to
    115 	 * determine
    116 	 */
    117 	(void) guinfo(Uid, User);
    118 
    119 	/*
    120 	 * create/append command log
    121 	 */
    122 	commandlog(argc,argv);
    123 
    124 	while ((ret = getopt(argc, argv, "Ccdfg:jmn:rs:x:")) != EOF) {
    125 		switch (ret) {
    126 
    127 		/*
    128 		 * make a copy of the file in the spool
    129 		 * directory.
    130 		 */
    131 		case 'C':
    132 			Copy = 1;
    133 			Optns[2] = 'C';
    134 			break;
    135 
    136 		/*
    137 		 * not used (default)
    138 		 */
    139 		case 'c':
    140 			break;
    141 
    142 		/*
    143 		 * not used (default)
    144 		 */
    145 		case 'd':
    146 			break;
    147 		case 'f':
    148 			Optns[1] = 'f';
    149 			break;
    150 
    151 		/*
    152 		 * set service grade
    153 		 */
    154 		case 'g':
    155 			snprintf(Xopts, sizeof (Xopts), "-g%s", optarg);
    156 			if (!Sgrades) {
    157 				if (strlen(optarg) < (size_t)2 && isalnum(*optarg))
    158 					Grade = *optarg;
    159 				else {
    160 					(void) fprintf(stderr, gettext("No"
    161 					    " administrator defined service"
    162 					    " grades available on this"
    163 					    " machine.\n"));
    164 					(void) fprintf(stderr, gettext("UUCP"
    165 					    " service grades range from"
    166 					    " [A-Z][a-z] only.\n"));
    167 					cleanup(-1);
    168 				}
    169 			}
    170 			else {
    171 				(void) strncpy(Sgrade, optarg, NAMESIZE-1);
    172 				Sgrade[NAMESIZE-1] = NULLCHAR;
    173 				if (vergrd(Sgrade) != SUCCESS)
    174 					cleanup(FAIL);
    175 			}
    176 			break;
    177 
    178 		case 'j':	/* job id */
    179 			jflag = 1;
    180 			break;
    181 
    182 		/*
    183 		 * send notification to local user
    184 		 */
    185 		case 'm':
    186 			Mail = 1;
    187 			(void) strcat(Optns, "m");
    188 			break;
    189 
    190 		/*
    191 		 * send notification to user on remote
    192 		 * if no user specified do not send notification
    193 		 */
    194 		case 'n':
    195 			/*
    196 			 * We should add "n" option to Optns only once,
    197 			 * even if multiple -n option are passed to uucp
    198 			 */
    199 			if (!Notify) {
    200 				(void) strlcat(Optns, "n", sizeof (Optns));
    201 				Notify = 1;
    202 			}
    203 			(void) sprintf(Nuser, "%.8s", optarg);
    204 
    205 			/*
    206 			 * We do the copy multiple times when multiple
    207 			 * -n options are specified, but
    208 			 * only the last -n value is used.
    209 	 		 */
    210 			(void) snprintf(Uopts, sizeof (Uopts), "-n%s ", Nuser);
    211 
    212 			break;
    213 
    214 		/*
    215 		 * create JCL files but do not start uucico
    216 		 */
    217 		case 'r':
    218 			Ropt = "-r";
    219 			break;
    220 
    221 		/*
    222 		 * return status file
    223 		 */
    224 		case 's':
    225 			fopt = optarg;
    226 			/* "m" needed for compatability */
    227 			(void) strcat(Optns, "mo");
    228 			break;
    229 
    230 		/*
    231 		 * turn on debugging
    232 		 */
    233 		case 'x':
    234 			Debug = atoi(optarg);
    235 			if (Debug <= 0)
    236 				Debug = 1;
    237 #ifdef SMALL
    238 			fprintf(stderr, gettext("WARNING: uucp built with SMALL"
    239 			    " flag defined -- no debug info available\n"));
    240 #endif /* SMALL */
    241 			break;
    242 
    243 		default:
    244 			usage();
    245 			break;
    246 		}
    247 	}
    248 	DEBUG(4, "\n\n** %s **\n", "START");
    249 	gwd(Wrkdir);
    250 	if (fopt) {
    251 		if (*fopt != '/')
    252 			(void) snprintf(Sfile, MAXFULLNAME, "%s/%s",
    253 					Wrkdir, fopt);
    254 		else
    255 			(void) snprintf(Sfile, MAXFULLNAME, "%s", fopt);
    256 
    257 	}
    258 	else
    259 		if (strlcpy(Sfile, "dummy", sizeof (Sfile)) >= sizeof (Sfile))
    260 			return (2);
    261 
    262 	/*
    263 	 * work in WORKSPACE directory
    264 	 */
    265 	ret = chdir(WORKSPACE);
    266 	if (ret != 0) {
    267 		(void) fprintf(stderr, gettext("No work directory - %s -"
    268 		    " get help\n"), WORKSPACE);
    269 		cleanup(-12);
    270 	}
    271 
    272 	if (Nuser[0] == NULLCHAR)
    273 		(void) strcpy(Nuser, User);
    274 	(void) strcpy(Loginuser, User);
    275 	DEBUG(4, "UID %ld, ", (long) Uid);
    276 	DEBUG(4, "User %s\n", User);
    277 	if (argc - optind < 2) {
    278 		usage();
    279 	}
    280 
    281 	/*
    282 	 * set up "to" system and file names
    283 	 */
    284 
    285 	(void) split(argv[argc - 1], sys2, fwd2, file2);
    286 	if (*sys2 != NULLCHAR) {
    287 		(void) strncpy(Rmtname, sys2, MAXBASENAME);
    288 		Rmtname[MAXBASENAME] = NULLCHAR;
    289 
    290 		/* get real Myname - it depends on who I'm calling--Rmtname */
    291 		(void) mchFind(Rmtname);
    292 		myName(Myname);
    293 
    294 		if (versys(sys2) != 0) {
    295 			(void) fprintf(stderr,
    296 			    gettext("bad system: %s\n"), sys2);
    297 			cleanup(-EX_NOHOST);
    298 		}
    299 	}
    300 
    301 	DEBUG(9, "sys2: %s, ", sys2);
    302 	DEBUG(9, "fwd2: %s, ", fwd2);
    303 	DEBUG(9, "file2: %s\n", file2);
    304 
    305 	/*
    306 	 * if there are more than 2 argsc, file2 is a directory
    307 	 */
    308 	if (argc - optind > 2)
    309 		(void) strcat(file2, "/");
    310 
    311 	/*
    312 	 * do each from argument
    313 	 */
    314 
    315 	for ( ; optind < argc - 1; optind++) {
    316 	    (void) split(argv[optind], sys1, fwd1, file1);
    317 	    if (*sys1 != NULLCHAR) {
    318 		if (versys(sys1) != 0) {
    319 			(void) fprintf(stderr,
    320 			    gettext("bad system: %s\n"), sys1);
    321 			cleanup(-EX_NOHOST);
    322 		}
    323 	    }
    324 
    325 	    /*  source files can have at most one ! */
    326 	    if (*fwd1 != NULLCHAR) {
    327 		/* syntax error */
    328 	        (void) fprintf(stderr,
    329 		    gettext("illegal  syntax %s\n"), argv[optind]);
    330 	        exit(2);
    331 	    }
    332 
    333 	    /*
    334 	     * check for required remote expansion of file names -- generate
    335 	     *	and execute a uux command
    336 	     * e.g.
    337 	     *		uucp   owl!~/dan/..  ~/dan/
    338 	     *
    339 	     * NOTE: The source file part must be full path name.
    340 	     *  If ~ it will be expanded locally - it assumes the remote
    341 	     *  names are the same.
    342 	     */
    343 
    344 	    if (*sys1 != NULLCHAR)
    345 		if ((strchr(file1, '*') != NULL
    346 		      || strchr(file1, '?') != NULL
    347 		      || strchr(file1, '[') != NULL)) {
    348 		        /* do a uux command */
    349 		        if (ckexpf(file1) == FAIL)
    350 			    exit(6);
    351 			(void) strncpy(Rmtname, sys1, MAXBASENAME);
    352 			Rmtname[MAXBASENAME] = NULLCHAR;
    353 			/* get real Myname - it depends on who I'm calling--Rmtname */
    354 			(void) mchFind(Rmtname);
    355 			myName(Myname);
    356 			if (*sys2 == NULLCHAR)
    357 			    sys2p = Myname;
    358 		        ruux(sys1, sys1, file1, sys2p, fwd2, file2);
    359 		        continue;
    360 		}
    361 
    362 	    /*
    363 	     * check for forwarding -- generate and execute a uux command
    364 	     * e.g.
    365 	     *		uucp uucp.c raven!owl!~/dan/
    366 	     */
    367 
    368 	    if (*fwd2 != NULLCHAR) {
    369 	        ruux(sys2, sys1, file1, "", fwd2, file2);
    370 	        continue;
    371 	    }
    372 
    373 	    /*
    374 	     * check for both source and destination on other systems --
    375 	     *  generate and execute a uux command
    376 	     */
    377 
    378 	    if (*sys1 != NULLCHAR )
    379 		if ( (!EQUALS(Myname, sys1))
    380 	    	  && *sys2 != NULLCHAR
    381 	    	  && (!EQUALS(sys2, Myname)) ) {
    382 		    ruux(sys2, sys1, file1, "", fwd2, file2);
    383 	            continue;
    384 	        }
    385 
    386 
    387 	    sys2p = sys2;
    388 	    if (*sys1 == NULLCHAR) {
    389 		if (*sys2 == NULLCHAR)
    390 		    sys2p = Myname;
    391 		(void) strcpy(sys1, Myname);
    392 	    } else {
    393 		(void) strncpy(Rmtname, sys1, MAXBASENAME);
    394 		Rmtname[MAXBASENAME] = NULLCHAR;
    395 		/* get real Myname - it depends on who I'm calling--Rmtname */
    396 		(void) mchFind(Rmtname);
    397 		myName(Myname);
    398 		if (*sys2 == NULLCHAR)
    399 		    sys2p = Myname;
    400 	    }
    401 
    402 	    DEBUG(4, "sys1 - %s, ", sys1);
    403 	    DEBUG(4, "file1 - %s, ", file1);
    404 	    DEBUG(4, "Rmtname - %s\n", Rmtname);
    405 	    if (copy(sys1, file1, sys2p, file2))
    406 	    	errors++;
    407 	}
    408 
    409 	/* move the work files to their proper places */
    410 	commitall();
    411 
    412 	/*
    413 	 * Wait for all background uux processes to finish so
    414 	 * that our caller will know that we're done with all
    415 	 * input files and it's safe to remove them.
    416 	 */
    417 	while (wait(NULL) != -1)
    418 		;
    419 
    420 	/*
    421 	 * do not spawn daemon if -r option specified
    422 	 */
    423 	if (*Ropt != '-') {
    424 #ifndef	V7
    425 		long	limit;
    426 		char	msg[100];
    427 		limit = ulimit(1, (long) 0);
    428 		if (limit < MINULIMIT)  {
    429 			(void) sprintf(msg,
    430 			    "ULIMIT (%ld) < MINULIMIT (%ld)", limit, MINULIMIT);
    431 			logent(msg, "Low-ULIMIT");
    432 		}
    433 		else
    434 #endif
    435 			xuucico(Rmtname);
    436 	}
    437 	if (jflag) {
    438 		(void) strncpy(Jobid, jid(), NAMESIZE);
    439 		printf("%s\n", Jobid);
    440 	}
    441 	cleanup(errors);
    442 	/*NOTREACHED*/
    443 	return (0);
    444 }
    445 
    446 /*
    447  * cleanup lock files before exiting
    448  */
    449 void
    450 cleanup(code)
    451 int	code;
    452 {
    453 	static int first = 1;
    454 
    455 	if (first) {
    456 		first = 0;
    457 		rmlock(CNULL);
    458 		if (code != 0)
    459 			wfabort();  /* this may be extreme -- abort all work */
    460 	}
    461 	if (code < 0) {
    462 	       (void) fprintf(stderr,
    463 		   gettext("uucp failed completely (%d)\n"), (-code));
    464 		exit(-code);
    465 	}
    466 	else if (code > 0) {
    467 		(void) fprintf(stderr, gettext(
    468 		    "uucp failed partially: %d file(s) sent; %d error(s)\n"),
    469 		 _Transfer, code);
    470 		exit(code);
    471 	}
    472 	exit(code);
    473 }
    474 
    475 /*
    476  * generate copy files for s1!f1 -> s2!f2
    477  *	Note: only one remote machine, other situations
    478  *	have been taken care of in main.
    479  * return:
    480  *	0	-> success
    481  * Non-zero     -> failure
    482  */
    483 int
    484 copy(s1, f1, s2, f2)
    485 char *s1, *f1, *s2, *f2;
    486 {
    487 	FILE *cfp;
    488 	static FILE *syscfile();
    489 	struct stat stbuf, stbuf1;
    490 	int type, statret;
    491 	char dfile[NAMESIZE];
    492 	char cfile[NAMESIZE];
    493 	char command[10+(2*MAXFULLNAME)];
    494 	char file1[MAXFULLNAME], file2[MAXFULLNAME];
    495 	char msg[BUFSIZ];
    496 
    497 	type = 0;
    498 	(void) strcpy(file1, f1);
    499 	(void) strcpy(file2, f2);
    500 	if (!EQUALS(s1, Myname))
    501 		type = 1;
    502 	if (!EQUALS(s2, Myname))
    503 		type = 2;
    504 
    505 	DEBUG(4, "copy: file1=<%s> ", file1);
    506 	DEBUG(4, "file2=<%s>\n", file2);
    507 	switch (type) {
    508 	case 0:
    509 
    510 		/*
    511 		 * all work here
    512 		 */
    513 		DEBUG(4, "all work here %d\n", type);
    514 
    515 		/*
    516 		 * check access control permissions
    517 		 */
    518 		if (ckexpf(file1))
    519 			 return(-6);
    520 		if (ckexpf(file2))
    521 			 return(-7);
    522 
    523 		setuid(Uid);
    524 		if (chkperm(file1, file2, strchr(Optns, 'd')) &&
    525 		    (access(file2, W_OK) == -1)) {
    526 			(void) fprintf(stderr, gettext("permission denied\n"));
    527 			cleanup(1);
    528 		}
    529 
    530 		/*
    531 		 * copy file locally
    532 		 *
    533 		 * Changed from uidxcp() to fic file made and owner
    534 		 * being modified for existing files, and local file
    535 		 * name expansion.
    536 		 */
    537 		DEBUG(2, "local copy: %s -> ", file1);
    538 		DEBUG(2, "%s\n", file2);
    539 
    540 		sprintf(command, "cp %s %s", file1, file2);
    541 		if ((cfp = popen(command, "r")) == NULL) {
    542 			perror("popen");
    543 			DEBUG(5, "popen failed - errno %d\n", errno);
    544 			setuid(Euid);
    545 			return (FAIL);
    546 		}
    547 		if (pclose(cfp) != 0) {
    548 			DEBUG(5, "Copy failed - errno %d\n", errno);
    549 			return (FAIL);
    550 		}
    551 		setuid(Euid);
    552 
    553 		/*
    554 		 * if user specified -m, notify "local" user
    555 		 */
    556 		 if ( Mail ) {
    557 		 	sprintf(msg,
    558 		 	"REQUEST: %s!%s --> %s!%s (%s)\n(SYSTEM %s) copy succeeded\n",
    559 		 	s1, file1, s2, file2, User, s2 );
    560 		 	mailst(User, "copy succeeded", msg, "", "");
    561 		}
    562 		/*
    563 		 * if user specified -n, notify "remote" user
    564 		 */
    565 		if ( Notify ) {
    566 			sprintf(msg, "%s from %s!%s arrived\n",
    567 				file2, s1, User );
    568 			mailst(Nuser, msg, msg, "", "");
    569 		}
    570 		return(0);
    571 	case 1:
    572 
    573 		/*
    574 		 * receive file
    575 		 */
    576 		DEBUG(4, "receive file - %d\n", type);
    577 
    578 		/*
    579 		 * expand source and destination file names
    580 		 * and check access permissions
    581 		 */
    582 		if (file1[0] != '~')
    583 			if (ckexpf(file1))
    584 				 return(6);
    585 		if (ckexpf(file2))
    586 			 return(7);
    587 
    588 
    589 		gename(DATAPRE, s2, Grade, dfile);
    590 
    591 		/*
    592 		 * insert JCL card in file
    593 		 */
    594 		cfp = syscfile(cfile, s1);
    595 		(void) fprintf(cfp,
    596 	       	"R %s %s %s %s %s %o %s %s\n", file1, file2,
    597 			User, Optns,
    598 			*Sfile ? Sfile : "dummy",
    599 			0777, Nuser, dfile);
    600 		(void) fclose(cfp);
    601 		(void) sprintf(msg, "%s!%s --> %s!%s", Rmtname, file1,
    602 		    Myname, file2);
    603 		logent(msg, "QUEUED");
    604 		break;
    605 	case 2:
    606 
    607 		/*
    608 		 * send file
    609 		 */
    610 		if (ckexpf(file1))
    611 			 return(6);
    612 		/* XQTDIR hook enables 3rd party uux requests (cough) */
    613 		DEBUG(4, "Workdir = <%s>\n", Wrkdir);
    614 		if (file2[0] != '~' && !EQUALS(Wrkdir, XQTDIR))
    615 			if (ckexpf(file2))
    616 				 return(7);
    617 		DEBUG(4, "send file - %d\n", type);
    618 
    619 		if (uidstat(file1, &stbuf) != 0) {
    620 			(void) fprintf(stderr,
    621 			    gettext("can't get status for file %s\n"), file1);
    622 			return(8);
    623 		}
    624 		if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
    625 			(void) fprintf(stderr,
    626 			    gettext("directory name illegal - %s\n"), file1);
    627 			return(9);
    628 		}
    629 		/* see if I can read this file as read uid, gid */
    630 		if (access(file1, R_OK) != 0) {
    631 			(void) fprintf(stderr,
    632 			    gettext("uucp can't read (%s) mode (%o)\n"),
    633 			    file1, stbuf.st_mode&0777);
    634 			return(3);
    635 		}
    636 
    637 		/*
    638 		 * make a copy of file in spool directory
    639 		 */
    640 
    641 		gename(DATAPRE, s2, Grade, dfile);
    642 
    643 		if (Copy || !READANY(file1) ) {
    644 
    645 			if (uidxcp(file1, dfile))
    646 			    return(5);
    647 
    648 			(void) chmod(dfile, DFILEMODE);
    649 		}
    650 
    651 		cfp = syscfile(cfile, s2);
    652 		(void) fprintf(cfp, "S %s %s %s %s %s %lo %s %s\n",
    653 		    file1, file2, User, Optns, dfile,
    654 		    (long) stbuf.st_mode & LEGALMODE, Nuser, Sfile);
    655 		(void) fclose(cfp);
    656 		(void) sprintf(msg, "%s!%s --> %s!%s", Myname, file1,
    657 		    Rmtname, file2);
    658 		logent(msg, "QUEUED");
    659 		break;
    660 	}
    661 	_Transfer++;
    662 	return(0);
    663 }
    664 
    665 
    666 /*
    667  *	syscfile(file, sys)
    668  *	char	*file, *sys;
    669  *
    670  *	get the cfile for system sys (creat if need be)
    671  *	return stream pointer
    672  *
    673  *	returns
    674  *		stream pointer to open cfile
    675  *
    676  */
    677 
    678 static FILE	*
    679 syscfile(file, sys)
    680 char	*file, *sys;
    681 {
    682 	FILE	*cfp;
    683 
    684 	if (gtcfile(file, sys) == FAIL) {
    685 		gename(CMDPRE, sys, Grade, file);
    686 		ASSERT(access(file, 0) != 0, Fl_EXISTS, file, errno);
    687 		cfp = fdopen(creat(file, CFILEMODE), "w");
    688 		svcfile(file, sys, Sgrade);
    689 	} else
    690 		cfp = fopen(file, "a");
    691 	ASSERT(cfp != NULL, Ct_OPEN, file, errno);
    692 	return(cfp);
    693 }
    694 
    695 
    696 /*
    697  * generate and execute a uux command
    698  */
    699 
    700 void
    701 ruux(rmt, sys1, file1, sys2, fwd2, file2)
    702 char *rmt, *sys1, *file1, *sys2, *fwd2, *file2;
    703 {
    704     char cmd[BUFSIZ];
    705     char xcmd[BUFSIZ];
    706     char * xarg[6];
    707     int narg = 0;
    708     int i;
    709 
    710     /* get real Myname - it depends on who I'm calling--rmt */
    711     (void) mchFind(rmt);
    712     myName(Myname);
    713 
    714     xarg[narg++] = UUX;
    715     xarg[narg++] = "-C";
    716     if (*Xopts != NULLCHAR)
    717 	xarg[narg++] = Xopts;
    718     if (*Ropt  != ' ')
    719 	xarg[narg++] = Ropt;
    720 
    721     (void) sprintf(cmd, "%s!uucp -C", rmt);
    722 
    723     if (*Uopts != NULLCHAR)
    724 	(void) sprintf(cmd+strlen(cmd), " (%s) ", Uopts);
    725 
    726     if (*sys1 == NULLCHAR || EQUALS(sys1, Myname)) {
    727         if (ckexpf(file1))
    728   	    exit(6);
    729 	(void) sprintf(cmd+strlen(cmd), " %s!%s ", sys1, file1);
    730     }
    731     else
    732 	if (!EQUALS(rmt, sys1))
    733 	    (void) sprintf(cmd+strlen(cmd), " (%s!%s) ", sys1, file1);
    734 	else
    735 	    (void) sprintf(cmd+strlen(cmd), " (%s) ", file1);
    736 
    737     if (*fwd2 != NULLCHAR) {
    738 	if (*sys2 != NULLCHAR)
    739 	    (void) sprintf(cmd+strlen(cmd),
    740 		" (%s!%s!%s) ", sys2, fwd2, file2);
    741 	else
    742 	    (void) sprintf(cmd+strlen(cmd), " (%s!%s) ", fwd2, file2);
    743     }
    744     else {
    745 	if (*sys2 == NULLCHAR || EQUALS(sys2, Myname))
    746 	    if (ckexpf(file2))
    747 		exit(7);
    748 	(void) sprintf(cmd+strlen(cmd), " (%s!%s) ", sys2, file2);
    749     }
    750 
    751     xarg[narg++] = cmd;
    752     xarg[narg] = (char *) 0;
    753 
    754     xcmd[0] = NULLCHAR;
    755     for (i=0; i < narg; i++) {
    756 	strcat(xcmd, xarg[i]);
    757 	strcat(xcmd, " ");
    758     }
    759     DEBUG(2, "cmd: %s\n", xcmd);
    760     logent(xcmd, "QUEUED");
    761 
    762     if (fork() == 0) {
    763 	ASSERT(setuid(getuid()) == 0, "setuid", "failed", 99);
    764 	execv(UUX, xarg);
    765 	exit(0);
    766     }
    767     return;
    768 }
    769 
    770 void
    771 usage()
    772 {
    773 
    774 	(void) fprintf(stderr, gettext(
    775 	"Usage:  %s [-c|-C] [-d|-f] [-g GRADE] [-jm] [-n USER]\\\n"
    776 	"[-r] [-s FILE] [-x DEBUG_LEVEL] source-files destination-file\n"),
    777 	Progname);
    778 	cleanup(-2);
    779 }
    780