diff --git a/Makefile.am b/Makefile.am
index d541fa25c7a13562ce7fce27b493ea4c4242e8ee..40202272a2ee50ef79a5e22639394559a60e2578 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1317,7 +1317,7 @@ man/%.gen: man/%.rst lib/query.py lib/build/sphinx_ext.py \
 man/%.7.in man/%.8.in man/%.1.in: man/%.gen man/footer.rst
 	@test -n "$(PANDOC)" || \
 	  { echo 'pandoc' not found during configure; exit 1; }
-	set -o pipefail ; \
+	set -o pipefail -e; \
 	trap 'echo auto-removing $@; rm $@' EXIT; \
 	$(PANDOC) -s -f rst -t man $< man/footer.rst | \
 	  sed -e 's/\\@/@/g' > $@; \
@@ -1847,10 +1847,8 @@ $(APIDOC_HS_DIR)/index.html: $(HS_LIBTESTBUILT_SRCS) Makefile
 	rm -rf $(APIDOC_HS_DIR)/*
 	for i in $(ALL_APIDOC_HS_DIRS); do \
 	  @mkdir_p@ $$i; \
+	  $(HSCOLOUR) -print-css > $$i/hscolour.css; \
 	done
-	$(HSCOLOUR) -print-css > $(APIDOC_HS_DIR)/Ganeti/hscolour.css
-	$(LN_S) ../hscolour.css $(APIDOC_HS_DIR)/Ganeti/HTools/hscolour.css
-	$(LN_S) ../hscolour.css $(APIDOC_HS_DIR)/Ganeti/Confd/hscolour.css
 	set -e ; \
 	export LC_ALL=en_US.UTF-8; \
 	OPTGHC="--optghc=-isrc --optghc=-itest/hs"; \
diff --git a/NEWS b/NEWS
index dc9a8266f4c4485156f8eed0fdcb63506f00367b..dd823c05d9df4843f0943d1565e66a5b49e0d89f 100644
--- a/NEWS
+++ b/NEWS
@@ -98,6 +98,10 @@ Version 2.7.0 beta1
 - Instance renames of LVM-based instances will now update the LV tags
   (which can be used to recover the instance-to-LV mapping in case of
   emergencies)
+- ``hbal`` will now exit with status 0 if, during job execution over
+  LUXI, early exit has been requested and all jobs are successful;
+  before, exit status 1 was used, which cannot be differentiated from
+  "job error" case
 
 
 Version 2.6.2
diff --git a/autotools/check-man-dashes b/autotools/check-man-dashes
index 3ddd3ba8674b965a26737a1b99dd142ebefffcfa..9ad87249c740cea46dcf7fc9254befb4d02c6633 100755
--- a/autotools/check-man-dashes
+++ b/autotools/check-man-dashes
@@ -1,7 +1,7 @@
 #!/bin/bash
 #
 
-# Copyright (C) 2012 Google Inc.
+# Copyright (C) 2012, 2013 Google Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -20,5 +20,5 @@
 
 set -e
 
-! grep -F -q '\[em]' "$1" || \
+! grep -F '\[em]' "$1" || \
   { echo "Unescaped dashes found in $1, use \\-- instead of --" 1>&2; exit 1; }
diff --git a/lib/build/sphinx_ext.py b/lib/build/sphinx_ext.py
index 58d7cc5d53c5d6b06fc075bff699585d5fc4791b..55e67cb1cce02ee896cc537df1d4d7e69c4b5331 100644
--- a/lib/build/sphinx_ext.py
+++ b/lib/build/sphinx_ext.py
@@ -1,7 +1,7 @@
 #
 #
 
-# Copyright (C) 2011, 2012 Google Inc.
+# Copyright (C) 2011, 2012, 2013 Google Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -168,15 +168,15 @@ def _BuildOpcodeParams(op_id, include, exclude, alias):
     has_test = not (test is None or test is ht.NoType)
 
     buf = StringIO()
-    buf.write("``%s``" % rapi_name)
+    buf.write("``%s``" % (rapi_name,))
     if has_default or has_test:
       buf.write(" (")
       if has_default:
-        buf.write("defaults to ``%s``" % default)
+        buf.write("defaults to ``%s``" % (default,))
         if has_test:
           buf.write(", ")
       if has_test:
-        buf.write("must be ``%s``" % test)
+        buf.write("must be ``%s``" % (test,))
       buf.write(")")
     yield buf.getvalue()
 
@@ -335,8 +335,8 @@ def BuildValuesDoc(values):
   """
   for name, doc in values:
     assert len(doc.splitlines()) == 1
-    yield "``%s``" % name
-    yield "  %s" % doc
+    yield "``%s``" % (name,)
+    yield "  %s" % (doc,)
 
 
 def _ManPageNodeClass(*args, **kwargs):
diff --git a/man/gnt-job.rst b/man/gnt-job.rst
index 20e5aa51e970075fe8d3e5bb7ef2a84042b0601c..83a336136d29d4b56d205707b4be506486dc2508 100644
--- a/man/gnt-job.rst
+++ b/man/gnt-job.rst
@@ -53,7 +53,7 @@ respective state, ``--pending`` includes both.
 CHANGE-PRIORITY
 ~~~~~~~~~~~~~~~
 
-| **change-priority** --priority {low | normal | high}
+| **change-priority** \--priority {low | normal | high}
 | {[\--force] {\--pending | \--queued | \--waiting} | *job-id* ...}
 
 Changes the priority of one or multiple pending jobs. Jobs currently
diff --git a/man/gnt-network.rst b/man/gnt-network.rst
index 69848cde32a279e9a94b2dba154e8719f4fd203d..59e8e02b992fadcdc855755060a12d5c9ae9fb18 100644
--- a/man/gnt-network.rst
+++ b/man/gnt-network.rst
@@ -26,13 +26,13 @@ ADD
 ~~~
 
 | **add**
-| [--network=*NETWORK*]
-| [--gateway=*GATEWAY*]
-| [--add-reserved-ips=*RESERVEDIPS*]
-| [--network6=*NETWORK6*]
-| [--gateway6=*GATEWAY6*]
-| [--mac-prefix=*MACPREFIX*]
-| [--submit]
+| [\--network=*NETWORK*]
+| [\--gateway=*GATEWAY*]
+| [\--add-reserved-ips=*RESERVEDIPS*]
+| [\--network6=*NETWORK6*]
+| [\--gateway6=*GATEWAY6*]
+| [\--mac-prefix=*MACPREFIX*]
+| [\--submit]
 | {*network*}
 
 Creates a new network with the given name. The network will be unused
@@ -62,13 +62,13 @@ MODIFY
 ~~~~~~
 
 | **modify**
-| [--gateway=*GATEWAY*]
-| [--add-reserved-ips=*RESERVEDIPS*]
-| [--remove-reserved-ips=*RESERVEDIPS*]
-| [--network6=*NETWORK6*]
-| [--gateway6=*GATEWAY6*]
-| [--mac-prefix=*MACPREFIX*]
-| [--submit]
+| [\--gateway=*GATEWAY*]
+| [\--add-reserved-ips=*RESERVEDIPS*]
+| [\--remove-reserved-ips=*RESERVEDIPS*]
+| [\--network6=*NETWORK6*]
+| [\--gateway6=*GATEWAY6*]
+| [\--mac-prefix=*MACPREFIX*]
+| [\--submit]
 | {*network*}
 
 Modifies parameters from the network.
@@ -83,7 +83,7 @@ options.
 REMOVE
 ~~~~~~
 
-| **remove** [--submit] {*network*}
+| **remove** [\--submit] {*network*}
 
 Deletes the indicated network, which must be not connected to any node group.
 
@@ -92,7 +92,7 @@ See **ganeti**\(7) for a description of ``--submit`` and other common options.
 LIST
 ~~~~
 
-| **list** [--no-headers] [--separator=*SEPARATOR*] [-v]
+| **list** [\--no-headers] [\--separator=*SEPARATOR*] [-v]
 | [-o *[+]FIELD,...*] [network...]
 
 Lists all existing networks in the cluster. If no group names are given,
diff --git a/man/gnt-node.rst b/man/gnt-node.rst
index 78edd5d037602dad76f5fd228908fb71d5033973..af95a27bf266475eeeb8cb158f1afc35d40c1374 100644
--- a/man/gnt-node.rst
+++ b/man/gnt-node.rst
@@ -585,7 +585,7 @@ annotated in the command line output.
 RESTRICTED-COMMAND
 ~~~~~~~~~~~~~~~~~~
 
-| **restricted-command** [-M] [--sync]
+| **restricted-command** [-M] [\--sync]
 | { -g *group* *command* | *command* *nodes*... }
 
 Executes a restricted command on the specified nodes. Restricted commands are
diff --git a/man/hbal.rst b/man/hbal.rst
index 701b551d14f91bf3855d4d3cdf19a65ea4fe553c..766baace4bd2933afb00650726a838fb130a8c59 100644
--- a/man/hbal.rst
+++ b/man/hbal.rst
@@ -400,16 +400,18 @@ in two ways:
 
 - by sending a ``SIGINT`` (``^C``), hbal will register the termination
   request, and will wait until the currently submitted jobs finish, at
-  which point it will exit (with exit code 1)
+  which point it will exit (with exit code 0 if all jobs finished
+  correctly, otherwise with exit code 1 as usual)
+
 - by sending a ``SIGTERM``, hbal will immediately exit (with exit code
-  2); it is the responsibility of the user to follow up with Ganeti the
-  result of the currently-executing jobs
+  2\); it is the responsibility of the user to follow up with Ganeti
+  and check the result of the currently-executing jobs
 
 Note that in any situation, it's perfectly safe to kill hbal, either via
 the above signals or via any other signal (e.g. ``SIGQUIT``,
 ``SIGKILL``), since the jobs themselves are processed by Ganeti whereas
 hbal (after submission) only watches their progression. In this case,
-the use will again have to query Ganeti for job results.
+the user will have to query Ganeti for job results.
 
 EXIT STATUS
 -----------
diff --git a/src/Ganeti/HTools/Program/Hbal.hs b/src/Ganeti/HTools/Program/Hbal.hs
index 26b1e3c83a1618007cc835941342b1684516bffa..ece465fc2a7f2a1a9e48b135ff1e1aab50127f47 100644
--- a/src/Ganeti/HTools/Program/Hbal.hs
+++ b/src/Ganeti/HTools/Program/Hbal.hs
@@ -186,8 +186,10 @@ execCancelWrapper _    _      _  _  _    [] = return $ Ok ()
 execCancelWrapper anno master nl il cref alljss = do
   cancel <- readIORef cref
   if cancel > 0
-    then return . Bad $ "Exiting early due to user request, " ++
-                        show (length alljss) ++ " jobset(s) remaining."
+    then do
+      putStrLn $ "Exiting early due to user request, " ++
+               show (length alljss) ++ " jobset(s) remaining."
+      return $ Ok ()
     else execJobSet anno master nl il cref alljss
 
 -- | Execute an entire jobset.