diff --git a/doc/language.txt b/doc/language.txt
index 75fcebb831f68314b163a330b7849eb8eab7925a..671efe5312fb2cc2e680d268a92a1074260c15ff 100644
--- a/doc/language.txt
+++ b/doc/language.txt
@@ -433,6 +433,32 @@ NOTE: Originally there was also option `ignore` that allowed pass for different
problems but most of those were not working and usage of them was questionable.
This options is now considered as obsolete and is ignored.
+Mode
+~~~~
+
+ Mode("mode", "mode")
+
+Updater supports various modifications to standard execution. Such modification
+can be requested by this command as well as some of them being accessible directly
+as arguments to *pkgupdate* command.
+
+Supported modes:
+
+reinstall_all::
+ Consider all packages as not being installed. Such consideration leads to full
+ system reinstall by updater. This is handy if versions of packages might be same
+ but content of installed package don't. This is effectively like if all
+ `Install` calls would have extra `reinstall = true`.
+no_removal::
+ Do not remove not required packages in this run from system. This has exception
+ and those are conflicting packages with to be installed packages.
+optional_installs::
+ Behave like if all `Install` requests would have extra `optional = true`. This
+ means that any install request that is not satisfied is just ignored. You can
+ use this in combination with `no_removal` to update system when some of the
+ repositories are not at the moment available without needing to tweak
+ configuration nor remove those packages.
+
Export and Unexport
~~~~~~~~~~~~~~~~~~~
diff --git a/src/lib/Makefile.dir b/src/lib/Makefile.dir
index c218c3defe7cf3269274ba6f4a4815f74c971ad5..f96341ffd6ef61ea9af1ff9e249f4b8b183a8abd 100644
--- a/src/lib/Makefile.dir
+++ b/src/lib/Makefile.dir
@@ -34,7 +34,8 @@ libupdater_MODULES := \
util \
syscnf \
multiwrite \
- logging
+ logging \
+ opmode
ifdef COV
libupdater_MODULES += lcoverage.embed
endif
diff --git a/src/lib/autoload/a_09_requests.lua b/src/lib/autoload/a_09_requests.lua
index 906cf83060b7cfaa626a7468355a7deda4b78d44..07b5ac8db3ebe66e3fc891cab68ca95990abac70 100644
--- a/src/lib/autoload/a_09_requests.lua
+++ b/src/lib/autoload/a_09_requests.lua
@@ -35,13 +35,14 @@ local assert = assert
local table = table
local utils = require "utils"
local uri = require "uri"
+local opmode = opmode
local DBG = DBG
local WARN = WARN
local ERROR = ERROR
module "requests"
--- luacheck: globals known_packages known_repositories repositories_uri_master repo_serial repository content_requests install uninstall script package
+-- luacheck: globals known_packages known_repositories repositories_uri_master repo_serial repository content_requests install uninstall mode script package
-- Verifications fields are same for script, repository and package. Lets define them here once and then just append.
local allowed_extras_verification = {
@@ -361,6 +362,22 @@ function uninstall(_, ...)
return content_request("uninstall", allowed_uninstall_extras, ...)
end
+local known_modes = {
+ ["reinstall_all"] = true,
+ ["no_removal"] = true,
+ ["optional_installs"] = true,
+}
+
+function mode(_, ...)
+ for _, md in pairs({...}) do
+ if known_modes[md] then
+ opmode:set(md)
+ else
+ WARN("Ignoring request for unknown mode: " .. md)
+ end
+ end
+end
+
local allowed_script_extras = {
["security"] = utils.arr2set({"string"}),
["optional"] = utils.arr2set({"boolean"}),
diff --git a/src/lib/autoload/a_10_sandbox.lua b/src/lib/autoload/a_10_sandbox.lua
index 9744dd5a5464880bab3a7fab5ee00bd7a45aa817..e953784c047cf9cea0354324b07749caabceac91 100644
--- a/src/lib/autoload/a_10_sandbox.lua
+++ b/src/lib/autoload/a_10_sandbox.lua
@@ -54,7 +54,7 @@ local updater_features = utils.arr2set({
'replan_string',
'relative_uri',
'no_returns',
- 'no-error-virtual'
+ 'no_error_virtual'
})
-- Available functions and "constants" from global environment
@@ -181,6 +181,10 @@ local funcs = {
mode = "wrap",
value = requests.script
},
+ Mode = {
+ mode = "wrap",
+ value = requests.mode
+ },
Unexport = {
mode = "wrap",
value = function(context, variable)
diff --git a/src/lib/autoload/a_12_planner.lua b/src/lib/autoload/a_12_planner.lua
index bee975b5834ad79982950c9b2fd1394e29d4b7ef..4472fce6fb4f54fc541a04c153a30184e03c764c 100644
--- a/src/lib/autoload/a_12_planner.lua
+++ b/src/lib/autoload/a_12_planner.lua
@@ -31,6 +31,7 @@ local DBG = DBG
local TRACE = TRACE
local WARN = WARN
local picosat = picosat
+local opmode = opmode
local utils = require "utils"
local backend = require "backend"
local requests = require "requests"
@@ -266,7 +267,7 @@ local function sat_build(sat, pkgs, requests)
}
-- Go trough requests and add them to SAT
for _, req in ipairs(requests) do
- if not pkgs[req.package.name] and not req.optional then
+ if not pkgs[req.package.name] and not req.optional and not opmode.optional_installs then
error(utils.exception('inconsistent', "Requested package " .. req.package.name .. " doesn't exists."))
end
local req_var = sat:var()
@@ -284,16 +285,6 @@ local function sat_build(sat, pkgs, requests)
return state
end
-
-local planned_action = 'require'
-function set_reinstall_all(enable)
- if enable then
- planned_action = 'reinstall'
- else
- planned_action = 'require'
- end
-end
-
-- Iterate trough all packages in given dependency tree.
-- TODO This goes trough all dependencies, so even negative dependencies and
-- packages used only as conditionals are returned. This is harmless for what we
@@ -431,12 +422,15 @@ local function build_plan(pkgs, requests, sat, satmap)
-- And finally plan it --
planned[name] = #plan + 1
r = {
- action = planned_action,
+ action = 'require',
package = candidates[1],
modifier = (pkg or {}).modifier or {},
critical = false,
name = name
}
+ if opmode.reinstall_all then
+ r.action = 'reinstall'
+ end
plan[#plan + 1] = r
return {r}
end
@@ -452,7 +446,7 @@ local function build_plan(pkgs, requests, sat, satmap)
for _, req in pairs(requests) do
if sat[satmap.req2sat[req]] then -- Plan only if we can satisfy given request
if req.tp == "install" then -- And if it is install request, uninstall requests are resolved by not being planned.
- local pln = pkg_plan(req.package, false, req.optional, 'Requested package')
+ local pln = pkg_plan(req.package, false, req.optional or opmode.optional_installs, 'Requested package')
-- Note that if pln is nil than we ignored missing package. We have to compute with that here
if pln then
if req.reinstall then
@@ -757,7 +751,7 @@ function filter_required(status, requests, allow_replan)
end
end
end
- if not replan then
+ if not replan and not opmode.no_removal then
-- We don't remove unused packages just yet if we do immediate replan, we do it after the replanning.
utils.arr_append(result, check_removal(status, unused))
end
diff --git a/src/lib/interpreter.c b/src/lib/interpreter.c
index 6f118b0d63cd9b2c890530d03fff52e970ba35ef..166b1a17a48049356f6770aaeba44e1106e18e17 100644
--- a/src/lib/interpreter.c
+++ b/src/lib/interpreter.c
@@ -26,6 +26,7 @@
#include "locks.h"
#include "arguments.h"
#include "syscnf.h"
+#include "opmode.h"
#include "uri_lua.h"
#include "picosat.h"
@@ -1022,6 +1023,7 @@ struct interpreter *interpreter_create(struct events *events) {
journal_mod_init(L);
locks_mod_init(L);
syscnf_mod_init(L);
+ opmode_mod_init(L);
uri_mod_init(L);
picosat_mod_init(L);
#ifdef COVERAGE
diff --git a/src/lib/opmode.c b/src/lib/opmode.c
new file mode 100644
index 0000000000000000000000000000000000000000..3be5e54e599e3ad57ebe43bed8ccc67ee67c723d
--- /dev/null
+++ b/src/lib/opmode.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2019, CZ.NIC z.s.p.o. (http://www.nic.cz/)
+ *
+ * This file is part of the Turris Updater.
+ *
+ * Updater is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Updater is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Updater. If not, see .
+ */
+#include "opmode.h"
+#include "logging.h"
+#include "inject.h"
+#include
+#include
+#include
+
+static bool modes[OPMODE_LAST];
+
+bool opmode(enum OPMODE mode) {
+ assert(mode < OPMODE_LAST);
+ return modes[mode];
+}
+
+void opmode_set(enum OPMODE mode) {
+ assert(mode < OPMODE_LAST);
+ modes[mode] = true;
+}
+
+void opmode_unset(enum OPMODE mode) {
+ assert(mode < OPMODE_LAST);
+ modes[mode] = false;
+}
+
+
+static enum OPMODE lua_str2opmode(const char *str_mode) {
+ if (!strcmp("reinstall_all", str_mode))
+ return OPMODE_REINSTALL_ALL;
+ else if (!strcmp("no_removal", str_mode))
+ return OPMODE_NO_REMOVAL;
+ else if (!strcmp("optional_installs", str_mode))
+ return OPMODE_OPTIONAL_INSTALLS;
+ return OPMODE_LAST;
+}
+
+static int lua_opmode_set(lua_State *L) {
+ const char *str_mode = luaL_checkstring(L, 2);
+ enum OPMODE mode = lua_str2opmode(str_mode);
+ if (mode >= OPMODE_LAST)
+ luaL_error(L, "Setting unknown mode: %s", str_mode);
+ opmode_set(mode);
+ return 0;
+}
+
+static int lua_opmode_unset(lua_State *L) {
+ const char *str_mode = luaL_checkstring(L, 2);
+ enum OPMODE mode = lua_str2opmode(str_mode);
+ if (mode >= OPMODE_LAST)
+ luaL_error(L, "Unsetting unknown mode: %s", str_mode);
+ opmode_unset(mode);
+ return 0;
+}
+
+static int lua_opmode_index(lua_State *L) {
+ const char *idx = luaL_checkstring(L, 2);
+ enum OPMODE mode = lua_str2opmode(idx);
+ if (mode < OPMODE_LAST)
+ lua_pushboolean(L, opmode(mode));
+ else if (luaL_getmetafield(L, 1, idx) == 0)
+ lua_pushnil(L);
+ return 1;
+}
+
+static const struct inject_func funcs[] = {
+ { lua_opmode_set, "set" },
+ { lua_opmode_unset, "unset" },
+ { lua_opmode_index, "__index" },
+};
+
+void opmode_mod_init(lua_State *L) {
+ TRACE("Opmode module init");
+ lua_newtable(L);
+ inject_func_n(L, "opmode", funcs, sizeof funcs / sizeof *funcs);
+ lua_pushvalue(L, -1);
+ lua_setmetatable(L, -2);
+ inject_module(L, "opmode");
+}
diff --git a/src/lib/opmode.h b/src/lib/opmode.h
new file mode 100644
index 0000000000000000000000000000000000000000..385fb2cd1d9294dae0a1300674631adf759f35e9
--- /dev/null
+++ b/src/lib/opmode.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2020, CZ.NIC z.s.p.o. (http://www.nic.cz/)
+ *
+ * This file is part of the Turris Updater.
+ *
+ * Updater is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Updater is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Updater. If not, see .
+ */
+#ifndef UPDATER_OPMODE_H
+#define UPDATER_OPMODE_H
+#include
+#include
+
+// All operation modes are set at beginning to false
+
+enum OPMODE {
+ // Reinstall all installed packages (consider them not installed)
+ OPMODE_REINSTALL_ALL,
+ // Do not remove any package with exception of collisions
+ OPMODE_NO_REMOVAL,
+ // Consider all install requests optional
+ OPMODE_OPTIONAL_INSTALLS,
+ // Not technically opmode but it can be used to get enum size
+ OPMODE_LAST
+};
+
+
+bool opmode(enum OPMODE);
+
+void opmode_set(enum OPMODE);
+void opmode_unset(enum OPMODE);
+
+
+// Create opmode module and inject it into the lua state
+void opmode_mod_init(lua_State *L) __attribute__((nonnull));
+
+#endif
diff --git a/src/pkgupdate/arguments.c b/src/pkgupdate/arguments.c
index 79d50296587076b07113930811320f7f5e44b444..5e783888095998cf74ddea96a061661898c4c7b3 100644
--- a/src/pkgupdate/arguments.c
+++ b/src/pkgupdate/arguments.c
@@ -2,6 +2,7 @@
#include "../lib/arguments.h"
#include "../lib/util.h"
#include "../lib/logging.h"
+#include "../lib/opmode.h"
const char *argp_program_version = "pkgupdate " UPDATER_VERSION;
static const char usage_doc[] = "[SCRIPT]";
@@ -44,7 +45,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) {
opts->batch = true;
break;
case OPT_REINSTALL_ALL:
- opts->reinstall_all = true;
+ opmode_set(OPMODE_REINSTALL_ALL);
break;
case OPT_ASK_APPROVAL:
opts->approval_file = arg;
diff --git a/src/pkgupdate/arguments.h b/src/pkgupdate/arguments.h
index 4acb0eed9722e5b9f6d02caeb05b6faaa69897ab..e833a3f98663c1973570dc093be54022b1a0d464 100644
--- a/src/pkgupdate/arguments.h
+++ b/src/pkgupdate/arguments.h
@@ -24,7 +24,6 @@
struct opts {
bool batch; // --batch
- bool reinstall_all; // --reinstall-all
const char *approval_file; // --ask-approval
const char **approve; // --approve
size_t approve_cnt;
diff --git a/src/pkgupdate/main.c b/src/pkgupdate/main.c
index f056aed268b19a83cdc3bc84dd2ce798237e6f66..376036acbe69a098128dc6299ec80709c68535fd 100644
--- a/src/pkgupdate/main.c
+++ b/src/pkgupdate/main.c
@@ -23,6 +23,7 @@
#include
#include
#include "../lib/syscnf.h"
+#include "../lib/opmode.h"
#include "../lib/events.h"
#include "../lib/interpreter.h"
#include "../lib/util.h"
@@ -110,7 +111,6 @@ int main(int argc, char *argv[]) {
// Parse the arguments
struct opts opts = {
.batch = false,
- .reinstall_all = false,
.approval_file = NULL,
.approve = NULL,
.approve_cnt = 0,
@@ -135,12 +135,10 @@ int main(int argc, char *argv[]) {
bool trans_ok = true;
size_t result_count;
// Set some configuration
- if (opts.no_replan || opts.reinstall_all) {
+ if (opts.no_replan || opmode(OPMODE_REINSTALL_ALL)) {
err = interpreter_call(interpreter, "updater.disable_replan", NULL, "");
ASSERT_MSG(!err, "%s", err);
}
- err = interpreter_call(interpreter, "planner.set_reinstall_all", NULL, "b", opts.reinstall_all);
- ASSERT_MSG(!err, "%s", err);
// Check if we should recover previous execution first if so do
if (journal_exists(root_dir())) {
INFO("Detected existing journal. Trying to recover it.");
diff --git a/tests/luacheck.config b/tests/luacheck.config
index 167ef17f792d68d5ac19635eda4d8a15e4532abc..35464a718cb841a1875cf35c97f3e5bafde27d07 100644
--- a/tests/luacheck.config
+++ b/tests/luacheck.config
@@ -27,4 +27,6 @@ globals = {
"picosat",
-- syscnf
"syscnf",
+ -- opmode
+ "opmode",
}
diff --git a/tests/system/Makefile.dir b/tests/system/Makefile.dir
index 29330f664718132d4d1ad5fffd4924202db438ba..9623286fe182347569e0aaa81d877f587b053bdc 100644
--- a/tests/system/Makefile.dir
+++ b/tests/system/Makefile.dir
@@ -25,7 +25,9 @@ UPD_SYS_TESTS := \
postinst \
reboot-recover-update \
reinstall-all \
- new-virtual
+ new-virtual \
+ optional-installs \
+ no-removal
.PHONY: test-sys valgrind-sys check
diff --git a/tests/system/no-removal/cleanup b/tests/system/no-removal/cleanup
new file mode 100644
index 0000000000000000000000000000000000000000..d0da743efc8c09b72745db34b8a404697cdd637c
--- /dev/null
+++ b/tests/system/no-removal/cleanup
@@ -0,0 +1,2 @@
+rm "$ROOT_DIR"/config
+rm -r "$ROOT_DIR"/repo
diff --git a/tests/system/no-removal/input/config b/tests/system/no-removal/input/config
new file mode 100644
index 0000000000000000000000000000000000000000..b2ec54ed8fd0c5c1d15bcc0992c4e0d3f71cf5d2
--- /dev/null
+++ b/tests/system/no-removal/input/config
@@ -0,0 +1,2 @@
+Repository("test", "file://%ROOT_DIR%/repo")
+Mode("no_removal")
diff --git a/tests/system/no-removal/input/repo/Packages b/tests/system/no-removal/input/repo/Packages
new file mode 100644
index 0000000000000000000000000000000000000000..c72cd4262f4d6561c23c1b9eedc5ac5c7f42495e
--- /dev/null
+++ b/tests/system/no-removal/input/repo/Packages
@@ -0,0 +1,11 @@
+Package: test-package
+Version: 1
+License: GPL-2.0
+Section: none
+Architecture: all
+Installed-Size: 0
+Filename: test-package.ipk
+MD5Sum: 4292887e668cf52e9c1a29595dc7404e
+SHA256sum: f5af0e34364df67309ca92c4ee4a374eea12223d69e38759fea518c533d55feb
+Description: Test package
+
diff --git a/tests/system/no-removal/input/repo/test-package.ipk b/tests/system/no-removal/input/repo/test-package.ipk
new file mode 100644
index 0000000000000000000000000000000000000000..90c1bfdffc6a0fbd177f5500add64a5f984c9338
Binary files /dev/null and b/tests/system/no-removal/input/repo/test-package.ipk differ
diff --git a/tests/system/no-removal/input/text.txt b/tests/system/no-removal/input/text.txt
new file mode 100644
index 0000000000000000000000000000000000000000..82ece4fb23f4fc084ea53f3861ffa39eda49c4fb
--- /dev/null
+++ b/tests/system/no-removal/input/text.txt
@@ -0,0 +1 @@
+Some file
diff --git a/tests/system/no-removal/input/usr/lib/opkg/info/test-package.control b/tests/system/no-removal/input/usr/lib/opkg/info/test-package.control
new file mode 100644
index 0000000000000000000000000000000000000000..2492490470616d22c487ae7b5b3720131fe95754
--- /dev/null
+++ b/tests/system/no-removal/input/usr/lib/opkg/info/test-package.control
@@ -0,0 +1,8 @@
+Package: test-package
+Version: 1
+License: GPL-2.0
+Section: none
+Architecture: all
+Installed-Size: 0
+Description: Test package
+
diff --git a/tests/system/no-removal/input/usr/lib/opkg/info/test-package.files-sha256 b/tests/system/no-removal/input/usr/lib/opkg/info/test-package.files-sha256
new file mode 100644
index 0000000000000000000000000000000000000000..26b1c76b631d2fcc04d7e10702d23009baaef71a
--- /dev/null
+++ b/tests/system/no-removal/input/usr/lib/opkg/info/test-package.files-sha256
@@ -0,0 +1 @@
+c2ca984117f9ec2f606475b17ca2af9d3f80ad937d4ccbc6e10da6a591dd024d /text.txt
diff --git a/tests/system/no-removal/input/usr/lib/opkg/info/test-package.list b/tests/system/no-removal/input/usr/lib/opkg/info/test-package.list
new file mode 100644
index 0000000000000000000000000000000000000000..61fa6a10adf0e214d4383f8b74a238e3e5a7e9d4
--- /dev/null
+++ b/tests/system/no-removal/input/usr/lib/opkg/info/test-package.list
@@ -0,0 +1 @@
+/text.txt
diff --git a/tests/system/no-removal/input/usr/lib/opkg/status b/tests/system/no-removal/input/usr/lib/opkg/status
new file mode 100644
index 0000000000000000000000000000000000000000..5709bd297760fef3019b4bcabc6e36ca6bce47d6
--- /dev/null
+++ b/tests/system/no-removal/input/usr/lib/opkg/status
@@ -0,0 +1,6 @@
+Package: test-package
+Version: 1
+Status: install user installed
+Architecture: all
+Installed-Time: 0
+
diff --git a/tests/system/no-removal/input/usr/share/updater/.keep b/tests/system/no-removal/input/usr/share/updater/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/no-removal/input/usr/share/updater/unpacked/.keep b/tests/system/no-removal/input/usr/share/updater/unpacked/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/no-removal/input/var/lock/.keep b/tests/system/no-removal/input/var/lock/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/no-removal/input/var/lock/opkg.lock b/tests/system/no-removal/input/var/lock/opkg.lock
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/no-removal/output/text.txt b/tests/system/no-removal/output/text.txt
new file mode 100644
index 0000000000000000000000000000000000000000..82ece4fb23f4fc084ea53f3861ffa39eda49c4fb
--- /dev/null
+++ b/tests/system/no-removal/output/text.txt
@@ -0,0 +1 @@
+Some file
diff --git a/tests/system/no-removal/output/usr/lib/opkg/info/test-package.control b/tests/system/no-removal/output/usr/lib/opkg/info/test-package.control
new file mode 100644
index 0000000000000000000000000000000000000000..2492490470616d22c487ae7b5b3720131fe95754
--- /dev/null
+++ b/tests/system/no-removal/output/usr/lib/opkg/info/test-package.control
@@ -0,0 +1,8 @@
+Package: test-package
+Version: 1
+License: GPL-2.0
+Section: none
+Architecture: all
+Installed-Size: 0
+Description: Test package
+
diff --git a/tests/system/no-removal/output/usr/lib/opkg/info/test-package.files-sha256 b/tests/system/no-removal/output/usr/lib/opkg/info/test-package.files-sha256
new file mode 100644
index 0000000000000000000000000000000000000000..26b1c76b631d2fcc04d7e10702d23009baaef71a
--- /dev/null
+++ b/tests/system/no-removal/output/usr/lib/opkg/info/test-package.files-sha256
@@ -0,0 +1 @@
+c2ca984117f9ec2f606475b17ca2af9d3f80ad937d4ccbc6e10da6a591dd024d /text.txt
diff --git a/tests/system/no-removal/output/usr/lib/opkg/info/test-package.list b/tests/system/no-removal/output/usr/lib/opkg/info/test-package.list
new file mode 100644
index 0000000000000000000000000000000000000000..61fa6a10adf0e214d4383f8b74a238e3e5a7e9d4
--- /dev/null
+++ b/tests/system/no-removal/output/usr/lib/opkg/info/test-package.list
@@ -0,0 +1 @@
+/text.txt
diff --git a/tests/system/no-removal/output/usr/lib/opkg/status b/tests/system/no-removal/output/usr/lib/opkg/status
new file mode 100644
index 0000000000000000000000000000000000000000..5709bd297760fef3019b4bcabc6e36ca6bce47d6
--- /dev/null
+++ b/tests/system/no-removal/output/usr/lib/opkg/status
@@ -0,0 +1,6 @@
+Package: test-package
+Version: 1
+Status: install user installed
+Architecture: all
+Installed-Time: 0
+
diff --git a/tests/system/no-removal/output/usr/share/updater/.keep b/tests/system/no-removal/output/usr/share/updater/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/no-removal/output/usr/share/updater/unpacked/.keep b/tests/system/no-removal/output/usr/share/updater/unpacked/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/no-removal/output/var/lock/.keep b/tests/system/no-removal/output/var/lock/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/no-removal/output/var/lock/opkg.lock b/tests/system/no-removal/output/var/lock/opkg.lock
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/no-removal/params b/tests/system/no-removal/params
new file mode 100644
index 0000000000000000000000000000000000000000..2b74f594afc388504278dadc6ad939f3606adfc6
--- /dev/null
+++ b/tests/system/no-removal/params
@@ -0,0 +1 @@
+file://$ROOT_DIR/config --batch -R "$ROOT_DIR"
diff --git a/tests/system/no-removal/setup b/tests/system/no-removal/setup
new file mode 100644
index 0000000000000000000000000000000000000000..c7a57ece4e39d91e0ce836d4991832309c05055f
--- /dev/null
+++ b/tests/system/no-removal/setup
@@ -0,0 +1 @@
+sed -i -e "s#%ROOT_DIR%#$ROOT_DIR#" $ROOT_DIR/config
diff --git a/tests/system/optional-installs/cleanup b/tests/system/optional-installs/cleanup
new file mode 100644
index 0000000000000000000000000000000000000000..d0da743efc8c09b72745db34b8a404697cdd637c
--- /dev/null
+++ b/tests/system/optional-installs/cleanup
@@ -0,0 +1,2 @@
+rm "$ROOT_DIR"/config
+rm -r "$ROOT_DIR"/repo
diff --git a/tests/system/optional-installs/input/config b/tests/system/optional-installs/input/config
new file mode 100644
index 0000000000000000000000000000000000000000..4e71ac2059643b102eb69acf7219cd273bbdef04
--- /dev/null
+++ b/tests/system/optional-installs/input/config
@@ -0,0 +1,4 @@
+Repository("test", "file://%ROOT_DIR%/repo")
+Install("test-package")
+Install("missing-package")
+Mode("optional_installs")
diff --git a/tests/system/optional-installs/input/repo/Packages b/tests/system/optional-installs/input/repo/Packages
new file mode 100644
index 0000000000000000000000000000000000000000..c72cd4262f4d6561c23c1b9eedc5ac5c7f42495e
--- /dev/null
+++ b/tests/system/optional-installs/input/repo/Packages
@@ -0,0 +1,11 @@
+Package: test-package
+Version: 1
+License: GPL-2.0
+Section: none
+Architecture: all
+Installed-Size: 0
+Filename: test-package.ipk
+MD5Sum: 4292887e668cf52e9c1a29595dc7404e
+SHA256sum: f5af0e34364df67309ca92c4ee4a374eea12223d69e38759fea518c533d55feb
+Description: Test package
+
diff --git a/tests/system/optional-installs/input/repo/test-package.ipk b/tests/system/optional-installs/input/repo/test-package.ipk
new file mode 100644
index 0000000000000000000000000000000000000000..90c1bfdffc6a0fbd177f5500add64a5f984c9338
Binary files /dev/null and b/tests/system/optional-installs/input/repo/test-package.ipk differ
diff --git a/tests/system/optional-installs/input/text.txt b/tests/system/optional-installs/input/text.txt
new file mode 100644
index 0000000000000000000000000000000000000000..82ece4fb23f4fc084ea53f3861ffa39eda49c4fb
--- /dev/null
+++ b/tests/system/optional-installs/input/text.txt
@@ -0,0 +1 @@
+Some file
diff --git a/tests/system/optional-installs/input/usr/lib/opkg/info/test-package.control b/tests/system/optional-installs/input/usr/lib/opkg/info/test-package.control
new file mode 100644
index 0000000000000000000000000000000000000000..2492490470616d22c487ae7b5b3720131fe95754
--- /dev/null
+++ b/tests/system/optional-installs/input/usr/lib/opkg/info/test-package.control
@@ -0,0 +1,8 @@
+Package: test-package
+Version: 1
+License: GPL-2.0
+Section: none
+Architecture: all
+Installed-Size: 0
+Description: Test package
+
diff --git a/tests/system/optional-installs/input/usr/lib/opkg/info/test-package.files-sha256 b/tests/system/optional-installs/input/usr/lib/opkg/info/test-package.files-sha256
new file mode 100644
index 0000000000000000000000000000000000000000..26b1c76b631d2fcc04d7e10702d23009baaef71a
--- /dev/null
+++ b/tests/system/optional-installs/input/usr/lib/opkg/info/test-package.files-sha256
@@ -0,0 +1 @@
+c2ca984117f9ec2f606475b17ca2af9d3f80ad937d4ccbc6e10da6a591dd024d /text.txt
diff --git a/tests/system/optional-installs/input/usr/lib/opkg/info/test-package.list b/tests/system/optional-installs/input/usr/lib/opkg/info/test-package.list
new file mode 100644
index 0000000000000000000000000000000000000000..61fa6a10adf0e214d4383f8b74a238e3e5a7e9d4
--- /dev/null
+++ b/tests/system/optional-installs/input/usr/lib/opkg/info/test-package.list
@@ -0,0 +1 @@
+/text.txt
diff --git a/tests/system/optional-installs/input/usr/lib/opkg/status b/tests/system/optional-installs/input/usr/lib/opkg/status
new file mode 100644
index 0000000000000000000000000000000000000000..5709bd297760fef3019b4bcabc6e36ca6bce47d6
--- /dev/null
+++ b/tests/system/optional-installs/input/usr/lib/opkg/status
@@ -0,0 +1,6 @@
+Package: test-package
+Version: 1
+Status: install user installed
+Architecture: all
+Installed-Time: 0
+
diff --git a/tests/system/optional-installs/input/usr/share/updater/.keep b/tests/system/optional-installs/input/usr/share/updater/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/optional-installs/input/usr/share/updater/unpacked/.keep b/tests/system/optional-installs/input/usr/share/updater/unpacked/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/optional-installs/input/var/lock/.keep b/tests/system/optional-installs/input/var/lock/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/optional-installs/input/var/lock/opkg.lock b/tests/system/optional-installs/input/var/lock/opkg.lock
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/optional-installs/output/text.txt b/tests/system/optional-installs/output/text.txt
new file mode 100644
index 0000000000000000000000000000000000000000..82ece4fb23f4fc084ea53f3861ffa39eda49c4fb
--- /dev/null
+++ b/tests/system/optional-installs/output/text.txt
@@ -0,0 +1 @@
+Some file
diff --git a/tests/system/optional-installs/output/usr/lib/opkg/info/test-package.control b/tests/system/optional-installs/output/usr/lib/opkg/info/test-package.control
new file mode 100644
index 0000000000000000000000000000000000000000..2492490470616d22c487ae7b5b3720131fe95754
--- /dev/null
+++ b/tests/system/optional-installs/output/usr/lib/opkg/info/test-package.control
@@ -0,0 +1,8 @@
+Package: test-package
+Version: 1
+License: GPL-2.0
+Section: none
+Architecture: all
+Installed-Size: 0
+Description: Test package
+
diff --git a/tests/system/optional-installs/output/usr/lib/opkg/info/test-package.files-sha256 b/tests/system/optional-installs/output/usr/lib/opkg/info/test-package.files-sha256
new file mode 100644
index 0000000000000000000000000000000000000000..26b1c76b631d2fcc04d7e10702d23009baaef71a
--- /dev/null
+++ b/tests/system/optional-installs/output/usr/lib/opkg/info/test-package.files-sha256
@@ -0,0 +1 @@
+c2ca984117f9ec2f606475b17ca2af9d3f80ad937d4ccbc6e10da6a591dd024d /text.txt
diff --git a/tests/system/optional-installs/output/usr/lib/opkg/info/test-package.list b/tests/system/optional-installs/output/usr/lib/opkg/info/test-package.list
new file mode 100644
index 0000000000000000000000000000000000000000..61fa6a10adf0e214d4383f8b74a238e3e5a7e9d4
--- /dev/null
+++ b/tests/system/optional-installs/output/usr/lib/opkg/info/test-package.list
@@ -0,0 +1 @@
+/text.txt
diff --git a/tests/system/optional-installs/output/usr/lib/opkg/status b/tests/system/optional-installs/output/usr/lib/opkg/status
new file mode 100644
index 0000000000000000000000000000000000000000..5709bd297760fef3019b4bcabc6e36ca6bce47d6
--- /dev/null
+++ b/tests/system/optional-installs/output/usr/lib/opkg/status
@@ -0,0 +1,6 @@
+Package: test-package
+Version: 1
+Status: install user installed
+Architecture: all
+Installed-Time: 0
+
diff --git a/tests/system/optional-installs/output/usr/share/updater/.keep b/tests/system/optional-installs/output/usr/share/updater/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/optional-installs/output/usr/share/updater/unpacked/.keep b/tests/system/optional-installs/output/usr/share/updater/unpacked/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/optional-installs/output/var/lock/.keep b/tests/system/optional-installs/output/var/lock/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/optional-installs/output/var/lock/opkg.lock b/tests/system/optional-installs/output/var/lock/opkg.lock
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/system/optional-installs/params b/tests/system/optional-installs/params
new file mode 100644
index 0000000000000000000000000000000000000000..2b74f594afc388504278dadc6ad939f3606adfc6
--- /dev/null
+++ b/tests/system/optional-installs/params
@@ -0,0 +1 @@
+file://$ROOT_DIR/config --batch -R "$ROOT_DIR"
diff --git a/tests/system/optional-installs/setup b/tests/system/optional-installs/setup
new file mode 100644
index 0000000000000000000000000000000000000000..c7a57ece4e39d91e0ce836d4991832309c05055f
--- /dev/null
+++ b/tests/system/optional-installs/setup
@@ -0,0 +1 @@
+sed -i -e "s#%ROOT_DIR%#$ROOT_DIR#" $ROOT_DIR/config
diff --git a/tests/system/reinstall-all/input/config b/tests/system/reinstall-all/input/config
index bdde9c16b40903c88ad6fdf0bf2d988e709c295e..9c840d9d995f12c0ba4d75bae90216bd490f0ee4 100644
--- a/tests/system/reinstall-all/input/config
+++ b/tests/system/reinstall-all/input/config
@@ -1,2 +1,3 @@
Repository("test", "./repo")
Install("test-package")
+Mode("reinstall_all")
diff --git a/tests/system/reinstall-all/params b/tests/system/reinstall-all/params
index 2266a31e8e3cd6e8103c6b38e2d182d5f52a0a63..2b74f594afc388504278dadc6ad939f3606adfc6 100644
--- a/tests/system/reinstall-all/params
+++ b/tests/system/reinstall-all/params
@@ -1 +1 @@
-file://$ROOT_DIR/config --batch -R "$ROOT_DIR" --reinstall-all
+file://$ROOT_DIR/config --batch -R "$ROOT_DIR"