...
 
Commits (10)
FROM debian:stable
FROM debian:unstable
ENV HOME=/root
......@@ -9,7 +9,7 @@ RUN \
busybox ca-certificates curl git \
make pkg-config gcc \
check cppcheck lua-check valgrind \
libcurl4-openssl-dev libevent-dev libssl-dev \
libcurl4-openssl-dev libevent-dev libssl-dev uthash-dev \
lua5.1 liblua5.1-0-dev \
asciidoc lcov markdown libcommon-sense-perl \
wget procps && \
......
......@@ -11,7 +11,7 @@ __pycache__
# The desired results
*.html
*.so
/src/opkg-trans/opkg-trans
/src/pkgtransaction/pkgtransaction
/src/pkgupdate/pkgupdate
/src/migrator/pkgmigrate
# Some stuff for debugging
......
UPDATER_VERSION := $(shell (git describe --match 'v*' --dirty || echo 'unknown') | sed -e 's/^v//')
LUA_NAME := $(shell for lua in lua5.1 lua-5.1 lua51 lua ; do if pkg-config $$lua ; then echo $$lua ; break ; fi ; done)
VALGRIND:=IN_VALGRIND=1 valgrind --leak-check=full --show-leak-kinds=all --track-fds=yes --trace-children=no --child-silent-after-fork=yes --error-exitcode=1 --track-origins=yes
VALGRIND:=IN_VALGRIND=1 valgrind --leak-check=full --show-leak-kinds=definite,indirect,possible --track-fds=yes --trace-children=no --child-silent-after-fork=yes --error-exitcode=1 --track-origins=yes
# For picosat, it otherwise needs some headers not available on musl for a feature we don't need. And we need trace enabled.
EXTRA_DEFINES := NGETRUSAGE TRACE UPDATER_VERSION='"$(UPDATER_VERSION)"'
ifdef BUSYBOX_EXEC
......
......@@ -598,34 +598,6 @@ root_dir
Root directory specified from command line or `/` if no such option
was specified. Use this if you are accessing some files.
serial
~~~~~~
The variable contains the serial number of the device. It may be `nil`
in case it is not supported on the given device.
architectures
~~~~~~~~~~~~~
Allowed package architectures (in a table).
model
~~~~~
Content of `/tmp/sysinfo/model`. On non-OpenWRT systems it has to be supplied by
`--model` argument.
board_name
~~~~~~~~~~
Content of `/tmp/sysinfo/board_name`. On non-OpenWRT systems it has to be supplied
by `--board` argument.
turris_version
~~~~~~~~~~~~~~
Content of `/etc/turris-version`. Might be nil on non-Turris systems.
self_version
~~~~~~~~~~~~
......@@ -683,6 +655,32 @@ The top-level table is instantiated (not generated through
meta-tables), therefore it is possible to get the list of installed
packages.
os_release
~~~~~~~~~~
This is table with parsed content of os-release file. Path to this file is
`etc/os-release` but relative to target root. This means that if you are running
updater on root file system that is not current root then values in this table are
for target not for host system.
This is normal table and you can iterate trough it using `pairs` or you can
directly access specific value by indexing it. List of standard options can be
found https://www.freedesktop.org/software/systemd/man/os-release.html[here].
The most interesting value is `os_release.VERSION` as this contains current system
release version.
This table can be empty if there was no `os-release` file.
host_os_release
~~~~~~~~~~~~~~~
This is table with parsed content of os-release file for host system. Source file
for this is always `/etc/os-release`. See variable os_release for example usage
and expected content.
Table can be empty if there was no `/etc/os-release`.
Export variables to Script
--------------------------
......
......@@ -25,10 +25,12 @@ libupdater_MODULES := \
embed_types \
events \
subprocess \
download \
journal \
locks \
picosat \
util \
syscnf \
logging
ifdef COV
libupdater_MODULES += lcoverage.embed
......
......@@ -77,10 +77,6 @@ static const char *opt_help[COT_LAST] = {
"--exclude=<name> Exclude this from output.\n",
[COT_USIGN] =
"--usign=<path> Path to usign tool used to verify packages signature. In default /usr/bin/usign.\n",
[COT_MODEL] =
"--model=<model> Set/override target system model (e.g. Turris Omnia)\n",
[COT_BOARD] =
"--board=<board> Set/override target system board (e.g. rtrom01)\n",
[COT_NO_REPLAN] =
"--no-replan Don't replan. Install everyting at once. Use this if updater you are running isn't from packages it installs.\n",
[COT_NO_IMMEDIATE_REBOOT] =
......@@ -102,8 +98,6 @@ enum option_val {
OPT_TASK_LOG_VAL,
OPT_EXCLUDE,
OPT_USIGN,
OPT_MODEL,
OPT_BOARD,
OPT_NO_REPLAN,
OPT_NO_IMMEDIATE_REBOOT,
OPT_OUT_OF_ROOT,
......@@ -127,8 +121,6 @@ static const struct option opt_long[] = {
{ .name = "task-log", .has_arg = required_argument, .val = OPT_TASK_LOG_VAL },
{ .name = "exclude", .has_arg = required_argument, .val = OPT_EXCLUDE },
{ .name = "usign", .has_arg = required_argument, .val = OPT_USIGN },
{ .name = "model", .has_arg = required_argument, .val = OPT_MODEL },
{ .name = "board", .has_arg = required_argument, .val = OPT_BOARD },
{ .name = "no-replan", .has_arg = no_argument, .val = OPT_NO_REPLAN },
{ .name = "no-immediate-reboot", .has_arg = no_argument, .val = OPT_NO_IMMEDIATE_REBOOT },
{ .name = "out-of-root", .has_arg = no_argument, .val = OPT_OUT_OF_ROOT },
......@@ -154,8 +146,6 @@ static const struct simple_opt {
[OPT_TASK_LOG_VAL] = { COT_TASK_LOG, true, true },
[OPT_EXCLUDE] = { COT_EXCLUDE, true, true },
[OPT_USIGN] = { COT_USIGN, true, true },
[OPT_MODEL] = { COT_MODEL, true, true },
[OPT_BOARD] = { COT_BOARD, true, true },
[OPT_NO_REPLAN] = { COT_NO_REPLAN, false, true },
[OPT_NO_IMMEDIATE_REBOOT] = { COT_NO_IMMEDIATE_REBOOT, false, true },
[OPT_OUT_OF_ROOT] = { COT_OUT_OF_ROOT, false, false },
......@@ -276,8 +266,6 @@ struct cmd_op *cmd_args_parse(int argc, char *argv[], const enum cmd_op_type acc
case COT_APPROVE:
case COT_EXCLUDE:
case COT_USIGN:
case COT_MODEL:
case COT_BOARD:
case COT_NO_REPLAN:
case COT_TASK_LOG: {
struct cmd_op tmp = result[i];
......
......@@ -68,10 +68,6 @@ enum cmd_op_type {
COT_EXCLUDE,
// Path to usign tool
COT_USIGN,
// Target model specification
COT_MODEL,
// Target board specification
COT_BOARD,
// Don't replan (do whole install at once)
COT_NO_REPLAN,
// Don't immediatelly reboot system
......
--[[
Copyright 2018, 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 <http://www.gnu.org/licenses/>.
]]--
local os = os
local utils = require "utils"
local getcwd = getcwd
local DIE = DIE
module "syscnf"
-- Variables accessed from outside of this module
-- luacheck: globals root_dir status_file info_dir pkg_download_dir pkg_unpacked_dir dir_opkg_collided target_model target_board
-- Functions that we want to access from outside of this module
-- luacheck: globals set_root_dir set_target
local status_file_suffix = "usr/lib/opkg/status"
local info_dir_suffix = "usr/lib/opkg/info/"
local pkg_unpacked_dir_suffix = "usr/share/updater/unpacked/"
local pkg_download_dir_suffix = "usr/share/updater/download/"
local dir_opkg_collided_suffix = "usr/share/updater/collided/"
--[[
Canonizes path to absolute path. It does no change in case path is already an
absolute but it if not then it prepends current working directory. There is also
special handling in case path starts with tilde (~) in that case that character is
replaced with content of HOME environment variable.
]]
local function path2abspath(path)
if path:match("^/") then
return path
elseif path:match("^~/") then
return os.getenv('HOME') .. "/" .. path
else
return getcwd() .. "/" .. path
end
end
--[[
Set all the configurable directories to be inside the provided dir
Effectively sets that the whole system is mounted under some
prefix.
]]
function set_root_dir(dir)
if dir then
dir = (path2abspath(dir) .. "/"):gsub("/+", "/")
else
dir = "/"
end
-- A root directory
root_dir = dir
-- The file with status of installed packages
status_file = dir .. status_file_suffix
-- The directory where unpacked control files of the packages live
info_dir = dir .. info_dir_suffix
-- A directory to which we download packages
pkg_download_dir = dir .. pkg_download_dir_suffix
-- A directory where unpacked packages live
pkg_unpacked_dir = dir .. pkg_unpacked_dir_suffix
-- Directory where we move files and directories that weren't part of any package.
dir_opkg_collided = dir .. dir_opkg_collided_suffix
end
--[[
Set variables taget_model and target_board.
You can explicitly specify model or board or both. If not specified then detection
is performed. That is files from /tmp/sysinfo directory are used.
If no model or board is specified (passed as nil) and detection failed than this
function causes error and execution termination.
]]
function set_target(model, board)
-- Name of the target model (ex: Turris Omnia)
target_model = model or utils.strip(utils.read_file('/tmp/sysinfo/model'))
-- Name of the target board (ex: rtrom01)
target_board = board or utils.strip(utils.read_file('/tmp/sysinfo/board_name'))
if not target_model or not target_board then
DIE("Auto detection of target model or board failed.You can specify them " ..
"explicitly using --model and --board arguments.")
end
end
......@@ -763,13 +763,13 @@ function steal_configs(current_status, installed_confs, configs)
end
--[[
Move anything on given path to dir_opkg_collided. This backups and removes original files.
Move anything on given path to opkg_collided_dir. This backups and removes original files.
When keep is set to true, file is copied instead of moved.
]]
function user_path_move(path, keep)
-- At first create same parent directory relative to dir_opkg_collided
-- At first create same parent directory relative to opkg_collided_dir
local fpath = ""
for dir in (syscnf.dir_opkg_collided .. path):gsub("[^/]*/?$", ""):gmatch("[^/]+") do
for dir in (syscnf.opkg_collided_dir .. path):gsub("[^/]*/?$", ""):gmatch("[^/]+") do
local randex = ""
while not utils.dir_ensure(fpath .. "/" .. dir .. randex) do
-- If there is file with same name, then append some random extension
......
......@@ -33,8 +33,6 @@ local tostring = tostring
local error = error
local WARN = WARN
local ERROR = ERROR
local run_command = run_command
local events_wait = events_wait
local get_updater_version = get_updater_version
local utils = require "utils"
local backend = require "backend"
......@@ -120,12 +118,11 @@ function load_state_vars()
]]
state_vars = {
root_dir = syscnf.root_dir,
model = syscnf.target_model,
board_name = syscnf.target_board,
turris_version = utils.strip(utils.read_file('/etc/turris-version')),
self_version = get_updater_version(),
language_version = 1,
features = updater_features,
os_release = syscnf.os_release(),
host_os_release = syscnf.host_os_release(),
--[[
In case we fail to read that file (it is not there), we match against
an empty string, which produces nil ‒ the element won't be in there.
......@@ -147,11 +144,6 @@ function load_state_vars()
end
end)
}
events_wait(run_command(function (ecode, _, stdout, _)
if ecode == 0 then
state_vars.serial = utils.strip(stdout)
end
end, nil, nil, -1, -1, '/usr/bin/atsha204cmd', 'serial-number'))
end
......
This diff is collapsed.
/*
* Copyright 2018, 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 <http://www.gnu.org/licenses/>.
*/
#ifndef UPDATER_DOWNLOAD_H
#define UPDATER_DOWNLOAD_H
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <event2/event.h>
#include <curl/curl.h>
#include "logging.h"
struct download_i;
// Download manager object
struct downloader {
struct event_base *ebase; // libevent base
CURLM *cmulti; // Curl multi instance
struct event *ctimer; // Timer used by curl
struct download_i **instances; // Registered instances
size_t i_size, i_allocated; // instances size and allocated size
int pending; // Number of still not downloaded instances
struct download_i *failed; // Latest failed instance (used internally)
};
// Download options (additional options configuring security and more)
struct download_opts {
long timeout; // Download timeout (including download retries)
long connect_timeout; // Timeout for single connection
int retries; // Number of full download retries
bool follow_redirect; // If HTTP request 3xx should be followed
bool ssl_verify; // If SSL should be verified
bool ocsp; // If OCSP should be used for certificate verification
const char *cacert_file; // Path to custom CA certificate bundle
const char *capath; // Path to directory containing CA certificates
const char *crl_file; // Path to custom CA crl
};
enum download_output_type {
DOWN_OUT_T_FILE,
DOWN_OUT_T_BUFFER
};
// Download instance. Identifier of single download.
struct download_i {
bool done; // What ever is download finished
bool success; // If download was successful. Not valid if done is false.
char error[CURL_ERROR_SIZE]; // error message if download fails
int retries; // Number of reties we have
struct downloader *downloader; // parent downloader
enum download_output_type out_t; // What output this instance utilizes
union {
struct {
int fd; // File descriptor
char *fpath; // Path to output file
} *file; // Used when writing to file
struct {
uint8_t *data; // Buffer for output data
size_t size; // Amount of downloaded data
} *buff; // Used when writing to buffer
} out; // Output data
CURL *curl; // easy curl session
};
// Initialize new download manager
// parallel: Number of possible parallel downloadings
// Returns new instance of downloader
struct downloader *downloader_new(int parallel);
// Free given instance of downloader
void downloader_free(struct downloader*) __attribute__((nonnull));
// Run downloader and download all registered URLs
// return: NULL on success otherwise pointer to download instance that failed.
struct download_i *downloader_run(struct downloader*) __attribute__((nonnull));
// Remove all download instances from downloader
void downloader_flush(struct downloader*) __attribute__((nonnull));
// Set default values for download_opts
// opts: Allocated instance of download options to be set to defaults
// Note: strings in download_opts are set to NULL and previous values are NOT
// freed.
void download_opts_def(struct download_opts *opts) __attribute__((nonnull));
// Register given URL to be downloaded to file.
// url: URL data are downloaded from
// output_path: Path where data are going to be stored (written to)
// opts: Download options (does not have to exist during instance existence)
// Returns download instance
struct download_i *download_file(struct downloader *downloader, const char *url,
const char *output_path, const struct download_opts *opts)
__attribute__((nonnull(1, 2, 3, 4)));
// Register given URL to be downloaded to temporally file. Output file path is
// generated using mkstemp function.
// url: URL data are downloaded from
// output_template: Template for path where data are going to be stored (written
// to). Passed string has to end with XXXXXX and is modified to contain used
// path. This string should be freed only after download instance is freed.
// opts: Download options (does not have to exist during instance existence)
// Returns download instance
struct download_i *download_temp_file(struct downloader *downloader,
const char *url, char *output_template, const struct download_opts *opts)
__attribute__((nonnull(1, 2, 3, 4)));
// Register given URL to be downloaded to internal buffer.
// url: URL data are downloaded from
// opts: Download options (does not have to exist during instance existence)
// Returns download instance
struct download_i *download_data(struct downloader *downloader, const char *url,
const struct download_opts *opts) __attribute__((nonnull(1, 2, 3)));
// Free download instance
void download_i_free(struct download_i*) __attribute__((nonnull));
// This is same as download_i_free but where download_i_free just frees downloaded
// buffer, this passes it to caller. Instance is freed the same way as in case of
// download_i_free but data buffer has to be freed later by caller.
// In other words this overtakes allocated buffer and frees rest of instance.
// This can be called only on instance that was created by download_data.
void download_i_collect_data(struct download_i*, uint8_t **data, size_t *size);
#endif
......@@ -25,6 +25,7 @@
#include "journal.h"
#include "locks.h"
#include "arguments.h"
#include "syscnf.h"
#include "picosat.h"
#include <lua.h>
......@@ -1020,6 +1021,7 @@ struct interpreter *interpreter_create(struct events *events) {
// Some binary embedded modules
journal_mod_init(L);
locks_mod_init(L);
syscnf_mod_init(L);
picosat_mod_init(L);
#ifdef COVERAGE
interpreter_load_coverage(result);
......
......@@ -154,11 +154,6 @@ enum log_level log_level_get(const char *level) {
return LL_UNKNOWN;
}
static const char *type_string[] = {
[LST_PKG_SCRIPT] = "pkg-script",
[LST_HOOK] = "hook"
};
// log_subproc cookie
struct c_log_subproc {
bool err; // Is this out or err
......
......@@ -19,7 +19,9 @@
#ifndef UPDATER_LOGGING_H
#define UPDATER_LOGGING_H
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
......
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "syscnf.h"
#include "util.h"
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <regex.h>
#include <uthash.h>
#include <lauxlib.h>
#include <lualib.h>
#include "logging.h"
#include "inject.h"
enum e_paths {
P_ROOT_DIR,
P_FILE_STATUS,
P_DIR_INFO,
P_DIR_PKG_UNPACKED,
P_DIR_PKG_DOWNLOAD,
P_DIR_OPKG_COLLIDED,
P_LAST
};
static const char* const default_paths[] = {
[P_ROOT_DIR] = "/",
[P_FILE_STATUS] = "/usr/lib/opkg/status",
[P_DIR_INFO] = "/usr/lib/opkg/info/",
[P_DIR_PKG_UNPACKED] = "/usr/share/updater/unpacked/",
[P_DIR_PKG_DOWNLOAD] = "/usr/share/updater/download/",
[P_DIR_OPKG_COLLIDED] = "/usr/share/updater/collided/",
};
static char* paths[] = {
[P_ROOT_DIR] = NULL,
[P_FILE_STATUS] = NULL,
[P_DIR_INFO] = NULL,
[P_DIR_PKG_UNPACKED] = NULL,
[P_DIR_PKG_DOWNLOAD] = NULL,
[P_DIR_OPKG_COLLIDED] = NULL,
};
struct os_release_data {
char *field;
char *content;
UT_hash_handle hh;
};
static struct os_release_data *osr = NULL;
static struct os_release_data *osr_host = NULL;
void set_path(enum e_paths tp, const char *value) {
if (paths[tp])
free(paths[tp]);
if (value)
asprintf(&paths[tp], "%s%s", value, default_paths[tp]);
else
paths[tp] = NULL;
}
void set_root_dir(const char *root) {
char *pth = NULL;
if (root) {
if (root[0] == '/')
pth = aprintf("%s", root);
else if (root[0] == '~' && root[1] == '/') {
struct passwd *pw = getpwuid(getuid());
pth = aprintf("%s%s", pw->pw_dir, root + 1);
} else {
char *cwd = getcwd(NULL, 0);
pth = aprintf("%s/%s", cwd, root);
free(cwd);
}
size_t last = strlen(pth) - 1;
while (last > 0 && pth[last] == '/')
pth[last--] = '\0';
}
set_path(P_ROOT_DIR, pth);
set_path(P_FILE_STATUS, pth);
set_path(P_DIR_INFO, pth);
set_path(P_DIR_PKG_UNPACKED, pth);
set_path(P_DIR_PKG_DOWNLOAD, pth);
set_path(P_DIR_OPKG_COLLIDED, pth);
TRACE("Target root directory set to: %s", root_dir());
}
static struct os_release_data *read_os_release(const char *path) {
FILE *f = fopen(path, "r");
if (!f) {
ERROR("Unable to open os-release (%s): %s", path, strerror(errno));
return NULL;
}
TRACE("Parsing os-release: %s", path);
struct os_release_data *osr_dt = NULL;
regex_t rgex;
ASSERT(!regcomp(&rgex, "^([^=]*)=(\"?)(.*)\\2$", REG_NEWLINE | REG_EXTENDED));
regmatch_t match[4];
char *line = NULL;
size_t linel = 0;
while (getline(&line, &linel, f) != -1) {
if (regexec(&rgex, line, 4, match, 0) == REG_NOMATCH) {
ERROR("Unable to parse os-release (%s) line: %.*s", path, (int)strlen(line) - 1, line);
} else {
struct os_release_data *n = malloc(sizeof *n);
n->field = strndup(&line[match[1].rm_so], match[1].rm_eo - match[1].rm_so);
n->content = strndup(&line[match[3].rm_so], match[3].rm_eo - match[3].rm_so);
HASH_ADD_KEYPTR(hh, osr_dt, n->field, strlen(n->field), n);
TRACE("Parsed os-release (%s): %s=\"%s\"", path, n->field, n->content);
}
}
free(line);
regfree(&rgex);
fclose(f);
return osr_dt;
}
static void os_release_free(struct os_release_data *dt) {
struct os_release_data *w, *tmp;
HASH_ITER(hh, dt, w, tmp) {
HASH_DEL(dt, w);
free(w->field);
free(w->content);
free(w);
}
}
void system_detect() {
if (osr == osr_host)
osr = NULL;
os_release_free(osr_host);
os_release_free(osr);
osr_host = NULL;
osr = NULL;
osr_host = read_os_release("/etc/os-release");
if (root_dir_is_root()) {
TRACE("Detecting system: native run");
osr = osr_host;
} else {
TRACE("Detecting system: out of root run");
osr = read_os_release(aprintf("%setc/os-release", root_dir()));
}
}
static const char *os_release_get(struct os_release_data *dt, const char *option) {
struct os_release_data *w = NULL;
HASH_FIND_STR(dt, option, w);
if (!w)
return NULL;
return w->content;
}
const char *os_release(const char *option) {
return os_release_get(osr, option);
}
const char *host_os_release(const char *option) {
return os_release_get(osr_host, option);
}
static const char *get_path(enum e_paths tp) {
if (paths[tp])
return paths[tp];
return default_paths[tp];
}
const char *root_dir() {
return get_path(P_ROOT_DIR);
}
const char *status_file() {
return get_path(P_FILE_STATUS);
}
const char *info_dir() {
return get_path(P_DIR_INFO);
}
const char *pkg_unpacked_dir() {
return get_path(P_DIR_PKG_UNPACKED);
}
const char *pkg_download_dir() {
return get_path(P_DIR_PKG_DOWNLOAD);
}
const char *opkg_collided_dir() {
return get_path(P_DIR_OPKG_COLLIDED);
}
bool root_dir_is_root() {
return !strcmp("/", root_dir());
}
static int lua_set_root_dir(lua_State *L) {
if (lua_isnoneornil(L, 1))
set_root_dir(NULL);
else
set_root_dir(luaL_checkstring(L, 1));
return 0;
}
static int lua_system_detect(lua_State *L __attribute__((unused))) {
system_detect();
return 0;
}
static int lua_os_release_gen(lua_State *L, struct os_release_data *dt) {
lua_newtable(L);
struct os_release_data *w, *tmp;
HASH_ITER(hh, dt, w, tmp) {
lua_pushstring(L, w->field);
lua_pushstring(L, w->content);
lua_settable(L, -3);
}
return 1;
}
static int lua_os_release(lua_State *L) {
return lua_os_release_gen(L, osr);
}
static int lua_host_os_release(lua_State *L) {
return lua_os_release_gen(L, osr_host);
}
static int lua_syscnf_index(lua_State *L) {
const char *idx = luaL_checkstring(L, 2);
if (!strcmp("root_dir", idx))
lua_pushstring(L, root_dir());
else if (!strcmp("status_file", idx))
lua_pushstring(L, status_file());
else if (!strcmp("info_dir", idx))
lua_pushstring(L, info_dir());
else if (!strcmp("pkg_unpacked_dir", idx))
lua_pushstring(L, pkg_unpacked_dir());
else if (!strcmp("pkg_download_dir", idx))
lua_pushstring(L, pkg_download_dir());
else if (!strcmp("opkg_collided_dir", idx))
lua_pushstring(L, opkg_collided_dir());
else if (luaL_getmetafield(L, 1, idx) == 0)
lua_pushnil(L);
return 1;
}
static const struct inject_func funcs[] = {
{ lua_set_root_dir, "set_root_dir" },
{ lua_system_detect, "system_detect" },
{ lua_os_release, "os_release" },
{ lua_host_os_release, "host_os_release" },
{ lua_syscnf_index, "__index" },
};
void syscnf_mod_init(lua_State *L) {
TRACE("Syscnf module init");
lua_newtable(L);
inject_func_n(L, "syscnf", funcs, sizeof funcs / sizeof *funcs);
lua_pushvalue(L, -1);
lua_setmetatable(L, -2);
inject_module(L, "syscnf");
}
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef UPDATER_SYSCNF_H
#define UPDATER_SYSCNF_H
#include <lua.h>
#include <stdbool.h>
//// Setting calls ////
// Note: for correct approach you should first set root_dir and then detect system
// Modify root directory
void set_root_dir(const char*);
// Parses different system files and fills internal variables
// Note: detection considers root_dir so you should set it before calling this.
void system_detect();
//// Getting calls ////
// System os-release values
#define OS_RELEASE_NAME "NAME"
#define OS_RELEASE_VERSION "VERSION"
#define OS_RELEASE_ID "ID"
#define OS_RELEASE_PRETTY_NAME "PRETTY_NAME"
// This returns field as read from etc/os-release relative to root_dir
const char *os_release(const char *option) __attribute__((nonnull));
// This returns field as read from /etc/os-release
const char *host_os_release(const char *option) __attribute__((nonnull));
// Root directory of update system
// This never returns NULL and always contains trailing slash if it is a directory
const char *root_dir();
// Updater specific paths
const char *status_file();
const char *info_dir();
const char *pkg_unpacked_dir();
const char *pkg_download_dir();
const char *opkg_collided_dir();
// Returns true if root_dir() is "/", otherwise false.
bool root_dir_is_root();
// Create syscnf module and inject it into the lua state
void syscnf_mod_init(lua_State *L) __attribute__((nonnull));
#endif
......@@ -23,11 +23,13 @@
#include "logging.h"
#include "subprocess.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <poll.h>
......@@ -41,6 +43,31 @@ bool dump2file (const char *file, const char *text) {
return true;
}
char *readfile(const char *file) {
FILE *f = fopen(file, "r");
if (!f) {
ERROR("Read of file \"%s\" failed: %s", file, strerror(errno));
return NULL;
}
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *ret = malloc(fsize + 1);
fread(ret, fsize, 1, f);
fclose(f);
ret[fsize] = 0;
return ret;
}
bool statfile(const char *file, int mode) {
struct stat st;
if (stat(file, &st))
return false;
if (!S_ISREG(st.st_mode))
return false;
return !access(file, mode);
}
static int exec_dir_filter(const struct dirent *de) {
// ignore system paths and accept only files
return strcmp(de->d_name, ".") && strcmp(de->d_name, "..") && de->d_type == DT_REG;
......
......@@ -26,10 +26,19 @@
#include <stdio.h>
#include <stdbool.h>
#include <alloca.h>
#include <unistd.h>
// Writes given text to file. Be aware that no information about failure is given.
bool dump2file (const char *file, const char *text) __attribute__((nonnull,nonnull));
// Read content of whole file and return it as string
// Returned memory has to be freed by used.
char *readfile(const char *file) __attribute__((nonnull));
// Returns true if file exists and is accessible in given mode
// Mode is bitwise OR of one or more of R_OK, W_OK, and X_OK.
bool statfile(const char *file, int mode);
// Executes all executable files in given directory
void exec_hook(const char *dir, const char *message) __attribute__((nonnull));
......
......@@ -2,3 +2,4 @@ BINARIES += src/pkgtransaction/pkgtransaction
pkgtransaction_MODULES := main
pkgtransaction_LOCAL_LIBS := updater
pkgtransaction_PKG_CONFIGS := $(LUA_NAME)
......@@ -21,6 +21,7 @@
#include "../lib/events.h"
#include "../lib/interpreter.h"
#include "../lib/util.h"
#include "../lib/syscnf.h"
#include "../lib/logging.h"
#include <stdlib.h>
......@@ -66,9 +67,9 @@ int main(int argc, char *argv[]) {
struct cmd_op *op = ops;
// Prepare the interpreter and load it with the embedded lua scripts
struct interpreter *interpreter = interpreter_create(events);
const char *error = interpreter_autoload(interpreter);
if (error) {
fputs(error, stderr);
const char *err = interpreter_autoload(interpreter);
if (err) {
fputs(err, stderr);
return 1;
}
bool transaction_run = false;
......@@ -76,7 +77,6 @@ int main(int argc, char *argv[]) {
bool trans_ok = true;
bool early_exit = false;
const char *usign_exec = NULL;
const char *root_dir = NULL;
for (; op->type != COT_EXIT && op->type != COT_CRASH; op ++)
switch (op->type) {
case COT_HELP:
......@@ -93,28 +93,30 @@ int main(int argc, char *argv[]) {
case COT_JOURNAL_RESUME:
journal_resume = true;
break;
case COT_INSTALL: {
const char *err = interpreter_call(interpreter, "transaction.queue_install", NULL, "s", op->parameter);
case COT_INSTALL:
err = interpreter_call(interpreter, "transaction.queue_install", NULL, "s", op->parameter);
ASSERT_MSG(!err, "%s", err);
transaction_run = true;
break;
}
case COT_REMOVE: {
const char *err = interpreter_call(interpreter, "transaction.queue_remove", NULL, "s", op->parameter);
case COT_REMOVE:
err = interpreter_call(interpreter, "transaction.queue_remove", NULL, "s", op->parameter);
ASSERT_MSG(!err, "%s", err);
transaction_run = true;
break;
}
#define NIP(TYPE) case COT_##TYPE: fputs("Operation " #TYPE " not implemented yet\n", stderr); return 1
NIP(JOURNAL_ABORT);
case COT_ROOT_DIR: {
root_dir = op->parameter;
case COT_ROOT_DIR:
set_root_dir(op->parameter);
break;
}
case COT_USIGN: {
const char *err = interpreter_call(interpreter, "uri.usign_exec_set", NULL, "s", usign_exec);
case COT_USIGN:
err = interpreter_call(interpreter, "uri.usign_exec_set", NULL, "s", usign_exec);
ASSERT_MSG(!err, "%s", err);
break;
case COT_STDERR_LEVEL: {
enum log_level level = log_level_get(op->parameter);
ASSERT_MSG(level != LL_UNKNOWN, "Unknown log level %s", op->parameter);
log_stderr_level(level);
break;
}
case COT_SYSLOG_LEVEL: {
enum log_level level = log_level_get(op->parameter);
......@@ -122,16 +124,9 @@ int main(int argc, char *argv[]) {
log_syslog_level(level);
break;
}
case COT_SYSLOG_NAME: {
case COT_SYSLOG_NAME:
log_syslog_name(op->parameter);
break;
}
case COT_STDERR_LEVEL: {
enum log_level level = log_level_get(op->parameter);
ASSERT_MSG(level != LL_UNKNOWN, "Unknown log level %s", op->parameter);
log_stderr_level(level);
break;
}
case COT_REEXEC:
// We are currenty not using this here, but lets accept it so we would prevent problems with reexecuting.
break;
......@@ -141,10 +136,7 @@ int main(int argc, char *argv[]) {
enum cmd_op_type exit_type = op->type;
if (exit_type != COT_EXIT || early_exit)
goto CLEANUP;
// Some configurations
const char *err = interpreter_call(interpreter, "syscnf.set_root_dir", NULL, "s", root_dir);
ASSERT_MSG(!err, "%s", err);
system_detect();
size_t result_count;
if (journal_resume) {
......
......@@ -17,6 +17,7 @@
* along with Updater. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../lib/syscnf.h"
#include "../lib/events.h"
#include "../lib/interpreter.h"
#include "../lib/util.h"
......@@ -45,7 +46,7 @@ static bool results_interpret(struct interpreter *interpreter, size_t result_cou
}
static const enum cmd_op_type cmd_op_allows[] = {
COT_BATCH, COT_NO_OP, COT_REEXEC, COT_REBOOT, COT_STATE_LOG, COT_ROOT_DIR, COT_SYSLOG_LEVEL, COT_STDERR_LEVEL, COT_SYSLOG_NAME, COT_ASK_APPROVAL, COT_APPROVE, COT_TASK_LOG, COT_USIGN, COT_MODEL, COT_BOARD, COT_NO_REPLAN, COT_NO_IMMEDIATE_REBOOT, COT_LAST
COT_BATCH, COT_NO_OP, COT_REEXEC, COT_REBOOT, COT_STATE_LOG, COT_ROOT_DIR, COT_SYSLOG_LEVEL, COT_STDERR_LEVEL, COT_SYSLOG_NAME, COT_ASK_APPROVAL, COT_APPROVE, COT_TASK_LOG, COT_USIGN, COT_NO_REPLAN, COT_NO_IMMEDIATE_REBOOT, COT_LAST
};
static void print_help() {
......@@ -125,9 +126,6 @@ int main(int argc, char *argv[]) {
struct cmd_op *ops = cmd_args_parse(argc, argv, cmd_op_allows);
struct cmd_op *op = ops;
const char *top_level_config = NULL;
const char *root_dir = NULL;
const char *target_model = NULL;
const char *target_board = NULL;
bool batch = false, early_exit = false, replan = false, reboot_finished = false;
const char *approval_file = NULL;
const char **approvals = NULL;
......@@ -161,42 +159,34 @@ int main(int argc, char *argv[]) {
reboot_finished = true;
break;
case COT_ROOT_DIR:
root_dir = op->parameter;
break;
case COT_MODEL:
target_model = op->parameter;
break;
case COT_BOARD:
target_board = op->parameter;
set_root_dir(op->parameter);
break;
case COT_STATE_LOG:
set_state_log(true);
break;
case COT_SYSLOG_LEVEL: {
case COT_STDERR_LEVEL: {
enum log_level level = log_level_get(op->parameter);
ASSERT_MSG(level != LL_UNKNOWN, "Unknown log level %s", op->parameter);
log_syslog_level(level);
break;
}
case COT_SYSLOG_NAME: {
log_syslog_name(op->parameter);
log_stderr_level(level);
break;
}
case COT_STDERR_LEVEL: {
case COT_SYSLOG_LEVEL: {
enum log_level level = log_level_get(op->parameter);
ASSERT_MSG(level != LL_UNKNOWN, "Unknown log level %s", op->parameter);
log_stderr_level(level);
log_syslog_level(level);
break;
}
case COT_SYSLOG_NAME:
log_syslog_name(op->parameter);
break;
case COT_ASK_APPROVAL:
approval_file = op->parameter;
break;
case COT_APPROVE: {
case COT_APPROVE:
// cppcheck-suppress memleakOnRealloc
approvals = realloc(approvals, (++ approval_count) * sizeof *approvals);
approvals[approval_count - 1] = op->parameter;
break;
}
case COT_TASK_LOG:
task_log = op->parameter;
break;
......@@ -214,25 +204,20 @@ int main(int argc, char *argv[]) {
}
enum cmd_op_type exit_type = op->type;
free(ops);
system_detect();
update_state(LS_INIT);
struct events *events = events_new();
// Prepare the interpreter and load it with the embedded lua scripts
struct interpreter *interpreter = interpreter_create(events);
const char *error = interpreter_autoload(interpreter);
ASSERT_MSG(!error, "%s", error);
const char *err = interpreter_autoload(interpreter);
ASSERT_MSG(!err, "%s", err);
bool trans_ok = true;
if (exit_type != COT_EXIT || early_exit)
goto CLEANUP;
size_t result_count;
// Set some configuration
const char *err = interpreter_call(interpreter, "syscnf.set_root_dir", NULL, "s", root_dir);
ASSERT_MSG(!err, "%s", err);
if (!root_dir)
root_dir = "";
err = interpreter_call(interpreter, "syscnf.set_target", NULL, "ss", target_model, target_board);
ASSERT_MSG(!err, "%s", err);
if (usign_exec) {
err = interpreter_call(interpreter, "uri.usign_exec_set", NULL, "s", usign_exec);
ASSERT_MSG(!err, "%s", err);
......@@ -242,7 +227,7 @@ int main(int argc, char *argv[]) {
ASSERT_MSG(!err, "%s", err);
}
// Check if we should recover previous execution first if so do
if (journal_exists(root_dir)) {
if (journal_exists(root_dir())) {
INFO("Detected existing journal. Trying to recover it.");
err = interpreter_call(interpreter, "transaction.recover_pretty", &result_count, "");
ASSERT_MSG(!err, "%s", err);
......@@ -280,8 +265,8 @@ int main(int argc, char *argv[]) {
ASSERT_MSG(!err, "%s", err);
if (!replan) {
update_state(LS_PREUPD);
const char *hook_path = aprintf("%s%s", root_dir, hook_preupdate);
setenv("ROOT_DIR", root_dir, true);
const char *hook_path = aprintf("%s%s", root_dir(), hook_preupdate);
setenv("ROOT_DIR", root_dir(), true);
exec_hook(hook_path, "Executing preupdate hook");
}
if (task_log) {
......@@ -307,7 +292,7 @@ int main(int argc, char *argv[]) {
bool reboot_delayed;
ASSERT(interpreter_collect_results(interpreter, "bb", &reboot_delayed, &reboot_finished) == -1);
if (reboot_delayed) {
const char *hook_path = aprintf("%s%s", root_dir, hook_reboot_delayed);
const char *hook_path = aprintf("%s%s", root_dir(), hook_reboot_delayed);
exec_hook(hook_path, "Executing reboot_required hook");
}
err = interpreter_call(interpreter, "updater.cleanup", NULL, "bb", reboot_finished);
......@@ -322,7 +307,7 @@ int main(int argc, char *argv[]) {
}
REPLAN_CLEANUP:
update_state(LS_POSTUPD);
const char *hook_path = aprintf("%s%s", root_dir, hook_postupdate);
const char *hook_path = aprintf("%s%s", root_dir(), hook_postupdate);
setenv("SUCCESS", trans_ok ? "true" : "false", true); // ROOT_DIR is already set
exec_hook(hook_path, "Executing postupdate hook");
CLEANUP:
......
......@@ -9,7 +9,9 @@ C_TESTS := \
arguments \
events \
util \
syscnf \
subprocess \
download \
interpreter
LUA_TESTS := \
......@@ -51,14 +53,14 @@ clean-coverage:
rm -rf $(O)/coverage
# Ignore stacktraceplus and dumper, not our creation.
LUA_AUTOLOAD := $(filter-out 01_stacktraceplus 07_dumper,$(patsubst a_%.lua,%,$(notdir $(wildcard $(S)/src/lib/autoload/a_*.lua))))
LUA_AUTOLOAD := $(filter-out 01_stacktraceplus 06_dumper,$(patsubst a_%.lua,%,$(notdir $(wildcard $(S)/src/lib/autoload/a_*.lua))))
define DO_C_TEST
BINARIES_NOTARGET += tests/ctest-$(1)
ctest-$(1)_MODULES += $(1) ctest
ctest-$(1)_MODULES += $(1) ctest test_data
ctest-$(1)_SYSTEM_LIBS += m rt
ctest-$(1)_PKG_CONFIGS += check
ctest-$(1)_PKG_CONFIGS += check $(LUA_NAME)
ctest-$(1)_LOCAL_LIBS += updater
test: test-c-$(1)
......
......@@ -62,3 +62,28 @@ function test_cleanup_unregister()
assert_false(cleanup_unregister(cleanup_local))
assert_false(cleaned);
end
-- Test if we correctly recognize closures
function test_cleanup_local()
local cl_a = false
local cl_b = false
local function new_clean(is_a)
local function lclean()
if is_a then
cl_a = true
else
cl_b = true
end
end
cleanup_register(lclean)
return lclean
end
local f_a = new_clean(true)
local f_b = new_clean(false)
cleanup_run(f_a)
assert_true(cl_a)
assert_false(cl_b)
cleanup_run(f_b)
assert_true(cl_b)
end
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----
This diff is collapsed.
-----BEGIN CERTIFICATE-----
MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUA
MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w
ZW5UcnVzdCBSb290IENBIEcxMB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAw
MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU
T3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
AoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7faYp6b
wiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX
/uMftk87ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR0
77F9jAHiOH3BX2pfJLKOYheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGP
uY4zbGneWK2gDqdkVBFpRGZPTBKnjix9xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLx
p2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO9z0M+Yo0FMT7MzUj8czx
Kselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq3ywgsNw2
TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+W
G+Oin6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPw
vFEVVJSmdz7QdFG9URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYY
EQRVzXR7z2FwefR7LFxckvzluFqrTJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUl0YhVyE1
2jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/PxN3DlCPaTKbYw
DQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E
PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kf
gLMtMrpkZ2CvuVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbS
FXJfLkur1J1juONI5f6ELlgKn0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0
V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLhX4SPgPL0DTatdrOjteFkdjpY3H1P
XlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80nR14SohWZ25g/4/I
i+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcmGS3t
TAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L91
09S5zvE/bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/Ky
Pu1svf0OnWZzsD2097+o4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJ
AwSQiumPv+i2tCqjI40cHLI5kqiPAlxAOXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj
1oxx
-----END CERTIFICATE-----
NAME="TurrisOS"
VERSION="4.0-alpha2"
ID="turrisos"
ID_LIKE="lede openwrt"
PRETTY_NAME="TurrisOS 4.0-alpha2"
VERSION_ID="4.0-alpha2"
HOME_URL="http://www.turris.cz/"
BUG_URL="http://gitlab.labs.nic.cz/groups/turris/-/issues"
SUPPORT_URL="http://www.turris.cz/support-community/"
BUILD_ID="d5e7b7d371"
LEDE_BOARD="mvebu/cortexa53"
LEDE_ARCH="aarch64_cortex-a53"
LEDE_TAINTS="no-all busybox"
LEDE_DEVICE_MANUFACTURER="CZ.NIC"
LEDE_DEVICE_MANUFACTURER_URL="https://www.turris.cz"
LEDE_DEVICE_PRODUCT="Turris Mox"
LEDE_DEVICE_REVISION="v0"
LEDE_RELEASE="TurrisOS 4.0-alpha2 d5e7b7d371"
NAME="TurrisOS"
VERSION="4.0"
ID="turrisos"
ID_LIKE="lede openwrt"
PRETTY_NAME="TurrisOS 4.0"
VERSION_ID="4.0"
HOME_URL="http://www.turris.cz/"
BUG_URL="http://gitlab.labs.nic.cz/groups/turris/-/issues"
SUPPORT_URL="http://www.turris.cz/support-community/"
BUILD_ID="ba6bf5d6b1"
LEDE_BOARD="mvebu/cortexa9"
LEDE_ARCH="arm_cortex-a9_vfpv3"
LEDE_TAINTS="no-all busybox"
LEDE_DEVICE_MANUFACTURER="CZ.NIC"
LEDE_DEVICE_MANUFACTURER_URL="https://www.turris.cz"
LEDE_DEVICE_PRODUCT="Turris Omnia"
LEDE_DEVICE_REVISION="v0"
LEDE_RELEASE="TurrisOS 4.0 ba6bf5d6b1"
/*
* Copyright 2018-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 <http://www.gnu.org/licenses/>.
*/
#include "ctest.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../src/lib/download.h"
#include "../src/lib/syscnf.h"
#include "test_data.h"
START_TEST(downloader_empty) {
struct downloader *d = downloader_new(1);
ck_assert_ptr_null(downloader_run(d));
downloader_free(d);
}
END_TEST
// Test simple download from http with redirect to https and Let's encrypt certificate
START_TEST(simple_download) {
struct downloader *d = downloader_new(1);
ck_assert_ptr_null(downloader_run(d));
struct download_opts opts;
download_opts_def(&opts);
struct download_i *inst = download_data(d, HTTP_LOREM_IPSUM_SHORT, &opts);
ck_assert_ptr_null(downloader_run(d));
ck_assert_uint_eq(LOREM_IPSUM_SHORT_SIZE, inst->out.buff->size);
ck_assert_str_eq(LOREM_IPSUM_SHORT, (char *)inst->out.buff->data);
downloader_free(d);
}
END_TEST
// Test download to file. Otherwise it's same test as in case of simple_download.
START_TEST(file_download) {
struct downloader *d = downloader_new(1);
ck_assert_ptr_null(downloader_run(d));
struct download_opts opts;
download_opts_def(&opts);
char *file = aprintf("%s/updater-download.txt", get_tmpdir());
ck_assert_ptr_nonnull(download_file(d, HTTP_LOREM_IPSUM_SHORT, file, &opts));
ck_assert_ptr_null(downloader_run(d));
char *str = readfile(file);
ck_assert(str);
ck_assert_uint_eq(LOREM_IPSUM_SHORT_SIZE, strlen(str));
ck_assert_str_eq(LOREM_IPSUM_SHORT, str);
free(str);
unlink(file);
downloader_free(d);
}
END_TEST
// Test download to temporally file. We download different data to different
// files to test that having same template we end up with two different files.
START_TEST(temp_file_download) {
struct downloader *d = downloader_new(2);
ck_assert_ptr_null(downloader_run(d));
struct download_opts opts;
download_opts_def(&opts);
const char *tmpdir = get_tmpdir();
char *file1 = aprintf("%s/updater-download-temp-XXXXXX", tmpdir);
char *file2 = aprintf("%s/updater-download-temp-XXXXXX", tmpdir);
ck_assert_str_eq(file1, file2); // Templates are same
ck_assert_ptr_nonnull(download_temp_file(d, HTTP_LOREM_IPSUM_SHORT, file1, &opts));
ck_assert_ptr_nonnull(download_temp_file(d, HTTP_LOREM_IPSUM, file2, &opts));
ck_assert_str_ne(file1, file2); // Paths are not same
ck_assert_ptr_null(downloader_run(d));
char *str = readfile(file1);
ck_assert(str);
ck_assert_uint_eq(LOREM_IPSUM_SHORT_SIZE, strlen(str));
ck_assert_str_eq(LOREM_IPSUM_SHORT, str);
free(str);
char *lorem_ipsum_file = FILE_LOREM_IPSUM;
char *big_content = readfile(lorem_ipsum_file);
size_t big_size = strlen(big_content);
str = readfile(file2);
ck_assert(str);
ck_assert_uint_eq(big_size, strlen(str));
ck_assert_str_eq(big_content, str);
free(str);
free(big_content);
unlink(file1);
unlink(file2);
downloader_free(d);
}
END_TEST
// Test that we can have multiple downloads and that all are downloaded
// Half of them are small file and half of them are bigger ones
// This test requires min. 20MB of memory.
START_TEST(multiple_downloads) {
struct downloader *d = downloader_new(4);
ck_assert_ptr_null(downloader_run(d));
struct download_opts opts;
download_opts_def(&opts);
const size_t cnt = 32;
struct download_i *insts[cnt];
for (size_t i = 0; i < cnt; i++) {
if (i % 2)
insts[i] = download_data(d, HTTP_LOREM_IPSUM_SHORT, &opts);
else
insts[i] = download_data(d, HTTP_LOREM_IPSUM, &opts);
}
ck_assert_ptr_null(downloader_run(d));