Index: uspace/app/sysctl/main.c
===================================================================
--- uspace/app/sysctl/main.c	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/app/sysctl/main.c	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -37,4 +37,5 @@
 #include <stdlib.h>
 #include <str.h>
+#include <str_error.h>
 #include <sysman/ctl.h>
 
@@ -91,5 +92,28 @@
 		continue;
 fail:
-		printf(" -- unit skipped due to IPC error (%i) --\n", rc);
+		printf(" -- unit skipped due to IPC error (%s) --\n",
+		    str_error(rc));
+	}
+
+	return 0;
+}
+
+static int stop(int argc, char *argv[])
+{
+	unit_handle_t handle;
+	char *unit_name = argv[1];
+
+	int rc = sysman_unit_handle(unit_name, &handle);
+	if (rc != EOK) {
+		printf("Cannot obtain handle for unit '%s' (%s).\n",
+		    unit_name, str_error(rc));
+		return rc;
+	}
+
+	rc = sysman_unit_stop(handle, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		printf("Error when stopping unit '%s' handle (%s).\n",
+		    unit_name, str_error(rc));
+		return rc;
 	}
 
@@ -99,4 +123,5 @@
 command_t commands[] = {
 	{ "list-units", 0, &list_units },
+	{ "stop",       1, &stop },
 	{ 0 }
 };
Index: uspace/lib/c/include/ipc/sysman.h
===================================================================
--- uspace/lib/c/include/ipc/sysman.h	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/lib/c/include/ipc/sysman.h	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -44,5 +44,7 @@
 	SYSMAN_BROKER_EXP_ADDED,
 	SYSMAN_BROKER_EXP_REMOVED,
+	SYSMAN_CTL_UNIT_HANDLE,
 	SYSMAN_CTL_UNIT_START,
+	SYSMAN_CTL_UNIT_STOP,
 	SYSMAN_CTL_GET_UNITS,
 	SYSMAN_CTL_UNIT_GET_NAME,
@@ -71,4 +73,5 @@
 	STATE_STARTED,
 	STATE_STOPPED,
+	STATE_STOPPING,
 	STATE_FAILED
 } unit_state_t;
Index: uspace/lib/sysman/include/sysman/ctl.h
===================================================================
--- uspace/lib/sysman/include/sysman/ctl.h	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/lib/sysman/include/sysman/ctl.h	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -33,5 +33,8 @@
 #include <sysman/unit.h>
 
+int sysman_unit_handle(const char *, unit_handle_t *);
+
 int sysman_unit_start(const char *, int);
+int sysman_unit_stop(unit_handle_t, int);
 
 int sysman_get_units(unit_handle_t **, size_t *);
Index: uspace/lib/sysman/src/ctl.c
===================================================================
--- uspace/lib/sysman/src/ctl.c	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/lib/sysman/src/ctl.c	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -34,4 +34,25 @@
 #include <sysman/sysman.h>
 
+int sysman_unit_handle(const char *unit_name, unit_handle_t *handle_ptr)
+{
+	async_exch_t *exch = sysman_exchange_begin(SYSMAN_PORT_CTL);
+
+	ipc_call_t call;
+	aid_t req = async_send_0(exch, SYSMAN_CTL_UNIT_HANDLE, &call);
+	sysarg_t rc = async_data_write_start(exch, unit_name, str_size(unit_name));
+	sysman_exchange_end(exch);
+
+	if (rc != EOK) {
+		async_forget(req);
+		return rc;
+	}
+
+	async_wait_for(req, &rc);
+	if (rc == EOK) {
+		*handle_ptr = IPC_GET_ARG1(call);
+	}
+	return rc;
+}
+
 /*
  * TODO
@@ -41,4 +62,5 @@
  * broker knows when appropriate exposee is created and the request succeeded.
  * Still though, it's necessary to centralize timeout into sysman.
+ * TODO convert to name->handle API
  */
 int sysman_unit_start(const char *unit_name, int flags)
@@ -56,4 +78,14 @@
 
 	async_wait_for(req, &rc);
+	return rc;
+}
+
+int sysman_unit_stop(unit_handle_t handle, int flags)
+{
+	async_exch_t *exch = sysman_exchange_begin(SYSMAN_PORT_CTL);
+
+	int rc = async_req_2_0(exch, SYSMAN_CTL_UNIT_STOP, handle, flags);
+	sysman_exchange_end(exch);
+	
 	return rc;
 }
Index: uspace/srv/sysman/connection_ctl.c
===================================================================
--- uspace/srv/sysman/connection_ctl.c	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/srv/sysman/connection_ctl.c	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -63,4 +63,33 @@
 	job_del_ref(&job);
 }
