uux.c revision 462be471126495414a94f9fa35e16c02dc462c04
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
#include "uucp.h"
#define SHORTBUF 64
#define NOSYSPART 0
#define GENSEND(f, a, b, c) {\
ASSERT(fprintf(f, "S %s %s %s -%s %s 0666 %s %s\n", a, b, User, _Statop?"o":"", c, User, _Sfile) >= 0, Ct_WRITE, "", errno);\
}
#define GENRCV(f, a, b) {\
char tbuf[SHORTBUF]; \
gename (DATAPRE, xsys, 'Z', tbuf); \
ASSERT(fprintf(f, "R %s %s %s - %s 0666 %s %s\n", a, b, User, _Sfile, User, tbuf) \
>= 0, Ct_WRITE, "", errno);\
}
#define STRNCPY(str1, str2) { \
(void) strncpy(str1, str2, (sizeof(str1) - 1)); \
str1[sizeof(str1) - 1] = '\0'; \
}
#define STRNCAT(str1, str2) { \
(void) strncat(str1, str2, \
(sizeof(str1) - 1 - strlen(str1))); \
}
#define APPCMD(p) {STRNCAT(cmd, p); STRNCAT(cmd, " ");}
static char _Sfile[MAXFULLNAME];
static int _Statop;
char Sgrade[NAMESIZE];
void cleanup();
static void usage();
/*
* uux
*/
int
main(argc, argv, envp)
int argc;
char *argv[];
char *envp[];
{
char *jid();
FILE *fprx = NULL, *fpc = NULL, *fpd = NULL, *fp = NULL;
static void onintr();
int cfileUsed = 0; /* >0 if commands put in C. file flag */
int cflag = 0; /* if > 0 make local copy of files to be sent */
int nflag = 0; /* if != 0, do not request error notification */
int zflag = 0; /* if != 0, request success notification */
int pipein = 0;
int startjob = 1;
short jflag = 0; /* -j flag output Jobid */
int bringback = 0; /* return stdin to invoker on error */
int ret, i;
char *getprm();
char redir = '\0'; /* X_STDIN, X_STDOUT, X_STDERR as approprite */
char command = TRUE;
char cfile[NAMESIZE]; /* send commands for files from here */
char dfile[NAMESIZE]; /* used for all data files from here */
char rxfile[NAMESIZE]; /* file for X_ commands */
char tfile[NAMESIZE]; /* temporary file name */
char t2file[NAMESIZE]; /* temporary file name */
char buf[BUFSIZ];
char inargs[BUFSIZ];
char cmd[BUFSIZ];
char *ap;
char prm[BUFSIZ];
char syspart[MAXFULLNAME], rest[BUFSIZ];
char xsys[MAXFULLNAME];
char *fopt = NULL;
char *retaddr = NULL;
struct stat stbuf;
/* Set locale environment variables local definitions */
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
#endif
(void) textdomain(TEXT_DOMAIN);
/* we want this to run as uucp, even if the kernel doesn't */
Uid = getuid();
Euid = geteuid(); /* this should be UUCPUID */
if (Uid == 0)
setuid(UUCPUID);
/* init environment for fork-exec */
Env = envp;
/* choose LOGFILE */
STRNCPY(Logfile, LOGUUX);
/*
* determine local system name
*/
(void) strcpy(Progname, "uux");
Pchar = 'X';
(void) signal(SIGILL, onintr);
(void) signal(SIGTRAP, onintr);
(void) signal(SIGIOT, onintr);
(void) signal(SIGEMT, onintr);
(void) signal(SIGFPE, onintr);
(void) signal(SIGBUS, onintr);
(void) signal(SIGSEGV, onintr);
(void) signal(SIGSYS, onintr);
(void) signal(SIGTERM, SIG_IGN);
uucpname(Myname);
Ofn = 1;
Ifn = 0;
*_Sfile = '\0';
/*
* determine id of user starting remote
* execution
*/
guinfo(Uid, User);
STRNCPY(Loginuser,User);
*Sgrade = NULLCHAR;
/*
* this is a check to see if we are using the administrator
* defined service grade. The GRADES file will determine if
* we are. If so then setup the default grade variables.
*/
if (eaccess(GRADES, 04) != -1) {
Grade = 'A';
Sgrades = TRUE;
STRNCPY(Sgrade, "default");
}
/*
* create/append command log
*/
commandlog(argc,argv);
/*
* since getopt() can't handle the pipe input option '-';
* change it to "-p"
*/
for (i=1; i<argc && *argv[i] == '-'; i++)
if (EQUALS(argv[i], "-"))
argv[i] = "-p";
while ((i = getopt(argc, argv, "a:bcCjg:nprs:x:z")) != EOF) {
switch(i){
/*
* use this name in the U line
*/
case 'a':
retaddr = optarg;
break;
/*
* if return code non-zero, return command's input
*/
case 'b':
bringback = 1;
break;
/* do not make local copies of files to be sent (default) */
case 'c':
cflag = 0;
break;
/* make local copies of files to be sent */
case 'C':
cflag = 1;
break;
/*
* set priority of request
*/
case 'g':
if (!Sgrades) {
if (strlen(optarg) < (size_t) 2 && isalnum(*optarg))
Grade = *optarg;
else {
(void) fprintf(stderr, gettext("No"
" administrator defined service"
" grades available on this"
" machine.\n"));
(void) fprintf(stderr, gettext("UUCP"
" service grades range from"
" [A-Z][a-z] only.\n"));
cleanup(-1);
}
}
else {
STRNCPY(Sgrade, optarg);
if (vergrd(Sgrade) != SUCCESS)
cleanup(FAIL);
}
break;
case 'j': /* job id */
jflag = 1;
break;
/*
* do not send failure notification to user
*/
case 'n':
nflag++;
break;
/*
* send success notification to user
*/
case 'z':
zflag++;
break;
/*
* -p or - option specifies input from pipe
*/
case 'p':
pipein = 1;
break;
/*
* do not start transfer
*/
case 'r':
startjob = 0;
break;
case 's':
fopt = optarg;
_Statop++;
break;
/*
* debugging level
*/
case 'x':
Debug = atoi(optarg);
if (Debug <= 0)
Debug = 1;
break;
default:
usage();
}
}
DEBUG(4, "\n\n** %s **\n", "START");
if( optind >= argc )
usage();
/*
* copy arguments into a buffer for later
* processing
*/
inargs[0] = '\0';
for (; optind < argc; optind++) {
DEBUG(4, "arg - %s:", argv[optind]);
STRNCAT(inargs, " ");
STRNCAT(inargs, argv[optind]);
}
/*
* get working directory and change
* to spool directory
*/
DEBUG(4, "arg - %s\n", inargs);
gwd(Wrkdir);
if(fopt){
if(*fopt != '/') {
(void) snprintf(_Sfile, (sizeof(_Sfile) - 1),
"%s/%s", Wrkdir, fopt);
_Sfile[sizeof(_Sfile) - 1] = '\0';
}
else {
(void) snprintf(_Sfile, (sizeof(_Sfile) - 1),
"%s", fopt);
_Sfile[sizeof(_Sfile) - 1] = '\0';
}
}
else
strcpy(_Sfile, "dummy");
if (chdir(WORKSPACE) != 0) {
(void) fprintf(stderr,
gettext("No spool directory - %s - get help\n"), WORKSPACE);
cleanup(EX_OSERR);
}
/*
* find remote system name
* remote name is first to know that
* is not > or <
*/
ap = inargs;
xsys[0] = '\0';
while ((ap = getprm(ap, (char *)NULL, prm)) != NULL) {
if (prm[0] == '>' || prm[0] == '<') {
ap = getprm(ap, (char *)NULL, prm);
continue;
}
/*
* split name into system name
* and command name
*/
(void) split(prm, xsys, CNULL, rest);
break;
}
if (xsys[0] == '\0')
STRNCPY(xsys, Myname);
STRNCPY(Rmtname, xsys);
DEBUG(4, "xsys %s\n", xsys);
/* get real Myname - it depends on who I'm calling--Rmtname */
(void) mchFind(Rmtname);
myName(Myname);
/*
* check to see if system name is valid
*/
if (versys(xsys) != 0) {
/*
* bad system name
*/
fprintf(stderr, gettext("bad system name: %s\n"), xsys);
if (fprx != NULL)
(void) fclose(fprx);
if (fpc != NULL)
(void) fclose(fpc);
cleanup(EX_NOHOST);
}
DEBUG(6, "User %s\n", User);
if (retaddr == NULL)
retaddr = User;
/*
* initialize command buffer
*/
*cmd = '\0';
/*
* generate JCL files to work from
*/
/*
* fpc is the C. file for the local site.
* collect commands into cfile.
* commit if not empty (at end).
*
* the appropriate C. file.
*/
gename(CMDPRE, xsys, Grade, cfile);
DEBUG(9, "cfile = %s\n", cfile);
ASSERT(access(cfile, 0) != 0, Fl_EXISTS, cfile, errno);
fpc = fdopen(ret = creat(cfile, CFILEMODE), "w");
ASSERT(ret >= 0 && fpc != NULL, Ct_OPEN, cfile, errno);
setbuf(fpc, CNULL);
/* set Jobid -- C.jobid */
STRNCPY(Jobid, BASENAME(cfile, '.'));
/*
* rxfile is the X. file for the job, fprx is its stream ptr.
* if the command is to be executed locally, rxfile becomes
* a local X. file, otherwise we send it as a D. file to the
* remote site.
*/
gename(DATAPRE, xsys, 'X', rxfile);
DEBUG(9, "rxfile = %s\n", rxfile);
ASSERT(access(rxfile, 0) != 0, Fl_EXISTS, rxfile, errno);
fprx = fdopen(ret = creat(rxfile, DFILEMODE), "w");
ASSERT(ret >= 0 && fprx != NULL, Ct_WRITE, rxfile, errno);
setbuf(fprx, CNULL);
clearerr(fprx);
(void) fprintf(fprx,"%c %s %s\n", X_USER, User, Myname);
if (zflag) {
(void) fprintf(fprx, "%c return status on success\n",
X_COMMENT);
(void) fprintf(fprx,"%c\n", X_SENDZERO);
}
if (nflag) {
(void) fprintf(fprx, "%c don't return status on failure\n",
X_COMMENT);
(void) fprintf(fprx,"%c\n", X_SENDNOTHING);
} else {
(void) fprintf(fprx, "%c return status on failure\n",
X_COMMENT);
fprintf(fprx,"%c\n", X_NONZERO);
}
if (bringback) {
(void) fprintf(fprx, "%c return input on abnormal exit\n",
X_COMMENT);
(void) fprintf(fprx,"%c\n", X_BRINGBACK);
}
if (_Statop)
(void) fprintf(fprx,"%c %s\n", X_MAILF, _Sfile);
if (retaddr != NULL) {
(void) fprintf(fprx, "%c return address for status or input return\n",
X_COMMENT);
(void) fprintf(fprx,"%c %s\n", X_RETADDR, retaddr);
}
(void) fprintf(fprx, "%c job id for status reporting\n", X_COMMENT);
(void) fprintf(fprx,"%c %s\n", X_JOBID, Jobid);
/*
* create a JCL file to spool pipe input into
*/
if (pipein) {
/*
* fpd is the D. file into which we now read
* input from stdin
*/
gename(DATAPRE, Myname, 'B', dfile);
ASSERT(access(dfile, 0) != 0, Fl_EXISTS, dfile, errno);
fpd = fdopen(ret = creat(dfile, DFILEMODE), "w");
ASSERT(ret >= 0 && fpd != NULL, Ct_OPEN, dfile, errno);
/*
* read pipe to EOF
*/
while (!feof(stdin)) {
ret = fread(buf, 1, BUFSIZ, stdin);
ASSERT(fwrite(buf, 1, ret, fpd) == ret, Ct_WRITE,
dfile, errno);
}
ASSERT(fflush(fpd) != EOF && ferror(fpd) == 0, Ct_WRITE, dfile, errno);
(void) fclose(fpd);
/*
* if command is to be executed on remote
* create extra JCL
*/
if (!EQUALSN(Myname, xsys, MAXBASENAME)) {
GENSEND(fpc, dfile, dfile, dfile);
}
/*
* create file for X_ commands
*/
(void) fprintf(fprx, "%c %s\n", X_RQDFILE, dfile);
(void) fprintf(fprx, "%c %s\n", X_STDIN, dfile);
if (EQUALS(Myname, xsys))
wfcommit(dfile, dfile, xsys);
}
/*
* parse command
*/
ap = inargs;
while ((ap = getprm(ap, (char *)NULL, prm)) != NULL) {
DEBUG(4, "prm - %s\n", prm);
/*
* redirection of I/O
*/
if ( prm[0] == '<' ) {
if (prm[1] == '<') {
fprintf(stderr,
gettext("'<<' may not be used in command\n"));
cleanup(EX_USAGE);
}
redir = X_STDIN;
continue;
}
if ( prm[0] == '>' ) {
if (prm[1] == '>') {
fprintf(stderr,
gettext("'>>' may not be used in command\n"));
cleanup(EX_USAGE);
}
if (prm[1] == '|') {
fprintf(stderr,
gettext("'>|' may not be used in command\n"));
cleanup(EX_USAGE);
}
if (prm[1] == '&') {
fprintf(stderr,
gettext("'>&' may not be used in command\n"));
cleanup(EX_USAGE);
}
redir = X_STDOUT;
continue;
}
if ( EQUALS(prm, "2>") ) {
redir = X_STDERR;
continue;
}
/*
* some terminator
*/
if ( prm[0] == '|' || prm[0] == '^'
|| prm[0] == '&' || prm[0] == ';') {
if (*cmd != '\0') /* not 1st thing on line */
APPCMD(prm);
command = TRUE;
continue;
}
/*
* process command or file or option
* break out system and file name and
* use default if necessary
*/
ret = split(prm, syspart, CNULL, rest);
DEBUG(4, "syspart -> %s, ", syspart);
DEBUG(4, "rest -> %s, ", rest);
DEBUG(4, "ret -> %d\n", ret);
if (command && redir == '\0') {
/*
* command
*/
APPCMD(rest);
command = FALSE;
continue;
}
if (syspart[0] == '\0') {
STRNCPY(syspart, Myname);
DEBUG(6, "syspart -> %s\n", syspart);
} else if (versys(syspart) != 0) {
/*
* bad system name
*/
fprintf(stderr,
gettext("bad system name: %s\n"), syspart);
if (fprx != NULL)
(void) fclose(fprx);
if (fpc != NULL)
(void) fclose(fpc);
cleanup(EX_NOHOST);
}
/*
* process file or option
*/
/*
* process file argument
* expand filename and create JCL card for
* redirected output
* e.g., X file sys
*/
if ((redir == X_STDOUT) || (redir == X_STDERR)) {
if (rest[0] != '~')
if (ckexpf(rest))
cleanup(EX_OSERR);
ASSERT(fprintf(fprx, "%c %s %s\n", redir, rest,
syspart) >= 0, Ct_WRITE, rxfile, errno);
redir = '\0';
continue;
}
/*
* if no system specified, then being
* processed locally
*/
if (ret == NOSYSPART && redir == '\0') {
/*
* option
*/
APPCMD(rest);
continue;
}
/* local xeqn + local file (!x !f) */
if ((EQUALSN(xsys, Myname, MAXBASENAME))
&& (EQUALSN(xsys, syspart, MAXBASENAME))) {
/*
* create JCL card
*/
if (ckexpf(rest))
cleanup(EX_OSERR);
/*
* JCL card for local input
* e.g., I file
*/
if (redir == X_STDIN) {
(void) fprintf(fprx, "%c %s\n", X_STDIN, rest);
} else
APPCMD(rest);
ASSERT(fprx != NULL, Ct_WRITE, rxfile, errno);
redir = '\0';
continue;
}
/* remote xeqn + local file (sys!x !f) */
if (EQUALSN(syspart, Myname, MAXBASENAME)) {
/*
* check access to local file
* if cflag is set, copy to spool directory
* otherwise, just mention it in the X. file
*/
if (ckexpf(rest))
cleanup(EX_OSERR);
DEBUG(4, "rest %s\n", rest);
/* see if I can read this file as read uid, gid */
if (uidstat(rest, &stbuf) != 0) {
(void) fprintf(stderr,
gettext("can't get file status %s\n"), rest);
cleanup(EX_OSERR);
}
/* XXX - doesn't check group list */
if ( !(stbuf.st_mode & ANYREAD)
&& !(stbuf.st_uid == Uid && stbuf.st_mode & 0400)
&& !(stbuf.st_gid ==getgid() && stbuf.st_mode & 0040)
) {
fprintf(stderr,
gettext("permission denied %s\n"), rest);
cleanup(EX_CANTCREAT);
}
/* D. file for sending local file */
gename(DATAPRE, xsys, 'A', dfile);
if (cflag || !(stbuf.st_mode & ANYREAD)) {
/* make local copy */
if (uidxcp(rest, dfile) != 0) {
fprintf(stderr,
gettext("can't copy %s\n"), rest);
cleanup(EX_CANTCREAT);
}
(void) chmod(dfile, DFILEMODE);
/* generate 'send' entry in command file */
GENSEND(fpc, rest, dfile, dfile);
} else /* don't make local copy */
GENSEND(fpc, rest, dfile, dfile);
/*
* JCL cards for redirected input in X. file,
* e.g.
* I D.xxx
* F D.xxx
*/
if (redir == X_STDIN) {
/*
* don't bother making a X_RQDFILE line that
* renames stdin on the remote side, since the
* remote command can't know its name anyway
*/
(void) fprintf(fprx, "%c %s\n", X_STDIN, dfile);
(void) fprintf(fprx, "%c %s\n", X_RQDFILE, dfile);
} else {
APPCMD(BASENAME(rest, '/'));;
/*
* generate X. JCL card that specifies
* F file
*/
(void) fprintf(fprx, "%c %s %s\n", X_RQDFILE,
dfile, BASENAME(rest, '/'));
}
redir = '\0';
continue;
}
/* local xeqn + remote file (!x sys!f ) */
if (EQUALS(Myname, xsys)) {
/*
* expand receive file name
*/
if (ckexpf(rest))
cleanup(EX_OSERR);
/*
* strategy:
* request rest from syspart. when it arrives,
* we can run the command.
*
* tfile is command file for receive from remote.
* we defer commiting until later so
* that only one C. file is created per site.
*
* dfile is name of data file to receive into;
* we don't use it, just name it.
*
* once the data file arrives from syspart.
* arrange so that in the X. file (fprx), rest is
* required and named appropriately. this
* necessitates local access to SPOOL/syspart, which
* is handled by a hook in uuxqt that allows files
* in SPOOL/syspart to be renamed on the F line.
*
* pictorially:
*
* ===== syspart/C.syspart.... ===== (tfile)
* R rest D.syspart... (dfile)
*
*
* ===== local/X.local... ===== (fprx)
* F SPOOL/syspart/D.syspart... rest (dfile)
*
*
*/
if (gtcfile(tfile, syspart) != SUCCESS) {
gename(CMDPRE, syspart, 'R', tfile);
ASSERT(access(tfile, 0) != 0,
Fl_EXISTS, tfile, errno);
svcfile(tfile, syspart, Sgrade);
(void) close(creat(tfile, CFILEMODE));
}
fp = fopen(tfile, "a");
ASSERT(fp != NULL, Ct_OPEN, tfile, errno);
setbuf(fp, CNULL);
gename(DATAPRE, syspart, 'R', dfile);
/* prepare JCL card to receive file */
GENRCV(fp, rest, dfile);
ASSERT(fflush(fp) != EOF && ferror(fp) == 0, Ct_WRITE, dfile, errno);
(void) fclose(fp);
if (rest[0] != '~')
if (ckexpf(rest))
cleanup(EX_OSERR);
/*
* generate receive entries
*/
if (redir == X_STDIN) {
(void) fprintf(fprx,
"%c %s/%s/%s\n", X_RQDFILE, Spool,
syspart, dfile);
(void) fprintf(fprx, "%c %s\n", X_STDIN, dfile);
} else {
(void) fprintf(fprx, "%c %s/%s/%s %s\n",
X_RQDFILE, Spool, syspart, dfile,
BASENAME(rest, '/'));
APPCMD(BASENAME(rest, '/'));
}
redir = '\0';
continue;
}
/* remote xeqn/file, different remotes (xsys!cmd syspart!rest) */
if (!EQUALS(syspart, xsys)) {
/*
* strategy:
* request rest from syspart.
*
* set up a local X. file that will send rest to xsys,
* once it arrives from syspart.
*
* arrange so that in the xsys D. file (fated to become
* an X. file on xsys), rest is required and named.
*
* pictorially:
*
* ===== syspart/C.syspart.... ===== (tfile)
* R rest D.syspart... (dfile)
*
*
* ===== local/X.local... ===== (t2file)
* F Spool/syspart/D.syspart... rest (dfile)
* C uucp -C rest D.syspart... (dfile)
*
* ===== xsys/D.xsysG.... (fprx)
* F D.syspart... rest (dfile)
* or, in the case of redir == '<'
* F D.syspart... (dfile)
* I D.syspart... (dfile)
*
* while we do push rest around a bunch,
* we use the protection scheme to good effect.
*
* we must rely on uucp's treatment of requests
* from XQTDIR to get the data file to the right
* place ultimately.
*/
/* build (or append to) C.syspart... */
if (gtcfile(tfile, syspart) != SUCCESS) {
gename(CMDPRE, syspart, 'R', tfile);
ASSERT(access(tfile, 0) != 0,
Fl_EXISTS, tfile, errno);
svcfile(tfile, syspart, Sgrade);
(void) close(creat(tfile, CFILEMODE));
}
fp = fopen(tfile, "a");
ASSERT(fp != NULL, Ct_OPEN, tfile, errno);
setbuf(fp, CNULL);
gename(DATAPRE, syspart, 'R', dfile);
GENRCV(fp, rest, dfile);
ASSERT(fflush(fp) != EOF && ferror(fp) == 0, Ct_WRITE, dfile, errno);
(void) fclose(fp);
/* build local/X.localG... */
/* name might collide with rxfile; no real danger */
gename(XQTPRE, Myname, Grade, t2file);
ASSERT(access(t2file, 0)!=0, Fl_EXISTS, t2file, errno);
(void) close(creat(t2file, CFILEMODE));
fp = fopen(t2file, "w");
ASSERT(fp != NULL, Ct_OPEN, t2file, errno);
setbuf(fp, CNULL);
(void) fprintf(fp, "%c third party request, job id\n",
X_COMMENT);
(void) fprintf(fp, "%c %s\n", X_JOBID, Jobid);
(void) fprintf(fp, "%c %s/%s/%s %s\n", X_RQDFILE,
Spool, syspart, dfile, BASENAME(rest, '/'));
(void) fprintf(fp, "%c uucp -C %s %s!%s\n",
X_CMD, BASENAME(rest, '/'), xsys, dfile);
ASSERT(fflush(fp) != EOF && ferror(fp) == 0, Ct_WRITE, t2file, errno);
(void) fclose(fp);
/* put t2file where uuxqt can get at it */
wfcommit(t2file, t2file, Myname);
/* generate xsys/X.sysG... cards */
if (redir == X_STDIN) {
(void) fprintf(fprx, "%c %s\n",
X_RQDFILE, dfile);
(void) fprintf(fprx, "%c %s\n", X_STDIN, dfile);
} else {
(void) fprintf(fprx, "%c %s %s\n", X_RQDFILE,
dfile, BASENAME(rest, '/'));
APPCMD(BASENAME(rest, '/'));
}
redir = '\0';
continue;
}
/* remote xeqn + remote file, same remote (sys!x sys!f) */
if (rest[0] != '~') /* expand '~' on remote */
if (ckexpf(rest))
cleanup(EX_OSERR);
if (redir == X_STDIN) {
(void) fprintf(fprx, "%c %s\n", X_STDIN, rest);
}
else
APPCMD(rest);
redir = '\0';
continue;
}
/*
* place command to be executed in JCL file
*/
(void) fprintf(fprx, "%c %s\n", X_CMD, cmd);
ASSERT(fflush(fprx) != EOF && ferror(fprx) == 0, Ct_WRITE, rxfile, errno);
(void) fclose(fprx); /* rxfile is ready for commit */
logent(cmd, "QUEUED");
gename(XQTPRE, Myname, Grade, tfile);
if (EQUALS(xsys, Myname)) {
/* local xeqn -- use X_ file here */
/* this use of the X_ file can not collide with the earlier one */
wfcommit(rxfile, tfile, xsys);
/*
* see if -r option requested JCL to be queued only
*/
if (startjob)
xuuxqt(Myname);
} else {
/* remote xeqn -- send rxfile to remote */
/* put it in a place where cico can get at it */
/* X_ file name might collide with an earlier use, */
/* but that one lives locally, while this one gets shipped */
GENSEND(fpc, rxfile, tfile, rxfile);
}
cfileUsed = (ftell(fpc) != 0L); /* was cfile used? */
ASSERT(fflush(fpc) != EOF && ferror(fpc) == 0, Ct_WRITE, cfile, errno);
(void) fclose(fpc);
/* commit C. files for remote receive */
commitall();
/*
* has any command been placed in command JCL file
*/
if (cfileUsed) {
svcfile(cfile, xsys, Sgrade);
commitall();
/*
* see if -r option requested JCL to be queued only
*/
if (startjob)
xuucico(xsys);
} else
unlink(cfile);
if (jflag) { /* print Jobid */
STRNCPY(Jobid, jid());
printf("%s\n", Jobid);
}
cleanup(0);
/* NOTREACHED */
return (0);
}
/*
* cleanup and unlink if error
* code -> exit code
* return:
* none
*/
void
cleanup(code)
int code;
{
static int first = 1;
/* prevent recursion on errors */
if (first) {
first = 0;
rmlock(CNULL);
if (code) {
fprintf(stderr, gettext("uux failed ( %d )\n"), code);
wfabort();
}
}
DEBUG(1, "exit code %d\n", code);
if (code < 0)
exit(-code);
else
exit(code);
}
/*
* catch signal then cleanup and exit
*/
static void
onintr(inter)
int inter;
{
char str[30];
(void) signal(inter, SIG_IGN);
(void) sprintf(str, "XSIGNAL %d", inter);
logent(str, "XCAUGHT");
cleanup(EX_TEMPFAIL);
}
static void
usage()
{
(void) fprintf(stderr, gettext("Usage: %s [-bcCjnprz] [-a NAME]"
" [-g GRADE] [-s FILE] [-x NUM] command-string\n"), Progname);
exit(EX_USAGE);
}