Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

config: add --action-env cli option #2136

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Documentation/criu.txt
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ not compatible with *--external* *dev*.
notification message contains a file descriptor for
the master pty

*--action-env* 'name'='value'::
This option allows arbitrary environment variables to be passed to
the action scripts.

*--unprivileged*::
This option tells *criu* to accept the limitations when running
as non-root. Running as non-root requires *criu* at least to have
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ lint:
shellcheck -x test/others/libcriu/*.sh
shellcheck -x test/others/crit/*.sh test/others/criu-coredump/*.sh
shellcheck -x test/others/config-file/*.sh
shellcheck -x test/others/action-script/*.sh
codespell -S tags
# Do not append \n to pr_perror or fail
! git --no-pager grep -E '^\s*\<(pr_perror|fail)\>.*\\n"'
Expand Down
44 changes: 44 additions & 0 deletions criu/action-scripts.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,35 @@ struct script {
char *path;
};

struct script_env {
struct list_head node;
char *name;
char *value;
};

enum { SCRIPTS_NONE, SCRIPTS_SHELL, SCRIPTS_RPC };

static int scripts_mode = SCRIPTS_NONE;
static LIST_HEAD(scripts);
static LIST_HEAD(script_env_vars);

static int run_shell_scripts(const char *action)
{
int retval = 0;
struct script *script;
struct script_env *script_env;
static unsigned env_set = 0;

#define ENV_IMGDIR 0x1
#define ENV_ROOTPID 0x2

list_for_each_entry(script_env, &script_env_vars, node) {
if (setenv(script_env->name, script_env->value, 1)) {
pr_perror("Can't set %s=%s", script_env->name, script_env->value);
return -1;
}
}

if (setenv("CRTOOLS_SCRIPT_ACTION", action, 1)) {
pr_perror("Can't set CRTOOLS_SCRIPT_ACTION=%s", action);
return -1;
Expand Down Expand Up @@ -92,6 +107,10 @@ static int run_shell_scripts(const char *action)

unsetenv("CRTOOLS_SCRIPT_ACTION");

list_for_each_entry(script_env, &script_env_vars, node) {
unsetenv(script_env->name);
}

return retval;
}

Expand Down Expand Up @@ -138,6 +157,31 @@ int run_scripts(enum script_actions act)
return ret;
}

int add_script_env(char *name, char *value)
{
struct script_env *script_env;

script_env = xmalloc(sizeof(struct script_env));
if (script_env == NULL)
return -1;

script_env->name = xstrdup(name);
if (!script_env->name) {
xfree(script_env);
return -1;
}

script_env->value = xstrdup(value);
if (!script_env->value) {
xfree(script_env->name);
xfree(script_env);
return -1;
}

list_add(&script_env->node, &script_env_vars);
return 0;
}

int add_script(char *path)
{
struct script *script;
Expand Down
34 changes: 34 additions & 0 deletions criu/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,28 @@ static int parse_file_validation_method(struct cr_options *opts, const char *opt
return -1;
}

int parse_action_env(char *input, char *name, char **value)
{
int name_length;
char *equal_sign_ptr = strchr(input, '=');

if (equal_sign_ptr == NULL || equal_sign_ptr == input || input[strlen(input) - 1] == '=') {
pr_err("Invalid action-env format; input should be \"<NAME>=<VALUE>\"\n");
return -1;
}

name_length = equal_sign_ptr - input;
if (name_length > NAME_MAX) {
pr_err("Invalid action-env name\n");
return -1;
}

strncpy(name, input, name_length);
name[name_length] = '\0';
*value = equal_sign_ptr + 1;
return 0;
}

/*
* parse_options() is the point where the getopt parsing happens. The CLI
* parsing as well as the configuration file parsing happens here.
Expand Down Expand Up @@ -639,6 +661,7 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd,
BOOL_OPT("evasive-devices", &opts.evasive_devices),
{ "pidfile", required_argument, 0, 1046 },
{ "veth-pair", required_argument, 0, 1047 },
{ "action-env", required_argument, 0, 1048 },
{ "action-script", required_argument, 0, 1049 },
BOOL_OPT(LREMAP_PARAM, &opts.link_remap_ok),
BOOL_OPT(OPT_SHELL_JOB, &opts.shell_job),
Expand Down Expand Up @@ -836,6 +859,17 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd,
return 1;
}
} break;
case 1048: {
char action_env_name[NAME_MAX], *action_env_value = NULL;
if (parse_action_env(optarg, action_env_name, &action_env_value) || action_env_value == NULL) {
pr_err("Failed to parse action-env: %s.\n", optarg);
return 1;
}
if (add_script_env(action_env_name, action_env_value)) {
pr_err("Failed to add action-env: %s.\n", optarg);
return 1;
}
} break;
case 1049:
if (add_script(optarg)) {
pr_err("Failed to add action-script: %s.\n", optarg);
Expand Down
2 changes: 2 additions & 0 deletions criu/crtools.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,8 @@ int main(int argc, char *argv[], char *envp[])
" --ghost-limit size limit max size of deleted file contents inside image\n"
" --ghost-fiemap enable dumping of deleted files using fiemap\n"
" --action-script FILE add an external action script\n"
" --action-env NAME=VALUE\n"
" set environment variable for action scripts\n"
" -j|--" OPT_SHELL_JOB " allow one to dump and restore shell jobs\n"
" -l|--" OPT_FILE_LOCKS " handle file locks, for safety, only used for container\n"
" -L|--libdir path to a plugin directory (by default " CR_PLUGIN_DEFAULT ")\n"
Expand Down
1 change: 1 addition & 0 deletions criu/include/action-scripts.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum script_actions {
};

extern int add_script(char *path);
extern int add_script_env(char *name, char *value);
extern int add_rpc_notify(int sk);
extern int run_scripts(enum script_actions);
extern int rpc_send_fd(enum script_actions, int fd);
Expand Down
5 changes: 5 additions & 0 deletions criu/unittest/mock.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ int add_script(char *path)
return 0;
}

int add_script_env(char *path)
{
return 0;
}

int veth_pair_add(char *in, char *out)
{
return 0;
Expand Down
31 changes: 31 additions & 0 deletions criu/unittest/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,35 @@
#include "criu-log.h"

int parse_statement(int i, char *line, char **configuration);
int parse_action_env(char *input, char *name, char **value);

void test_action_env(char **configuration)
{
int i;
char name[255], *value;

i = parse_statement(0, "action-env FOO=BAR\n", configuration);
assert(i == 2);
assert(!strcmp(configuration[0], "--action-env"));
assert(!strcmp(configuration[1], "FOO=BAR"));

// Should fail if the value does not contain equal sign
i = parse_action_env("TEST", NULL, NULL);
assert(i == -1);

// Should fail if the env name is empty
i = parse_action_env("=TEST", NULL, NULL);
assert(i == -1);

// Should fail if the env value is empty
i = parse_action_env("TEST=", NULL, NULL);
assert(i == -1);

i = parse_action_env("FOO=BAR", name, &value);
assert(i == 0);
assert(!strcmp(name, "FOO"));
assert(!strcmp(value, "BAR"));
}

int main(int argc, char *argv[], char *envp[])
{
Expand Down Expand Up @@ -143,6 +172,8 @@ int main(int argc, char *argv[], char *envp[])
/* leaves punctuation in returned string as is */
assert(!strcmp(get_relative_path("./a////.///./b//././c", "a"), "b//././c"));

