page@swan.ulowell.edu (Bob Page) (12/06/88)
Submitted-by: gno@stacken.kth.se (Gunnar Nordmark) Posting-number: Volume 2, Issue 91 Archive-name: devices/null.1 This is a dos-handler called null: that acts like NIL: except this is is a *real* handler. [uuencoded binary also included here; it's small. ..Bob] # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # Makefile # MountList # amigaline-D1 # misc.c # null.c # null.doc # null.uu # This archive created: Mon Dec 5 17:54:58 1988 cat << \SHAR_EOF > Makefile ######################################################################### # # null-handler Makefile # V 0.0 (c) Gunnar Nordmark 1988 # For Manx 3.6a # ######################################################################### null-handler : misc.o null.o ln -o null-handler misc.o null.o -lc32 misc.o : misc.c cc +L +Hnull.syms misc.c null.o : null.c cc +L +Inull.syms null.c SHAR_EOF cat << \SHAR_EOF > MountList /* Installs null-handler V 0.0 (C) Gunnar Nordmark */ null: Handler = L:null-handler Stacksize = 500 Priority = 5 GlobVec = 1 # SHAR_EOF cat << \SHAR_EOF > amigaline-D1 AMIGALINE #D1, Matthew Dillon Disconnecting a program such that you can EndCLI and also allow the program to call Execute(). Problem: You want to disconnect a program such that when you RUN <nil: >nil: (using the new 1.3 RUN) you can then EndCLI the cli. This program wants to be able to use Execute() to run other programs. The problem is that Execute() requires a valid pr_ConsoleTask (console) or it will freeze. Solution: General Run <nil: >nil: mycprogram If using the main() entry point, you can fclose(stderr) to remove the reference to "*". If using the _main() entry point, stdio is not setup and thus you do not need to do this (in fact, you can't use stdio at all without crashing the computer). note: being able to fclose(stderr) from the main() entry point works with Aztec C. I don't know about Lattice. Aztec always does an Open("*", 1006) to setup stderr and this reference must be removed. -- At this point, you can EndCLI and the cli window goes away. However, the 'mycprogram' cannot call Execute() or otherwise run other external programs for two reasons: (1) pr_ConsoleTask is still non-NULL and points to the now defunct window (i.e. you will cause a task-held requester) (2) you cannot set pr_ConsoleTask to NULL... Execute() does not accept it and freezes up. -- So, you must set pr_ConsoleTask to some other valid device. Guess what? Any device will do except NIL: which isn't a real device. For example, RAM: : extern APTR DeviceProc(); proc->pr_ConsoleTask = DeviceProc("ram:"); (assuming RAM: exists) What does this do? Any program which tries to open the console will actually open the file "RAM:*", as in Open("RAM:*", 1006). Unfortunetly, there is no way to place "*" in anything but the root directory of the device. This is essentially a garbage file. But the ultimate goal is achieved ... you can kill the CLI window and still arbitrarily run programs from the detached program with impunity. The only possible problem which I have yet to test is when several programs try to access RAM:* as their console at the same time. Since the file is openned 1006, other programs trying to Open() it will fail while the first programs is still running. What happens? -Matt SHAR_EOF cat << \SHAR_EOF > misc.c /* * misc.c - support routines - Phillip Lindsay (C) Commodore 1986 * You may freely distribute this source and use it for Amiga Development - * as long as the Copyright notice is left intact. * * 30-SEP-86 * */ #include <functions.h> #include <stdio.h> #include <exec/types.h> #include <exec/nodes.h> #include <exec/lists.h> #include <exec/ports.h> #include <exec/libraries.h> #include <exec/devices.h> #include <exec/io.h> #include <exec/memory.h> #include <devices/console.h> #include <libraries/dos.h> #include <libraries/dosextens.h> #include <libraries/filehandler.h> extern void returnpkt(); /* returnpkt() - packet support routine * here is the guy who sends the packet back to the sender... * * (I modeled this just like the BCPL routine [so its a little redundant] ) */ void returnpktplain(packet, myproc) struct DosPacket *packet; struct Process *myproc; { returnpkt(packet, myproc, packet->dp_Res1, packet->dp_Res2); } void returnpkt(packet, myproc, res1, res2) struct DosPacket *packet; struct Process *myproc; ULONG res1, res2; { struct Message *mess; struct MsgPort *replyport; packet->dp_Res1 = res1; packet->dp_Res2 = res2; replyport = packet->dp_Port; mess = packet->dp_Link; packet->dp_Port = &myproc->pr_MsgPort; mess->mn_Node.ln_Name = (char *) packet; mess->mn_Node.ln_Succ = NULL; mess->mn_Node.ln_Pred = NULL; PutMsg(replyport, mess); } /* * taskwait() ... Waits for a message to arrive at your port and * extracts the packet address which is returned to you. */ struct DosPacket * taskwait(myproc) struct Process *myproc; { struct MsgPort *myport; struct Message *mymess; myport = &myproc->pr_MsgPort; WaitPort(myport); mymess = GetMsg(myport); return((struct DosPacket *)mymess->mn_Node.ln_Name); } /* end of misc.c */ SHAR_EOF cat << \SHAR_EOF > null.c /**************************************************************************** * * null driver V0.0 (c)CopyRight 1988, Gunnar Nordmark. All Rights Reserved. * * null-handler Ver. 0.0 20-Jul-1988 * * Gunnar Nordmark * Nora strand 5 * 182 34 DANDERYD * SWEDEN * * |You may freely distribute this source as long as | * |the Copyright notice is left intact. | ***************************************************************************/ #undef BADDR #define BADDR(x) ((APTR)((long)x << 2)) #define ACTION_FINDINPUT 1005L #define ACTION_FINDOUTPUT 1006L #define ACTION_END 1007L #define DOS_FALSE 0L #define DOS_TRUE -1L /* My Globals */ long SysBase; struct Process *myproc; _main() { extern void returnpkt(); /* sends back the packet */ extern void returnpktplain(); /* use args in Res1 */ extern struct DosPacket *taskwait(); char *version = "Ver 0.0 (c) Gunnar Nordmark 1988"; struct DosPacket *mypkt; /* a pointer to the dos packet */ struct DeviceNode *mynode; /* our device node (parmpkt Arg3) */ struct FileHandle *fh; /* a pointer to our file handle */ long run = TRUE; /* handler main loop flag */ int null_open = 0; /* null open count */ /* Initializing the handler */ myproc = (struct Process *)FindTask(0L); mypkt = taskwait(myproc); /* Wait for my startup message */ /* I don't need the name or extra info passed in Arg1/2 */ mynode = (struct DeviceNode *)BADDR(mypkt->dp_Arg3); mynode->dn_Task = &myproc->pr_MsgPort; returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2); /* done initial stuff, now for some work */ while(run) { mypkt = taskwait(myproc); switch(mypkt->dp_Type) { /* find what action to perform */ case ACTION_FINDINPUT: case ACTION_FINDOUTPUT: null_open++; fh = (struct FileHandle *)BADDR(mypkt->dp_Arg1); fh->fh_Arg1 = mypkt->dp_Type; fh->fh_Port = (struct MsgPort *)DOS_FALSE; /* not interactive */ returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2); break; case ACTION_READ: returnpkt(mypkt, myproc, 0, mypkt->dp_Res2); /* zero-length=EOF */ break; case ACTION_WRITE: mypkt->dp_Res1 = mypkt->dp_Arg3; /* tell em we wrote them all */ returnpktplain(mypkt, myproc); break; case ACTION_END: if (--null_open == 0) run = 0; returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2); break; default: returnpkt(mypkt, myproc, DOS_FALSE, ERROR_ACTION_NOT_KNOWN); break; } } /* end while */ mynode->dn_Task = FALSE; } SHAR_EOF cat << \SHAR_EOF > null.doc *************************************************************************** * * null.doc 20 Nov 88 Gunnar Nordmark * *************************************************************************** What is null:? Tt's a new animal that you will be glad to put in your private ZOO, (also known as the L: directory). "Oh no, not another silly handler!" you cry, but read on! In the very good article by Matt Dillon, AMIGALINE#D1, that I've included in this distribution, the problem is fully explained. I suggests that you take a look at the file amigaline-D1 before reading further. As Matt explains, the NIL: device is not a "real" device. In fact it is no device at all in the physical sense. It is just an Amiga-DOS convention that says: If you have a process-identifier for a device, and that identifier is just a null pointer, then that "identifier" referrs to the NIL: device. Did you get that? I'm not surprised if you didn't, because it *is* strange. I'll try to explain: Every normal dos-device is a process that have an own private message-port that is used as a comunication link between AmigaDOS and the device. Since you must know the address of the message port of a device in order to comunicate with it, it is a natural decision that that address also is used as the identifier of the device. AmigaDOS has a function called DeviceProc() that finds the address for you. If you say port=DeviceProc("RAM:") you get the address of the message prot of the RAM: device. Now the strange part: If you try port=DeviceProc("NIL:") and then sends packets to that port you'll crash the machine instantly. Why? Because NIL: has *no* message-port at all. When you have a NULL-pointer as identifier for a handler, the identifier referrs to the NIL: device. The *only* reason I can think of for this lack of generality, is efficiency. You save time, becase you don't have to comunicate with a device. You save memory, because you don't have to start a new process named NIL:. But unfortunately this has a lot of drawbacks. Most of them are deadly. The reason is that AmigaDOS does *not* allways check for the NIL: oddity. Sometimes it thinks that the NULL-pointer (the NIL: identifier) is a valid message port and merilly sends messages to it. Poof! The solution is a new dos-device called "null:". This is a real dos-device that has has its own message port. It just doesn't do anything useful. It behaves exactly as NIL: i.e. you can write to it, and read from it (then you get EOF). The great thing about null: is that you can say extern APTR DeviceProc(); proc->pr_ConsoleTask = DeviceProc("null:"); and you'll be able to close the console. (see amigaline-D1) Any process can open null: as many times as it like. And it doesn't matter if you say Open("null:" MODE_OLDFILE); Open("null:*" MODE_NEWFILE); Open("null:@#$@!!" MODE_OLDFILE); Open("null:foo.bar" MODE_OLDFILE); everything works. To install null: just append the included mountlist to DEVS:MountList Copy null-handler to your L: directory and say Mount null: I have used it for half a year now with no problems at all. I have a written my own version of AmiCron that uses null: as pr_ConsoleTask. That means I now have a cron-deamon that doesn't requires a window to run! I wan't to thank Steve Drew who wrote the aux-handler that was posted to the net last year. I've "stolen" all the code from that handler. :-) I hope you don't mind Steve. - Gunnar Gunnar Nordmark Nora strand 5 S-182 34 DANDERYD SWEDEN gno@stacken.kth.se stacken.kth.se!gno@uunet.uu.net (if the above doesn't work) gno@SESTAK.BITNET SHAR_EOF cat << \SHAR_EOF > null.uu begin 644 null-handler M```#\P`````````#``````````(```#*````%@````$```/I````RD[Z`FY.8 M50``(&T`""\H`!`@;0`(+R@`#"\M``PO+0`(80A/[P`03EU.=4Y5__@@;0`(I M(6T`$``,(&T`""%M`!0`$"!M``@K:``$__@@;0`(*U#__"!M``@B;0`,T_P`> M``!<(4D`!"!M__PA;0`(``H@;?_\0I`@;?_\0J@`!"\M__PO+?_X3KH"@E!/7 M3EU.=4Y5__@@;0`(T?P```!<*TC__"\M__Q.N@)P6$\O+?_\3KH"2%A/*T#_F M^"!M__@@*``*3EU.=4Y5_^A!^@&"*TC__"M\`````?_L0JW_Z$*G3KH""%A/] M*4"`$B\L@!).NO^@6$\K0/_X(&W_^"`H`!SE@"M`__0@;?_T(FR`$M/\````R M7"%)``@@;?_X+R@`$$AX__\O+(`2+RW_^$ZZ_OQ/[P`02JW_[&<``0@O+(`2& M3KK_3EA/*T#_^"!M__@@*``(8```QE*M_^@@;?_X("@`%.6`*T#_\"!M__@B# M;?_P(V@`"``D(&W_\$*H``0@;?_X+R@`$$AX__\O+(`2+RW_^$ZZ_I9/[P`00 M8```HB!M__@O*``00J<O+(`2+RW_^$ZZ_GA/[P`08```A"!M__@B;?_X(V@`; M'``,+RR`$B\M__A.NOXP4$]@9%.M_^AF!$*M_^P@;?_X+R@`$$AX__\O+(`2" M+RW_^$ZZ_C!/[P`08#Q(>`#10J<O+(`2+RW_^$ZZ_AA/[P`08"20O````%)GB M`/]\6X!GE)"\```#EF<`_R93@&<`_R!3@&>>8,1@`/[T(&W_]$*H``A.74YU) M5F5R(#`N,"`H8RD@1W5N;F%R($YO<F1M87)K(#$Y.#@``&%P0^R`#D7L@`ZU4 MR68.,CP`$FL(=``BPE')__PI3X`6+'@`!"E.@`Y(YX"`""X`!`$I9Q!+^@`(O M3J[_XF`&0J?S7TYS0_H`($ZN_F@I0(`:9@PN/``#@`=.KO^48`1.NOWV4$]." M=61O<RYL:6)R87)Y`$GY``!__DYU3OH``B)O``0L;(`.3N[^VD[Z``(@;P`$6 M+&R`#D[N_HQ,[P,```0L;(`.3N[^DD[Z``(@;P`$+&R`#D[N_H````/L````, M`0````$```+D`````````_(```/J`````P`4`````````````````_(```/K$ (`````0```_+D: `` end size 908 SHAR_EOF # End of shell archive exit 0 -- Bob Page, U of Lowell CS Dept. page@swan.ulowell.edu ulowell!page Have five nice days.