From b63e5d2972b420296ec9f7533a091a1cdcf1d9a8 Mon Sep 17 00:00:00 2001 From: Fabio Erculiani Date: Wed, 25 Jul 2012 16:22:53 +0200 Subject: [PATCH] [molecule/utils] add eval_shell_argument function --- molecule/utils.py | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/molecule/utils.py b/molecule/utils.py index ee77f20..b9bab3f 100644 --- a/molecule/utils.py +++ b/molecule/utils.py @@ -18,6 +18,7 @@ import os import errno +import fcntl import sys import time import tempfile @@ -78,6 +79,53 @@ def is_exec_available(exec_name): return True return False +def eval_shell_argument(argument, env = None): + """ + Evaluate a single shell argument (taken from a full + shlex.split()) replacing the environment variables with + actual values and executing functions and external commands + as well (so pay attention, command injection is actually a + wanted side-effect). + + In case of errors, AttributeError() is raised. + """ + read, write = None, None + try: + shell_exec = os.getenv("SHELL", "/bin/sh") + read, write = os.pipe() + # set non-blocking + fcntl.fcntl(read, fcntl.F_SETFL, os.O_NONBLOCK) + exit_st = subprocess.call( + [shell_exec, "-c", + "printf \"" + argument + "\""], + env = env, stdout = write) + if exit_st != 0: + raise AttributeError( + "error while parsing argument: '%s'" % ( + argument,)) + # maximum 1024 chars + try: + evaluated = os.read(read, 1024) + except OSError as err: + # errno 11 is due to O_NONBLOCK + if err.errno == errno.EAGAIN: + raise AttributeError( + "error while parsing argument: '%s'" %( + argument,)) + raise + return evaluated + finally: + if read is not None: + try: + os.close(read) + except OSError: + pass + if write is not None: + try: + os.close(write) + except OSError: + pass + def exec_cmd(args, env = None): return subprocess.call(args, env = env)