[comp.sys.amiga] How to write an AmiCron that WORKS!

nordmark@nada.kth.se (Arne Nordmark) (12/17/88)

Since several people have asked how to write a cron-program that runs
as a daemon, i.e. without a window, I think this will be useful 
information for the net.

I have my own extremely undocumented, uncommented and messy version
called "CronSafe" :-) (only Swedes will understand the smiley) that
seems *impossible* to crash. Even if you patch in the new 1.3 Shell
instead of the CLI, it runs without gurus.

I haven't got the time to clean up the code and write the documentation,
but if you insist I could mail you a binary.
The changes to an old AmiCron program is *so* simple, so I think that
interested persons could make them themselves without much trouble.

I don't know if it will work with other shells that do evil things
like patching Execute() or mess with the resident list though.
I wouldn't count on it.
All I know is that it works with the new 1.3 Run and the standard CLI
or Shell. (and fortunately, most other shells don't do evil things)

This is what you should do:

1. Get the null: device that I posted to comp.sources.amiga recently.
   Append the supplied MountList and say
	Mount null:
   The null: device is of *vital* importance and you know why if you
   have followed the discussion in .tech

2. Add this to the cron code (if it is not allready there)
	/* #include <stdio.h> */
	fclose(stderr); 
   or do something of that effect.
	close(2);
   will do as well. You must close stderr to get rid of the "lock" on
   the current console. Then you will be able to close the window.
   You can also change _main.c and remove the line that Open("*", 1006);

3. Do this early in the program, i.e. before launching any commands:
	/* #include <libraries/dosextens.h> */
	struct MsgPort *old_console, *new_console, *DeviceProc();
	struct Process *proc;
	struct Task *FindTask();

	proc=(struct Process *)FindTask(NULL);
	old_console=(struct MsgPort *)proc->pr_ConsoleTask;
	new_console=DeviceProc("null:");
	if (new_console==NULL) {
		/* error, null: must be mounted */
	}
	proc->pr_ConsoleTask=(APTR)new_console;

3. Find the place where Execute() is called and do the following:
   If there is a line that looks like
	ret=Execute(command, NULL, NULL);
   change it to
	BPTR cli_input, Open();

	cli_input=Open("null:", MODE_OLDFILE);
	if (cli_input==NULL) {
		/* didn't I told you that null: must be mounted :-) */
	}
	ret=Execute(command, cli_input, NULL);
	Close(cli_input);
   this *works*. Don't try to do it in a different way, pplleeease :-)
   It took several weeks to find out that you indeed must supply a
   input file-handle. And you can't use NIL: (= guru)
   If you don't supply a null: input-handle you will get a hanging
   background cli if the command is "Run foo" and foo isn't found.
   This is a bug deep down in AmigaDOS that you have to find out
   the hard way.

4. When the cron program finally exits, you must restore the old console:
	proc->pr_ConsoleTask=(APTR)old_console;

Done! You now have a SAFE cron-program.

Using the 1.3 Run command you would probably start cron by
	Run > NIL: cron    ; (Here you *must* use NIL:, not null:)
then you can safely close the console-window.

Have fun!

  -- Gunnar

SNAIL: Gunnar Nordmark          VOICE: (+46) 8 - 755 42 52
       Nora strand 5
       S-182 34 DANDERYD        EMAIL: gno@stacken.kth.se
       SWEDEN                          gno@SESTAK.BITNET

"Words, words, words."  William Shakespeare