test_action_env(configuration);

pr_msg("OK\n");
return 0;
}
3 changes: 3 additions & 0 deletions scripts/ci/run-ci-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,9 @@ make -C test/others/ns_ext run
# config file parser and parameter testing
make -C test/others/config-file run

# action script testing
make -C test/others/action-script run

# Skip all further tests when running with GCOV=1
# The one test which currently cannot handle GCOV testing is compel/test
# Probably because the GCOV Makefile infrastructure does not exist in compel
Expand Down
1 change: 1 addition & 0 deletions test/others/action-script/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
img-dir-*
5 changes: 5 additions & 0 deletions test/others/action-script/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
run:
@make -C .. loop
./run.sh

.PHONY: run
13 changes: 13 additions & 0 deletions test/others/action-script/action-script.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash
touch action-hook-"$CRTOOLS_SCRIPT_ACTION"

vars=("E1" "E2" "E3" "E4")

for var in "${vars[@]}"
do
if [ -n "${!var}" ]; then
echo "${!var}" > "action-env-$var"
fi
done

exit 0
74 changes: 74 additions & 0 deletions test/others/action-script/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/bin/bash

set -ebm

# shellcheck source=test/others/env.sh
source ../env.sh || exit 1

SELFDIR="$(dirname "$(readlink -f "$0")")"
SCRIPT="$SELFDIR/action-script.sh"
IMGDIR="$SELFDIR/img-dir-$$"

rm -rf "$IMGDIR"
mkdir "$IMGDIR"

trap "cleanup" QUIT TERM INT HUP EXIT

function cleanup()
{
if [[ -n "$PID" ]]; then
kill -9 "$PID"
fi
}

PID=$(../loop)
if ! $CRIU dump -v4 -o dump.log -t "$PID" -D "$IMGDIR" --action-script "$SCRIPT" --action-env E1=A --action-env E2=B; then
echo "Failed to checkpoint process $PID"
cat dump.log
kill -9 "$PID"
exit 1
fi

if ! $CRIU restore -v4 -o restore.log -D "$IMGDIR" -d --pidfile test.pidfile --action-script "$SCRIPT" --action-env E3=C --action-env E4=D; then
echo "CRIU restore failed"
echo FAIL
exit 1
fi

PID=$(cat "$IMGDIR"/test.pidfile)

found_missing_file=false
hooks=("pre-dump" "post-dump" "pre-restore" "pre-resume" "post-restore" "post-resume")

for hook in "${hooks[@]}"
do
if [ ! -e "$IMGDIR/action-hook-$hook" ]; then
echo "ERROR: action-hook-$hook does not exist"
found_missing_file=true
fi
done

if [ "$found_missing_file" = true ]; then
exit 1
fi

found_mismatch=false
vars=("E1:A" "E2:B" "E3:C" "E4:D")

for var in "${vars[@]}"
do
IFS=':' read -r file expected <<< "$var"
actual=$(< "$IMGDIR/action-env-$file")

if [ "$actual" != "$expected" ]; then
echo "ERROR: action-env-$file does not contain '$expected'."
found_mismatch=true
fi
done

if [ "$found_mismatch" = true ]; then
exit 1
fi

rm -rf "$IMGDIR"
exit 0
6 changes: 6 additions & 0 deletions test/others/config-file/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,10 @@ $CRIU check --file-validation filesizefilesize
$CRIU dump --file-validation filesize
$CRIU restore --file-validation buildid
$CRIU check --file-validation buildid --deprecated
$CRIU dump --action-env TEST
$CRIU dump --action-env TEST=
$CRIU dump --action-env =TEST
$CRIU restore --action-env TEST
$CRIU restore --action-env TEST=
$CRIU restore --action-env =TEST
exit 0