#!/usr/bin/env python

# Copyright C 2002-2003 by Isilon Systems, Inc. All rights not expressly
# granted herein are reserved.
# Created in the United States of America.
#
# This digital media is protected by U.S. and international copyright and
# intellectual property laws. Unless otherwise specified, all information
# and screens appearing as part of this digital medium, including
# software, services, documents, text, images, icons, and logos design;
# the selection, assembly, arrangement, and design thereof; and the code
# that enables its presentation, are the sole property of Isilon Systems,
# Inc.
#
# Except as otherwise required by applicable law, no part of any
# copyrighted material may be reproduced, modified, translated,
# distributed, published, or transmitted by any means, electronic or
# mechanical, for any purpose, without the prior written consent of Isilon
# Systems.
#
# Isilon and Isilon Systems are registered trademarks of Isilon Systems,
# Inc.  Legion is a trademark of Isilon Systems, Inc.  All other
# trademarks and registered trademarks are the property of their
# respective holders.

import os
import os.path
import signal
import subprocess
import sys
import time

import isi.app.lib.procs as procs
import isi.ui.lcd.screens as screens
import isi.ui.lcd.library as lcdlibrary

def pause_isi_rc_parallel():
    subprocess.Popen("killall -USR1 isi_rc_parallel 2>/dev/null", shell=True)

def unpause_isi_rc_parallel():
    subprocess.Popen("killall -USR2 isi_rc_parallel 2>/dev/null", shell=True)

def user_input(prompt,valid_options):
    u_input = None
    while u_input not in valid_options:
        sys.stdout.write(prompt)
        u_input = sys.stdin.readline()[:-1]
    return u_input

def kill_other(pid):
    try:
        os.kill(pid, signal.SIGINT)
    except os.error:
        pass

def main(prompt_output):
    # don't terminate init script on ^C
    signal.signal(signal.SIGINT,signal.SIG_IGN)

    pause_isi_rc_parallel()

    # Create one process to handle the LCD, another to handle 
    # the serial console, and a third to write to a log file
    lcd_pid = os.fork()

    # Child handles LCD
    if lcd_pid == 0:
        tries = 0
        while True:
            screen = screens.StaticScreen(prompt_output)
            screen._can_exit = False
            screen._timeout = 10

            #
            # When we actually drop into single user mode, the LCD
            # daemon gets stopped, so catch the exception and restart
            # the daemon so we can keep the message refreshed on the
            # screen. Don't keep trying to show on the LCD / restart
            # after 5 attempts as this will cause console spam when
            # booted from a reimage flash.
            #
            if tries < 5:
                try:
                    lcdlibrary.show(screen)
                except:
                    tries += 1
                    subprocess.call("/usr/bin/isi_lcd_d restart", shell=True,
                            close_fds=True)
                    time.sleep(3)
        sys.exit(0)

    log_pid = os.fork()
    if log_pid == 0:
        # Log this.
        try:
            fh = open("/var/log/isi_stop_boot.log","a")
            fh.write("%s: %s\n" % (
                time.strftime("%C%y-%m-%dT%H:%M:%S%Z"), prompt_output))
            fh.close()
        except:
            pass
        os._exit(0)

    ret_val = choose_recovery_option(prompt_output)

    kill_other(lcd_pid)
    os.waitpid(log_pid, 0)
    return ret_val


def choose_recovery_option(prompt_output):
    should_continue = 1
    message = ""

    options = ("1", "2", "3")

    # functions to call in the switch statement
    actions = {
        "1":recovery_shell,
        "2":continue_boot,
        "3":reboot_node,
        }

    prompt = '''
%s
Please contact EMC Customer Support:
United States: 1 800 782 4362 (1 800 SVC 4EMC)
Canada: 1 800 543 4782 (1 800 543 4SVC)
Worldwide Country Code: 1 508 497 7901

%s
Command Options:
1) Enter recovery shell
2) Continue booting
3) Reboot
option> '''

    # stay at this prompt until the user chooses option 2
    while should_continue:
        answer = user_input((prompt % (prompt_output, message)), options)
        if answer in actions:
            should_continue, message = actions[answer]()

def recovery_shell():
    print "Entering recovery shell..."
    subprocess.call('pgrep -af isi_rc_parallel | xargs kill -3',
        close_fds=True, shell=True)

    return (1, "")

def continue_boot():
    unpause_isi_rc_parallel()
    return (0, "")

def print_error (e):
    print e

def reboot_node():
    print "Rebooting..."
    error = procs.proc_cmd_output('/sbin/reboot',print_error)[0]
    if error != 0:
        return (1, "\nReboot failed\n")
    else:
        return (0, "")

if __name__ == '__main__':
    sys.exit(main(sys.argv[1]) if len(sys.argv) > 1 else '')
