diff --git a/.travis.yml b/.travis.yml index 06f16e2d..df4b3e97 100644 --- a/.travis.yml +++ b/.travis.yml @@ -80,7 +80,7 @@ install: # Ubuntu's default umask is 0002, but this break's swupd hash calculations. before_script: - autoreconf --verbose --warnings=none --install --force - - ./configure CFLAGS="$CFLAGS -fsanitize=address -Werror" --prefix=/usr --with-fallback-capaths=$TRAVIS_BUILD_DIR/swupd_test_certificates --with-systemdsystemunitdir=/usr/lib/systemd/system --with-config-file-path=./testconfig + - ./configure CFLAGS="$CFLAGS -fsanitize=address -Werror" --prefix=/usr --enable-third-party --with-fallback-capaths=$TRAVIS_BUILD_DIR/swupd_test_certificates --with-systemdsystemunitdir=/usr/lib/systemd/system --with-config-file-path=./testconfig - sudo find test/functional -exec chmod g-w {} \; - make && sudo sh -c 'umask 0022 && make install' && diff --git a/Makefile.am b/Makefile.am index 09a6fe9f..9b579c62 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,6 +32,11 @@ bin_PROGRAMS = swupd AM_CPPFLAGS = $(AM_CFLAGS) $(libarchive_CFLAGS) swupd_SOURCES = \ + src/3rd_party_add.c \ + src/3rd_party.c \ + src/3rd_party_internal.h \ + src/3rd_party_list.c \ + src/3rd_party_remove.c \ src/alias.c \ src/alias.h \ src/autoupdate.c \ diff --git a/configure.ac b/configure.ac index 1a233677..0a7821f0 100644 --- a/configure.ac +++ b/configure.ac @@ -72,6 +72,25 @@ AS_IF( [SIGVERIFICATION="no"] ) +AC_ARG_ENABLE( + [third-party], + [AS_HELP_STRING([--enable-third-party], [Enable 3rd-party (disabled by default)])] +) +THIRDPARTY="no" +AS_IF( + [test "x$enable_third_party" = "xyes"], + [AC_DEFINE(THIRDPARTY, 1, [Enable third party]) + THIRDPARTY="yes"], + [THIRDPARTY="no"] +) + +AH_TEMPLATE([THIRDPARTY_REPO_PREFIX], [prefix path for third party repos]) + +AS_IF( + [test "$enable_third_party" = "yes"], + [AC_DEFINE([THIRDPARTY_REPO_PREFIX], ["/opt/user-repo/"])] +) + AC_ARG_ENABLE( [tests], [AS_HELP_STRING([--disable-tests], [Do not enable unit or functional test framework (enabled by default)])] @@ -383,6 +402,7 @@ Configuration to build swupd-client: Version URL: ${VERSIONURL} Format Identifier: ${FORMATID} Signature verification: ${SIGVERIFICATION} + Third party: ${THIRDPARTY} Update certificate path: ${cert_path} Configuration file path(s): ${config_file_path} Use bzip compression: ${BZIP} diff --git a/src/3rd_party.c b/src/3rd_party.c new file mode 100644 index 00000000..04c6b8f6 --- /dev/null +++ b/src/3rd_party.c @@ -0,0 +1,110 @@ +/* + * Software Updater - client side + * + * Copyright © 2019 Intel Corporation. + * + * This program 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, version 2 or later of the License. + * + * This program 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 this program. If not, see . + * + */ + +#define _GNU_SOURCE +#include "config.h" +#include "swupd.h" +#include "swupd_internal.h" + +#ifdef THIRDPARTY + +static struct subcmd third_party_commands[] = { + { "add", "Add third party repo", third_party_add_main }, + { "remove", "Remove third party repo", third_party_remove_main }, + { "list", "List third party repo", third_party_list_main }, + { 0 } +}; + +static void print_help(const char *name) +{ + print("Usage:\n"); + print(" or %s SUBCOMMAND [OPTION...]\n\n", basename((char *)name)); + print("Help Options:\n"); + print(" -h, --help Show help options\n"); + print("Subcommands:\n"); + + struct subcmd *entry = third_party_commands; + + while (entry->name != NULL) { + print(" %-20s %-30s\n", entry->name, entry->doc); + entry++; + } + print("\n"); + print("To view subcommand options, run `%s SUBCOMMAND --help'\n", basename((char *)name)); +} + +static const struct option prog_opts[] = { + { "help", no_argument, 0, 'h' }, + { 0 } +}; + +static int parse_options(int argc, char **argv, int *index) +{ + int opt; + int ret; + + /* The leading "-" in the optstring is required to preserve option parsing order */ + while ((opt = getopt_long(argc, argv, "-h", prog_opts, NULL)) != -1) { + switch (opt) { + case 'h': + print_help(argv[0]); + exit(EXIT_SUCCESS); + case '\01': + /* found a subcommand, or a random non-option argument */ + ret = subcmd_index(optarg, third_party_commands); + if (ret < 0) { + error("unrecognized subcommand `%s'\n\n", + optarg); + goto error; + } else { + *index = ret; + return 0; + } + case '?': + /* for unknown options, an error message is printed automatically */ + info("\n"); + goto error; + default: + /* should be unreachable */ + break; + } + } + + /* no subcommands implies -h/--help */ + print_help(argv[0]); + exit(EXIT_SUCCESS); +error: + print_help(argv[0]); + return -1; +} + +enum swupd_code third_party_main(int argc, char **argv) +{ + int index = 0, ret; + + if (parse_options(argc, argv, &index) < 0) { + return SWUPD_INVALID_OPTION; + } + optind = 0; + ret = third_party_commands[index].mainfunc(argc - 1, argv + 1); + + return ret; +} + +#endif diff --git a/src/3rd_party_add.c b/src/3rd_party_add.c new file mode 100644 index 00000000..35057b8d --- /dev/null +++ b/src/3rd_party_add.c @@ -0,0 +1,94 @@ +/* + * Software Updater - client side + * + * Copyright © 2019 Intel Corporation. + * + * This program 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, version 2 or later of the License. + * + * This program 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 this program. If not, see . + * + */ + +#define _GNU_SOURCE +#include "3rd_party_internal.h" +#include "config.h" + +#ifdef THIRDPARTY + +static void print_help(void) +{ + print("Usage:\n"); + print(" swupd 3rd-party add [repo-name] [repo-URL]\n\n"); + + global_print_help(); + print("\n"); +} + +static const struct global_options opts = { + NULL, + 0, + NULL, + print_help, +}; + +static bool parse_options(int argc, char **argv) +{ +#define EXACT_ARG_COUNT 2 + int ind = global_parse_options(argc, argv, &opts); + + if (ind < 0) { + return false; + } + + if (argc == 1) { + error("The positional args: repo-name and URL are missing\n\n"); + return false; + } else if (argc == 2) { + error("The positional args: repo-URL is missing\n\n"); + return false; + } + + /* Ensure that repo add only expects only two args: repo-name, repo-url */ + if ((argc - ind) != EXACT_ARG_COUNT) { + error("Unexpected arguments\n\n"); + return false; + } + + return true; +} + +enum swupd_code third_party_add_main(int argc, char **argv) +{ + + enum swupd_code ret = SWUPD_OK; + const int step_in_third_party_add = 1; + + if (!parse_options(argc, argv)) { + print_help(); + return SWUPD_INVALID_OPTION; + } + progress_init_steps("third-party", step_in_third_party_add); + + ret = swupd_init(SWUPD_NO_ROOT); + if (ret != SWUPD_OK) { + goto finish; + } + + /* TODO implement */ + + swupd_deinit(); + +finish: + progress_finish_steps(ret); + return ret; +} + +#endif diff --git a/src/3rd_party_internal.h b/src/3rd_party_internal.h new file mode 100644 index 00000000..75334e68 --- /dev/null +++ b/src/3rd_party_internal.h @@ -0,0 +1,26 @@ +#ifndef __THIRD_PARTY_INTERNAL_H +#define __THIRD_PARTY_INTERNAL_H + +#include "swupd.h" + +/** + * @file + * @brief Common functions which can be used by 3rd-party add, + * remove, list + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef THIRDPARTY + +/* TODO Implement */ + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/3rd_party_list.c b/src/3rd_party_list.c new file mode 100644 index 00000000..096b4172 --- /dev/null +++ b/src/3rd_party_list.c @@ -0,0 +1,83 @@ +/* + * Software Updater - client side + * + * Copyright © 2019 Intel Corporation. + * + * This program 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, version 2 or later of the License. + * + * This program 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 this program. If not, see . + * + */ + +#define _GNU_SOURCE +#include "3rd_party_internal.h" +#include "config.h" + +#ifdef THIRDPARTY + +static void print_help(void) +{ + print("Usage:\n"); + print(" swupd 3rd-party list\n\n"); + + global_print_help(); + print("\n"); +} + +static const struct global_options opts = { + NULL, + 0, + NULL, + print_help, +}; + +static bool parse_options(int argc, char **argv) +{ + int ind = global_parse_options(argc, argv, &opts); + + if (ind < 0) { + return false; + } + + if (argc > ind) { + error("Unexpected arguments\n\n"); + return false; + } + + return true; +} + +enum swupd_code third_party_list_main(int argc, char **argv) +{ + enum swupd_code ret = SWUPD_OK; + const int step_in_third_party_list = 1; + + if (!parse_options(argc, argv)) { + print_help(); + return SWUPD_INVALID_OPTION; + } + progress_init_steps("third-party", step_in_third_party_list); + + ret = swupd_init(SWUPD_NO_ROOT); + if (ret != SWUPD_OK) { + goto finish; + } + + /* TODO Implement */ + + swupd_deinit(); + +finish: + progress_finish_steps(ret); + return ret; +} + +#endif diff --git a/src/3rd_party_remove.c b/src/3rd_party_remove.c new file mode 100644 index 00000000..c874a066 --- /dev/null +++ b/src/3rd_party_remove.c @@ -0,0 +1,90 @@ +/* + * Software Updater - client side + * + * Copyright © 2019 Intel Corporation. + * + * This program 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, version 2 or later of the License. + * + * This program 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 this program. If not, see . + * + */ + +#define _GNU_SOURCE +#include "3rd_party_internal.h" +#include "config.h" + +#ifdef THIRDPARTY + +static void print_help(void) +{ + print("Usage:\n"); + print(" swupd 3rd-party remove [repo-name]\n\n"); + + global_print_help(); + print("\n"); +} + +static const struct global_options opts = { + NULL, + 0, + NULL, + print_help, +}; + +static bool parse_options(int argc, char **argv) +{ +#define EXACT_ARG_COUNT 1 + int ind = global_parse_options(argc, argv, &opts); + + if (ind < 0) { + return false; + } + + if (argc == 1) { + error("The positional args: repo-name is missing\n\n"); + return false; + } + + /* Ensure that repo remove only expects only one arg: repo-name */ + if ((argc - ind) != EXACT_ARG_COUNT) { + error("Unexpected arguments\n\n"); + return false; + } + + return true; +} + +enum swupd_code third_party_remove_main(int argc, char **argv) +{ + enum swupd_code ret = SWUPD_OK; + const int step_in_third_party_remove = 1; + + if (!parse_options(argc, argv)) { + print_help(); + return SWUPD_INVALID_OPTION; + } + progress_init_steps("third-party", step_in_third_party_remove); + + ret = swupd_init(SWUPD_NO_ROOT); + if (ret != SWUPD_OK) { + goto finish; + } + + /* TODO Implement */ + + swupd_deinit(); + +finish: + progress_finish_steps(ret); + return ret; +} + +#endif diff --git a/src/main.c b/src/main.c index 7caa5903..d6a9a1b8 100644 --- a/src/main.c +++ b/src/main.c @@ -28,12 +28,6 @@ #include "swupd_build_opts.h" #include "swupd_internal.h" -struct subcmd { - char *name; - char *doc; - enum swupd_code (*mainfunc)(int, char **); -}; - static enum swupd_code external_search_main(int argc, char **argv) { int ret; @@ -49,7 +43,7 @@ static enum swupd_code external_search_main(int argc, char **argv) // TODO(castulo): remove the superseded command from the help menu by end of November 2019, // so it is not visible but the command must remain available in the back so we don't break users -static struct subcmd commands[] = { +static struct subcmd main_commands[] = { { "info", "Show the version and the update URLs", info_main }, { "autoupdate", "Enable/disable automatic system updates", autoupdate_main }, { "check-update", "Check if a new OS version is available", check_update_main }, @@ -91,7 +85,7 @@ static void print_help(const char *name) print(" -v, --version Output version information and exit\n\n"); print("Subcommands:\n"); - struct subcmd *entry = commands; + struct subcmd *entry = main_commands; while (entry->name != NULL) { print(" %-20s %-30s\n", entry->name, entry->doc); @@ -115,27 +109,6 @@ static void print_compile_opts(void) info("Compile-time configuration:\n%s\n", BUILD_CONFIGURE); } -static int subcmd_index(char *arg) -{ - struct subcmd *entry = commands; - int i = 0; - size_t input_len; - size_t cmd_len; - - input_len = strlen(arg); - - while (entry->name != NULL) { - cmd_len = strlen(entry->name); - if (cmd_len == input_len && strcmp(arg, entry->name) == 0) { - return i; - } - entry++; - i++; - } - - return -1; -} - static int parse_options(int argc, char **argv, int *index) { int opt; @@ -153,7 +126,7 @@ static int parse_options(int argc, char **argv, int *index) exit(EXIT_SUCCESS); case '\01': /* found a subcommand, or a random non-option argument */ - ret = subcmd_index(optarg); + ret = subcmd_index(optarg, main_commands); if (ret < 0) { error("unrecognized subcommand `%s'\n\n", optarg); @@ -204,7 +177,7 @@ int main(int argc, char **argv) */ optind = 0; - ret = commands[index].mainfunc(argc - 1, argv + 1); + ret = main_commands[index].mainfunc(argc - 1, argv + 1); return ret; } diff --git a/src/swupd_internal.h b/src/swupd_internal.h index 6c0d8f38..ed33458d 100644 --- a/src/swupd_internal.h +++ b/src/swupd_internal.h @@ -1,6 +1,9 @@ #ifndef __SWUPD_INTERNAL__ #define __SWUPD_INTERNAL__ +#include +#include + #ifdef __cplusplus extern "C" { #endif @@ -22,6 +25,57 @@ enum swupd_code repair_main(int argc, char **argv); enum swupd_code diagnose_main(int argc, char **argv); enum swupd_code bundle_info_main(int argc, char **argv); enum swupd_code verify_main(int argc, char **argv); +enum swupd_code third_party_main(int argc, char **argv); + +/** + * @brief Creates a new third-party repo under THIRDPARTY_REPO_PREFIX + * if it does not exist + * + * @return SWUPD_OK on success + */ +extern enum swupd_code third_party_add_main(int argc, char **argv); + +/** + * @brief Removes a third-party repo under THIRDPARTY_REPO_PREFIX + * if it does exist + * + * @return SWUPD_OK on success + */ +extern enum swupd_code third_party_remove_main(int argc, char **argv); + +/** + * @brief Lists all the third-party repos under THIRDPARTY_REPO_PREFIX + * + * @return SWUPD_OK on success + */ +extern enum swupd_code third_party_list_main(int argc, char **argv); + +struct subcmd { + char *name; + char *doc; + enum swupd_code (*mainfunc)(int, char **); +}; + +static inline int subcmd_index(char *arg, struct subcmd *commands) +{ + struct subcmd *entry = commands; + int i = 0; + size_t input_len; + size_t cmd_len; + + input_len = strlen(arg); + + while (entry->name != NULL) { + cmd_len = strlen(entry->name); + if (cmd_len == input_len && strcmp(arg, entry->name) == 0) { + return i; + } + entry++; + i++; + } + + return -1; +} #ifdef __cplusplus } diff --git a/swupd.bash b/swupd.bash index 4d8b4ce8..ea1de16b 100644 --- a/swupd.bash +++ b/swupd.bash @@ -28,7 +28,9 @@ _swupd() for ((i=COMP_CWORD-1;i>=0;i--)) do case "${COMP_WORDS[$i]}" in ("$1") - opts="--help --version autoupdate bundle-add bundle-remove bundle-list hashdump update diagnose check-update search search-file info clean mirror os-install repair verify " + opts="--help --version autoupdate bundle-add bundle-remove + bundle-list hashdump update diagnose check-update search + search-file info clean mirror os-install repair verify 3rd-party" break;; ("info") opts="$global " @@ -81,6 +83,15 @@ _swupd() ("verify") opts="$global --version --manifest --fix --picky --picky-tree --picky-whitelist --install --quick --force --install " break;; + ("3rd-party") + opts="$global add remove list" + break;; + ("add") + opts="$global --repo" + break;; + ("remove") + opts="$global --repo" + break;; esac done # Add in additional completion options if we need to diff --git a/swupd.zsh b/swupd.zsh index 36652490..956039b9 100644 --- a/swupd.zsh +++ b/swupd.zsh @@ -175,6 +175,7 @@ if [[ -n "$state" ]]; then "mirror:Configure mirror url for swupd content" "clean:Clean cached files" "hashdump:Dump the HMAC hash of a file" + "3rd-party: Indicate Swupd to use user's third party repo" ) _describe -t subcmds 'swupd subcommand' subcmds && ret=0 ;; @@ -183,6 +184,32 @@ if [[ -n "$state" ]]; then info) _arguments $global_opts && ret=0 ;; + 3rd-party) + local -a thirdparty; thirdparty=( + $global_opt + '(help)list[List third party repo(s)]' + '(help)remove[Remove third party repo]' + '(help)add[Add third party repo]' + _arguments $thirdparty && ret=0 + ;; + add) + local -a add; add=( + $global_opt + '(help)Positional arg: [repo-name]' + '(help)Positional arg: [repo-url]' + _arguments $add && ret=0 + ;; + remove) + local -a remove; remove=( + $global_opt + '(help)Positional arg: [repo-name]' + _arguments $remove && ret=0 + ;; + list) + local -a list; list=( + $global_opt + _arguments $list && ret=0 + ;; autoupdate) local -a autoupdates; autoupdates=( $global_opts