From 5f263d88822324d98350fc660b3ca0b077bd1501 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Mon, 12 Nov 2012 09:02:54 -0500 Subject: flush input buffers before accepting stdin --- src/lib/Bcfg2/Client/Frame.py | 5 +++ src/lib/Bcfg2/Client/Tools/Action.py | 7 ++++ src/lib/Bcfg2/Client/Tools/__init__.py | 6 ++++ src/lib/Bcfg2/Server/Admin/Init.py | 59 ++++++++++++++++++++-------------- src/lib/Bcfg2/Server/Admin/Pull.py | 8 ++++- 5 files changed, 60 insertions(+), 25 deletions(-) (limited to 'src/lib/Bcfg2') diff --git a/src/lib/Bcfg2/Client/Frame.py b/src/lib/Bcfg2/Client/Frame.py index 64460ea66..53180ab68 100644 --- a/src/lib/Bcfg2/Client/Frame.py +++ b/src/lib/Bcfg2/Client/Frame.py @@ -1,8 +1,10 @@ """ Frame is the Client Framework that verifies and installs entries, and generates statistics. """ +import os import sys import time +import select import fnmatch import logging import Bcfg2.Client.Tools @@ -160,6 +162,9 @@ class Frame(object): iprompt = entry.get('qtext') else: iprompt = prompt % (entry.tag, entry.get('name')) + # flush input buffer + while len(select.select([sys.stdin.fileno()], [], [], 0.0)[0]) > 0: + os.read(sys.stdin.fileno(), 4096) try: ans = input(iprompt.encode(sys.stdout.encoding, 'replace')) if ans in ['y', 'Y']: diff --git a/src/lib/Bcfg2/Client/Tools/Action.py b/src/lib/Bcfg2/Client/Tools/Action.py index 7726da94c..b1a897c81 100644 --- a/src/lib/Bcfg2/Client/Tools/Action.py +++ b/src/lib/Bcfg2/Client/Tools/Action.py @@ -1,5 +1,8 @@ """Action driver""" +import os +import sys +import select import Bcfg2.Client.Tools from Bcfg2.Client.Frame import matches_white_list, passes_black_list from Bcfg2.Compat import input # pylint: disable=W0622 @@ -33,6 +36,10 @@ class Action(Bcfg2.Client.Tools.Tool): if self.setup['interactive']: prompt = ('Run Action %s, %s: (y/N): ' % (entry.get('name'), entry.get('command'))) + # flush input buffer + while len(select.select([sys.stdin.fileno()], [], [], + 0.0)[0]) > 0: + os.read(sys.stdin.fileno(), 4096) ans = input(prompt) if ans not in ['y', 'Y']: return False diff --git a/src/lib/Bcfg2/Client/Tools/__init__.py b/src/lib/Bcfg2/Client/Tools/__init__.py index 4022692be..927b25ba8 100644 --- a/src/lib/Bcfg2/Client/Tools/__init__.py +++ b/src/lib/Bcfg2/Client/Tools/__init__.py @@ -1,7 +1,9 @@ """This contains all Bcfg2 Tool modules""" import os +import sys import stat +import select from subprocess import Popen, PIPE import Bcfg2.Client.XML from Bcfg2.Compat import input, walk_packages # pylint: disable=W0622 @@ -373,6 +375,10 @@ class SvcTool(Tool): if self.setup['interactive']: prompt = ('Restart service %s?: (y/N): ' % entry.get('name')) + # flush input buffer + while len(select.select([sys.stdin.fileno()], [], [], + 0.0)[0]) > 0: + os.read(sys.stdin.fileno(), 4096) ans = input(prompt) if ans not in ['y', 'Y']: continue diff --git a/src/lib/Bcfg2/Server/Admin/Init.py b/src/lib/Bcfg2/Server/Admin/Init.py index 869dc1aca..14065980d 100644 --- a/src/lib/Bcfg2/Server/Admin/Init.py +++ b/src/lib/Bcfg2/Server/Admin/Init.py @@ -1,11 +1,13 @@ """ Interactively initialize a new repository. """ -import getpass + import os +import sys +import stat +import select import random import socket -import stat import string -import sys +import getpass import subprocess import Bcfg2.Server.Admin @@ -85,6 +87,14 @@ OS_LIST = [('Red Hat/Fedora/RHEL/RHAS/Centos', 'redhat'), ('Arch', 'arch')] +def safe_input(prompt): + """ input() that flushes the input buffer before accepting input """ + # flush input buffer + while len(select.select([sys.stdin.fileno()], [], [], 0.0)[0]) > 0: + os.read(sys.stdin.fileno(), 4096) + return input(prompt) + + def gen_password(length): """Generates a random alphanumeric password with length characters.""" chars = string.letters + string.digits @@ -116,8 +126,8 @@ def create_conf(confpath, confdata): """ create the config file """ # Don't overwrite existing bcfg2.conf file if os.path.exists(confpath): - result = input("\nWarning: %s already exists. " - "Overwrite? [y/N]: " % confpath) + result = safe_input("\nWarning: %s already exists. " + "Overwrite? [y/N]: " % confpath) if result not in ['Y', 'y']: print("Leaving %s unchanged" % confpath) return @@ -186,8 +196,8 @@ class Init(Bcfg2.Server.Admin.Mode): def _prompt_hostname(self): """Ask for the server hostname.""" - data = input("What is the server's hostname [%s]: " % - socket.getfqdn()) + data = safe_input("What is the server's hostname [%s]: " % + socket.getfqdn()) if data != '': self.data['shostname'] = data else: @@ -195,21 +205,21 @@ class Init(Bcfg2.Server.Admin.Mode): def _prompt_config(self): """Ask for the configuration file path.""" - newconfig = input("Store Bcfg2 configuration in [%s]: " % - self.configfile) + newconfig = safe_input("Store Bcfg2 configuration in [%s]: " % + self.configfile) if newconfig != '': self.data['configfile'] = os.path.abspath(newconfig) def _prompt_repopath(self): """Ask for the repository path.""" while True: - newrepo = input("Location of Bcfg2 repository [%s]: " % + newrepo = safe_input("Location of Bcfg2 repository [%s]: " % self.data['repopath']) if newrepo != '': self.data['repopath'] = os.path.abspath(newrepo) if os.path.isdir(self.data['repopath']): - response = input("Directory %s exists. Overwrite? [y/N]:" % - self.data['repopath']) + response = safe_input("Directory %s exists. Overwrite? [y/N]:" + % self.data['repopath']) if response.lower().strip() == 'y': break else: @@ -225,8 +235,8 @@ class Init(Bcfg2.Server.Admin.Mode): def _prompt_server(self): """Ask for the server name.""" - newserver = input("Input the server location [%s]: " % - self.data['server_uri']) + newserver = safe_input("Input the server location [%s]: " % + self.data['server_uri']) if newserver != '': self.data['server_uri'] = newserver @@ -238,7 +248,7 @@ class Init(Bcfg2.Server.Admin.Mode): prompt += ': ' while True: try: - osidx = int(input(prompt)) + osidx = int(safe_input(prompt)) self.data['os_sel'] = OS_LIST[osidx - 1][1] break except ValueError: @@ -248,27 +258,28 @@ class Init(Bcfg2.Server.Admin.Mode): """Ask for the key details (country, state, and location).""" print("The following questions affect SSL certificate generation.") print("If no data is provided, the default values are used.") - newcountry = input("Country name (2 letter code) for certificate: ") + newcountry = safe_input("Country name (2 letter code) for " + "certificate: ") if newcountry != '': if len(newcountry) == 2: self.data['country'] = newcountry else: while len(newcountry) != 2: - newcountry = input("2 letter country code (eg. US): ") + newcountry = safe_input("2 letter country code (eg. US): ") if len(newcountry) == 2: self.data['country'] = newcountry break else: self.data['country'] = 'US' - newstate = input("State or Province Name (full name) for " - "certificate: ") + newstate = safe_input("State or Province Name (full name) for " + "certificate: ") if newstate != '': self.data['state'] = newstate else: self.data['state'] = 'Illinois' - newlocation = input("Locality Name (eg, city) for certificate: ") + newlocation = safe_input("Locality Name (eg, city) for certificate: ") if newlocation != '': self.data['location'] = newlocation else: @@ -277,12 +288,12 @@ class Init(Bcfg2.Server.Admin.Mode): def _prompt_keypath(self): """ Ask for the key pair location. Try to use sensible defaults depending on the OS """ - keypath = input("Path where Bcfg2 server private key will be created " - "[%s]: " % self.data['keypath']) + keypath = safe_input("Path where Bcfg2 server private key will be " + "created [%s]: " % self.data['keypath']) if keypath: self.data['keypath'] = keypath - certpath = input("Path where Bcfg2 server cert will be created" - "[%s]: " % self.data['certpath']) + certpath = safe_input("Path where Bcfg2 server cert will be created" + "[%s]: " % self.data['certpath']) if certpath: self.data['certpath'] = certpath diff --git a/src/lib/Bcfg2/Server/Admin/Pull.py b/src/lib/Bcfg2/Server/Admin/Pull.py index e41652205..130e85b67 100644 --- a/src/lib/Bcfg2/Server/Admin/Pull.py +++ b/src/lib/Bcfg2/Server/Admin/Pull.py @@ -1,8 +1,10 @@ """ Retrieves entries from clients and integrates the information into the repository """ -import getopt +import os import sys +import getopt +import select import Bcfg2.Server.Admin from Bcfg2.Compat import input # pylint: disable=W0622 @@ -99,6 +101,10 @@ class Pull(Bcfg2.Server.Admin.MetadataCore): else: print(" => host entry: %s" % (choice.hostname)) + # flush input buffer + while len(select.select([sys.stdin.fileno()], [], [], + 0.0)[0]) > 0: + os.read(sys.stdin.fileno(), 4096) ans = input("Use this entry? [yN]: ") in ['y', 'Y'] if ans: return choice -- cgit v1.2.3-1-g7c22