home *** CD-ROM | disk | FTP | other *** search
- /*
- shutdown.c --- shutdown frontend.
-
- (c) Copyright 1995 SHW Wabnitz
- Written by Bernhard Fastenrath (fasten@shw.com)
-
- This file may be distributed under the terms
- of the GNU General Public License.
- */
-
- #include <dos.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <intuition/intuition.h>
- #include <proto/exec.h>
- #include <proto/intuition.h>
-
- #if defined (__GNUC__)
- #include "halt_inline.h"
- #else
- #include "halt_pragmas.h"
- #endif
- #include "halt.h"
-
- int GoDown (int now);
-
- #define SIGBREAKF_MASK ( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | \
- SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F )
-
- struct IntuitionBase *IntuitionBase = NULL;
- struct Library *HaltBase = NULL;
- ShutdownMessage *Smsg = NULL;
- ShutdownContext SContext;
- struct timerequest *TimerReq = NULL;
- struct MsgPort *TimerPort = NULL;
- struct MsgPort *ReplyPort = NULL;
- struct MsgPort *ShutdownPort = NULL;
- ULONG TimerMask;
- ULONG TimerErr = 1;
- ULONG ShutdownMask;
- ULONG ReplyMask;
- ULONG WaitMask;
- int point_of_no_return = 0;
- int ExpectTimeout = 0;
- char *ShutdownPortname = "Shutdown";
- int SpNameLen;
- ULONG ShutdownFlags;
- ULONG BroadcastTimeout = 5;
- char *CantAllocatePort = "Can't allocate message port.\n";
- char *ShutdownCancelled = "shutdown cancelled.\n";
- char *OutOfMemory = "Out of memory.\n";
- char *SorryTooLate = "Too late to stop shutdown.\n";
- int MessageTimedOut = 0;
- int HaltFlag = 1, SyncTime = 5;
- int FastBoot = 0;
- int Error;
- char *optarg = NULL;
-
- int
- getopt (int argc, char *argv[], char *opts)
- {
- static int pos = 0;
- char *c;
-
- while (++pos < argc && argv[pos][0] != '-');
- if (pos >= argc)
- return -1;
- if ((c = strchr (opts, (int) argv[pos][1])) == 0)
- return (int) '?';
- if (*(c+1) != ':')
- return (int) *c;
- if (strlen (argv[pos]) > 2)
- optarg = argv[pos] + 2;
- else if (pos+1 < argc)
- optarg = argv[pos+1];
- else
- return (int) '?';
- return (int) *c;
- }
-
- ShutdownMessage *
- AllocShutdownMessage ()
- {
- ShutdownNode *node;
-
- if (!(node = (ShutdownNode *)
- AllocMem (sizeof (ShutdownNode), MEMF_PUBLIC | MEMF_CLEAR)))
- {
- return NULL;
- }
- node -> sn_Msg.sm_Msg.mn_ReplyPort = ReplyPort;
- node -> sn_Msg.sm_Msg.mn_Length = sizeof (ShutdownMessage);
- node -> sn_Msg.sm_Context = &SContext;
- AddTail (&SContext.sc_List, (struct Node *) node);
- return &node -> sn_Msg;
- }
-
- ULONG
- PutAndGet (ShutdownMessage *smsg, char *portname)
- {
- struct MsgPort *prt;
-
- Forbid ();
- if (prt = FindPort (portname))
- {
- PutMsg (prt, (struct Message *) smsg);
- Permit ();
- do
- WaitPort (ReplyPort);
- while (!GetMsg (ReplyPort));
- }
- else
- Permit ();
- return ((ULONG) prt);
- }
-
- void
- CleanUp (char *error)
- {
- ShutdownNode *node, *next;
-
- if (error)
- printf (error);
- if (!TimerErr)
- CloseDevice ((struct IORequest *) TimerReq);
- if (TimerReq)
- DeleteIORequest (TimerReq);
- if (TimerPort)
- DeleteMsgPort (TimerPort);
- if (ReplyPort)
- DeleteMsgPort (ReplyPort);
- if (ShutdownPort)
- {
- if (ShutdownPort -> mp_Node.ln_Name)
- FreeMem (ShutdownPort -> mp_Node.ln_Name, SpNameLen);
- RemPort (ShutdownPort);
- DeleteMsgPort (ShutdownPort);
- }
- node = (ShutdownNode *) SContext.sc_List.lh_Head;
- while (next = (ShutdownNode *) node -> sn_MinNode.mln_Succ)
- {
- FreeMem (node, sizeof (ShutdownNode));
- node = next;
- }
- if (HaltBase)
- CloseLibrary (HaltBase);
- if (IntuitionBase)
- CloseLibrary ((struct Library *) IntuitionBase);
- exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
- }
-
- int
- CancelShutdown (void)
- {
- if (point_of_no_return)
- return 0;
-
- if (SContext.sc_TimeOuts)
- {
- printf ("Shutdown cannot exit, there are still %d unreplied messages.\n",
- SContext.sc_TimeOuts);
- return 0;
- }
- if (ExpectTimeout == 1)
- {
- printf ("Press CTRL-C to abort the following "
- "cancel message before it times out.\n");
- ExpectTimeout = 2;
- }
- if (Smsg)
- {
- BroadcastTimeout = 0;
- Smsg -> sm_Status = SHUTDOWN_ABORT;
- BroadcastShutdownMsg ();
- }
- CleanUp (ShutdownCancelled);
- }
-
- int
- BroadcastShutdownMsg ()
- {
- if (BroadcastTimeout)
- {
- TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
- TimerReq -> tr_time.tv_secs = BroadcastTimeout;
- TimerReq -> tr_time.tv_micro = 0;
- SendIO ((struct IORequest *) TimerReq);
- }
- Smsg -> sm_Flags = ShutdownFlags;
- ShutdownStatus (Smsg);
- if (Smsg -> sm_Flags & SDMF_SIG_MASK)
- {
- printf ("Warning: shutdown message timed out.\n");
- if (!ExpectTimeout)
- ExpectTimeout = 1;
- }
- if (Smsg -> sm_Flags & SDMF_CTRL_C)
- {
- /* We didn't receive a timeout yet but a CTRL-C during a
- broadcast is unlikely if there was no timeout ahead.
- */
- if (!ExpectTimeout)
- ExpectTimeout = 1;
- }
- if (BroadcastTimeout)
- {
- if (Smsg -> sm_Flags & SDMF_SIG_MASK)
- {
- RemShutdownPort (Smsg -> sm_Context -> sc_Port);
-
- while (!(Smsg = AllocShutdownMessage ()))
- Delay (50); /* Better ideas welcome ... */
- }
- else
- AbortIO ((struct IORequest *) TimerReq);
- WaitIO ((struct IORequest *) TimerReq);
- SetSignal (0L, TimerMask);
- }
- if (!point_of_no_return)
- {
- if (Smsg -> sm_Flags & SDMF_CANCEL)
- CancelShutdown ();
- }
- }
-
- void
- AbortableDelay (int seconds)
- {
- ShutdownMessage *sm;
- int abort = 0;
- ULONG mask;
-
- TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
- TimerReq -> tr_time.tv_secs = seconds;
- TimerReq -> tr_time.tv_micro = 0;
- SendIO ((struct IORequest *) TimerReq);
-
- while (1)
- {
- mask = Wait (WaitMask);
- if (mask & ShutdownMask)
- {
- do
- WaitPort (ShutdownPort);
- while (!(sm = (ShutdownMessage *) GetMsg (ShutdownPort)));
- if (sm -> sm_Status == SHUTDOWN_ABORT)
- if (point_of_no_return)
- sm -> sm_Status = SHUTDOWN_UMOUNT;
- else
- abort = 1;
- ReplyMsg ((struct Message *) sm);
- }
- if (mask & ReplyMask) /* late reply */
- {
- if (GetMsg (ReplyPort))
- SContext.sc_TimeOuts --;
- }
- if (mask & SIGBREAKF_MASK || abort)
- {
- if (point_of_no_return)
- {
- printf (SorryTooLate);
- continue;
- }
- if (!(mask & TimerMask))
- AbortIO ((struct IORequest *) TimerReq);
- WaitIO ((struct IORequest *) TimerReq);
- SetSignal (0L, TimerMask);
-
- if (mask & SIGBREAKF_CTRL_C || abort)
- {
- if (mask & SIGBREAKF_CTRL_C && !ExpectTimeout)
- printf ("CTRL-C\n");
- CancelShutdown ();
- printf ("Timer stopped, press CTRL-E or CTRL-F to reboot.\n");
- }
- if (mask & SIGBREAKF_CTRL_D) /* CTRL-D: speed up */
- {
- printf ("CTRL-D\n");
- return;
- }
- if (!FastBoot)
- {
- FastBoot = 1;
- if (mask & SIGBREAKF_CTRL_E) /* CTRL-E: fast reboot */
- {
- printf ("CTRL-E\n");
- GoDown (0);
- }
- if (mask & SIGBREAKF_CTRL_F) /* CTRL-F: very fast reboot */
- {
- printf ("CTRL-F\n");
- GoDown (1);
- }
- }
- else
- return;
- }
- if (mask & TimerMask) /* done waiting */
- return;
- }
- }
-
- int
- main (int argc, char *argv[])
- {
- int cancel_flag = 0, abortable_flag = 1;
- int shutdown_time = 10, shutdown_interval;
- int opt;
-
- bzero (&SContext, sizeof (ShutdownContext));
- NewList (&SContext.sc_List);
- SetTaskPri (FindTask (0L), 10);
-
- while ((opt = getopt (argc, argv, "chnrs:t:T:")) != -1)
- switch (opt)
- {
- case 'n': abortable_flag = 0; break;
- case 'r': HaltFlag = 0; break;
- case 'h': HaltFlag = 1; break;
- case 't': shutdown_time = atoi (optarg); break;
- case 's': SyncTime = atoi (optarg); break;
- case 'c': cancel_flag = 1; break;
- case 'T': BroadcastTimeout = atoi (optarg); break;
- default:
- printf ("Usage: %s [-chnr] [-t <time>] [-s <sync time>] [-T <timeout>].\n", argv[0]);
- exit (EXIT_FAILURE);
- }
-
- if (HaltFlag)
- IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 37);
- if (!(HaltBase = OpenLibrary ("halt.library", 0)))
- CleanUp ("Failed to open halt.library.\n");
-
- if (!(ReplyPort = CreateMsgPort ()))
- CleanUp (CantAllocatePort);
- ReplyMask = 1 << ReplyPort -> mp_SigBit;
- if (!(Smsg = AllocShutdownMessage ()))
- CleanUp (OutOfMemory);
- if (abortable_flag)
- ShutdownFlags = SDMF_ABORTABLE;
-
- /* open timer device */
- if (!(TimerPort = CreateMsgPort ()))
- CleanUp (CantAllocatePort);
- if (!(TimerReq = (struct timerequest *)
- CreateIORequest (TimerPort, sizeof (struct timerequest))))
- CleanUp (OutOfMemory);
- if (TimerErr = OpenDevice (TIMERNAME, UNIT_VBLANK, (struct IORequest *) TimerReq, 0))
- CleanUp ("Can't open timer device.\n");
- Smsg -> sm_Context -> sc_Mask = TimerMask = 1 << TimerPort -> mp_SigBit;
-
- if (cancel_flag)
- {
- Smsg -> sm_Status = SHUTDOWN_ABORT;
- if (!PutAndGet (Smsg, ShutdownPortname))
- CleanUp ("Shutdown is not running.\n");
- if (Smsg -> sm_Status == SHUTDOWN_UMOUNT)
- CleanUp (SorryTooLate);
- CleanUp (ShutdownCancelled);
- }
-
- /* don't start shutdown twice */
- Forbid ();
- if (FindPort (ShutdownPortname))
- {
- Permit ();
- CleanUp ("Shutdown is already running.\n");
- }
- Permit ();
- if (!(ShutdownPort = CreateMsgPort ()))
- CleanUp (CantAllocatePort);
- if (!(ShutdownPort -> mp_Node.ln_Name =
- AllocMem (SpNameLen = strlen (ShutdownPortname) + 1, MEMF_PUBLIC)))
- CleanUp (OutOfMemory);
- bcopy (ShutdownPortname, ShutdownPort -> mp_Node.ln_Name, SpNameLen);
- ShutdownPort -> mp_Node.ln_Pri = 0;
- AddPort (ShutdownPort);
- ShutdownMask = 1 << ShutdownPort -> mp_SigBit;
- WaitMask = ReplyMask | ShutdownMask | TimerMask | SIGBREAKF_MASK;
-
- while (shutdown_time > 5)
- {
- shutdown_interval = shutdown_time / 2;
- printf ("The system is going down in %d seconds.\n", shutdown_time);
- Smsg -> sm_Status = SHUTDOWN_WARN;
- Smsg -> sm_TimeLeft = shutdown_time;
- BroadcastShutdownMsg ();
- AbortableDelay (shutdown_interval);
- shutdown_time -= shutdown_interval;
- }
- GoDown (0);
- }
-
- int
- GoDown (int now)
- {
- struct EasyStruct es = {
- sizeof (struct EasyStruct), 0, "AmigaDOS", "The system is halted", "Ok"
- };
-
- if (!now)
- {
- /* last warning */
- Smsg -> sm_Status = SHUTDOWN_NOW;
- Smsg -> sm_TimeLeft = 5;
- BroadcastShutdownMsg ();
- printf ("The system is going down in 5 seconds.\n");
- AbortableDelay (5);
-
- /* too late for writing */
- Smsg -> sm_Status = SHUTDOWN_UMOUNT;
- Smsg -> sm_TimeLeft = 0;
- BroadcastShutdownMsg ();
- }
- point_of_no_return = 1;
- ShutdownFlags &= ~SDMF_ABORTABLE;
-
- printf ("The system is going down, unmounting filesystems.\n");
- Unmount (NULL);
- AbortableDelay (SyncTime);
-
- if (!now) /* all done, who turns off the light? */
- {
- Smsg -> sm_Status = SHUTDOWN_HALT;
- Smsg -> sm_TimeLeft = 0;
- BroadcastShutdownMsg ();
- }
- printf ("The system is halted.\n");
-
- if (IntuitionBase)
- BuildEasyRequest (NULL, &es, NULL);
- Delay (10); /* wait 0.5 seconds */
- Reboot (HaltFlag); /* 0 = reboot, 1 = halt */
- }
-