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