home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
TELECOM
/
OS9_Unix.lzh
/
RSHSRC
/
printbsd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-06
|
11KB
|
423 lines
/*
OSK version developed by Ivan Powis <pczip@chem.nott.ac.uk>
*/
/*
* Send files to a Berkeley (BSD) line printer daemon.
* This is done using a TCP connection, following the protocol
* inherent (and undocumented) in the BSD printer daemon (/usr/lib/lpd).
*
* This program differs from the normal BSD lpr(1) command in the
* following ways. The BSD lpr command writes the files to be
* printed into the spooling directory, and then notifies the
* line printer daemon (lpd) that the files are there (using a
* UNIX domain socket message). The lpd program then sees that
* the files get printed at some time. If the files are to be
* printed on another host's line printer, then the printer daemon
* will contact the daemon on the other host (using an Internet
* TCP socket) and will transfer the file to the other daemon,
* who will then see to it that the file gets printed.
* This program, however, acts like a UNIX printer daemon (lpd)
* as we assume the files are to be printed on another system.
* We go ahead and contact the UNIX lpd program on the remote host
* (using an Internet TCP socket) and send the files to that
* daemon for printing.
*
* There are three functions in this file that main() calls:
* send_start() - called once, before the first file
* send_file() - called for every file that can be opened by main
* send_done() - called at the end
*/
#include "lpr.h"
#include <pwd.h>
#define gethostname(A,B) g_hostname( (A),(B) ) /*cos os9 standard is no good*/
/*
* Variables specific to this file.
*/
static FILE *cfp; /* file pointer for control file */
static long cfilesize; /* size of cfile, in bytes */
static char cfname[MAXLEN]; /* name of "cf" file */
static char dfname[MAXLEN]; /* name of "df" file */
static char buf[MAXLINE]; /* temp buffer */
static int sockfd; /* network connection */
static int seqnum; /* seq#, set to same value for now */
long get_size();
/*
* Make connection to remote host
*/
setup_conn()
{
register int uid;
struct passwd *pw, *getpwuid();
/* we need a reserved port */
uid=getuid();
setuid(0); /*become super !*/
if ( (sockfd = tcp_open(hostname, LPR_SERVICE, -1)) < 0)
exit(_errmsg(errno,"can't connect to service: %s on host: %s",
LPR_SERVICE, hostname));
/*
* If we got the reserved port, then we're either running as
* root, or the program is set-user-ID root. In the latter case,
* the only reason we need to be set-user-ID root is to bind the
* reserved port, so we can now go back to being the "real"
* user who executed this program. We really need to do
* this anyway, to assure we can't read files as root
* that the user doesn't have normal access to.
*/
setuid(uid);
/*
* Get the name of the local host.
*/
if (gethostname(myhostname, MAXHOSTNAMELEN) < 0)
perror("gethostname error");
/*
* Get the name of the user executing this program.
*/
if ( (pw = getpwuid(uid)) == NULL)
exit(_errmsg(0,"getpwuid failed, uid = %d; who are you", uid));
strcpy(username, pw->pw_name);
}
/*
* Get a status message from server
*/
void query_server(s)
char *s;
{
register int c;
int time=0;
if (*s++ == '+') time=5;
if (*s >= '0' && *s <='9') time=atoi(s);
if(!qflag) printf("%s on %s: ",printername,hostname);
fflush(stdout);
re_query:
setup_conn();
sprintf(buf,"\004%s\l",printername);
if (write(sockfd, buf, strlen(buf)) < strlen(buf))
perror("status output: ");
while ((c=readline(sockfd, buf, MAXLINE)) > 0)
writeln(1,buf,c);
if(time==0) return;
close(sockfd);
sleep(time);
goto re_query;
}
/*
* Send a cancel or kill message to server
*/
send_kill(s)
char *s;
{
register int c;
setup_conn();
sprintf(buf,"\005%s %s %s\l",printername,rusername,s);
if (writen(sockfd, buf, strlen(buf)) != strlen(buf))
perror("writen error");
while ((c=readline(sockfd, buf, MAXLINE)) > 0){
writeln(1,buf,c);
}
}
/*
* Start things up.
*/
send_start()
{
DEBUG2("send_start: host = %s, printer = %s", hostname, printername);
setup_conn();
/*
* We must insert a 3-digit sequence number into the filenames
* that we're creating to send to the server. This is to
* distinguish between successive files that are sent to the
* same server for the same printer.
*/
seqnum = get_seqno();
sprintf(cfname, "cfA%03d%s", seqnum, myhostname);
sprintf(dfname, "dfA%03d%s", seqnum, myhostname);
sprintf(jcname, "%s-%03d",myhostname,seqnum);
DEBUG2("cfname = %s, dfname = %s", cfname, dfname);
/*
* Create the control file and open it for writing.
*/
if ( (cfp = fopen(cfname, "w")) == NULL)
fprintf(stderr,"can't open control file: %s for writing", cfname);
cfilesize = 0L;
/*
* Initialize the control file by inserting the following lines:
*
* H<hostname> (host on which the lpr was executed)
* P<username> (person executing the lpr)
* J<jobname> (for the banner page)
* C<classname> (for the banner page)
* L<username> (literal value for banner page)
* M<user> (for mail when job done)
*
* Then, for each file to be printed, send_file() will add
* the following three lines:
*
* f<df_filename> (name of text file to print)
* U<df_filename> (to unlink the file after printing)
* N<filename> (real name of the file, used by lpq)
*
* The <df_filename> is of the form "df[A-Z]nnn<host>" where
* "nnn" is the 3-digit sequence number from this host,
* and "<host>" is the name of the host on which the lpr
* was executed.
*/
add_com('H',myhostname);
add_com('P',rusername);
add_com('C',Cname);
add_com('L',rusername);
if(mailflag) add_com('M',rusername);
/*
* Send a line to the print server telling it we want
* to send it some files to print, and specifying the
* printer to be used.
*/
sprintf(buf, "%c%s\l", '\002', printername);
if (writen(sockfd, buf, strlen(buf)) != strlen(buf))
perror("writen error");
if (readn(sockfd, buf, 1) != 1)
perror("readn error");
if (buf[0] != '\0') {
if (readline(sockfd, &buf[1], MAXLINE-1) > 0)
exit(_errmsg(0,"error, server returned: %s", buf));
else
exit(_errmsg(0,"didn't get ACK from server, got 0x%02x", buf[0]));
}
}
/*
* Send a single file.
* This function is called by main once for every file to be printed.
* Main has already opened the file for reading, but it still passes
* us the actual filename from the command line, so that we can
* use the filename for identifying the file to the server.
*/
void send_file(filename, fp)
char *filename; /* filename from command line, or "-stdin" */
FILE *fp; /* file pointer on which file is open for reading */
{
static int filecount = 0;
register char *ptr;
char *rindex();
filecount++;
/*
* First strip any leading directory names off the filename.
* This is to get the base filename for the job banner.
*/
if ( (ptr = rindex(filename, '/')) != NULL) {
filename = ptr + 1;
}
/*
* If this is the first file, set the Job Class on the banner
* page to the filename.
*/
if (filecount == 1){
if (Jname != 0) add_com('J',Jname);
else add_com('J',filename);
}
else
dfname[2]++; /* A, B, C, ... */
/*
* Add the 'f', 'U' and 'N' lines to the control file.
*/
add_com('T',filename);
if(rflag)
add_com('l',dfname);
else
add_com('f',dfname);
add_com('U',dfname);
add_com('N',filename);
DEBUG2("send_file: %s, dfname = %s", filename, dfname);
xmit_file(filename, fp, dfname, '\003');
/* transmit file across network */
}
/*
* All done with the user's files.
* Now we must transmit the control file that we've been building
* to the other side.
*/
send_done()
{
fclose(cfp);
if ( (cfp = fopen(cfname, "r")) == NULL)
perror("can't reopen cfile for reading");
xmit_file("-cfile", cfp, cfname, '\002');
fclose(cfp);
/*
* We're done with the control file, so delete it.
* (Don't unlink if debugflag is 1, assuming we're debugging.)
*/
if (debugflag == 0 && unlink(cfname) < 0)
perror("can't unlink control file: %s", cfname);
close(sockfd);
}
/*
* Transmit one file to the server.
* This routine is used to send both the actual text files (data files)
* that the user wants printed, and to send the control file (cfile)
* that we build up as we send the data files.
* The only difference between transmitting these two types of files
* is the first byte of the transmission (002 for the cfile and 003
* for the dfiles).
*/
xmit_file(filename, fp, fname, xmittype)
char *filename; /* name from command line, or "-stdin" or "-cfile" */
FILE *fp;
char *fname; /* the cfname or dfname */
char xmittype; /* '\002' or '\003' */
{
register long size;
/*
* We have to get the exact size of the file in bytes
* to send to the server, so that it knows how much
* data to read from the net.
*/
size = get_size(filename, fp);
DEBUG2("xmit_file: %s, size = %ld", filename, size);
/*
* Send a line to the print server giving the type of
* file, the exact size of the file in bytes,
* and the name of the file (its dfname, not its actual
* name).
*/
sprintf(buf, "%c%ld %s\l", xmittype, size, fname);
if (writen(sockfd, buf, strlen(buf)) != strlen(buf))
perror("writen error");
if (readn(sockfd, buf, 1) != 1)
perror("readn error");
if (buf[0] != '\0')
fprintf(stderr,"didn't get an ACK from server, got 0x%02x", buf[0]);
/*
* Now send the actual file itself.
*/
copyfile(fp);
/*
* Write a byte of zero to the server, and wait for
* a byte of zero to be returned from the server,
* telling us all is OK (I'm OK, you're OK).
*/
if (writen(sockfd, "", 1) != 1)
perror("writen error");
if (readn(sockfd, buf, 1) != 1)
perror("readn error");
if (buf[0] != '\0')
fprintf(stderr,"Server responds with error code %02x", buf[0]);
}
/*
* Copy a file to the network.
* We read the file using standard i/o, one line at a time,
* and write the data to the network one line at a time.
*/
copyfile(fp)
FILE *fp;
{
register int len;
char line[MAXLINE];
while (fgets(line, MAXLINE, fp) != NULL) {
len = strlen(line);
if(!rflag) r_to_l(line,len); /* os9 \n -> UNIX \l */
if (writen(sockfd, line, len) != len)
perror("writen error");
}
if (ferror(fp))
perror("read error from fgets");
}
/*
* Determine the exact size of a file.
* Under UNIX this is easy - we just call the fstat() system call.
* Under other operating systems it is harder, since they may not use
* exactly one character to represent a newline.
*/
long
get_size(filename, fp)
char *filename;
FILE *fp;
{
int l;
if ((l=_gs_size(fileno(fp))) < 0)
perror("can't fstat");
return(l);
}
add_com(c,str)
char c, *str;
{
fprintf(cfp, "%c%s\l", c,str);
cfilesize += strlen(str) + 2;
}
r_to_l(str,len)
register int len;
register char *str;
{
int i;
for(i=0;i<len;i++,str++){
if(*str == '\r') *str='\l';
}
}