V10/cmd/uucp/uucp.c
/* @(#)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;
}