Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

571 lines
12 KiB
C

static char sccsid[] = "@(#)76 1.24.1.4 src/bos/usr/bin/que/rem/rembak.c, cmdque, bos411, 9430C411a 7/26/94 16:38:53";
/*
* COMPONENT_NAME: (CMDQUE) spooling commands
*
* FUNCTIONS: rembak
*
* ORIGINS: 27
*
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
* combined with the aggregated modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1985, 1994
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
/* This is the remote backend for the queueing system.
It communicates with remote hosts using the BSD lpr/lpd
protocol. See commonr.h for protocol description.
*/
#include "commonr.h"
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include <sys/stat.h>
#include <errno.h>
#include <IN/standard.h>
#include <IN/backend.h>
#include <stdio.h>
#include <locale.h>
#include <time.h>
#include <sys/id.h>
#include "outr.h"
#define STDSTAT 3
#include <ctype.h>
#include "rem_msg.h"
nl_catd catd;
#define MSGSTR(num,str) catgets(catd,MS_REM,num,str)
extern boolean backend; /* global control flag in common.c */
char *progname = "rembak";
char *senddatafile();
char *makecontrolfile();
int remsock; /* socket file descriptor */
char **saveArgv;
#ifdef DEBUG
FILE *outfp;
#endif
main(argc,argv)
int argc;
char **argv;
{
int i;
struct job thisjob, *j;
struct comline thiscomline, *c;
int firstfile; /* array num of first file in argv*/
#ifdef DEBUG
if((outfp = fopen("/tmp/rembak.out","w")) == NULL)
outfp = stderr;
if(getenv("ALLPARMS"))
{
fprintf(outfp,"rembak: ");
for(i = 0; i < argc; i++)
fprintf(outfp,"[%s]",argv[i]);
fprintf(outfp,"\n");
fflush(outfp);
}
#endif
/*
* Save arguments so that they can be printed when
* rembak dies.
*/
saveArgv = Qalloc((size_t) ( (argc+1) * sizeof(char *) ));
for ( i = 0; i < argc; i++) {
saveArgv[i] = Qalloc((size_t) (strlen(argv[i]) + 1));
strcpy(saveArgv[i], argv[i]);
}
saveArgv[i] = NULL;
(void)setlocale(LC_ALL,"");
catd = catopen(MF_REM, NL_CAT_LOCALE);
firstfile = 0;
j = &thisjob;
c = &thiscomline;
/* D31739, we will run as user's UID, but with privileges from root */
setuidx(ID_EFFECTIVE, getuidx(ID_REAL));
/* R we being run by the Queueing system? */
backend = get_backend();
#ifdef DEBUG
if(getenv("REMBAK"))
{
fprintf(outfp,"rbmain: backend = %d\n",backend);
fflush(outfp);
}
#endif
if (backend)
if ((i=log_init())<0)
syserr((int)EXITFATAL,MSGSTR(MSGLBQB,"Error: libqb's log_init returned %d."),i);
bzero((char *) j,sizeof(struct job));
/* look at command line */
definejob(argc,argv,c,j,&firstfile);
/* hookup to Server */
if ( -1 == ( remsock = hookup(c->c_Srem)) ) {
printf("%s\n",MSGSTR(MSGDWN2,"HOST_DOWN"));
qexit((int)EXITFATAL);
/* rsyserr(MSGSTR(MSGSERV,"Failure to hook up to remote server.")); */
}
if (backend) log_status(SENDING);
if ( c->c_xflg )
{ rcancel(remsock,c,j);
goto done;
}
if ( c->c_qflg || c->c_Lflg )
{ rstatus(remsock,c,j);
goto done;
}
if ( c->c_Rflg )
{ restart(remsock,c);
goto done;
}
sendjob(remsock,j,c,argv,firstfile);
done:
return(0);
}
/* Sends a job request and all datafiles(using senddatafile) and the
control file(again using senddatafile) see commonr.h for a protocol
description.
*/
boolean sendjob(s,j,c,argv,firstfile)
int s;
struct job *j;
struct comline *c;
char **argv;
int firstfile;
{
int i,k ;
char *cfname;
char *datafn[MAXFILES];
char *makecontrolfile();
for (i = 0; i < MAXFILES; datafn[i++] = 0);
short_sendreq(s,c->c_Prem,'\2');
i = firstfile;
while (argv[i]) /* i is the counter in argv, k everywhere else*/
{ k = i - firstfile;
if (!(datafn[k] = senddatafile(s,argv[i],k,c->c_Nrem)))
syserr((int)EXITFATAL,MSGSTR(MSGDATA,"Could not send datafile %s."),argv[i]);
i++;
}
if (backend == TRUE)
j->j_jobname = scopy(get_title());
else
j->j_jobname = scopy(argv[firstfile]);
if (!(cfname = makecontrolfile(j,c,argv,firstfile,datafn)))
syserr((int)EXITFATAL,MSGSTR(MSGMAKE,"Could not make control file"));
if (!sendcontrolfile(s,cfname,datafn[0]))
syserr((int)EXITFATAL,MSGSTR(MSGSEND,"Could not send control file."));
for (i=k; i; free((void *)datafn[i--]));
unlink(cfname);
return (TRUE);
}
/* send a restart request to the lpd daemon*/
boolean restart(s,c)
int s;
struct comline *c;
{
if (!short_sendreq(s,c->c_Prem,'\1'))
syserr((int)EXITFATAL,MSGSTR(MSGREST,"Could not send restart."));
else
return (TRUE);
}
/* send a status request to the lpd daemon*/
boolean rstatus(s,c,j)
int s;
struct comline *c;
struct job *j;
{
char stattype;
int numread;
if (c->c_Lflg)
stattype = '\4';
else
stattype = '\3';
long_sendreq(s,j->j_u,j->j_jn,c->c_Prem,stattype);
numread=readsock(s,fileno(stdout));
if (numread) /* if any data came back, assume success.
It will be the qstatus output from remote.
Who cares anyway? The caller of this doesn't! */
return (TRUE);
else
return (FALSE);
}
/* send a cancel request to the lpd daemon*/
boolean rcancel(s,c,j)
int s;
struct job *j;
struct comline *c;
{
int numread;
long_sendreq(s,j->j_u,j->j_jn,c->c_Prem,'\5');
numread = readsock(s,(backend ? STDSTAT : fileno(stderr)));
if (numread) /* if any data came back, assume failure because
it will be an error message.
Who cares anyway? The caller of this doesn't! */
return (FALSE);
else
return (TRUE);
}
/* read the command line argv and parse it*/
definejob(argc,argv,c,j,firstfile)
int argc;
char **argv;
struct comline *c; /* the main idea of this routine*/
int *firstfile; /* how far did we read thru the argv*/
struct job *j;
{
rrdopts(argc,argv,c,j,firstfile);
validate(c,argv[*firstfile]);
}
/*
* Create a connection to the remote printer server.
*/
int hookup(rhost)
char *rhost;
{
struct hostent *hp;
struct servent *sp;
struct sockaddr_in sin;
char *tmpaddr;
int s, timo = 1, lport = IPPORT_RESERVED - 1;
int err;
/*
* Get the host address and port number to connect to.
*/
if (rhost == NULL)
syserr((int)EXITFATAL,MSGSTR(MSGNORM,"No remote host to connect to."));
if (backend) log_status(GETHOST);
if (!(isinet_addr(rhost)))
hp = gethostbyname(rhost);
else {
tmpaddr = inet_addr(rhost);
hp = gethostbyaddr(&tmpaddr,sizeof(tmpaddr),AF_INET);
}
if (hp == NULL)
syserr((int)EXITFATAL,MSGSTR(MSGUNKN,"Unknown host %s."), rhost);
sp = getservbyname("printer", "tcp");
if (sp == NULL)
syserr((int)EXITFATAL,MSGSTR(MSGPTCP,"Unknown service for printer/tcp."));
bzero((char *)&sin, sizeof(sin));
bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
sin.sin_family = hp->h_addrtype;
sin.sin_port = sp->s_port;
/*
* Try connecting to the server.
*/
if (backend) log_status(CONNECT);
retry:
s = rresvport(&lport);
if (s < 0)
syserr((int)EXITFATAL,"rresvport"); /* insanity */
if (connect(s, (caddr_t)&sin, sizeof(sin)) < 0)
{
err = errno;
(void) close(s);
errno = err;
if (errno == EADDRINUSE)
{
lport--;
goto retry;
}
if (errno == ECONNREFUSED && timo <= 16)
{
sleep(timo);
timo *= 2;
goto retry;
}
return(-1);
}
return(s);
}
char *userstr();
char *jobnumstr();
/* short requests never have an acknowledgement
long ones do.
*/
long_sendreq(sockfd,users,jobnums,printername,reqtype )
int sockfd;
struct users *users;
struct jobnum *jobnums;
char * printername;
char reqtype;
{
char * reqstr;
char reqtypestr[] = " ";
reqtypestr[0]=reqtype;
reqstr=sconcat( reqtypestr,
printername,
" ",
users ? userstr(users) : "",
" ",
jobnums ? jobnumstr(jobnums) : "",
"\n",
0);
sendreq(sockfd,reqstr);
free((void *)reqstr);
}
/* short requests always have an acknowledgement and a printername*/
boolean short_sendreq(sockfd,printername,reqtype )
int sockfd;
char *printername;
char reqtype;
{
char * reqstr;
char reqtypestr[] = " ";
reqtypestr[0]=reqtype;
reqstr=sconcat( reqtypestr,
printername,
"\n",
0);
sendreq(sockfd,reqstr);
free((void *)reqstr);
if (!gotack(sockfd))
return(FALSE);
else
return(TRUE);
}
sendreq(sockfd,reqstring)
int sockfd;
char * reqstring;
{
int size;
#ifdef DEBUG
if(getenv("REMBAK"))
{
fprintf(outfp,"sendreq: \\%d%s",reqstring[0],&reqstring[1]);
fflush(outfp);
}
#endif
size=strlen(reqstring);
if (write(sockfd,reqstring,size) != size)
syserr((int)EXITFATAL,MSGSTR(MSGSOCK,"Send request write error on socket %d %s."),sockfd,reqstring);
return(0);
}
/* read from a sock, write to a filedes ( use
log_message to do the write if it's the
statusfil.
*/
int readsock(sock,where)
int sock;
int where;
{
char *current,buf[BUFSIZ*10];
int size ;
int bigsize =0;
current=buf;
while (1)
{
errno=0;
size = read(sock, current, BUFSIZ);
/* pretend like a broken pipe or reset is EOF */
if ((size < 0) && (errno == EPIPE || errno == ECONNRESET))
size=0;
if (size < 0)
syserr((int)EXITFATAL,MSGSTR(MSGLOST,"Lost connection reading socket."));
if (size == 0) break;
current += size;
bigsize += size;
}
if (!bigsize)
goto bottom;
buf[bigsize++] = 0; /* add null byte */
if ((where==STDSTAT) && backend)
syswarn(buf);
else
{
errno=0;
if ((size=write(where, buf, bigsize)) != bigsize)
syserr((int)EXITFATAL,MSGSTR(MSGERWT,"Error writing to fd %d."),where);
}
bottom:
(void) close(sock);
return (bigsize);
}
/* send a datafile across the net, which means:
send req string
get ack
send the data file
send ack
get ack */
char * senddatafile(s,realfn,k,filtstr)
int s; /* socket file descriptor. */
char * realfn; /* filename of file to send. */
int k; /* this is the (k+1)th file in this job*/
char *filtstr;
{
char fakefn[MAXPATHLEN]; /* spooler filename */
struct stat sbuf;
char reqtype = '\3';
time_t curtime;
int jobnum,filefd;
if (backend)
{ if (( jobnum = get_job_number()) < 0)
syserr((int)EXITFATAL,MSGSTR(MSGGJOB,"Error getting job number %d."),jobnum);
}
else
time(&curtime);
sprintf(fakefn, "df%c%03ld%s",
numtochar(k),
(backend ? jobnum : curtime % 1000),
myhost() );
/*----Insure a reasonable file size */
if ((strlen(fakefn) > 10) && strstr(filtstr,V2FILT))
fakefn[10] = '\0';
if (stat(realfn,&sbuf) == -1)
syserr((int)EXITWARN,MSGSTR(MSGSTAT,"Status on %s failed: Errno = %d."),realfn,errno);
if (!send_file_req(s,sbuf.st_size,realfn,fakefn,reqtype))
return(NULL);
if ((filefd = open(realfn,O_RDONLY,0)) < 0 )
syserr((int)EXITWARN,MSGSTR(MSGCOPN,"Cannot open %s."),realfn);
if (!send_file(s,filefd,sbuf.st_size))
return(NULL);
return (scopy(fakefn));
}
/* send a file across the net and ack and then wait for ack.
it can be either a data file or a control file*/
send_file(sokfd,f, count)
register int sokfd; /* socket file descriptor */
register int f; /* open file descriptor of file to send*/
register int count;
{
static char buf[BUFSIZ];
register int amt, i, sizerr;
sizerr = 0;
for (i = 0; i < count; i += BUFSIZ)
{
amt = ((i + BUFSIZ > count) ? count - i : BUFSIZ);
if (sizerr == 0 && read(f, buf, amt) != amt)
{ write(sokfd,"\1\n",2);
syserr((int)EXITWARN,MSGSTR(MSGESIZ,"Error reading file or file changed size."));
break;
}
if (write(sokfd, buf, amt) != amt)
syserr((int)EXITFATAL,MSGSTR(MSGWSOK,"Could not write to socket while sending file."));
}
close(f);
#ifdef DEBUG
if(getenv("REMBAK"))
{
fprintf(outfp,"send_file: file sent\n");
fflush(outfp);
}
#endif
if (!ack(sokfd))
syserr((int)EXITFATAL,MSGSTR(MSGNACK,"Could not send acknowledgement while sending file."));
if (!gotack(sokfd ))
syserr((int)EXITFATAL,MSGSTR(MSGACKN,"Send file acknowledgement not recieved."));
return(TRUE);
}
/* send the file request string across the net and wait for ack*/
boolean send_file_req(sockfd,size,realfn,fakefn,reqtype )
int sockfd;
int size;
char *realfn;
char *fakefn;
char reqtype;
{
int retval = TRUE;
char * reqstr;
char reqtypestr[] = " ";
char sizestr[50];
reqtypestr[0] = reqtype;
sprintf(sizestr,"%d",size);
reqstr=sconcat( reqtypestr,
sizestr,
" ",
fakefn,
"\n",
0);
sendreq(sockfd,reqstr);
if (!gotack(sockfd))
retval = FALSE;
free((void *)reqstr);
return(retval);
}