--- a/configure.ac
+++ b/configure.ac
@@ -50,7 +50,7 @@ AS_IF([test "x$with_twin" != xno],
 		fi],
 		[${twin_LIBS}])])
 
-mkdir -p discover lib/list lib/log lib/pb-protocol lib/talloc lib/waiter \
-	test ui/common ui/ncurses ui/test ui/twin
+mkdir -p discover lib/list lib/log lib/pb-protocol lib/system lib/talloc \
+	lib/waiter test ui/common ui/ncurses ui/test ui/twin
 
 AC_OUTPUT
--- /dev/null
+++ b/lib/system/system.c
@@ -0,0 +1,157 @@
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "log/log.h"
+#include <talloc/talloc.h>
+#include "system.h"
+
+const struct pb_system_apps pb_system_apps = {
+	.cp = "/bin/cp",
+	.kexec = "/sbin/kexec",
+	.mount = "/bin/mount",
+	.sftp = "/usr/bin/sftp",
+	.tftp = "/usr/bin/tftp",
+	.umount = "/bin/umount",
+	.wget = "/usr/bin/wget",
+};
+
+int pb_mkdir_recursive(const char *dir)
+{
+	struct stat statbuf;
+	char *str, *sep;
+	int mode = 0755;
+
+	if (!*dir)
+		return 0;
+
+	if (!stat(dir, &statbuf)) {
+		if (!S_ISDIR(statbuf.st_mode)) {
+			pb_log("%s: %s exists, but isn't a directory\n",
+					__func__, dir);
+			return -1;
+		}
+		return 0;
+	}
+
+	str = talloc_strdup(NULL, dir);
+	sep = strchr(*str == '/' ? str + 1 : str, '/');
+
+	while (1) {
+
+		/* terminate the path at sep */
+		if (sep)
+			*sep = '\0';
+
+		if (mkdir(str, mode) && errno != EEXIST) {
+			pb_log("mkdir(%s): %s\n", str, strerror(errno));
+			return -1;
+		}
+
+		if (!sep)
+			break;
+
+		/* reset dir to the full path */
+		strcpy(str, dir);
+		sep = strchr(sep + 1, '/');
+	}
+
+	talloc_free(str);
+
+	return 0;
+}
+
+int pb_rmdir_recursive(const char *base, const char *dir)
+{
+	char *cur, *pos;
+
+	/* sanity check: make sure that dir is within base */
+	if (strncmp(base, dir, strlen(base)))
+		return -1;
+
+	cur = talloc_strdup(NULL, dir);
+
+	while (strcmp(base, dir)) {
+
+		rmdir(dir);
+
+		/* null-terminate at the last slash */
+		pos = strrchr(dir, '/');
+		if (!pos)
+			break;
+
+		*pos = '\0';
+	}
+
+	talloc_free(cur);
+
+	return 0;
+}
+
+/**
+ * pb_run_cmd - Run the supplied command.
+ * @cmd_argv: An argument list array for execv.
+ */
+
+int pb_run_cmd(const char *const *cmd_argv)
+{
+	int status;
+	pid_t pid;
+#if defined(DEBUG)
+	enum {do_debug = 1};
+#else
+	enum {do_debug = 0};
+#endif
+
+	if (do_debug) {
+		const char *const *p = cmd_argv;
+
+		pb_log("%s: ", __func__);
+		while (*p) {
+			pb_log("%s ", *p);
+			p++;
+		}
+		pb_log("\n");
+	} else
+		pb_log("%s: %s\n", __func__, cmd_argv[0]);
+
+	pid = fork();
+	if (pid == -1) {
+		pb_log("%s: fork failed: %s\n", __func__, strerror(errno));
+		return -1;
+	}
+
+	if (pid == 0) {
+		execvp(cmd_argv[0], (char *const *)cmd_argv);
+		pb_log("%s: exec failed: %s\n", __func__, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (waitpid(pid, &status, 0) == -1) {
+		pb_log("%s: waitpid failed: %s\n", __func__,
+				strerror(errno));
+		return -1;
+	}
+
+	if (do_debug && WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
+		pb_log("%s: signaled\n", __func__);
+
+	if (!WIFEXITED(status)) {
+		pb_log("%s: %s failed\n", __func__, cmd_argv[0]);
+		return -1;
+	}
+
+	if (WEXITSTATUS(status))
+		pb_log("%s: WEXITSTATUS %d\n", __func__, WEXITSTATUS(status));
+
+	return WEXITSTATUS(status);
+}
--- /dev/null
+++ b/lib/system/system.h
@@ -0,0 +1,20 @@
+#if !defined(_PB_LIB_SYSTEM_H)
+#define _PB_LIB_SYSTEM_H
+
+struct pb_system_apps {
+	const char *cp;
+	const char *kexec;
+	const char *mount;
+	const char *sftp;
+	const char *tftp;
+	const char *umount;
+	const char *wget;
+};
+
+extern const struct pb_system_apps pb_system_apps;
+
+int pb_run_cmd(const char *const *cmd_argv);
+int pb_mkdir_recursive(const char *dir);
+int pb_rmdir_recursive(const char *base, const char *dir);
+
+#endif
--- a/rules.mk
+++ b/rules.mk
@@ -33,6 +33,7 @@ rules = utils/99-petitboot.rules
 list_objs = lib/list/list.o
 log_objs = lib/log/log.o
 protocol_objs = lib/pb-protocol/pb-protocol.o
+system_objs = lib/system/system.o
 talloc_objs = lib/talloc/talloc.o
 waiter_objs = lib/waiter/waiter.o
 
@@ -51,8 +52,8 @@ twin_objs = ui/twin/pb-twin.o
 makefiles = Makefile $(top_srcdir)/rules.mk
 
 # object collections
-lib_objs = $(list_objs) $(log_objs) $(protocol_objs) $(talloc_objs) \
-	$(waiter_objs)
+lib_objs = $(list_objs) $(log_objs) $(protocol_objs) $(system_objs) \
+	$(talloc_objs) $(waiter_objs)
 
 daemon_objs = $(lib_objs) $(parser_objs) $(discover_objs)
 
