Export binaries of 3rd-party bundles after install

When a 3rd-party bundle is installed, in order for the user to be able
to use the binaries the bundle provides, it needs to have them exported.
This commit exports those binaries after they have been successfully
installed.

Signed-off-by: Castulo Martinez <castulo.martinez@intel.com>
This commit is contained in:
Castulo Martinez
2020-02-06 09:18:00 -08:00
committed by Otavio Pontes
parent 1bd709719a
commit 691f4b45e4
9 changed files with 333 additions and 26 deletions
+123 -11
View File
@@ -19,6 +19,8 @@
#define _GNU_SOURCE
#include <fcntl.h>
#include "3rd_party_repos.h"
#include "swupd.h"
@@ -27,6 +29,11 @@
#define FLAG_SKIP_OPTIONAL 2000
#define FLAG_SKIP_DISKSPACE_CHECK 2001
#define SCRIPT_TEMPLATE "#!/bin/bash\n\n" \
"export PATH=%s:$PATH\n" \
"export LD_LIBRARY_PATH=%s:$LD_LIBRARY_PATH\n\n" \
"%s \"$@\"\n"
static char **cmdline_bundles;
static char *cmdline_repo = NULL;
@@ -94,18 +101,121 @@ static bool parse_options(int argc, char **argv)
return true;
}
static enum swupd_code add_bundle(char *bundle)
static enum swupd_code create_wrapper_script(char *filename)
{
enum swupd_code ret_code = 0;
int fd;
FILE *fp = NULL;
char *bin_directory = NULL;
char *script = NULL;
char *binary = NULL;
char *third_party_bin_path = NULL;
char *third_party_ld_path = NULL;
mode_t mode = 0755;
bin_directory = third_party_get_bin_dir();
script = third_party_get_binary_path(sys_basename(filename));
binary = sys_path_join(globals.path_prefix, filename);
if (!sys_filelink_is_executable(binary)) {
goto close_and_exit;
}
if (sys_file_exists(script)) {
/* the binary already exists, this condition should never happen
* since we checked before installing */
ret_code = SWUPD_UNEXPECTED_CONDITION;
error("There is already a binary called %s in %s, it will be skipped\n", sys_basename(filename), bin_directory);
goto close_and_exit;
}
/* if the SWUPD_3RD_PARTY_BIN_DIR does not exist, attempt to create it */
if (mkdir_p(bin_directory)) {
ret_code = SWUPD_COULDNT_CREATE_DIR;
goto close_and_exit;
}
if (!is_dir(bin_directory)) {
error("The path %s for 3rd-party content exists but is not a directory\n", bin_directory);
ret_code = SWUPD_COULDNT_CREATE_DIR;
goto close_and_exit;
}
/* open the file with mode set to 0755 */
fd = open(script, O_RDWR | O_CREAT, mode);
if (fd < 0) {
error("The file %s failed to be created\n", script);
ret_code = SWUPD_COULDNT_CREATE_FILE;
goto close_and_exit;
}
fp = fdopen(fd, "w");
if (!fp) {
error("The file %s failed to be created\n", script);
ret_code = SWUPD_COULDNT_CREATE_FILE;
goto close_and_exit;
}
/* get the path for the 3rd-party content */
third_party_bin_path = str_or_die("%sbin:%susr/bin:%susr/local/bin", globals.path_prefix, globals.path_prefix, globals.path_prefix);
third_party_ld_path = str_or_die("%susr/lib64:%susr/local/lib64", globals.path_prefix, globals.path_prefix);
fprintf(fp, SCRIPT_TEMPLATE, third_party_bin_path, third_party_ld_path, binary);
close_and_exit:
if (fp) {
fclose(fp);
}
free_string(&binary);
free_string(&script);
free_string(&bin_directory);
free_string(&third_party_bin_path);
free_string(&third_party_ld_path);
return ret_code;
}
static enum swupd_code validate_binary(char *filename)
{
enum swupd_code ret_code = SWUPD_OK;
char *bin_directory = NULL;
char *script = NULL;
bin_directory = third_party_get_bin_dir();
script = third_party_get_binary_path(sys_basename(filename));
/* if a file already exists, report the problem to the user */
if (sys_file_exists(script)) {
error("There is already a binary called %s in %s\n", sys_basename(filename), bin_directory);
ret_code = SWUPD_COULDNT_CREATE_FILE;
}
free_string(&script);
free_string(&bin_directory);
return ret_code;
}
static enum swupd_code export_bundle_binaries(struct list *installed_files)
{
return third_party_process_binaries(installed_files, "\nExporting 3rd-party bundle binaries...\n", "export_binaries", create_wrapper_script);
}
static enum swupd_code validate_bundle_binaries(struct list *files_to_be_installed)
{
return third_party_process_binaries(files_to_be_installed, "\nValidating 3rd-party bundle binaries...\n", "validate_binaries", validate_binary);
}
static enum swupd_code add_bundle(char *bundle_name)
{
struct list *bundle_to_install = NULL;
enum swupd_code ret = SWUPD_OK;
/* execute_bundle_add expects a list */
bundle_to_install = list_append_data(bundle_to_install, bundle);
bundle_to_install = list_append_data(bundle_to_install, bundle_name);
info("\nBundles added from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons\n\n");
globals.no_scripts = true;
ret = execute_bundle_add(bundle_to_install);
ret = execute_bundle_add_extra(bundle_to_install, validate_bundle_binaries, export_bundle_binaries);
list_free_list(bundle_to_install);
return ret;
@@ -115,7 +225,7 @@ enum swupd_code third_party_bundle_add_main(int argc, char **argv)
{
struct list *bundles = NULL;
enum swupd_code ret_code = SWUPD_OK;
const int steps_in_bundleadd = 8;
const int steps_in_bundleadd = 10;
if (!parse_options(argc, argv)) {
print("\n");
@@ -133,13 +243,15 @@ enum swupd_code third_party_bundle_add_main(int argc, char **argv)
/*
* Steps for 3rd-party bundle-add:
* 1) load_manifests
* 2) download_packs
* 3) extract_packs
* 4) validate_fullfiles
* 5) download_fullfiles
* 6) extract_fullfiles
* 7) install_files
* 8) run_postupdate_scripts
* 2) validate_binaries
* 3) download_packs
* 4) extract_packs
* 5) validate_fullfiles
* 6) download_fullfiles
* 7) extract_fullfiles
* 8) install_files
* 9) run_postupdate_scripts
* 10) export_binaries
*/
progress_init_steps("3rd-party-bundle-add", steps_in_bundleadd);
+57 -5
View File
@@ -375,7 +375,7 @@ clean_and_exit:
return ret_code;
}
enum swupd_code third_party_run_operation(struct list *bundles, const char *repo, run_operation_fn_t run_operation_fn)
enum swupd_code third_party_run_operation(struct list *bundles, const char *repo, process_data_fn_t process_bundle_fn)
{
struct list *repos = NULL;
struct list *iter = NULL;
@@ -423,7 +423,7 @@ enum swupd_code third_party_run_operation(struct list *bundles, const char *repo
}
/* perform appropriate action on the bundle */
ret = run_operation_fn(bundle);
ret = process_bundle_fn(bundle);
if (ret) {
/* if we have an error here it is ok to overwrite any previous error */
ret_code = ret;
@@ -446,7 +446,7 @@ clean_and_exit:
return ret_code;
}
enum swupd_code third_party_run_operation_multirepo(const char *repo, run_operation_fn_t run_operation_fn, enum swupd_code expected_ret_code, const char *op_name, int op_steps)
enum swupd_code third_party_run_operation_multirepo(const char *repo, process_data_fn_t process_bundle_fn, enum swupd_code expected_ret_code, const char *op_name, int op_steps)
{
enum swupd_code ret_code = SWUPD_OK;
enum swupd_code ret;
@@ -482,7 +482,7 @@ enum swupd_code third_party_run_operation_multirepo(const char *repo, run_operat
goto clean_and_exit;
}
ret_code = run_operation_fn(NULL);
ret_code = process_bundle_fn(NULL);
} else {
@@ -499,7 +499,7 @@ enum swupd_code third_party_run_operation_multirepo(const char *repo, run_operat
/* set the repo's header */
third_party_repo_header(selected_repo->name);
ret = run_operation_fn(NULL);
ret = process_bundle_fn(NULL);
if (ret != expected_ret_code) {
/* if the operation failed in any of the repos,
* keep the error */
@@ -526,4 +526,56 @@ void third_party_repo_header(const char *repo_name)
free_string(&header);
}
static bool is_binary(const char *filename)
{
const char *binary_paths[] = { "/bin", "/usr/bin", "/usr/local/bin", NULL };
int i = 0;
while (binary_paths[i]) {
if (strncmp(filename, binary_paths[i], strlen(binary_paths[i])) == 0) {
return true;
}
i++;
}
return false;
}
bool third_party_file_is_binary(struct file *file)
{
if (file->is_exported && is_binary(file->filename)) {
return true;
} else
return false;
}
enum swupd_code third_party_process_binaries(struct list *files, const char *msg, const char *step, process_data_fn_t proc_binary_fn)
{
enum swupd_code ret, ret_code = SWUPD_OK;
struct list *iter = NULL;
struct file *file = NULL;
char *filename = NULL;
int count = 0;
int number_of_files = list_len(files);
info("%s", msg);
progress_next_step(step, PROGRESS_BAR);
for (iter = list_head(files); iter; iter = iter->next) {
file = iter->data;
filename = file->filename;
if (third_party_file_is_binary(file)) {
ret = proc_binary_fn(filename);
if (ret) {
/* at least one file failed to process */
ret_code = ret;
}
}
count++;
progress_report(count, number_of_files);
}
return ret_code;
}
#endif
+23 -6
View File
@@ -34,8 +34,8 @@ struct repo {
char *url;
};
/** @brief Definition of a function that performs an action on a given bundle */
typedef enum swupd_code (*run_operation_fn_t)(char *bundle);
/** @brief Definition of a function that performs some processing on a given data */
typedef enum swupd_code (*process_data_fn_t)(char *data_name);
/** @brief Function that returns the path to the 3rd-party bin directory */
char *third_party_get_bin_dir(void);
@@ -112,24 +112,24 @@ enum swupd_code third_party_set_repo(struct repo *repo, bool sigcheck);
* @param repo the name of the 3rd-party repository where the bundles
* should be looked for. If no repo is specified the bundles are searched for
* in all existing repos.
* @param run_operation_fn the function to be performed
* @param process_bundle_fn the bundle processing to be performed
*
* @returns a swupd_code
*/
enum swupd_code third_party_run_operation(struct list *bundles, const char *repo, run_operation_fn_t run_operation_fn);
enum swupd_code third_party_run_operation(struct list *bundles, const char *repo, process_data_fn_t process_bundle_fn);
/**
* @brief Performs an operation on 3rd-party repos.
*
* @param repo the name of the 3rd-party repository where the operation will be run
* @param run_operation_fn the function to be performed
* @param process_bundle_fn the bundle processing to be performed
* @param expected_ret_code the expected return code from the operation
* @param op_name the name of the operation to be run in all repos
* @param op_steps the number of steps involved in the operation
*
* @returns a swupd_code
*/
enum swupd_code third_party_run_operation_multirepo(const char *repo, run_operation_fn_t run_operation_fn, enum swupd_code expected_ret_code, const char *op_name, int op_steps);
enum swupd_code third_party_run_operation_multirepo(const char *repo, process_data_fn_t process_bundle_fn, enum swupd_code expected_ret_code, const char *op_name, int op_steps);
/**
* @brief Prints a header with the repository name, useful when showing info from multiple repos.
@@ -138,6 +138,23 @@ enum swupd_code third_party_run_operation_multirepo(const char *repo, run_operat
*/
void third_party_repo_header(const char *repo_name);
/**
* @brief Determines if a file from the manifest is 3rd-party exported binary
*
* @returns true if the file is an exported binary, false otherwise
*/
bool third_party_file_is_binary(struct file *file);
/**
* @brief Function that perform some processing to binaries from a 3rd-party bundle
*
* @param files is the list of files that are part of the bundle and its dependencies
* @param msg the message to be printed at the beginning of the processing
* @param step the name of the step to show during the reporting of progress
* @param proc_binary_fn the function with the processing to be performed on each binary file
*/
enum swupd_code third_party_process_binaries(struct list *files, const char *msg, const char *step, process_data_fn_t proc_binary_fn);
#endif
#ifdef __cplusplus
+30 -3
View File
@@ -319,7 +319,7 @@ static enum swupd_code download_content(struct manifest *mom, struct list *to_in
/* Bundle install one ore more bundles passed in bundles
* param as a null terminated array of strings
*/
enum swupd_code bundle_add(struct list *bundles_list, int version)
enum swupd_code bundle_add_extra(struct list *bundles_list, int version, extra_proc_fn_t pre_add_fn, extra_proc_fn_t post_add_fn)
{
int ret = 0;
struct manifest *mom;
@@ -391,6 +391,15 @@ enum swupd_code bundle_add(struct list *bundles_list, int version)
goto clean_and_exit;
}
/* execute pre-add processing (if any) */
if (pre_add_fn) {
ret = pre_add_fn(to_install_files);
if (ret != SWUPD_OK) {
info("Aborting bundle installation...\n\n");
goto clean_and_exit;
}
}
/* Check if we have enough space */
ret = check_disk_space_availability(to_install_bundles);
if (ret) {
@@ -406,11 +415,19 @@ enum swupd_code bundle_add(struct list *bundles_list, int version)
mom->files = installed_files;
ret = install_files(mom, to_install_files);
if (ret) {
goto clean_and_exit;
}
timelist_timer_stop(globals.global_times); // closing: Install bundles
timelist_print_stats(globals.global_times);
/* execute post-add processing (if any) */
if (post_add_fn) {
ret = post_add_fn(to_install_files);
}
clean_and_exit:
iter = list_head(to_install_bundles);
/* count how many of the requested bundles were actually installed, note that the
@@ -462,7 +479,12 @@ clean_and_exit:
return ret;
}
enum swupd_code execute_bundle_add(struct list *bundles_list)
enum swupd_code bundle_add(struct list *bundles_list, int version)
{
return bundle_add_extra(bundles_list, version, NULL, NULL);
}
enum swupd_code execute_bundle_add_extra(struct list *bundles_list, extra_proc_fn_t pre_add_fn, extra_proc_fn_t post_add_fn)
{
int version;
@@ -473,7 +495,12 @@ enum swupd_code execute_bundle_add(struct list *bundles_list)
return SWUPD_CURRENT_VERSION_UNKNOWN;
}
return bundle_add(bundles_list, version);
return bundle_add_extra(bundles_list, version, pre_add_fn, post_add_fn);
}
enum swupd_code execute_bundle_add(struct list *bundles_list)
{
return execute_bundle_add_extra(bundles_list, NULL, NULL);
}
enum swupd_code bundle_add_main(int argc, char **argv)
+4 -1
View File
@@ -329,8 +329,11 @@ extern int add_subscriptions(struct list *bundles, struct list **subs, struct ma
extern int subscription_get_tree(struct list *bundles, struct list **subs, struct manifest *mom, bool find_all, int recursion);
/* bundle_add.c */
extern enum swupd_code execute_bundle_add(struct list *bundles_list);
typedef enum swupd_code (*extra_proc_fn_t)(struct list *files);
extern enum swupd_code bundle_add(struct list *bundles_list, int version);
extern enum swupd_code bundle_add_extra(struct list *bundles_list, int version, extra_proc_fn_t pre_add_fn, extra_proc_fn_t post_add_fn);
extern enum swupd_code execute_bundle_add(struct list *bundles_list);
extern enum swupd_code execute_bundle_add_extra(struct list *bundles_list, extra_proc_fn_t pre_add_fn, extra_proc_fn_t post_add_fn);
/* bundle_remove.c */
extern enum swupd_code execute_remove_bundles(struct list *bundles);
@@ -33,11 +33,13 @@ test_setup() {
Bundle test-bundle2 found in 3rd-party repository test-repo2
Bundles added from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons
Loading required manifests...
Validating 3rd-party bundle binaries...
No packs need to be downloaded
Validate downloaded files
Starting download of remaining update content. This may take a while...
Installing files...
Warning: post-update helper scripts skipped due to --no-scripts argument
Exporting 3rd-party bundle binaries...
Successfully installed 1 bundle
EOM
)
@@ -89,11 +91,13 @@ test_setup() {
Bundle test-bundle2 found in 3rd-party repository test-repo2
Bundles added from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons
Loading required manifests...
Validating 3rd-party bundle binaries...
No packs need to be downloaded
Validate downloaded files
Starting download of remaining update content. This may take a while...
Installing files...
Warning: post-update helper scripts skipped due to --no-scripts argument
Exporting 3rd-party bundle binaries...
Successfully installed 1 bundle
EOM
)
@@ -116,11 +120,13 @@ test_setup() {
Bundle test-bundle2 found in 3rd-party repository test-repo2
Bundles added from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons
Loading required manifests...
Validating 3rd-party bundle binaries...
No packs need to be downloaded
Validate downloaded files
Starting download of remaining update content. This may take a while...
Installing files...
Warning: post-update helper scripts skipped due to --no-scripts argument
Exporting 3rd-party bundle binaries...
Successfully installed 1 bundle
Searching for bundle upstream-bundle in the 3rd-party repositories...
Error: bundle upstream-bundle was not found in any 3rd-party repository
@@ -42,11 +42,13 @@ test_setup() {
Bundle test-bundle1 found in 3rd-party repository test-repo
Bundles added from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons
Loading required manifests...
Validating 3rd-party bundle binaries...
No packs need to be downloaded
Validate downloaded files
Starting download of remaining update content. This may take a while...
Installing files...
Warning: post-update helper scripts skipped due to --no-scripts argument
Exporting 3rd-party bundle binaries...
Successfully installed 1 bundle
1 bundle was installed as dependency
EOM
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env bats
# Author: Castulo Martinez
# Email: castulo.martinez@intel.com
load "../testlib"
test_setup() {
create_test_environment "$TEST_NAME"
# create a 3rd-party bundle that has a couple of binaries
add_third_party_repo "$TEST_NAME" 10 1 test-repo1
create_bundle -n test-bundle1 -f /file1,/foo/file_2,/usr/bin/file_3,/bin/file_4 -u test-repo1 "$TEST_NAME"
}
@test "TPR056: Adding one bundle from a third party repo that will export binaries" {
# If a 3rd-party bundle has binaries to be exported (marked with 'x' in the
# manifest and within /bin, /usr/bin, or /usr/local/bin) they should have a
# script created in /opt/3rd-party/bin to make the binary available to the user
run sudo sh -c "$SWUPD 3rd-party bundle-add $SWUPD_OPTS test-bundle1"
assert_status_is "$SWUPD_OK"
expected_output=$(cat <<-EOM
Searching for bundle test-bundle1 in the 3rd-party repositories...
Bundle test-bundle1 found in 3rd-party repository test-repo1
Bundles added from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons
Loading required manifests...
Validating 3rd-party bundle binaries...
Downloading packs for:
- test-bundle1
Finishing packs extraction...
Validate downloaded files
No extra files need to be downloaded
Installing files...
Warning: post-update helper scripts skipped due to --no-scripts argument
Exporting 3rd-party bundle binaries...
Successfully installed 1 bundle
EOM
)
assert_is_output "$expected_output"
# the script files should have been generated for the exported files
assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/file_3
assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/file_4
# verify the content of the scripts is correct
run sudo sh -c "cat $TARGETDIR/$THIRD_PARTY_BIN_DIR/file_3"
expected_output=$(cat <<-EOM
#!/bin/bash
export PATH=.*
export LD_LIBRARY_PATH=.*
$PATH_PREFIX/$THIRD_PARTY_BUNDLES_DIR/test-repo1/usr/bin/file_3 .*
EOM
)
assert_regex_is_output "$expected_output"
}
@test "TPR057: Try adding one bundle from a third party repo that will export conflicting binaries" {
# If a 3rd-party bundle has binaries to be exported but the binary already exists
# in the target system, the bundle installation should be aborted
sudo mkdir -p "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"
sudo touch "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/file_3
run sudo sh -c "$SWUPD 3rd-party bundle-add $SWUPD_OPTS test-bundle1"
assert_status_is "$SWUPD_COULDNT_CREATE_FILE"
expected_output=$(cat <<-EOM
Searching for bundle test-bundle1 in the 3rd-party repositories...
Bundle test-bundle1 found in 3rd-party repository test-repo1
Bundles added from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons
Loading required manifests...
Validating 3rd-party bundle binaries...
Error: There is already a binary called file_3 in $PATH_PREFIX/opt/3rd-party/bin
Aborting bundle installation...
Failed to install 1 of 1 bundles
EOM
)
assert_is_output "$expected_output"
}
@@ -56,11 +56,13 @@ test_setup() {
expected_output=$(cat <<-EOM
Bundles added from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons
Loading required manifests...
Validating 3rd-party bundle binaries...
No packs need to be downloaded
Validate downloaded files
Starting download of remaining update content. This may take a while...
Installing files...
Warning: post-update helper scripts skipped due to --no-scripts argument
Exporting 3rd-party bundle binaries...
Successfully installed 1 bundle
EOM
)