+
+static void sysman_unit_handle(ipc_callid_t iid, ipc_call_t *icall)
+{
+	char *unit_name = NULL;
+	sysarg_t retval;
+
+	int rc = async_data_write_accept((void **) &unit_name, true,
+	    0, 0, 0, NULL);
+	if (rc != EOK) {
+		retval = rc;
+		goto fail;
+	}
+
+	// TODO this is connection fibril, UNSYNCHRONIZED access to units!
+	unit_t *unit = repo_find_unit_by_name(unit_name);
+	if (unit == NULL) {
+		retval = ENOENT;
+		goto fail;
+	}
+
+	async_answer_1(iid, EOK, unit->handle);
+	goto finish;
+
+fail:
+	async_answer_0(iid, retval);
+finish:
+	free(unit_name);
+}
+
 static void sysman_unit_start(ipc_callid_t iid, ipc_call_t *icall)
 {
@@ -109,4 +138,42 @@
 finish:
 	free(unit_name);
+}
+
+static void sysman_unit_stop(ipc_callid_t iid, ipc_call_t *icall)
+{
+	sysarg_t retval;
+
+	unit_handle_t handle = IPC_GET_ARG1(*icall);
+	int flags = IPC_GET_ARG2(*icall);
+	sysman_log(LVL_DEBUG2, "%s(%i, %x)", __func__, handle, flags);
+
+	// TODO this is connection fibril, UNSYNCHRONIZED access to units!
+	unit_t *unit = repo_find_unit_by_handle(handle);
+	if (unit == NULL) {
+		retval = ENOENT;
+		goto answer;
+	}
+
+	if (!(flags & IPC_FLAG_BLOCKING)) {
+		retval = sysman_run_job(unit, STATE_STOPPED, NULL, NULL);
+		goto answer;
+	}
+
+	ipc_callid_t *iid_ptr = box_callid(iid);
+	if (iid_ptr == NULL) {
+		retval = ENOMEM;
+		goto answer;
+	}
+	retval = sysman_run_job(unit, STATE_STOPPED, &answer_callback,
+	    iid_ptr);
+	if (retval != EOK) {
+		goto answer;
+	}
+
+	/* Answer asynchronously from callback */
+	return;
+
+answer:
+	async_answer_0(iid, retval);
 }
 
