/*
 *   halt: halt or reboot the system
 *
 *   Copyright (c) 1999 David Parsons. All rights reserved.
 *   
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *  3. All advertising materials mentioning features or use of this
 *     software must display the following acknowledgement:
 *     
 *   This product includes software developed by David Parsons
 *   (orc@pell.chi.il.us)
 *
 *  4. My name may not be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *     
 *  THIS SOFTWARE IS PROVIDED BY DAVID PARSONS ``AS IS'' AND ANY
 *  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
 *  PARSONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 *  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 *  THE POSSIBILITY OF SUCH DAMAGE.
 *
 * usage:  halt [-nwd]
 *	   reboot [-fnwd]
 *
 *         -f:  (f)orced reboot (don't ask init to do the deed)
 *         -n:  (n)o sync before halt or reboot
 *	   -w:  (w)rite utmp record, but don't actually do anything.
 *	   -d:  (d)on't write a utmp record.
 *
 */
static const char rcsid[] = "Mastodon $Id: halt.c,v 1.9 1999/06/09 10:04:38 orc Exp $";

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <utmp.h>
#include <getopt.h>
#include <signal.h>

#include "init.h"

int polite;		/* signal init, even if single user */
int forced = 0;		/* do the halt/reboot ourself */
int dosync = 1;		/* sync before our demise */
int wtmp   = 1;		/* write a wtmp record */
int faked  = 0;		/* pretend to do it */
int halt   = 0;		/* set nonzero if we're ``halt'' */

char *__progname;

/*
 * spit out an usage message, then exit
 */
void
usage(int iserror)
{
    fprintf(stderr, "usage: %s [-fnwdp]\n", __progname);
    exit(iserror ? 1 : 0);
} /* usage */


/*
 * halt, or reboot, we can't really tell
 */
float	/* we won't stay afloat for very long */
main(int argc, char **argv)
{
    int opt;
    char *runlevel = get_runlevel();

    __progname = basename(argv[0]);

    if (strcasecmp(__progname, "halt") == 0)
	halt = 1;

    polite = runlevel && (*runlevel == MULTI);
    opterr = 1;
    while ((opt = getopt(argc, argv, "fnwdp?")) != EOF)
	switch (opt) {
	case 'f':	forced = 1;	break;
	case 'p':	polite = 1;	break;
	case 'n':	dosync = 0;	break;
	case 'w':	wtmp = 1;
			faked = 1;	break;
	case 'd':	wtmp = 0;	break;
	case '?':
	default:	usage(opt == '?');
	}

    if (wtmp)
	log_runlevel(HALT, 0);

    if (faked)
	exit(0);

    if (forced)
	polite = 0;

    if (dosync) {
	sync();
	sleep(1);
	sync();
	sleep(1);
	sync();
	sleep(1);
    }
    /* If we're forcing it or we're not multiuser, Just Do It (tm),
     * otherwise ask init to do the deed for us
     */
    if (polite) {
	if (kill(1, halt ? S_HALT : S_REBOOT) == 0)
	    exit(0);
	perror("when signalling init");
	exit(1);
    }

    if (halt) {
#if DEBUG
	fprintf(stderr, "forced halt\n");
#else
	/* turn off special C-A-D handling */
	reboot(0xfee1dead, 672274793, 0xCDEF0123);
	/* try to kill all 'dem nasty processes off */
	kill(-1, SIGTSTP);
	kill(-1, SIGSTOP);
	kill(0, SIGSTOP);
	/* and at this point doing C-A-D will bring the
	 * remaining house of cards down
	 */
#endif
    }
    else {
	/* Goodbye, cruel world!
	 */
#if DEBUG
	fprintf(stderr, "forced reboot\n");
#else
	reboot(0xfee1dead, 672274793, 0x01234567);
#endif
    }
    exit(0);
}
