schreiner@iravcl.ira.uka.de (09/29/89)
This is a simple version of lpr(1) and lpd(1) that i wrote. It allowes
several processes to use the printer via lpr simultaneously. To keep
things small i didn't use the directory(3) routines, sorry. MAN pages
are included.
Ralf Wenk, using a friends account
------------------------ Cut here ----------------------------------------
echo x - Makefile
sed 's/^X//' > Makefile << '/'
X# Makefile for lpr, lpd, cancel
X
XPGMS = lpr lpd cancel
X
Xall : $(PGMS)
X
X
Xlpr : lpr.c
X cc -O -o $@ $?
X chmem =2000 $@
X
Xlpd : lpd.c
X cc -O -o $@ $?
X chmem =2000 $@
X
Xcancel : cancel.c
X cc -O -o $@ $?
X chmem =2000 $@
X
/
echo x - cancel.1
sed 's/^X//' > cancel.1 << '/'
XCOMMANDS
X cancel - line printer job remover
X
XINVOCATION
X cancel file ...
X
XEXPLANATION
X This program unlinks files from the line printer daemon directory
X for cancelling the job.
X
XFILES
X /usr/spool/lpd/*
X
XBUGS
X Actual the line printer daemon ins't told when the job is canceled,
X so it continues working.
X
/
echo x - cancel.c
sed 's/^X//' > cancel.c << '/'
X/**************************************************************************
X * cancel - line printer job remover
X * This program unlinks files from the line printer daemon directory.
X * Actual the line printer daemon ins't told when the job is canceled,
X * so it continues working.
X *
X * Ralf Wenk last update: Mon Jul 10 21:12:09 1989
X **************************************************************************/
X
X#define NULL ( char *)0
X#define BLOCK 64
X
Xchar spool[BLOCK];
X
Xextern char *rindex();
X
X
Xvoid panic ( st1 )
Xchar *st1;
X{
X std_err( st1 );
X std_err(\N);
X} /* panic */
X
X
X/**************************************************************************
X * remove given file(s) from /usr/spool/lpd
X **************************************************************************/
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X register int i, ret;
X register char *cptr;
X
X ret = 0;
X if ( argc > 1 )
X {
X for ( i = 1; i < argc; i++ ) /* all filenames given */
X {
X strcpy( spool, sp_dir );
X if (( cptr = rindex( argv[i],'/')) != NULL )
X strcat( spool, cptr + 1 );
X else
X strcat( spool, argv[i] );
X if ( unlink( spool ))
X panic( argv[i] );
X }
X }
X else
X ret = 1;
X exit( ret );
X} /* main */
X
/
echo x - lpd.c
sed 's/^X//' > lpd.c << '/'
X/**************************************************************************
X * lpd - the lineprinter daemon
X * This program copies files from the line printer daemon directory to
X * /dev/lp and then unlinks them. It uses a file in the printer daemon
X * directory named 'lock' to show if a daemon is already running. While
X * this isn't a real semaphore it is possible that no daemon does the work
X * until anotherone is started. If the printer is still quiet see if
X * /usr/spool/lpd/lock exists and no daemon is running ( should only occur
X * by killing a running daemon ).
X * If the daemon must expand tabs define TABS to 0 else to 1.
X * Parts of this program are inspirated form the original lpr written
X * by Andy Tanenbaum.
X *
X * Ralf Wenk last update: Mon Jul 10 20:46:04 1989
X **************************************************************************/
X
X
X#define TABS 1
X
X#include <sys/types.h>
X#include <sys/dir.h>
X#include <errno.h>
X
X#define NULL ( char *)0
X#define EOS '\0'
X#define BLOCK 1024
X#define TRIES 600 /* wait 10 minutes, then cry */
X#define E_SIZE sizeof( struct direct )
X
Xextern int errno;
X
Xchar lock[] = LOCK;
Xchar out_buf[BLOCK];
Xchar *i_am;
Xint out_count, column;
X
X
Xvoid panic( s1, s2 )
Xchar *s1, *s2;
X{
X unlink( lock ); /* remove the lock-file */
X std_err( i_am );
X std_err( s1 );
X if ( s2 )
X std_err( s2 );
X std_err(\N);
X exit( 1 );
X} /* panic */
X
X
X/**************************************************************************
X * write the output buffer thru /dev/lp
X * handle some errors
X **************************************************************************/
X
Xvoid flush ()
X{
X register int n, try;
X
X try = 0;
X if ( out_count )
X {
X while (( n = write( 1, out_buf, out_count )) != out_count && try < TRIES )
X {
X try++;
X sleep(1);
X }
X if ( try == TRIES )
X {
X if ( errno == EIO )
X else
X {
X perror( i_am );
X }
X }
X out_count = 0;
X }
X} /* flush */
X
X
X/**************************************************************************
X * insert a character into the output buffer, flush it if necessary
X * perform column counting for expanding tabs
X **************************************************************************/
X
Xvoid putc ( c )
Xchar c;
X{
X out_buf[out_count++] = c;
X#if ! TABS
X column++;
X if ( c == '\n' )
X column = 0;
X#endif /* ! TABS */
X if ( out_count == BLOCK )
X flush();
X} /* putc */
X
X
X/**************************************************************************
X * Print a file, adding carriage returns and ifndef'd expanding tabs.
X **************************************************************************/
X
Xvoid print ( fd )
Xint fd;
X{
X register int in_count, pos;
X register char c;
X char in_buf[BLOCK];
X
X out_count = 0;
X while ( in_count = read( fd, in_buf, BLOCK ))
X for ( pos = 0; pos < in_count; pos++ )
X {
X c = in_buf[pos];
X if ( c == '\n' )
X#if TABS
X putc('\r');
X putc( c );
X#else
X {
X putc('\r');
X putc('\n');
X }
X else if ( c == '\t' )
X do
X putc(' ');
X while ( column & 7 );
X else
X putc( c );
X#endif /* TABS */
X }
X flush();
X} /* print */
X
X
X/**************************************************************************
X * read a directory
X * return TRUE if a non reseved file was found
X **************************************************************************/
X
Xint nextfile ( fd, entry )
Xregister int fd;
Xregister struct direct *entry;
X{
X register int n;
X
X lseek( fd, 0, 0 );
X do
X n = read( fd, entry, E_SIZE );
X while ( n == E_SIZE &&
X return( n == E_SIZE );
X} /* nextfile */
X
X
X/**************************************************************************
X * test and terminate if a daemon already exists
X * else create the lock and print ervery interesting file found in
X * /usr/spool/lpd
X **************************************************************************/
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X{
X register int fd, dfd, pfd;
X union
X {
X char trick[ sizeof( struct direct ) + 1 ];
X struct direct dir;
X } entry;
X
X i_am = argv[0]; /* my name */
X entry.trick[ sizeof( struct direct ) ] = EOS; /* dirty trick to force EOS */
X chdir( spool );
X if ( access( lock, 0 ))
X {
X if (( fd = creat( lock, 0 )) < 0 )
X close( fd );
X if (( dfd = open( spool, 0 )) < 0 )
X panic( c_open, spool );
X else
X {
X close( 1 );
X if ( open( device, 1 ) < 0 )
X panic( c_open, device );
X while ( nextfile( dfd, &entry ))
X {
X if (( pfd = open( entry.dir.d_name, 0 )) < 0 )
X panic( c_open, entry.dir.d_name );
X else
X {
X print( pfd );
X close( pfd );
X unlink( entry.dir.d_name );
X }
X }
X unlink( lock );
X close( dfd );
X }
X }
X exit( 0 );
X} /* main */
X
X
/
echo x - lpr.1
sed 's/^X//' > lpr.1 << '/'
XNAME
X lpr(1) - copy a file to the line printer
X
XSYNOPSIS
X lpr [ file ] ...
X
XDESCRIPTION
X Each argument is interpreted as a file to be printed. lpr links or
X copies each file into /usr/spool/lpd where the line printer daemon
X lpd can find and copy them to /dev/lp. It inserts carriage returns
X and expands tabs ( compile time option ). The lpd is searched by
X lpr in /usr/lib, /etc and /usr/bin. lpd uses a file in the printer
X daemon directory named 'lock' to show if a daemon is already
X running. While this isn't a real semaphore it is possible that no
X daemon does the work until anotherone is started. If the printer is
X still quiet see if /usr/spool/lpd/lock exists and no daemon is
X running ( should only occur by killing a running daemon ).
X
XFILES
X /usr/lib/lpd
X /usr/spool/lpd/*
X /usr/spool/lpd/lock
X
XBUGS
X No sequential file numbering is done, so each file name can only
X occure once until printet.
X
/
echo x - lpr.c
sed 's/^X//' > lpr.c << '/'
X/**************************************************************************
X * lpr - line printer front end
X * This program links or copies files to the line printer daemon directory
X * and then calls the daemon to spool them.
X * Parts of this program are inspirated form the original lpr written
X * by Andy Tanenbaum.
X *
X * Ralf Wenk last update: Thu Sep 28 22:24:34 1989
X **************************************************************************/
X
X#include <signal.h>
X#include <sys/stat.h>
X
X#define EOS '\0'
X#define NULL ( char *)0
X#define NAME SPOOL
X#define MODE 0400
X#define MASK 0333
X#define BLOCK 1024
X
X NULL };
Xchar spool[BLOCK];
X
Xextern char *rindex();
X
X
Xvoid panic ( st1, st2 )
Xchar *st1, *st2;
X{
X std_err( st1 );
X if ( st2 )
X std_err( st2 );
X std_err(\N);
X} /* panic */
X
X
X/**************************************************************************
X * write std_in into a file with random name
X * before spooling stdin collect it into a temporary file, to prevent
X * a already running lpd of printing and removing it too eraly.
X **************************************************************************/
X
Xvoid get_stdin ()
X{
X register int fd, pid, n;
X char tmp_file[32];
X
X pid = getpid();
X strcpy( tmp_file, tmp_dir );
X strcat( tmp_file, NAME );
X n = strlen( tmp_file );
X while ( pid )
X {
X tmp_file[n++] = ( pid % 10 ) + '0';
X pid /= 10;
X }
X tmp_file[n] = EOS;
X umask( MASK );
X if (( fd = creat( tmp_file, MODE )) < 0 )
X {
X panic( c_spool,STDIN);
X exit( 1 );
X }
X while ( n = read( 0, spool, BLOCK ))
X write( fd, spool, n );
X close( fd );
X strcpy( spool, sp_dir );
X strcat( spool, &tmp_file[strlen( tmp_dir )] );
X link( tmp_file, spool ); /* that's why tmp_dir must on the */
X unlink( tmp_file ); /* same device as sp_dir */
X} /* get_stdin */
X
X
X/**************************************************************************
X * insert given file(s) into /usr/spool/lpd and start the daemon
X **************************************************************************/
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X register int fd, pid, i;
X register char *cptr;
X struct stat st, st1;
X int ret;
X
X signal( SIGHUP, SIG_IGN ); /* ignore some signals */
X signal( SIGINT, SIG_IGN );
X signal( SIGQUIT, SIG_IGN );
X signal( SIGTERM, SIG_IGN );
X if ( argc == 1 )
X {
X get_stdin(); /* standard input only */
X }
X else
X {
X for ( i = 1; i < argc; i++ ) /* all filenames given */
X {
X strcpy( spool, sp_dir );
X if (( cptr = rindex( argv[i],'/')) != NULL )
X strcat( spool, cptr + 1 );
X else
X strcat( spool, argv[i] );
X if ( link( argv[i], spool ))
X {
X pid = -1;
X if ( stat( argv[i], &st ) == 0 && ( st.st_mode & S_IFMT ) != S_IFDIR &&
X ( stat( spool, &st1 ) != 0 || st.st_dev != st1.st_dev ||
X st.st_ino != st.st_ino ) && ( pid = fork()) == 0 )
X {
X panic( c_spool, argv[i] );
X }
X else if ( pid != -1 )
X {
X wait( &ret );
X if ( ret )
X panic( c_spool, argv[i] );
X chmod( spool, MODE );
X }
X else
X panic( c_spool, argv[i] );
X }
X }
X }
X if (( pid = fork()) == 0 )
X {
X i = 0;
X while ( lpd[i] )
X execl( lpd[i++],LPD, NULL );
X exit( 1 );
X }
X else if ( pid == -1 )
X {
X exit( 1 );
X }
X exit( 0 );
X} /* main */
X
/
echo x - lpstat
sed 's/^X//' > lpstat << '/'
X#!/bin/sh
X# The 'style' of this script is forced by shell problems.
X# e.g. shift and $* together with case ... causes the shell to die.
X
XPATH=/usr/bin:/bin
XLPDIR=/usr/spool/lpd
XIFSOLD=$IFS
XNL='
X'
X#set -xv
X
Xargc=$#
Xargv1=$1
Xif test $argc -le 1 ; then
X IFS=$NL
X for i in $files; do
X IFS=$IFSOLD
X set $i
X shift
X done
X case $argv1 in
X -t) myself=':';;
X ) myself=`whoami`;;
X *) echo $USAGE; exit 1;;
X esac
X echo -n $NAMES | fgrep $myself
Xelse
X echo $USAGE; exit 1
Xfi
X
Xexit 0
X
/
exit 0