@@ -220,6 +287,12 @@
 
 		switch (IPC_GET_IMETHOD(call)) {
+		case SYSMAN_CTL_UNIT_HANDLE:
+			sysman_unit_handle(callid, &call);
+			break;
 		case SYSMAN_CTL_UNIT_START:
 			sysman_unit_start(callid, &call);
+			break;
+		case SYSMAN_CTL_UNIT_STOP:
+			sysman_unit_stop(callid, &call);
 			break;
 		case SYSMAN_CTL_GET_UNITS:
Index: uspace/srv/sysman/job.c
===================================================================
--- uspace/srv/sysman/job.c	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/srv/sysman/job.c	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -199,8 +199,8 @@
 
 	int rc;
+	// TODO put here similar evaluation as in job_check
+	//      goal is to have job_run "idempotent"
 	switch (job->target_state) {
 	case STATE_STARTED:
-		// TODO put here same evaluation as in job_check
-		//      goal is to have job_run "idempotent"
 		if (u->state == job->target_state) {
 			rc = EOK;
@@ -209,6 +209,13 @@
 		}
 		break;
+	case STATE_STOPPED:
+		if (u->state == job->target_state) {
+			rc = EOK;
+		} else {
+			rc = unit_stop(u);
+		}
+		break;
 	default:
-		// TODO implement other states
+		// TODO implement other states?
 		assert(false);
 	}
Index: uspace/srv/sysman/job_closure.c
===================================================================
--- uspace/srv/sysman/job_closure.c	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/srv/sysman/job_closure.c	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -39,5 +39,8 @@
 
 /** Struct describes how to traverse units graph */
-typedef struct {
+struct bfs_ops;
+typedef struct bfs_ops bfs_ops_t;
+
+struct bfs_ops {
 	enum {
 		BFS_FORWARD,  /**< Follow oriented edges */
@@ -46,12 +49,12 @@
 
 	/** Visit a unit via edge
-	 * unit, incoming edge, user data
+	 * unit, incoming edge, traversing ops, user data
 	 * return result of visit (error stops further traversal)
 	 */
-	int (* visit)(unit_t *, unit_edge_t *, void *);
+	int (* visit)(unit_t *, unit_edge_t *, bfs_ops_t *, void *);
 
 	/** Clean units remaining in BFS queue after error */
-	void (* clean)(unit_t *, void *);
-} bfs_ops_t;
+	void (* clean)(unit_t *, bfs_ops_t *, void *);
+};
 
 /*
@@ -83,5 +86,6 @@
  * @return EOK on success
  */
-static int start_visit(unit_t *u, unit_edge_t *e, void *arg)
+static int visit_propagate_job(unit_t *u, unit_edge_t *e, bfs_ops_t *ops,
+    void *arg)
 {
 	int rc = EOK;
@@ -99,5 +103,8 @@
 	}
 
-	job_t *job = e->input->bfs_data;
+	job_t *job = (ops->direction == BFS_FORWARD) ?
+	    e->input->bfs_data :
+	    e->output->bfs_data;
+
 	assert(job != NULL);
 
@@ -129,5 +136,5 @@
 }
 
-static void traverse_clean(unit_t *u, void *arg)
+static void traverse_clean(unit_t *u, bfs_ops_t *ops, void *arg)
 {
 	job_t *job = u->bfs_data;
@@ -144,5 +151,5 @@
 	unit_t *unit = origin;
 
-	rc = ops->visit(unit, NULL, arg);
+	rc = ops->visit(unit, NULL, ops, arg);
 	if (rc != EOK) {
 		goto finish;
@@ -164,5 +171,5 @@
 				list_append(&u->bfs_link, &units_fifo);
 			}
-			rc = ops->visit(u, e, arg);
+			rc = ops->visit(u, e, ops, arg);
 			if (rc != EOK) {
 				goto finish;
@@ -175,5 +182,5 @@
 				list_append(&u->bfs_link, &units_fifo);
 			}
-			rc = ops->visit(u, e, arg);
+			rc = ops->visit(u, e, ops, arg);
 			if (rc != EOK) {
 				goto finish;
@@ -187,5 +194,5 @@
 	list_foreach_safe(units_fifo, cur_link, next_link) {
 		unit_t *u = list_get_instance(cur_link, unit_t, bfs_link);
-		ops->clean(u, arg);
+		ops->clean(u, ops, arg);
 		list_remove(cur_link);
 	}
@@ -227,8 +234,19 @@
 
 	static bfs_ops_t ops = {
-		.direction = BFS_FORWARD,
-		.visit = start_visit,
 		.clean = traverse_clean,
+		.visit = visit_propagate_job
 	};
+
+	switch (main_job->target_state) {
+	case STATE_STARTED:
+		ops.direction = BFS_FORWARD;
+		break;
+	case STATE_STOPPED:
+		ops.direction = BFS_BACKWARD;
+		break;
+	default:
+		assert(false);
+	}
+
 	int rc = dyn_array_append(job_closure, job_t *, main_job);
 	if (rc != EOK) {
Index: uspace/srv/sysman/sm_task.c
===================================================================
--- uspace/srv/sysman/sm_task.c	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/srv/sysman/sm_task.c	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -101,10 +101,17 @@
 	sysman_log(LVL_DEBUG2, "%s, %s(%i)@%" PRIu64 " %i",
 	    __func__, unit_name(u), u->state, tev->task_id, tev->flags);
-	assert(u->state == STATE_STARTING);
 
 	if (tev->flags & TASK_WAIT_EXIT) {
 		// TODO maybe call unit_fail (would be nice to contain reason)
-		u->state = STATE_FAILED;
-	} else {
+		//      or move this whole logic to unit_svc.c
+		if (u->state == STATE_STOPPING) {
+			u->state = STATE_STOPPED;
+		} else {
+			// if it has also retval == 0 then it's not fail
+			u->state = STATE_FAILED;
+		}
+	}
+	if (tev->flags & TASK_WAIT_RETVAL) {
+		assert(u->state == STATE_STARTING);
 		u->state = STATE_STARTED;
 	}
Index: uspace/srv/sysman/unit.c
===================================================================
--- uspace/srv/sysman/unit.c	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/srv/sysman/unit.c	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -142,4 +142,14 @@
 }
 
+/** Issue request to restarter to stop a unit
+ *
+ * Same semantics like for unit_start applies.
+ */
+int unit_stop(unit_t *unit)
+{
+	sysman_log(LVL_DEBUG, "%s('%s')", __func__, unit_name(unit));
+	return UNIT_VMT(unit)->stop(unit);
+}
+
 void unit_exposee_created(unit_t *unit)
 {
Index: uspace/srv/sysman/unit.h
===================================================================
--- uspace/srv/sysman/unit.h	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/srv/sysman/unit.h	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -70,6 +70,11 @@
 	job_t *job;
 
+	/** Handle for IPC (immutable) */
 	unit_handle_t handle;
+
+	/** Unit type (immutable) */
 	unit_type_t type;
+
+	/** Unit name (immutable) */
 	char *name;
 
@@ -110,4 +115,6 @@
 	int (*start)(unit_t *);
 
+	int (*stop)(unit_t *);
+
 	void (*exposee_created)(unit_t *);
 
@@ -124,4 +131,5 @@
 		.destroy         = &PREFIX##_destroy,                          \
 		.start           = &PREFIX##_start,                            \
+		.stop            = &PREFIX##_stop,                             \
 		.exposee_created = &PREFIX##_exposee_created,                  \
 		.fail            = &PREFIX##_fail                              \
@@ -135,4 +143,5 @@
 extern int unit_load(unit_t *, ini_configuration_t *, text_parse_t *);
 extern int unit_start(unit_t *);
+extern int unit_stop(unit_t *);
 extern void unit_exposee_created(unit_t *);
 extern void unit_fail(unit_t *);
Index: uspace/srv/sysman/units/unit_cfg.c
===================================================================
--- uspace/srv/sysman/units/unit_cfg.c	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/srv/sysman/units/unit_cfg.c	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -240,4 +240,18 @@
 }
 
+static int unit_cfg_stop(unit_t *unit)
+{
+	unit_cfg_t *u_cfg = CAST_CFG(unit);
+	assert(u_cfg);
+
+	/*
+	 * It makes no sense to stop configuration (i.e. unload it), however,
+	 * lets virtually stop it not to make obstructions for potential
+	 * restart = reload of configuration.
+	 */
+	unit->state = STATE_STOPPED;
+	return EOK;
+}
+
 static void unit_cfg_exposee_created(unit_t *unit)
 {
Index: uspace/srv/sysman/units/unit_mnt.c
===================================================================
--- uspace/srv/sysman/units/unit_mnt.c	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/srv/sysman/units/unit_mnt.c	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -229,4 +229,40 @@
 }
 
+static int unit_mnt_stop(unit_t *unit)
+{
+	unit_mnt_t *u_mnt = CAST_MNT(unit);
+	assert(u_mnt);
+	/* autostart implies blocking */
+	assert(!u_mnt->autostart || u_mnt->blocking);
+
+	
+	// TODO think about unit's lifecycle (is STOPPED only acceptable?)
+	// note: we should never hit STATE_STARTING, since it'd mean there are
+	//       two jobs running at once (unless job cancellation is implemented)
+	assert(unit->state == STATE_STARTED);
+
+	/*
+	 * We don't expect unmount to be blocking, since if some files are
+	 * being used, it'd return EBUSY immediately. That's why we call
+	 * unmount synchronously in the event loop fibril.
+	 */
+	int rc = unmount(u_mnt->mountpoint);
+
+	if (rc == EOK) {
+		unit->state = STATE_STOPPED;
+		return EOK;
+	} else if (rc == EBUSY) {
+		assert(unit->state == STATE_STARTED);
+		return EBUSY;
+	} else {
+		/*
+		 * Mount may be still usable, but be conservative and mark unit
+		 * as failed.
+		 */
+		unit->state = STATE_FAILED;
+		return rc;
+	}
+}
+
 static void unit_mnt_exposee_created(unit_t *unit)
 {
Index: uspace/srv/sysman/units/unit_svc.c
===================================================================
--- uspace/srv/sysman/units/unit_svc.c	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/srv/sysman/units/unit_svc.c	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -112,4 +112,29 @@
 }
 
+static int unit_svc_stop(unit_t *unit)
+{
+	unit_svc_t *u_svc = CAST_SVC(unit);
+	assert(u_svc);
+
+	
+	// TODO think about unit's lifecycle (is STOPPED only acceptable?)
+	// note: May change when job cancellation is possible.
+	assert(unit->state == STATE_STARTED);
+
+	int rc = task_kill(u_svc->main_task_id);
+
+	if (rc != EOK) {
+		/* Task may still be running, but be conservative about unit's
+		 * state. */
+		unit->state = STATE_FAILED;
+		return rc;
+	}
+
+	unit->state = STATE_STOPPING;
+
+	return EOK;
+}
+
+
 static void unit_svc_exposee_created(unit_t *unit)
 {
Index: uspace/srv/sysman/units/unit_tgt.c
===================================================================
--- uspace/srv/sysman/units/unit_tgt.c	(revision 68ae40a6a440a4d5bc1f574a8df83e6eef781511)
+++ uspace/srv/sysman/units/unit_tgt.c	(revision ed5367bf0658ac1cd94d57a4a1d643226f868205)
@@ -63,4 +63,13 @@
 }
 
+static int unit_tgt_stop(unit_t *unit)
+{
+	unit_tgt_t *u_tgt = CAST_TGT(unit);
+	assert(u_tgt);
+
+	unit->state = STATE_STOPPED;
+	return EOK;
+}
+
 static void unit_tgt_exposee_created(unit_t *unit)
 {
