[PATCH] Harden os.system
authormpm@selenic.com
Tue, 28 Jun 2005 02:38:33 -0800
changeset 508 42a660abaf75
parent 507 dd8b19114fe7
child 509 98a2935c3d6c
[PATCH] Harden os.system -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 [PATCH] Harden os.system From: Bryan O'Sullivan <bos@serpentine.com> Add util.system function. This is similar to os.system, but will either succeed (if the process finishes with a zero exit code) or raise a util.CommandError (if the process exits uncleanly or is killed by a signal). Add util.explain_exit function. This tends to be ubiquitous in code that calls other processes, and must describe what has gone wrong. Change some uses of os.system over to util.system. manifest hash: e3bf4adcac5b915432ec0af00efdbcef86bea4b1 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.0 (GNU/Linux) iD8DBQFCwSipywK+sNU5EO8RAr0RAJkBDt8XQ7mYQAWNHNgTOVt1eyWU1QCfe1oO 2OwxyWqpbRNACVJHHfZ3/Xw= =OaRX -----END PGP SIGNATURE-----
mercurial/commands.py
mercurial/ui.py
mercurial/util.py
--- a/mercurial/commands.py	Tue Jun 28 02:34:14 2005 -0800
+++ b/mercurial/commands.py	Tue Jun 28 02:38:33 2005 -0800
@@ -291,7 +291,7 @@
 
         if link:
             ui.debug("copying by hardlink\n")
-            os.system("cp -al %s/.hg .hg" % source)
+            util.system("cp -al %s/.hg .hg" % source)
             try:
                 os.remove(".hg/dirstate")
             except: pass
@@ -871,6 +871,8 @@
             return r
         else:
             return d()
+    except util.CommandError, inst:
+        u.warn("abort: %s\n" % inst.args)
     except hg.RepoError, inst:
         u.warn("abort: ", inst, "!\n")
     except SignalInterrupt:
--- a/mercurial/ui.py	Tue Jun 28 02:34:14 2005 -0800
+++ b/mercurial/ui.py	Tue Jun 28 02:38:33 2005 -0800
@@ -5,7 +5,7 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-import os, sys, re, ConfigParser
+import os, sys, re, ConfigParser, util
 
 class ui:
     def __init__(self, verbose=False, debug=False, quiet=False,
@@ -78,10 +78,7 @@
         f.close()
 
         editor = os.environ.get("HGEDITOR") or os.environ.get("EDITOR", "vi")
-        r = os.system("%s %s" % (editor, name))
-
-        if r:
-            raise "Edit failed!"
+        util.system("%s %s" % (editor, name), errprefix = "edit failed")
 
         t = open(name).read()
         t = re.sub("(?m)^HG:.*\n", "", t)
--- a/mercurial/util.py	Tue Jun 28 02:34:14 2005 -0800
+++ b/mercurial/util.py	Tue Jun 28 02:38:33 2005 -0800
@@ -7,6 +7,29 @@
 
 import os
 
+class CommandError(Exception): pass
+
+def explain_exit(code):
+    """return a 2-tuple (desc, code) describing a process's status"""
+    if os.WIFEXITED(code):
+        val = os.WEXITSTATUS(code)
+        return "exited with status %d" % val, val
+    elif os.WIFSIGNALED(code):
+        val = os.WTERMSIG(code)
+        return "killed by signal %d" % val, val
+    elif os.WIFSTOPPED(code):
+        val = os.STOPSIG(code)
+        return "stopped by signal %d" % val, val
+    raise ValueError("invalid exit code")
+    
+def system(cmd, errprefix = "abort"):
+    """execute a shell command that must succeed"""
+    rc = os.system(cmd)
+    if rc:
+        errmsg = "%s: %s %s" % (errprefix, os.path.basename(cmd.split(None, 1)[0]),
+                                explain_exit(rc)[0])
+        raise CommandError(errmsg)
+
 def rename(src, dst):
     try:
         os.rename(src, dst)