DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download

⟦3a68dd9a2⟧ TextFile

    Length: 5180 (0x143c)
    Types: TextFile
    Notes: UNIX file
    Names: »lpd1.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦f4b8d8c84⟧ UNIX Filesystem
        └─⟦this⟧ »cmd/lpr/lpd1.c« 

TextFile

/*
 * The line printer spooler daemon.
 * This should be invoked from the `/etc/rc'
 * file and by the `lpr' command.
 * (NOTE: this command should be setuid to daemon)
 */

#include <stdio.h>
#include <dir.h>
#include <pwd.h>
#include <sgtty.h>
#include <signal.h>
#include <errno.h>

#define DAEMON	1		/* Daemon's magic number */
#define	BANWID	10		/* Longest banner */
#define	MAXCOM	40		/* Longest comment line sent through mail */
#define	FF	014		/* Form feed */
#define	SMALL	037		/* Set small characters -- paper tiger */
#define	NORMAL	036		/* Set normal characters -- paper tiger */

char	spooldir[] = "/usr/spool/lpd";
char	lockfile[] = "dpid";
char	*printer = "/dev/lp";

char	obuf[BUFSIZ];
char	cfline[300];		/* Control file line */
char	comment[300];		/* Comment line */
FILE	*lp;
int	printing;		/* On while printing */

char	*lgets();
int	cancel();
int	restart();

main(argc, argv)
char *argv[];
{
	int fd;
	int pid;

	setuid(DAEMON);
	if (chdir(spooldir) < 0)
		lperr("spool directory botch");
	if ((fd = creat(lockfile, 0400)) < 0)
		exit(0);
	if (fork())
		exit(0);
	signal(SIGINT, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	signal(SIGTRAP, cancel);
	signal(SIGREST, restart);
	pid = getpid();
	write(fd, &pid, sizeof pid);
	close(fd);
	if (argc > 1)
		printer = argv[1];
	if ((lp = fopen(printer, "w")) == NULL)
		lperr( "%s: %s", printer, sys_errlist[errno]);
	ioctl(fileno(lp), TIOCEXCL, NULL);
	setbuf(lp, obuf);
	process();
	rmexit(0);
}

/*
 * Find work to do.
 * The basic algorithm is to
 * run down the current directory
 * looking for files whose names
 * begin with `cf' and do the work
 * associated with each of them.
 */
process()
{
	FILE *dirfile;
	struct direct dir;
	char *r = "r";

	if ((dirfile = fopen(".", r)) != NULL) {
		while (fread(&dir, sizeof dir, 1, dirfile) == 1) {
			if (dir.d_ino == 0
			 || dir.d_name[0] != 'c'
			 || dir.d_name[1] != 'f')
				continue;
			control(dir.d_name);
			rewind(dirfile);
		}
		fclose(dirfile);
	}
}

/*
 * Do the action specified by the control
 * file.  Essentially, this must interpret
 * the control lines for such things as
 * mail notification, banners, etc.
 */
control(cfname)
register char *cfname;
{
	FILE *cfp;
	char mbuf[MAXCOM+40];
	char *message = "Listing complete: %.*s\n";

	if ((cfp = fopen(cfname, "r")) != NULL) {
again:
		printing = 1;
		fprintf(lp, "%s\n\n", cfname);
		while (lgets(cfline, sizeof cfline, cfp) != NULL) {
			if (!printing)
				message = "Listing killed by order: %.*s\n";
			else if (printing < 0) {
				rewind(cfp);
				putc(FF, lp);
				goto again;
			}
			switch (cfline[0]) {
			case 'A':
				if (print(cfline+1)) {
					message = "Printer file error: %.*s\n";
					strcpy(comment, cfline+1);
				}
				break;

			case 'D':
				strcpy(comment, cfline+1);
				break;

			case 'L':
				if (printing > 0) {
					cfline[BANWID+1] = '\0';
/* Paper tiger controls
					putc(SMALL, lp);
 */
					banner(cfline+1, lp);
/* Paper tiger controls
					putc(NORMAL, lp);
 */
				}
				break;

			case 'M':
				sprintf(mbuf, message, MAXCOM, comment);
				notify(cfline+1, mbuf);
				break;

			case 'R':
				/* Charge ID -- not used */
				break;

			case 'U':
				unlink(cfline+1);
				break;

			default:
				lperr("Bad control line `%s'", cfline);
			}
		}
		fclose(cfp);
		putc(FF, lp);
		printing = 0;
	}
	unlink(cfname);
}

/*
 * Routine to notify a user about
 * the completion of a transaction
 * Usually called by some daemon (e.g.
 * line printer daemon).
 * Return non-zero on failure.
 */
notify(name, msg)
char *name;
char *msg;
{
	register struct passwd *pwp;
	int pfd[2];
	register int pid, fd;
	int status;

	if (*name>='0' && *name<='9')
		if ((pwp = getpwuid(atoi(name))) == NULL)
			name = NULL; else
			name = pwp->pw_name;
	if (name==NULL || pipe(pfd)<0 || (pid = fork())<0)
		return (1);
	if (pid) {
		close(pfd[0]);
		write(pfd[1], msg, strlen(msg));
		close(pfd[1]);
		while (wait(&status) >= 0)
			;
	} else {
		close(pfd[1]);
		dup2(pfd[0], 0);
		close(pfd[0]);
		for (fd=3; fd<_NFILE; fd++)
			close(fd);
		execlp("/bin/mail", "mail", name, NULL);
		return (1);
	}
	return (0);
}

/*
 * Cancel the listing that is printing
 * just now.
 */
cancel()
{
	signal(SIGTRAP, SIG_IGN);
	if (printing) {
		printing = 0;
		fprintf(lp, "\n\n\nListing cancelled by order\n");
	}
	signal(SIGTRAP, cancel);
}

/*
 * Restart the listing that
 * is running just now.
 */
restart()
{
	signal(SIGREST, SIG_IGN);
	if (printing) {
		printing = -1;
		fprintf(lp, "\n\n\nListing restarted by order\n");
	}
	signal(SIGREST, restart);
}

/*
  * Like fgets but no newline is put at the end
 * of the string.  Also the rest of an input
 * line is flushed on tr▶15◀uncated strings.
 */
char *
lgets(as, lim, iop)
char *as;
register lim;
FILE *iop;
{
	register c;
	register char *s;

	s = as;
	while (--lim > 0 && (c = getc(iop)) != EOF)
		if ((*s++ = c) == '\n') {
			s--;
			break;
		}
	*s = 0;
	if (lim==0 && c!='\n')
		while ((c = getc(iop))!='\n' && c!=EOF)
			;
	return (c==EOF && s==as ? NULL : as);
}

/* VARARGS */
lperr(x)
{
	fprintf(stderr, "lpd: %r", &x);
	putc('\n', stderr);
	rmexit(1);
}

/*
 * Remove lock file and exit
 */
rmexit(s)
{
	unlink(lockfile);
	exit(s);
}