This is djf.c in view mode; [Download] [Up]
/* Hacked 9/91 by D. Beatty for HP DeskJet. */
/* Hacked 2/92 to support resolution & paper feed options.
* Includes printer setup and pswrap from Djf--Deskjet 500 printer filter
* Reimer Mellin & Uwe Meyer-Gruhl August 1991 with help of Christian Baur.
* Hacked 4-July-92 to fix EPS inclusion bug.
*/
/* djf--DeskJet line printer filter
* from iwf--Imagewriter II line printer filter by
* Eric P. Scott, San Francisco State University, November 1990
* Copyright 1990, 1991 by Eric P. Scott. All rights reserved.
*
* This file (and the accompanying iwwraps.psw) are freely
* redistributable in their original, unmodified forms. The
* author grants you a nonexclusive, royalty-free license to use
* this software, and modify it as needed provided that this
* copyright notice remains, and any changes are clearly
* indicated as such. No part may be incorporated in products or
* packages sold for profit without express permission of the
* copyright holder.
*
* Send bug reports, enhancements, etc. to <beatty+@cs.cmu.edu>
*
* This software makes certain assumptions that are valid in NeXT
* Software Release 2.0, and may not hold in future releases.
* NO WARRANTY is expressed or implied--use at your own risk!
*
* It's not the best code in the world--far from it--such is the
* price of working under time pressure...
*
* What it doesn't do:
* 8-bit ASCII
* use RLE (ESC V nnnn b) to reduce number of characters output
* trap SIGINT to guarantee writing accounting record
*
* Revision History
* 11/ 6/90 EPS 1.0 release
* 11/ 7/90 EPS 1.1 release
* fixed "creeping pixel" bug
* changed ysize default from 792 to length*12
* internal EPS 1.2
* <streams/error.h> => <objc/error.h>
* recognize R (Resolution) argument
* 3/28/91 EPS 2.0 release
* significant rewrite to use machportdevice
* instead of offscreen window
* add "sidedoor" code for no PublicWindowServer
*/
#include <stdio.h>
#include <pwd.h>
#include <signal.h>
#include <cthreads.h>
#include <servers/netname.h>
#include <windowserver/printmessage.h>
#import <dpsclient/dpsclient.h>
#import <objc/error.h>
#ifndef lint
static char sccsid[]="@(#)iwf.c\t2.0 (SFSU) 3/28/91";
#endif
int literal;
char *host;
int indent;
int length;
char *name;
int width;
int xsize, ysize;
int xbytes;
int resolution; /* dpi */
#ifdef DJCOMPRESS
char *out_row;
char *end_p;
#endif /* DJCOMPRESS */
int out_count;
int linect, pagect;
int status; /* exit status (0=ok; 1=reprint; 2=flush) */
port_t pport; /* port for machportdevice */
netname_name_t djfportname; /* name for machportdevice */
NXPrintPageMessage ppm; /* Mach messaging area */
#define KODMSGID 0xdeadbeef
mutex_t mutex1;
int seen_setup= 0; /* flag for parsing only the first setup section we see! */
/* DeskJet setup:
* ASCII characters
* normal placement
* 12 point (will change later per -l option)
* upright characters
* normal stroke weight
* 66 lines on a page (will change later per -l option)
* no top margin
* clear margins (will set left margin later per -i option)
* 6 lpi (will change per -l option)
* graphics resolution 300dpi (will change later if -R specified)
* cancel underline
* display off
* perforation skip off
* no wrap at end of line
* add CR at LF or FF
* enhancement not line-by-line
* si/so not line-by-line
* bidirectional printing
* text scale off (will turn on later for text mode)
* paper size US letter
* Deliberately omitted so as to be selectable from printer front panel:
* Fixed or proportional spacing,
* typeface selection,
* draft mode
* Set later:
* Graphics compression mode
* text pitch (per -w option)
* Type size limits assume original Deskjet with Prestige cartridge.
*/
static char setup[]="\
\033(0U\
\033(s0U\
\033(s12V\
\033(s0S\
\033(s0B\
\033&l66P\
\033&l0E\
\0339\
\033&l6D\
\033*t300R\
\033&d@\
\033Z\
\033&l0L\
\033&s1C\
\033&k2G\
\033&k1E\
\033&k1F\
\033&k1W\
\033&k5W\
\033&l2A";
#define UNPRINTABLE 32 /* total unprintable height on page, in points */
int match(char *pattern, char *data)
{
int r= !strncmp(pattern,data,strlen(pattern));
#ifdef DEBUG
if (r) fprintf(stderr,"DJF: matched %s\n", pattern);
#endif
return r;
}
char *skip_token(char *p) /* skip token and following spaces */
{
while (*p && *p!=' ') p++;
while (*p && *p==' ') p++;
return p;
}
main(int argc, char *argv[])
{
extern void *malloc(); /* stupid ANSI!!! */
extern void minit75( int w, int h, char *portname);
extern void minit100( int w, int h, char *portname);
extern void minit150( int w, int h, char *portname);
extern void minit300( int w, int h, char *portname);
extern int optind;
extern char *optarg;
void _textpl(DPSContext ctx, char *buf, unsigned long count);
int c, l;
int in_setup, res, pgwi, pghi, man;
char *b;
FILE *af;
DPSContext pctx;
struct passwd *pw;
cthread_t rthread; /* reader thread */
static msg_header_t kod;
char buf[8192];
while ((c=getopt(argc, argv, "cf:h:i:l:n:p:w:x:y:R:"))!=EOF)
switch (c) {
case 'c':
literal++;
break;
case 'f': /* file--NeXT extension */
break;
case 'h':
host=optarg;
break;
case 'i':
indent=atoi(optarg);
break;
case 'l':
length=atoi(optarg);
if (length>198) length=198; /* 72pt/" * 11" / 4pt */
break;
case 'n':
name=optarg;
break;
case 'p': /* printer--NeXT extension */
break;
case 'w':
width=atoi(optarg);
if (width>266) width=266; /* 8" * 33.33 cpi */
break;
case 'x':
xsize=atoi(optarg);
if (xsize>2400) xsize=2400; /* 8" * 300 dpi */
break;
case 'y':
ysize=atoi(optarg);
if (ysize>3150) ysize=3150; /* 10.5" * 300dpi */
break;
case 'R': /* Resolution--NeXT extension [2.0] */
resolution=atoi(optarg);
if (resolution <= 75) resolution= 75;
else if (resolution <= 100) resolution= 100;
else if (resolution <= 150) resolution= 150;
else resolution= 300;
break;
default:
usage:
(void)fprintf(stderr, "Usage: %s [options] [acctfile]\n",
*argv);
(void)fputs("\t-c don't interpret control characters\n",
stderr);
(void)fputs("\t-hhost host name of job owner\n", stderr);
(void)fputs("\t-i# indent\n", stderr);
(void)fputs("\t-l# page length in lines\n", stderr);
(void)fputs("\t-nname login name of job owner\n", stderr);
(void)fputs("\t-w# page width in characters\n", stderr);
(void)fputs("\t-x# horizontal page size in pixels\n", stderr);
(void)fputs("\t-y# vertical page size in pixels\n", stderr);
(void)fputs("\t-R# resolution (pixels/inch: 75/100/150/300)\n", stderr);
exit(2); /* can't use <sysexits.h>!!! */
break;
}
af=(FILE *)NULL;
switch (argc-optind) {
case 0:
break;
case 1:
if (argv[optind][0]&&!(af=fopen(argv[optind], "a"))) {
perror(argv[optind]);
exit(2);
}
break;
default:
goto usage;
}
if (length<=0) length=66;
if (width<=0) width=132;
if (indent>=width) indent=width-1;
if (xsize<=0) xsize=2400; /* 8" * 300dpi */
if (ysize<=0) ysize=3150; /* 10.5" * 300dpi */
if (resolution<=0) resolution= 150; /* compromise */
/* adjust bitmap size according to resolution */
xsize *= resolution; xsize /= 300;
ysize *= resolution; ysize /= 300;
xbytes= (xsize+7)/8;
/* <stdio.h> declares this as int but man page says void */
(void)setvbuf(stdout, (char *)NULL, _IOFBF, 8192);
(void)fwrite(setup, 1, (sizeof setup)-1, stdout);
(void)printf("\033&a%uL\033&l%uD", indent, length/11);
if ((c=getchar())==EOF) exit(0);
if (c!='%') {
normal: /* text mode filter */
(void)seteuid(getuid());
printf("\033(s%uH", (width+7)/8); /* set pitch, over 8" line */
printf("\033(s%uV", (72*11)/length); /* (point size) */
printf("\033&k6W"); /* set deskjet text scale on */
do {
rerun:
switch (c) { /* "but it's one instr. on a VAX" */
case '\0':
case '\001':
case '\002':
case '\003':
case '\004':
case '\005':
case '\006':
case '\007':
case '\013':
case '\016':
case '\017':
case '\020':
case '\021':
case '\022':
case '\023':
case '\024':
case '\025':
case '\026':
case '\027':
case '\030':
case '\032':
case '\033':
case '\034':
case '\035':
case '\036':
case '\037':
putchar(literal ? c : ' ');
break;
case '\031': /* Only at Berkeley... */
if ((c=getchar())==EOF) {
l='\031';
putchar(literal ? l : ' ');
goto done;
}
if (c=='\001') {
(void)fflush(stdout);
(void)kill(getpid(), SIGSTOP);
continue;
}
putchar(literal ? '\031' : ' ');
goto rerun;
case '\n':
linect++;
if (linect<length) goto anyway;
/*FALL THROUGH*/
case '\f':
pagect++; linect=0;
/*FALL THROUGH*/
case '\b': /* you expected intelligence? */
case '\t': /* may be wrong for deskjet */
case '\r':
default:
anyway:
putchar(c);
break;
}
l=c;
} while ((c=getchar())!=EOF);
done:
switch (l) {
default:
putchar('\n');
linect++; if (linect>=length) pagect++;
/*FALL THROUGH*/
case '\n': case '\r':
putchar('\f');
pagect++;
/*FALL THROUGH*/
case '\f':
break;
}
}
else {
int reader(any_t arg);
if ((c=getchar())==EOF) {
(void)seteuid(getuid());
l='%';
putchar(l);
goto done;
}
if (c!='!') {
putchar('%'); goto normal;
}
/* At this point, we are committed to PostScript */
pctx=(DPSContext)NULL;
NX_DURING
/* attempt to connect to Window Server using defaults */
pctx=DPSCreateContext((void *)NULL, (void *)NULL,
_textpl, DPSDefaultErrorProc);
NX_HANDLER
if (NXLocalHandler.code!=dps_err_cantConnect) NX_RERAISE();
NX_DURING
void sidedoor();
sidedoor(); /* try to climb in through side door */
pctx=DPSCreateContext((void *)NULL, (void *)NULL,
_textpl, DPSDefaultErrorProc);
NX_HANDLER
if (NXLocalHandler.code!=dps_err_cantConnect)
NX_RERAISE();
NX_ENDHANDLER
if (!pctx) {
/* This is so lame. NeXT should make _NXDpsReporter public!!! */
(void)fputs(
"DPS client library error: Could not form connection, host ", stderr);
(void)fputs((char *)NXLocalHandler.data2, stderr);
putc('\n', stderr);
}
NX_ENDHANDLER
if (!pctx) exit(2);
DPSSetContext(pctx); /* per postscript.321 this is unneeded */
(void)seteuid(getuid());
if ((c=port_allocate(task_self(), &pport))!=KERN_SUCCESS) {
mach_error("port_allocate failed", c);
exit(2);
}
(void)sprintf(djfportname, "djf-%d", getpid());
if ((c=netname_check_in(name_server_port, djfportname,
PORT_NULL, pport))!=KERN_SUCCESS) {
mach_error("netname_check_in failed", c);
exit(2);
}
/* printf("\033&k0W"); */ /* unidirectional printing */
printf("\033*t%dR", resolution);
if (pw=getpwnam(name ? name : "nobody"))
DPSPrintf(pctx, "%d %d setjobuser\n", pw->pw_uid,
pw->pw_gid);
/* endpwent() ? */
/* call function from djwraps.psw: */
switch (resolution) {
case 75: minit75( xsize, ysize, djfportname); break;
case 100: minit100( xsize, ysize, djfportname); break;
case 150: minit150( xsize, ysize, djfportname); break;
case 300: minit300( xsize, ysize, djfportname); break;
}
DPSWaitContext(pctx);
/* I don't want to rewrite things to use DPSAddPort()
* and friends, and C Threads are probably the lesser
* of several evils.
*/
mutex1=mutex_alloc();
rthread=cthread_fork((cthread_fn_t)reader, (any_t)0);
mutex_lock(mutex1);
DPSPrintf(pctx, "/-saveIW-%d- save def\n/note {} def\n\
/envelope {} def\n%%%%BeginDocument: IWGraphic\n", getpid());
mutex_unlock(mutex1);
NX_DURING
b=buf; *b++='%'; *b++='!';
l=0; /* sick, disgusting! */
in_setup=0;
while ((c=getchar())!=EOF) {
*b++=c;
if (c=='\n'||b>&buf[sizeof buf]) {
/* what a crock... */
if (buf[0]=='%') {
if (buf[1]=='%') {
if (!l) DPSWaitContext(pctx);
l=1;
}
/* here's where to interpret comments such as:
* %%BeginSetup
* %%PaperSize: Executive
* %%Feature: *ManualFeed True
* %%Feature: *Resolution 150
* %%EndSetup
* to set up the printer, and then call minit() again.
* (I think this might work.)
* How do you get these comments into your postscript file?
* PaperSize is from Page Layout, but where did the Feature lines come from?
* Copy /usr/shlib/libNeXT_s.C.shlib twice (once as a backup).
* Change some strings in one copy (! denotes null bytes):
* from "Cassette" "Manual" "NeXT 400 dpi Laser Printer" "400 dpi" "300 dpi"
* to "Tray!!!!" "Envlop" "Hewlett-Packard DeskJet!!!" "300 dpi" "150 dpi"
* (Use "DeskJet+!!" or "DeskJet500" if you like.)
* Login as root on the Console (not in NeXTStep!) and copy the edited file
* over the original.
* (If you screw up, boot single-user and restore from your backup.)
* You must match this string exactly in the Printer Type field of your
* printer entry. (Use NetInfoManager to edit your printer entry.)
* This enables the Paper Feed and Resolution buttons in Print panels.
*/
if ( (!seen_setup) && match("%%BeginSetup\n",buf)) {
in_setup= 1; seen_setup= 1;
pgwi=612; pghi=792; man=0; res= 300; /* default US letter, tray, 300dpi */
} else if (in_setup && match("%%PaperSize: ",buf)) {
if (match("Letter\n", buf+13)) { pgwi=612; pghi=792; }
else if (match("Legal\n", buf+13)) { pgwi=612; pghi=1008; }
else if (match("Executive\n", buf+13)) { pgwi=540; pghi= 720; }
else if (match("A4\n", buf+13)) { pgwi= 595; pghi= 842; }
else if (match("A5\n", buf+13)) { pgwi= 420; pghi= 595; }
else if (match("B5\n", buf+13)) { pgwi= 516; pghi= 729; }
else /* default to US Letter */ { pgwi= 612; pghi= 792; }
} else if (in_setup && match("%%Feature: *CustomPaperSize ", buf)) {
/* This shows up when you print Landscape. */
pgwi= atoi(buf+28); pghi= atoi(skip_token(buf+28));
} else if (in_setup && match("%%Feature: *ManualFeed ",buf)) {
if (match("True\n", buf+23)) { man= 1; }
else if (match("False\n", buf+23)) { man= 0; }
else /* default to tray feed */ { man= 0; }
} else if (in_setup && match("%%Feature: *Resolution ",buf)) {
if (match("300\n", buf+23)) { res= 300; }
else if (match("150\n", buf+23)) { res= 150; }
else /* default to 300 dpi */ { res = 300; }
} else if (in_setup && match("%%EndSetup\n",buf)) {
in_setup= 0;
mutex_lock(mutex1);
/* size paper based on height */
switch (pghi) {
case 792: printf("\033&l2A"); break; /* letter */
case 1008: printf("\033&l3A"); break; /* legal */
case 842: printf("\033&l26A"); break; /* A4 */
case 297: printf("\033&l81A"); break; /* #10 envelope */
default: printf("\033&l26A"); break;
}
/* now try the German hack of setting height by setting lines:
* set page length, top margin, and text length
*/
printf("\033&%dp0e%dF", pghi/12+2, pghi/12+1);
#ifdef DEBUG
fprintf(stderr,"DJF: page size %d x %d pt.\n", pgwi, pghi);
#endif
/* select envelope or paper tray */
printf("\033&l%dH", man ? 3 : 1);
#ifdef DEBUG
fprintf(stderr,"DJF: manual feed %d\n", man);
#endif
/* Select resolution; use draft mode at 150dpi and below */
printf("\033*t%dR", res);
printf("\033(s%dQ", res > 150 ? 2 : 1);
#ifdef DEBUG
fprintf(stderr,"DJF: resolution %d\n",
res);
#endif
mutex_unlock(mutex1);
/* Finally, tell PostScript about all this nonsense. */
/* Of course, UNPRINTABLE might really vary with paper size,
* but we'll assume not unless proven wrong...
*/
switch (res) {
case 75: minit75( (pgwi*res)/72, ((pghi-UNPRINTABLE)*res)/72, djfportname);
break;
case 100: minit100( (pgwi*res)/72, ((pghi-UNPRINTABLE)*res)/72, djfportname);
break;
case 150: minit150( (pgwi*res)/72, ((pghi-UNPRINTABLE)*res)/72, djfportname);
break;
case 300:
default: minit300( (pgwi*res)/72, ((pghi-UNPRINTABLE)*res)/72, djfportname);
break;
}
DPSWaitContext(pctx);
}
} else l=0;
DPSWritePostScript(pctx, buf, b-buf);
b=buf;
}
}
if (b>buf) {
*b++='\n';
DPSWritePostScript(pctx, buf, b-buf);
}
DPSWaitContext(pctx);
if (pagect==0) { /* wrong, but expected */
mutex_lock(mutex1);
DPSPrintf(pctx, "\nshowpage\n");
mutex_unlock(mutex1);
DPSWaitContext(pctx);
}
NX_HANDLER
if (NXLocalHandler.code!=dps_err_ps) NX_RERAISE();
else {
mutex_lock(mutex1);
DPSPrintError(stderr,
(DPSBinObjSeq)(NXLocalHandler.data2));
putc('\n', stderr);
mutex_unlock(mutex1);
}
status=2;
NX_ENDHANDLER
mutex_lock(mutex1);
DPSPrintf(pctx, "%%%%EndDocument\n-saveIW-%d- restore\n",
getpid());
mutex_unlock(mutex1);
DPSWaitContext(pctx);
PSnulldevice();
DPSWaitContext(pctx);
/* fake "EOF" on port */
kod.msg_simple=TRUE;
kod.msg_size=sizeof kod;
kod.msg_type=MSG_TYPE_NORMAL;
kod.msg_local_port=PORT_NULL;
kod.msg_remote_port=pport;
kod.msg_id=KODMSGID;
if ((c=msg_send(&kod, MSG_OPTION_NONE, 0))!=SEND_SUCCESS) {
mutex_lock(mutex1);
mach_error("msg_send failed", c);
mutex_unlock(mutex1);
}
else pagect=(int)cthread_join(rthread);
if (*djfportname&&
(c=netname_check_out(name_server_port, djfportname,
PORT_NULL))!=KERN_SUCCESS) {
mutex_lock(mutex1);
mach_error("netname_check_out failed", c);
mutex_unlock(mutex1);
}
(void)port_deallocate(task_self(), pport);
DPSDestroySpace(DPSSpaceFromContext(pctx));
}
if (af) {
if (name) {
mutex_lock(mutex1);
(void)fprintf(af, "%4d.00\t", pagect);
if (host) (void)fprintf(af, "%s:", host);
(void)fprintf(af, "%s\n", name);
mutex_unlock(mutex1);
}
(void)fclose(af);
}
exit(status);
}
/* msg_receive blocks until something happens, so this runs in
* its own thread. I'm trying to do a minimum amount of mutex
* locking (set fingers=crossed).
*
* This code could stand a serious rethink...
*/
int reader(any_t arg) {
register int rmask;
register char *p, *r, *w, *eop;
register msg_return_t m;
char *cmax;
#ifdef DJCOMPRESS
extern int mode2compress(char *strt, char *end, char *buf);
#endif /* DJCOMPRESS */
for (;;) {
ppm.msgHeader.msg_size=sizeof ppm;
ppm.msgHeader.msg_local_port=pport;
if ((m=msg_receive(&ppm.msgHeader, RCV_INTERRUPT|
RCV_NO_SENDERS, 0))!=RCV_SUCCESS) {
mutex_lock(mutex1);
mach_error("msg_receive failed", m);
mutex_unlock(mutex1);
break;
}
if (ppm.msgHeader.msg_id==KODMSGID) break;
if (ppm.msgHeader.msg_id!=NX_PRINTPAGEMSGID||
ppm.printPageVersion!=3) continue; /* munchers */
if (*djfportname) { /* recall send rights */
register kern_return_t s;
if ((s=netname_check_out(name_server_port,
djfportname, PORT_NULL))!=KERN_SUCCESS) {
mutex_lock(mutex1);
mach_error("netname_check_out failed", s);
mutex_unlock(mutex1);
}
*djfportname='\0';
if (ppm.oolImageParam.msg_type_long_size!=8) {
/* woke up in the wrong universe... */
if (port_deallocate(task_self(), pport)==
KERN_SUCCESS) pport=PORT_NULL;
return(0);
}
}
#ifdef OBSOLETE_JUNK
if (ppm.pixelsWide>xsize) ppm.pixelsWide=xsize; /* uh-oh! */
if (ppm.oolImageParam.msg_type_long_number
/ppm.bytesPerRow > ysize)
ppm.oolImageParam.msg_type_long_number= ysize *
ppm.bytesPerRow;
#endif /* OBSOLETE_JUNK */
xbytes= (ppm.pixelsWide+7)/8;
mutex_lock(mutex1);
/* position cursor horiz 0 dots, vert 1 dot; start graphics at current cursor position */
/* From DJ500 driver: *p0x1yr1a gives yet another 1/8" 'headroom' Cant beat German engineers. */
printf("\033*p0xp1yr1A");
#ifdef DJCOMPRESS
printf("\033*b2M"); /* mode 2 compression */
out_row= (char*) malloc(2*xbytes);
#endif /* DJCOMPRESS */
mutex_unlock(mutex1);
/* The Window Server returns horizontal scan-lines. */
p=(char *)ppm.printerData;
r=p+ppm.bytesPerRow;
eop=p+ppm.oolImageParam.msg_type_long_number;
while (p<eop) {
mutex_lock(mutex1);
#ifdef DJCOMPRESS
end_p= p+xbytes;
/* Remove trailing 0s. */
while ( end_p > p && end_p[-1] == 0 )
end_p--;
out_count= mode2compress(p,end_p,out_row);
printf("\033*b%dW", out_count);
fwrite(out_row, sizeof(char), out_count, stdout);
#else /* ndef DJCOMPRESS */
printf("\033*b%uW", ppm.bytesPerRow);
fwrite(p,sizeof(char), xbytes, stdout);
#endif /* def/ndef DJCOMPRESS */
mutex_unlock(mutex1);
p=r; /* raster could be padded */
r=p+ppm.bytesPerRow;
}
mutex_lock(mutex1);
printf("\033*rB\033&l0H"); /* end raster graphics; new page */
fflush(stdout);
mutex_unlock(mutex1);
pagect++;
/* unmap and ACK page */
(void)vm_deallocate(task_self(),
(vm_address_t)ppm.printerData,
(vm_size_t)ppm.oolImageParam.msg_type_long_number);
ppm.msgHeader.msg_simple=TRUE;
ppm.msgHeader.msg_size=sizeof ppm.msgHeader;
ppm.msgHeader.msg_type=MSG_TYPE_NORMAL;
ppm.msgHeader.msg_local_port=PORT_NULL;
ppm.msgHeader.msg_id=NX_PRINTPAGEMSGID;
if ((m=msg_send(&ppm.msgHeader, MSG_OPTION_NONE, 0))!=
SEND_SUCCESS) {
mutex_lock(mutex1);
mach_error("msg_send failed", m);
mutex_unlock(mutex1);
break;
}
}
return(pagect);
}
/* DPSCreateContext[WithTimeoutFromZone] looks in two places for
* a port to the Window Server:
*
* 1) The Bootstrap Server for "WindowServer"
* 2) The Network Name Server for "NextStep(tm) Window Server"
*
* If PublicWindowServer is *not* set, then (2) won't be checked
* in, and (1) will be checked in with a subset bootstrap port
* and available only to descendents of loginwindow (i.e.
* Workspace and its descendents).
*
* This horrible hack set us up to inherit from loginwindow, as
* if we were a proper descendent.
*
* Most is lifted straight from the 2.0 Reference.
* table() is undocumented according to NextAnswers.
*
* N.B. when a user with PublicWindowServer==No logs out, the
* subset port is destroyed and neither (1) nor (2) will work.
* No one said life was fair.
*
* This code *must* run as root; djf must be set-uid root if
* we're to be standalone (not running under control of lpd).
*
*/
#include <sys/table.h>
#include <servers/bootstrap.h>
#ifndef lint
static char sccsid_[]="@(#)sidedoor.c\t1.0 (SFSU) 3/27/91";
#endif
void sidedoor() {
register host_priv_t hpriv;
register unsigned int hidx, tidx;
processor_set_name_array_t hlist;
unsigned int hcount;
processor_set_t ppriv;
task_array_t tlist;
unsigned int tcount;
int pid, mypid;
port_t b;
struct tbl_procinfo pi;
if (!(hpriv=host_priv_self())) { /* must run as root! */
(void)fputs("couldn't get host privileged port\n", stderr);
return;
}
/* superuser privileges are not required beyond this point */
if (host_processor_sets(hpriv, &hlist, &hcount)!=KERN_SUCCESS)
(void)fputs("couldn't get processor sets\n", stderr);
else {
mypid=getpid();
for (hidx=0;hidx<hcount;hidx++) {
if (host_processor_set_priv(hpriv, hlist[hidx], &ppriv)!=
KERN_SUCCESS) ppriv=hlist[hidx];
if (processor_set_tasks(ppriv, &tlist, &tcount)==KERN_SUCCESS) {
for (tidx=0;tidx<tcount;tidx++) {
if (unix_pid(tlist[tidx], &pid)==KERN_SUCCESS&&pid>3) {
if (pid==mypid) continue;
if (table(TBL_PROCINFO, pid, (char *)&pi, 1,
sizeof pi)==1&&
pi.pi_status==PI_ACTIVE&&pi.pi_ppid==1&&
pi.pi_ttyd<0&&pi.pi_uid==0&&
!strncmp(pi.pi_comm, "loginwindow", PI_COMLEN)&&
task_get_bootstrap_port(tlist[tidx], &b)==
KERN_SUCCESS&&b!=PORT_NULL) {
if (task_set_bootstrap_port(task_self(), b)==
KERN_SUCCESS) bootstrap_port=b;
else (void)port_deallocate(task_self(), b);
}
}
(void)port_deallocate(task_self(), tlist[tidx]);
}
(void)vm_deallocate(task_self(), (vm_address_t)tlist,
tcount*sizeof (port_t));
}
else (void)fprintf(stderr,
"couldn't get tasks for processor set %d\n", hidx);
(void)port_deallocate(task_self(), ppriv);
if (hlist[hidx]!=ppriv)
(void)port_deallocate(task_self(), hlist[hidx]);
}
(void)vm_deallocate(task_self(), (vm_address_t)hlist,
hcount*sizeof (processor_set_name_t));
}
(void)port_deallocate(task_self(), hpriv);
/* have I deallocated everything I should? */
}
/* this shouldn't ever be called... */
void _textpl(DPSContext ctx, char *buf, unsigned long count)
{
(void)write(2, buf, count);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.