|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 5180 (0x143c)
Types: TextFile
Notes: UNIX file
Names: »lpd1.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/lpr/lpd1.c«
/*
* 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);
}