rsalz@bbn.com (Rich Salz) (09/15/88)
Submitted-by: papowell@julius.cs.umn.edu Posting-number: Volume 16, Issue 26 Archive-name: plp/part13 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 13 (of 16)." # Contents: src/print_support.c src/recvfiles.c PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'src/print_support.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/print_support.c'\" else echo shar: Extracting \"'src/print_support.c'\" \(17575 characters\) sed "s/^X//" >'src/print_support.c' <<'END_OF_FILE' X/*************************************************************************** X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell X *************************************************************************** X * MODULE: Print_support.c X * handle the actual output to the Printer X *************************************************************************** X * Revision History: Created Wed Jan 13 16:21:39 CST 1988 X * $Log: print_support.c,v $ X * Revision 3.1 88/06/18 09:35:18 papowell X * Version 3.0- Distributed Sat Jun 18 1988 X * X * Revision 2.4 88/05/27 08:28:01 papowell X * Added a SIGCONT to start up the output filter. X * X * Revision 2.3 88/05/19 10:34:19 papowell X * Fixed open() calls to have a 0 parameter, ie: open(f, perms, 0), where needed X * X * Revision 2.2 88/05/14 10:21:16 papowell X * Modified -X flag handling X * X * Revision 2.1 88/05/09 10:09:44 papowell X * PLP: Released Version X * X * Revision 1.4 88/03/25 15:01:04 papowell X * Debugged Version: X * 1. Added the PLP control file first transfer X * 2. Checks for MX during file transfers X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities; X * apparently they open files and then assume that they will stay X * open. X * 4. Made sure that stdin, stdout, stderr was available at all times. X * X * Revision 1.3 88/03/11 19:29:04 papowell X * Minor Changes, Updates X * X * Revision 1.2 88/03/05 15:01:11 papowell X * Minor Corrections, Lint Problems X * X * Revision 1.1 88/03/01 11:09:01 papowell X * Initial revision X * X *************************************************************************** X * void Print_open(): opens the Printer X * static int Print_of_fd(): makes an 'of' filter if needed X * void Print_close(): closes the Printer X * int Print_ready(): combines Print_open() and Print_of_fd() X * static int of_stop(): stops the 'of' filter X * int Print_string( str ): prints a string through 'of' or to Printer X * int Print_copy( fd ): copies a file through 'of' or to Printer X * int Print_filter( file, cmd ): makes a filter and copies file X * int Print_banner(): prints a banner through 'of' or to Printer X * Note: the above procedures which return values return JSUCC on success, X * and JFAIL or JABORT on failure X ***************************************************************************/ X X#ifndef lint static char id_str1[] = X "$Header: print_support.c,v 3.1 88/06/18 09:35:18 papowell Exp $ PLP Copyright 1988 Patrick Powell"; X#endif lint X X#include "lp.h" X X/*************************************************************************** X * Print_open() X * Open the Printer, and set the Print_fd variables X * If the RW printcap flag is set, output is opened RW, otherwise X * opened writeonly in append mode. X * X * If the Printer is a tty (i.e.- isatty returns non-zero), X * then the baud rate is set. The baud rate table is stolen from X * the original LPD code, which stole it from STTY, etc. X * Side Effect: X * sets the Print_fd variable to a non-zero value X * terminates if Printer is unable to be opened X ****************************************************************************/ struct bauds { X char *string; X int baud; X int speed; X} bauds[] = { X "110", 110, B110, X "134", 134, B134, X "150", 150, B150, X "300", 300, B300, X "600", 600, B600, X "1200", 1200, B1200, X "1800", 1800, B1800, X "2400", 2400, B2400, X "4800", 4800, B4800, X "9600", 9600, B9600, X "19200", 19200, B19200, X "38400", 38400, B38400, X (char *)0, 0, 0 X}; X static int of_pid; /* OF process pid */ static int of_fd; /* pipe to OF process */ static int of_running; /* of filter running */ static char filter_stop[] = "\031\001"; /* what to send filter */ X Print_open() X{ X int err; X X /* X * check to see if it is open X */ X if( Print_fd ){ X return; X } X if( LP == 0 || *LP == 0 ){ X fatal( XLOG_INFO, "Missing LP value for local Printer"); X } X setstatus("waiting for %s to become ready since %s (offline?)", X Printer, Time_str()); X Print_fd = open(LP, RW ? ( O_RDWR|O_APPEND ) : ( O_WRONLY|O_APPEND ), 0); X if( Print_fd < 0 ){ X err = errno; X setstatus("Print_open: '%s' open(%s) failed, %s",Printer,LP, X Errormsg(err)); X errno = err; X logerr_die( XLOG_INFO, "Print_open: cannot open %s", LP); X } else if( Print_fd == 0 ){ X fatal( XLOG_INFO, "Print_open: cannot happen- Print_fd == 0"); X } X /* X * if it is a tty, set the baud rates and control information X */ X if (isatty(Print_fd)){ X Do_stty(Print_fd); X } X if(Debug>3)log(XLOG_DEBUG,"Print_open: %s is fd %d", LP, Print_fd ); X} X X/* X * Start up an output filter, if needed. X */ Print_of_fd() X{ X int p[2]; X char *cmd; X X if( OF == 0 || *OF == 0 || of_pid ){ X return; X } X /* X * set OF command line X */ X cmd = Setup_filter('o',OF); X if( cmd == 0 || *cmd == 0 ){ X fatal(XLOG_INFO, "bad OF entry"); X } X if(Debug>2)log( XLOG_DEBUG, "starting OF, '%s'", cmd); X /* X * create pipe and fork X */ X if( pipe(p) < 0 ){ X logerr_die( XLOG_NOTICE, "Print_of_of: pipe failed" ); X } X if( p[0] < 3 || p[1] < 3 ){ X fatal( XLOG_INFO, "Print_of_fd: IMPOSSIBLE- pipe fd %d %d", p[0], p[1]); X } X if ((of_pid = fork()) == 0) { /* child */ X if( dup2(p[0], 0) < 0 /* pipe is std in */ X || dup2(Print_fd, 1) < 0 ){ /* Printer is std out */ X logerr_die( XLOG_NOTICE, "Print_of_fd: dup2 failed" ); X } X if(Debug>3)log( XLOG_DEBUG, "Print_of_fd: forked %d OF: %s", X getpid(), cmd ); X if( geteuid() == 0 && setreuid( Daemon_uid, Daemon_uid ) < 0 ){ X logerr_die( XLOG_NOTICE, "Print_of_fd: setreuid failed" ); X } X mexecv( cmd ); X logerr_die( XLOG_NOTICE,"Print_of_fd: execv failed %s", cmd); X } else if( of_pid < 0 ){ X logerr_die( XLOG_NOTICE, "Print_of_fd: fork failed" ); X } X (void)close(p[0]); /* close input side */ X of_fd = p[1]; X of_running = of_pid; X if(Debug>3)log(XLOG_DEBUG,"started OF process %d, fd %d", of_pid, of_fd); X} X X/*************************************************************************** X * Print_close() X * 1. Close the pipes and outputs. X * 2. Signal the of process that it is to do something. X * Note that there is a Reapchild() call that will collect the X * children; this will make sure that there is a minimal number of X * outstanding processes active. X ***************************************************************************/ X void Print_close() X{ X if( of_fd ){ X (void)close(of_fd); X of_fd = 0; X } X if( Print_fd ){ X (void)close(Print_fd); /* close Printer */ X Print_fd = 0; X } X /* X * when you kill the printer, make sure that you do it neatly X */ X if( of_pid ){ X (void)kill(of_pid, SIGCONT); X } X of_pid = 0; X} X X/*************************************************************************** X * Print_ready() X * 1. open the Printer if neccessary X * 2. start up the output filter X * 3. if the filter has been stopped, start it X * Return: JSUCC if started, JFAIL if not X ***************************************************************************/ Print_ready() X{ X /* X * open the Printer X */ X Print_open(); X Print_of_fd(); X if( of_pid && of_running == 0 ){ X if (kill(of_pid, SIGCONT) < 0) { X logerr( XLOG_INFO,"cannot restart output filter"); X Print_close(); X return( JFAIL ); X } X of_running = of_pid; X } X return( JSUCC ); X} X X/*************************************************************************** X * of_stop() X * stop the output filter if neccessary X * 1. open and create the filter X * 2. flush output X * 3. kill(SIGSTOP) it X * Return: JSUCC if stopped, JFAIL if not X ***************************************************************************/ X int of_stop() X{ X union wait statb; X int pid; X X Print_open(); X Print_of_fd(); X /* X * stop the OF filter X */ X if( of_pid && of_running ){ X if(Debug>3)log( XLOG_DEBUG, "stopping output filter" ); X if( write( of_fd, filter_stop, strlen(filter_stop)) X != strlen(filter_stop) ){ X logerr( XLOG_NOTICE,"of_stop: cannot write to OF"); X Print_close(); X return( JFAIL ); X } X /* X * wait until OF blocks X */ X if(Debug>3)log( XLOG_DEBUG, "of_stop: waiting for OF %d", of_pid ); X while ((pid = wait3(&statb,WUNTRACED,(struct rusage *)0)) != -1 X && pid != of_pid) ; X if( pid < 0 || statb.w_stopval != WSTOPPED ){ X logerr( XLOG_INFO, "of_stop: OF %d died (%s)", of_pid, X Decode_status( &statb ) ); X Print_close(); X return( JFAIL ); X } X if(Debug>3)log( XLOG_DEBUG, "of_stop: output filter stopped" ); X of_running = 0; X } X return( JSUCC ); X} X X/*************************************************************************** X * Print_string( char *str ) X * print a string through a filter X * 1. Enable the line Printer X * 2. get the filter or device fd; X * 3. put out the string X * 4. if unsuccessful, close the Printer X * Return: JSUCC if successful, JFAIL otherwise X ***************************************************************************/ int Print_string( str ) X char *str; X{ X int f; X int l; X X if( Print_ready() != JSUCC ){ X return( JFAIL ); X } X if( of_fd ){ X f = of_fd; X } else { X f = Print_fd; X } X l = strlen( str ); X if( write( f, str, l ) != l ){ X logerr( XLOG_INFO, "Print_string: write error"); X Print_close(); X return( JFAIL ); X } X return( JSUCC ); X} X X X/*************************************************************************** X * Print_copy( int fd ) X * copy a file through a filter X * 1. ready the Printer X * 2. copy the file to the appropriate output device X * 3. if an error, close the Printer X ***************************************************************************/ int Print_copy( fd ) X int fd; X{ X int f; X long cnt; X char buf[BUFSIZ]; X int in; /* bytes read */ X int out; /* bytes written out */ X X cnt = 0; X if( Print_ready() != JSUCC ){ X return( JFAIL ); X } X if( of_fd ){ X f = of_fd; X } else { X f = Print_fd; X } X while( (in = read( fd, buf, sizeof(buf) )) > 0 ){ X out = write( f, buf, in ); X if( in != out ){ X logerr( XLOG_INFO, "Print_copy: write error"); X Print_close(); X return( JFAIL ); X } X cnt = cnt + out; X } X /* X * completed the reading X */ X if( in < 0 ){ X logerr( XLOG_INFO, "Print_copy: read error"); X Print_close(); X return( JFAIL ); X } X if(Debug>3)log(XLOG_DEBUG,"Print_copy: printed %d bytes", cnt); X return( JSUCC ); X} X X/*************************************************************************** X *Print_filter( int fd, char *cmd ) X * spawn a subprocess to do the printing X * 1. stop the Printer X * 2. fork a process X * 3. wait for process to complete X * 4. restart the process X * Return: JSUCC if successful, JFAIL otherwise X ***************************************************************************/ int Print_filter( file, cmd ) X int file; X char *cmd; X{ X int succ; /* success code */ X int filter_pid; /* filter process */ X int pid; /* daughter pid */ X union wait status; /* daughter status */ X int err; /* saved value of errno */ X X /* X * stop the Printer X */ X succ = of_stop(); X if( succ != JSUCC ){ X return( succ ); X } X /* X * fork a process, and connect file to fd 0, Printer to fd 1. X */ X if ((filter_pid = fork()) == 0) { /* daughter */ X /* X * dup input file to standard in and Printer to stdout X */ X if( dup2(file, 0)<0 || dup2(Print_fd, 1)<0 ){ X logerr_die(XLOG_NOTICE,"Print_filter: dup2 failed filter %s",cmd); X } X mexecv(cmd); X logerr_die( XLOG_NOTICE,"Print_filter: cannot execv %s", cmd); X } else if( filter_pid < 0 ){ X logerr( XLOG_NOTICE, "Print_filter: fork failed" ); X Print_close(); X return( JFAIL ); X } X /* X * Wait for filter to complete X */ X if(Debug>2)log(XLOG_DEBUG,"Print_filter: waiting for pid %d",filter_pid); X while ((pid = wait(&status)) > 0 && pid != filter_pid){ X if(Debug>3)log( XLOG_DEBUG, "Print_filter:caught %d (%s)", X pid, Decode_status(&status) ); X } X err = errno; X if(Debug>2)log( XLOG_DEBUG, "Print_filter: filter %d finished (%s)", X pid,Decode_status(&status)); X errno = err; X /* X * Check to see how filter terminated X */ X if( pid < 0 || !WIFEXITED(status) X || (unsigned)status.w_retcode > 1 ){ X /* X * died for bad reasons, don't run this again X */ X log(XLOG_INFO,"Print_filter:Filter '%s' Malfunction (%s)", X cmd, Decode_status(&status)); X Print_close(); X return( JABORT ); X } else if (status.w_retcode != 0){ X /* X * try again X */ X log( XLOG_INFO, "Print_filter:Filter '%s' Retry wanted", cmd ); X Print_close(); X return(JFAIL); X } X return(JSUCC); X} X X/* X * Print_banner() X * 1. get the Printer ready X * 2. call the banner() routine with the correct parameter X */ Print_banner() X{ X int f; X X if(Debug>3)log(XLOG_DEBUG,"Print_banner: printing banner"); X if( Print_ready() != JSUCC ){ X return( JFAIL ); X } X if( of_fd ){ X f = of_fd; X } else { X f = Print_fd; X } X if( banner(f) != JSUCC ){ X if(Debug>3)log(XLOG_DEBUG,"Print_banner: banner failed"); X Print_close(); X return( JFAIL ); X } X return( JSUCC ); X} X X/* X * Fri Feb 26 08:44:53 CST 1988 Patrick Powell X * set terminal modes X * This code was based on a public domain version of public domain version X * of stty. I suppose that I could have created if from scratermctrlh, X * but I have seen the same table appearing X * in many "public domain" display terminal modes programs. X */ X struct tchars termctrl; struct ltchars linectrl; struct sgttyb mode; struct X{ X char *string; X int set; X int reset; X int lset; X int lreset; X} modes[] = { X "bs0", BS0, BS1, 0, 0, X "bs1", BS1, BS1, 0, 0, X "cbreak", CBREAK, 0, 0, 0, X "-cbreak", 0, CBREAK, 0, 0, X "cooked", 0, RAW, 0, 0, X "cr0", CR0, CR3, 0, 0, X "cr1", CR1, CR3, 0, 0, X "cr2", CR2, CR3, 0, 0, X "cr3", CR3, CR3, 0, 0, X "decctlq", 0, 0, LDECCTQ, 0, X "-decctlq", 0, 0, 0, LDECCTQ, X "echo", ECHO, 0, 0, 0, X "-echo", 0, ECHO, 0, 0, X "even", EVENP, 0, 0, 0, X "-even", 0, EVENP, 0, 0, X "ff0", FF0, FF1, 0, 0, X "ff1", FF1, FF1, 0, 0, X "lcase", LCASE, 0, 0, 0, X "-lcase", 0, LCASE, 0, 0, X "litout", 0, 0, LLITOUT, 0, X "-litout", 0, 0, 0, LLITOUT, X "nl", 0, CRMOD, 0, 0, X "-nl", CRMOD, 0, 0, 0, X "nl0", NL0, NL3, 0, 0, X "nl1", NL1, NL3, 0, 0, X "nl2", NL2, NL3, 0, 0, X "nl3", NL3, NL3, 0, 0, X "noflsh", 0, 0, LNOFLSH, 0, X "-noflsh", 0, 0, 0, LNOFLSH, X "nohang", 0, 0, LNOHANG, 0, X "-nohang", 0, 0, 0, LNOHANG, X "odd", ODDP, 0, 0, 0, X "-odd", 0, ODDP, 0, 0, X "raw", RAW, 0, 0, 0, X "-raw", 0, RAW, 0, 0, X "tab0", TAB0, XTABS, 0, 0, X "tab1", TAB1, XTABS, 0, 0, X "tab2", TAB2, XTABS, 0, 0, X "tabs", 0, XTABS, 0, 0, X "-tabs", XTABS, 0, 0, 0, X "tandem", TANDEM, 0, 0, 0, X "-tandem", 0, TANDEM, 0, 0, X "tilde", 0, 0, LTILDE, 0, X "-tilde", 0, 0, 0, LTILDE, X "tn300", CR1, ALLDELAY, 0, 0, X "tty33", CR1, ALLDELAY, 0, 0, X "tty37", FF1+CR2+TAB1+NL1, ALLDELAY, 0, 0, X "vt05", NL2, ALLDELAY, 0, 0, X 0, X}; X X struct special { X char *name; X char *cp; X char def; X} special[] = { X "stop", &termctrl.t_stopc, CSTOP, X "start", &termctrl.t_startc, CSTART, X 0 X}; X Do_stty( fd ) X int fd; X{ X int i; X int localmode; X int linedisc; X char buf[BUFSIZ], *bp, *ep, *arg; X X if( ioctl(fd, TIOCGETP, &mode) < 0 X || ioctl(fd, TIOCGETC, &termctrl) < 0 X || ioctl(fd, TIOCLGET, &localmode) < 0 X || ioctl(fd, TIOCGLTC, &linectrl) < 0 ){ X logerr_die( XLOG_INFO,"cannot get tty parameters"); X } X if(Debug>3)log(XLOG_DEBUG,"stty: before mode 0x%x, lmode 0x%x, speed 0x%x", X mode.sg_flags, localmode, mode.sg_ispeed ); X if( BR ){ X for(i=0; bauds[i].baud && BR != bauds[i].baud; i++); X if( i == 0){ X fatal(XLOG_INFO,"illegal baud rate %d", BR); X } X mode.sg_ispeed = mode.sg_ospeed = bauds[i].speed; X } X mode.sg_flags &= ~FC; X mode.sg_flags |= FS; X localmode &= ~XC; X localmode |= XS; X X X if( TY && *TY ){ X (void)strcpy(buf, TY); X ep = buf; X } else { X ep = 0; X } X while( ep && *ep ){ X for( ; *ep && isspace(*ep) ; ++ ep ); X for( arg = ep; *ep && !isspace(*ep) ; ++ ep ); X if( *ep ){ X *ep = 0; X ++ep; X } X for(i=0; modes[i].string && strcmp(modes[i].string,arg); i++); X if(modes[i].string) { X if(Debug>4)log(XLOG_DEBUG, X "stty: modes %s, mc 0x%x ms 0x%x lc 0x%x ls 0x%x", X modes[i].string, modes[i].reset, modes[i].set, X modes[i].lreset, modes[i].lset ); X mode.sg_flags &= ~modes[i].reset; X mode.sg_flags |= modes[i].set; X localmode &= ~modes[i].lreset; X localmode |= modes[i].lset; X continue; X } X for (i = 0; special[i].name && strcmp(special[i].name,arg); i++); X if( special[i].name ){ X for( ; *ep && isspace(*ep) ; ++ ep ); X for( bp = ep; *ep && !isspace(*ep) ; ++ ep ); X if( *ep ){ X *ep = 0; X ++ep; X } X if( *bp == 0 ){ X fatal( XLOG_INFO, "stty: missing parameter for %s", arg ); X } X if (bp[0] == '^'){ X if( bp[1] == '?' ){ X *special[i].cp = 0177; X } else { X *special[i].cp = 037 & bp[1]; X } X } else { X *special[i].cp = bp[0]; X } X if(Debug>4)log(XLOG_DEBUG,"stty: special %s %s", arg, bp ); X continue; X } X for(i=0; bauds[i].string && strcmp(bauds[i].string,arg); i++); X if(bauds[i].string) { X if(Debug>4)log(XLOG_DEBUG,"stty: speed %s", arg ); X mode.sg_ispeed = mode.sg_ospeed = bauds[i].speed; X continue; X } X if (!strcmp("new", arg)){ X if(Debug>4)log(XLOG_DEBUG,"stty: ldisc %s", arg ); X linedisc = NTTYDISC; X if (ioctl(fd, TIOCSETD, &linedisc)<0) X logerr_die(XLOG_INFO,"stty: TIOCSETD ioctl failed"); X continue; X } X if (!strcmp("old",arg)){ X if(Debug>4)log(XLOG_DEBUG,"stty: ldisc %s", arg ); X linedisc = 0; X if (ioctl(fd, TIOCSETD, &linedisc)<0) X logerr_die(XLOG_INFO,"stty: TIOCSETD ioctl failed"); X continue; X } X fatal(XLOG_INFO,"unknown mode: %s\n", arg); X } X if(Debug>3)log(XLOG_DEBUG,"stty: after mode 0x%x, lmode 0x%x, speed 0x%x", X mode.sg_flags, localmode, mode.sg_ispeed ); X if( ioctl(fd, TIOCSETN, &mode) < 0 X || ioctl(fd, TIOCSETC, &termctrl) < 0 X || ioctl(fd, TIOCSLTC, &linectrl) < 0 X || ioctl(fd, TIOCLSET, &localmode) < 0 ){ X logerr_die( XLOG_NOTICE,"cannot set tty parameters"); X } X} END_OF_FILE if test 17575 -ne `wc -c <'src/print_support.c'`; then echo shar: \"'src/print_support.c'\" unpacked with wrong size! fi # end of 'src/print_support.c' fi if test -f 'src/recvfiles.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/recvfiles.c'\" else echo shar: Extracting \"'src/recvfiles.c'\" \(18372 characters\) sed "s/^X//" >'src/recvfiles.c' <<'END_OF_FILE' X/*************************************************************************** X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell X *************************************************************************** X * MODULE: recvfiles.c X * Receive files from a remote site X *************************************************************************** X * Revision History: Created Sat Jan 16 07:10:12 CST 1988 X * $Log: recvfiles.c,v $ X * Revision 3.1 88/06/18 09:35:25 papowell X * Version 3.0- Distributed Sat Jun 18 1988 X * X * Revision 2.4 88/05/21 10:28:14 papowell X * Minor editing X * X * Revision 2.3 88/05/14 10:18:01 papowell X * Use long format for job file names; X * Added 'fd', no forward flag; X * Control file has to have hostname and origination agree. X * X * Revision 2.2 88/05/11 09:52:55 papowell X * Remote printer file transfer error fixed. X * X * Revision 2.1 88/05/09 10:09:55 papowell X * PLP: Released Version X * X * Revision 1.5 88/04/28 09:52:40 papowell X * added casts to shut up lint X * X * Revision 1.4 88/04/26 15:53:39 papowell X * Fixed up a horribly silly bug in the add_files and File_name X * routines; sigh. Would you believe an L (l) and a one (1) got mixed X * up? X * X * Revision 1.3 88/03/25 15:01:17 papowell X * Debugged Version: X * 1. Added the PLP control file first transfer X * 2. Checks for MX during file transfers X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities; X * apparently they open files and then assume that they will stay X * open. X * 4. Made sure that stdin, stdout, stderr was available at all times. X * X * Revision 1.2 88/03/05 15:01:07 papowell X * Minor Corrections, Lint Problems X * X * Revision 1.1 88/03/01 11:09:06 papowell X * Initial revision X * X ***************************************************************************/ X#ifndef lint static char id_str1[] = X "$Header: recvfiles.c,v 3.1 88/06/18 09:35:25 papowell Exp $ PLP Copyright 1988 Patrick Powell"; X#endif lint X X#include "lp.h" X X/*************************************************************************** X * This module implements the file transfer protocol at the receiving X * site. For each job: X * 1. The data files are transferred. X * 2. The control files are transferred. X * If the transfer is unsuccessful, all job files are removed. X * X * Individual files are transferred using the following protocol. X * X * 1. The sending site sends a line with the size and name of the file, X * and a flag indicating if it is a data or control file. X * 2. The receiving site will acknowledge reception. X * 3. The remote site will send the file. X * 4. The receiving site will acknowledge reception. X * X * The transfer protocol is implemented by a simple FSM: X * INIT: no files transferred X * DATA: data file transferred X * CONTROL: control file transferred X * X * A list of all files associated with the job is maintained, X * and if any errors result, the list of files will be deleted. X * X ***************************************************************************/ X X/*************************************************************************** X * recvfiles() X * X * Gets a job from the remote end. X * X * The old Berkeley protocol was to send data files and then the control X * file. The PLP protocol will send the control file first, then the data X * files, followed by the name of the control file. X * X * If there is an error during transfer, all the jobs associated with the X * file are removed. X * X * In order to be compatible with the Berkeley LPD, old Berkeley format is X * also supported. X ***************************************************************************/ recvfiles() X{ X int i; /* ACME Integers */ X int succ; /* success flag */ X int flag; /* file kind */ X long size; /* file size */ X char fname[CFNAMELEN+1]; /* file fname */ X char cfname[CFNAMELEN+1]; /* file fname */ X char tfname[CFNAMELEN+1]; /* file fname */ X int fd; /* file descriptor */ X FILE *cfp; /* FILE descriptor */ X int state; /* state: IDLE, BDATA, BCNTRL, PCNTRL, PDATA */ X long jobsize; /* job size */ X#define IDLE 0 /* nothing doing */ X#define BDATA 1 /* transferring Berkeley data file */ X#define BCNTRL 2 /* transferring Berkeley control file */ X#define PCNTRL 3 /* transferring PLP control file */ X#define PDATA 4 /* transferring PLP data file */ X#define PLAST 5 /* last file has been transferred */ X X /* X * get the printcap entry X */ X if( Get_pc_entry(Printer, Status_pc_vars, Status_pc_len ) == 0){ X log( XLOG_INFO, "revcfiles: trying to start non-existent Printer" ); X } X if( SD == 0 || *SD == 0 ){ X /* X * no spooling directory, not a Printer X */ X if(Debug>0)log(XLOG_DEBUG, "revcfiles: not a Printer"); X return; X } X /* chdir to spool directory */ X if (chdir(SD) < 0) { X logerr_die( XLOG_NOTICE,"revcfiles: cannot chdir to %s", SD); X } X if(Debug>3)log(XLOG_DEBUG,"recvfiles: setting up log"); X Setuplog( LF, 1 ); X if(Debug>3)log(XLOG_DEBUG,"recvfiles: sending confirm"); X if( send_ack(0) != JSUCC ){ X if(Debug>3)log(XLOG_DEBUG,"recvfiles: confirm failed"); X goto error; X } X X /* X * set up the file transfers X */ X state = IDLE; X while( (succ = get_file_xfer(&flag, &size, fname )) == JSUCC && flag ){ X if(Debug>3)log(XLOG_DEBUG,"recvfiles: state %d, flag %d, file %s", X state,flag,fname); X switch( state ){ X case IDLE: X cfp = NULL; X Rec_cnt = 0; X (void)strcpy( cfname, fname ); X jobsize = 0; X for( i = 0; i < 26; ++i ){ X CFparm[i][0] = 0; X } X switch( flag ){ X case CNAME: X state = PCNTRL; break; X case DFILE: X state = BDATA; break; X default: X goto protocol; X } X break; X case BDATA: X switch( flag ){ X case DFILE: X break; X case CFILE: X state = BCNTRL; X break; X default: X goto protocol; X } X break; X case PCNTRL: X switch( flag ){ X case DFILE: X state = PDATA; break; X default: X goto protocol; X } X break; X case PDATA: X switch( flag ){ X case DFILE: X break; X case CEND: X state = PLAST; X break; X default: X goto protocol; X } X break; X default: X goto protocol; X } X /* X * trying to send a file with a different sequence number? X */ X if( Job_match( cfname, fname ) == 0 ){ X log( XLOG_INFO, "recvfiles: file with bad format %s", fname ); X succ = JFAIL; X goto error; X } X switch( state ){ X case PDATA: X /* X * add names to list X */ X if( Find_name( fname ) < 0 ){ X log( XLOG_INFO, X "recvfiles: data file not in job '%s'", fname ); X succ = JFAIL; X goto error; X } X break; X case BCNTRL: X case PCNTRL: X (void)strcpy(tfname, fname ); X fname[0] = 't'; X break; X } X /* X * add the file name to the temporary list X */ X if( (i = add_recfiles( fname )) < 0 ){ X log( XLOG_INFO, "recvfiles: too many files (%s)", fname ); X succ = JFAIL; X goto error; X } X /* X * check to see that file size does not exceed the total X */ X Parms[i].num = 1; X Parms[i].size = ((size+1023)/1024); X jobsize = jobsize + Parms[i].size; X if( MX && jobsize > MX ){ X log( XLOG_INFO, "recvfiles: file (%s) exceeds MX",fname, MX); X succ = JFAIL; X goto error; X } X /* X * check to see if we have opened the file already X */ X if( state != PLAST ){ X /* X * we lock the file X */ X fd = Exlockcf( fname ); X if( fd < 0 ){ X /* X * The file is locked. This can only happen if some other X * process got hold of the file. We either have several X * processes transferring files or horrible collision course. X * DONT remove already transferred files. X */ X logerr(XLOG_NOTICE,"recvfiles: %s IMPOSSIBLE collision %s", X fname,From); X exit(1); X } X succ = get_file( size, fd, fname ); X if( succ != JSUCC ){ X goto error; X } X } X /* X * open a FILE for the control file, and check the entries in it. X * If we have just got the file in PLP, just scan for entries. X * Otherwise check to see that all are present. X */ X switch( state ){ X case BCNTRL: X case PCNTRL: X if( (cfp = fdopen( fd, "r" ) ) < 0 ){ X logerr_die( XLOG_INFO,"recvfiles: fdopen failed" ); X } X if( Validate_cf( state == PCNTRL, cfp, fname ) == 0 ){ X goto error; X } X break; X case PLAST: X if( Validate_cf( 0, cfp, fname ) == 0 ){ X goto error; X } X break; X } X switch( state ){ X case PLAST: X case BCNTRL: X Rename_cf( fname ); X Rec_cnt = 0; X (void)fclose(cfp); X state = IDLE; X break; X case PCNTRL: X break; X default: X (void)close( fd ); X break; X } X /* X * We can confirm transfer to the other end X */ X if( send_ack( 0 ) != JSUCC ){ X goto error; X } X } X if( succ == JSUCC && flag == 0 && state == IDLE ){ X /* X * finished! start up Printer X */ X if(Debug>3)log(XLOG_DEBUG,"recvfiles: done, starting Printer"); X Link_close(); X Startprinter(); X return; X } X /* X * Error conditions X * 1. remove files X * 2. reply with error status to remote end X */ protocol: X log(XLOG_INFO, X "recvfiles: protocol violation, state %d, flag %d, file %s", X state, flag, fname ); error: X rm_recfiles(); X (void)send_ack(1); X Startprinter(); X return; X} X X/*************************************************************************** X * add_recfiles(char * Name) X * add a file Name to the received files X ***************************************************************************/ X add_recfiles( filename ) X char *filename; X{ X int i; X X if(Debug>4)log(XLOG_DEBUG,"add_recfiles: %s", filename ); X /* X * add a control file name to the parameter list entries X * if there is nothing in the list, clobber the entry. X */ X if( Rec_cnt == 0 ){ X Parmcount = 0; X } X if( (i = Add_name( filename )) < 0 ){ X return( -1 ); X } X Rec_cnt = Parmcount; X return( i ); X} X X/*************************************************************************** X * rm_recfiles() X * remove the files that are in the receive list; X ***************************************************************************/ X rm_recfiles() X{ X int i; /* ACME Integer, Inc. */ X X if(Debug>4)log(XLOG_DEBUG,"rm_recfiles: removing files" ); X for( i = 0; i < Rec_cnt; ++i ){ X if(Debug>4)log(XLOG_DEBUG,"rm_recfiles: %s", Parms[i].filename ); X (void)unlink_daemon( Parms[i].filename ); X } X Rec_cnt = 0; X} X X/*************************************************************************** X * get_file_xfer(int *flag; long *size; char *name ) X * 1. read a line from the far end X * 2. the line has the format <flag><size> <name>\n X * "%c%d %s\n" format X * 3. extract the information from the line X * 4. acknowledge the information X ***************************************************************************/ get_file_xfer( flag, size, name ) X int *flag; X long *size; X char *name; X{ X char buf[BUFSIZ]; /* buffer for reading */ X int i; /* ACME Integers, Inc. */ X char *cp; /* ACME Pointers, Inc. */ X X /* X * read a line from the remote end X * use Bomb-proof Read (bpread), which reads up to the first \n X */ X if(Debug>3)log(XLOG_DEBUG,"get_file_xfer: starting", buf ); X if( (i = bpread(1, buf, sizeof(buf)) ) < 0 ){ X logerr(XLOG_INFO, "get_file_xfer: read error from remote"); X *flag = 0; X goto error; X } else if( i == 0 ){ X if(Debug>3)log(XLOG_DEBUG,"get_file_xfer: end of input"); X *flag = 0; X return( JSUCC ); X } X /* X * UGLY UGLY UGLY: X * what I wanted to do is: X * if( sscanf( buf, "%c%d %s", flag, size, name ) != 3 )... X * but the guilty-of-incestuous-rape sscanf is not portable across X * several implementations. X */ X if(Debug>3)log(XLOG_DEBUG,"get_file_xfer: %d'%s'", buf[0], &buf[1]); X /* X * pull off the flag information X */ X i = buf[0]; X if( i != DFILE && i != CFILE && i != CNAME && i != CEND){ X log(XLOG_INFO, "get_file_xfer: bad first char (%d)", i); X goto error; X } X *flag = i; X /* X * now pull off the size information X */ X *size = 0; X for( cp = &buf[1]; (i = *cp) && isdigit( i ); ++cp ){ X *size = 10*(*size) + (i - '0'); X } X if( *cp != ' '){ X log(XLOG_INFO, "get_file_xfer: no space separator (%d)", *cp); X goto error; X } X while( *cp == ' ' ) ++cp; X if( Job_match( cp, cp ) == 0 ){ X log(XLOG_INFO, "get_file_xfer: bad job name '%s'", cp); X goto error; X } X /* X * must be a data or control file only X */ X (void)strcpy( name, cp ); X /* X * send a confirmation X */ X if( send_ack( 0 ) != JSUCC ){ X goto error; X } X if(Debug>3)log(XLOG_DEBUG,"get_file_xfer: flag %d, size %d, name '%s'", X *flag, *size, name ); X return( JSUCC ); X /* X * error, give up X */ error: X Link_close(); X return( JFAIL ); X} X X/*************************************************************************** X * get_file(long size; int fd; char *name) X * 1. copy size bytes from fd 1 to fd X * 2. the next byte read should be 0; if not, then you have error X ***************************************************************************/ get_file( size, fd, name ) X long size; X int fd; X char *name; X{ X char buf[BUFSIZ]; /* buffer for reading */ X long cnt; /* number of bytes */ X int i; /* ACME Integers, Inc. */ X X /* X * we simply copy the file from the remote end X */ X if(Debug>3)log(XLOG_DEBUG,"get_file: get %d (%s) from %s",size,name,From); X cnt = size; X while( cnt > 0 ){ X if( cnt > sizeof(buf) ){ X i = sizeof(buf); X } else { X i = cnt; X } X i = read(1, buf, i); X if( i < 0 ){ X logerr(XLOG_INFO, "get_file: read from %s failed", From ); X goto error; X } X if( i == 0 ){ X log(XLOG_INFO,"get_file: read 0 bytes from %s, assume dead",From); X goto error; X } X if( write( fd, buf, i ) != i ){ X logerr(XLOG_INFO, "write to %s failed", name ); X goto error; X } X cnt = cnt - i; X } X if(Debug>3)log(XLOG_DEBUG,"get_file: success %d (%s) from %s", X size,name,From); X i = read(1, buf, 1); X if( i < 0 ){ X logerr(XLOG_INFO, "get_file: end from %s failed", From ); X goto error; X } X if( i == 0 ){ X log(XLOG_INFO, "get_file: end, 0 bytes from %s, assume dead", From ); X goto error; X } X if( buf[0] != 0 ){ X log(XLOG_INFO, "get_file: bad end confirm, %d from %s",buf[0],From); X goto error; X } X if(Debug>3)log(XLOG_DEBUG,"get_file: read %s from %s", name, From ); X return( JSUCC ); error: X Link_close(); X return( JFAIL ); X} X X/*************************************************************************** X * send_ack( int c ) X * acknowledge by sending back single char c X ***************************************************************************/ send_ack( c ) X int c; X{ X char buf[1]; X X buf[0] = c; X if( write( 1, buf, 1 ) != 1 ){ X logerr(XLOG_INFO,"send_ack: %d to %s failed", c, From ); X return( JFAIL ); X } X if(Debug>3)log(XLOG_DEBUG,"send_ack: %d to %s succeeded", c, From ); X return( JSUCC ); X} X X/*************************************************************************** X * Validate_cf( scan, fp, fname ) X * Check to ensure that the files contained in this control file X * were actually sent as part of the control file. X * 1. fseek to the start of the file X * 2. read the file, looking data file entries X * 3. Check that the names of the data files are consistent with the X * name of the control file X * 4. Check that the file was sent X ***************************************************************************/ Validate_cf( scan, fp, fname ) X int scan; X FILE *fp; X char *fname; X{ X char buf[BUFSIZ]; /* Buffer, Inc. */ X int c, l; /* AMCE Aluminum Siding and Integers, Inc. */ X char *bp; /* Buffer */ X long size; /* total job size */ X int perms; /* permissions */ X int name_len; /* length of hostname to check */ X X if(Debug>6){ X (void)fprintf( stderr,"Validate_cf: files %d", Parmcount ); X for( c = 0; c < Parmcount; ++c ){ X (void)fprintf(stderr,", %d '%s'(%d)",c, X Parms[c].filename,Parms[c].num); X } X (void)fprintf( stderr, "\n" ); X } X size = 0; X if( fseek( fp, 0L, 0 ) < 0 ){ X logerr_die( XLOG_INFO, "Validate_cf: fseek failed '%s'", fname ); X } X while( fgets( buf, sizeof(buf), fp ) ){ X l = strlen( buf ); X if( l > MAXPARMLEN ){ X log( XLOG_INFO, "Validate_cf: '%s' line too long '%s'",fname,buf); X return( 0 ); X } X if( buf[l-1] != '\n' ){ X log( XLOG_INFO, "Validate_cf: '%s', missing \\n", fname ); X return( 0 ); X } X buf[l-1] = 0; X c = *buf; X bp = buf+1; X if( !isascii(c) || !isalnum(c)){ X log( XLOG_INFO, "Validate_cf: file %s, bad line'%s'",fname,bp); X return( 0 ); X } X /* X * Check to see that data file information is OK X */ X if( isupper(c) && c != 'L' && c != 'U' ){ X (void)strcpy( CFparm[c-'A'], bp ); X } X if( islower(c) || c == 'U' ){ X /* X * check to see that the file is in the list X */ X if( Job_match( fname, bp ) == 0 ){ X log( XLOG_INFO,"Validate_cf: file %s, bad data file '%s'", X fname,bp); X return( 0 ); X } X /* X * if we are scanning, just enter name in list, otherwise X * check to see that file is in the Parms[] list and that the X * total job size is within limits X */ X if( scan ){ X if( Add_name( bp ) < 0 ){ X log( XLOG_INFO,"Validate_cf: too many files in job %s (%s)", X fname,bp); X return( 0 ); X } X } else if( (l = Find_name( bp )) < 0 ){ X log(XLOG_INFO, X "Validate_cf: file %s, data file '%s' not in list", X fname,bp); X return( 0 ); X } else if( Parms[l].num == 0 ){ X log( XLOG_INFO, X "Validate_cf: file %s, data file '%s' not transferred", X fname,bp); X return( 0 ); X } else if( islower( c ) ){ X size = size + Parms[l].size; X if( MX && size > MX ){ X log( XLOG_INFO,"Validate_cf: job %s too large", fname); X return( 0 ); X } X } X } X } X /* X * check to see if the remote submitter has valid authorizations X */ X if( LOGNAME[0] == 0 ){ X log( XLOG_INFO,"Validate_cf: job %s missing username", fname); X return( 0 ); X } X /* X * check for long or short name X */ X if( LH ){ X name_len = strlen( From ); X } else { X name_len = strlen( &fname[STARTFR] ); X } X if( strncmp( FROMHOST, &fname[STARTFR], name_len ) ){ X log( XLOG_INFO,"Validate_cf: bad filename '%s' FROMHOST '%s'", X fname, FROMHOST); X return( 0 ); X } X /* X * check to see if you will accept forwarded files X * if FD is set, then no forwarded files allowed X */ X if( FD && strcmp( FROMHOST, From ) ){ X log( XLOG_INFO,"Validate_cf: forwarded job '%s' FROMHOST '%s'", X fname, FROMHOST); X return( 0 ); X } X perms = 'R'; X if((Permfile && *Permfile && X !Checkperm(Permfile,FROMHOST,LOGNAME,First_name,&perms,(int *)0,0)) X ||(XU && *XU && X !Checkperm(XU,FROMHOST,LOGNAME,First_name,&perms,(int *)0,0 ) )){ X log(XLOG_INFO, "Validate_cf: %s@%s cannot use '%s'", X LOGNAME, FROMHOST, First_name ); X return( 0 ); X } X return( 1 ); X} END_OF_FILE if test 18372 -ne `wc -c <'src/recvfiles.c'`; then echo shar: \"'src/recvfiles.c'\" unpacked with wrong size! fi # end of 'src/recvfiles.c' fi echo shar: End of archive 13 \(of 16\). cp /dev/null ark13isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 16 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.