From 3a998e10218c318511b41739f276e572c1ede967 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 25 Jun 2024 17:10:01 +0100 Subject: [PATCH] auc: remove package With 'owut' there is now a much better alternative available. Retire and remove 'auc' in favor of 'owut'. Signed-off-by: Daniel Golle --- utils/auc/Makefile | 36 - utils/auc/src/CMakeLists.txt | 12 - utils/auc/src/auc.c | 2196 ---------------------------------- 3 files changed, 2244 deletions(-) delete mode 100644 utils/auc/Makefile delete mode 100644 utils/auc/src/CMakeLists.txt delete mode 100644 utils/auc/src/auc.c diff --git a/utils/auc/Makefile b/utils/auc/Makefile deleted file mode 100644 index bec42a1ddf..0000000000 --- a/utils/auc/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=auc -PKG_VERSION:=0.3.2 -PKG_RELEASE:=1 -PKG_LICENSE:=GPL-3.0 - -include $(INCLUDE_DIR)/package.mk -include $(INCLUDE_DIR)/cmake.mk - -define Package/auc - SECTION:=base - CATEGORY:=Base system - TITLE:=Attended sysUpgrade CLI (EXPERIMENTAL) - DEPENDS:=+attendedsysupgrade-common +libblobmsg-json +libubox +libubus \ - +libuci +libuclient +rpcd-mod-rpcsys -endef - -define Package/auc/description - CLI client for attended-sysupgrade -endef - -EXTRA_CFLAGS += \ - -D'AUC_VERSION=\"$(PKG_VERSION)-$(PKG_RELEASE)\"' \ - $(if $(CONFIG_DEBUG),-DAUC_DEBUG=ON) - -define Package/auc/install - $(INSTALL_DIR) $(1)/usr/sbin - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/auc $(1)/usr/sbin/ -endef - -$(eval $(call BuildPackage,auc)) diff --git a/utils/auc/src/CMakeLists.txt b/utils/auc/src/CMakeLists.txt deleted file mode 100644 index 14cc199ce2..0000000000 --- a/utils/auc/src/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -cmake_minimum_required(VERSION 2.6...3.12) - -PROJECT(auc C) -ADD_DEFINITIONS(-Os -ggdb -Wall --std=gnu99 -Wmissing-declarations) - -SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") - -find_library(json NAMES json-c json) - -ADD_EXECUTABLE(auc auc.c) -TARGET_LINK_LIBRARIES(auc uci ubox ubus uclient blobmsg_json ${json} ${CMAKE_DL_LIBS}) -INSTALL(TARGETS auc RUNTIME DESTINATION sbin) diff --git a/utils/auc/src/auc.c b/utils/auc/src/auc.c deleted file mode 100644 index 43940ff2a2..0000000000 --- a/utils/auc/src/auc.c +++ /dev/null @@ -1,2196 +0,0 @@ -/* - * auc - attendedsysUpgrade CLI - * Copyright (C) 2017-2021 Daniel Golle - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 - * as published by the Free Software Foundation - * - * 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. - */ - -#define _GNU_SOURCE -#ifndef AUC_VERSION -#define AUC_VERSION "unknown" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define REQ_TIMEOUT 15 - -#define API_BRANCHES "branches" -#define API_INDEX "index" -#define API_JSON "json" -#define API_JSON_VERSION "v1" -#define API_JSON_EXT "." API_JSON -#define API_PACKAGES "packages" -#define API_REQUEST "api/v1/build" -#define API_STATUS_QUEUED "queued" -#define API_STATUS_STARTED "started" -#define API_STORE "store" -#define API_TARGETS "targets" - -#define PUBKEY_PATH "/etc/opkg/keys" -#define SHA256SUM "/bin/busybox sha256sum" - -#ifdef AUC_DEBUG -#define DPRINTF(...) if (debug) fprintf(stderr, __VA_ARGS__) -#else -#define DPRINTF(...) -#endif - -static const char server_issues[]="https://github.com/openwrt/asu/issues"; - -static struct ubus_context *ctx; -static struct uclient *ucl = NULL; -static char user_agent[80]; -static char *serverurl; -static int upgrade_packages; -static struct ustream_ssl_ctx *ssl_ctx; -static const struct ustream_ssl_ops *ssl_ops; -static off_t out_bytes; -static off_t out_len; -static off_t out_offset; -static bool cur_resume; -static int output_fd = -1; -static bool retry = false; -static char *board_name = NULL; -static char *target = NULL; -static char *distribution = NULL, *version = NULL, *revision = NULL; -static char *rootfs_type = NULL; -static int uptodate; -static char *filename = NULL; -static void *dlh = NULL; -static int rc; -static bool dont_ask = false; - -static int avl_verrevcmp(const void *k1, const void *k2, void *ptr); - -struct branch { - struct avl_node avl; - char *name; - char *git_branch; - char *path_packages; - char *arch_packages; - char **repos; - struct avl_tree versions; - struct list_head package_changes; - bool snapshot; - unsigned int branch_off_rev; -}; -static struct avl_tree branches = AVL_TREE_INIT(branches, avl_verrevcmp, false, NULL); - -struct branch_version { - struct avl_node avl; - struct branch *branch; - char *path; - char *version; - char *version_code; - char *version_number; - bool snapshot; -}; - -struct package_changes { - struct list_head list; - unsigned int revision; - char *source; - char *target; - bool mandatory; -}; -static LIST_HEAD(selected_package_changes); - -struct avl_pkg { - struct avl_node avl; - char *name; - char *version; -}; -static struct avl_tree pkg_tree = AVL_TREE_INIT(pkg_tree, avl_strcmp, false, NULL); - -#ifdef AUC_DEBUG -static int debug = 0; -#endif - -/* - * policy for ubus call system board - * see procd/system.c - */ -enum { - BOARD_BOARD_NAME, - BOARD_RELEASE, - BOARD_ROOTFS_TYPE, - __BOARD_MAX, -}; - -static const struct blobmsg_policy board_policy[__BOARD_MAX] = { - [BOARD_BOARD_NAME] = { .name = "board_name", .type = BLOBMSG_TYPE_STRING }, - [BOARD_RELEASE] = { .name = "release", .type = BLOBMSG_TYPE_TABLE }, - [BOARD_ROOTFS_TYPE] = { .name = "rootfs_type", .type = BLOBMSG_TYPE_STRING }, -}; - -/* - * policy for release information in system board reply - * see procd/system.c - */ -enum { - RELEASE_DISTRIBUTION, - RELEASE_REVISION, - RELEASE_TARGET, - RELEASE_VERSION, - __RELEASE_MAX, -}; - -static const struct blobmsg_policy release_policy[__RELEASE_MAX] = { - [RELEASE_DISTRIBUTION] = { .name = "distribution", .type = BLOBMSG_TYPE_STRING }, - [RELEASE_REVISION] = { .name = "revision", .type = BLOBMSG_TYPE_STRING }, - [RELEASE_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING }, - [RELEASE_VERSION] = { .name = "version", .type = BLOBMSG_TYPE_STRING }, -}; - -/* - * policy for package list returned from rpc-sys or from server - * see rpcd/sys.c and ASU sources - */ -enum { - PACKAGES_ARCHITECTURE, - PACKAGES_PACKAGES, - __PACKAGES_MAX, -}; - -static const struct blobmsg_policy packages_policy[__PACKAGES_MAX] = { - [PACKAGES_ARCHITECTURE] = { .name = "architecture", .type = BLOBMSG_TYPE_STRING }, - [PACKAGES_PACKAGES] = { .name = "packages", .type = BLOBMSG_TYPE_TABLE }, -}; - -/* - * policy for upgrade_test - * see rpcd/sys.c - */ -enum { - UPGTEST_CODE, - UPGTEST_STDERR, - __UPGTEST_MAX, -}; - -static const struct blobmsg_policy upgtest_policy[__UPGTEST_MAX] = { - [UPGTEST_CODE] = { .name = "code", .type = BLOBMSG_TYPE_INT32 }, - [UPGTEST_STDERR] = { .name = "stderr", .type = BLOBMSG_TYPE_STRING }, -}; - -/* - * policy for branches.json - */ -enum { - BRANCH_ENABLED, - BRANCH_GIT_BRANCH, - BRANCH_BRANCH_OFF_REV, - BRANCH_NAME, - BRANCH_PATH, - BRANCH_PATH_PACKAGES, - BRANCH_SNAPSHOT, - BRANCH_REPOS, - BRANCH_TARGETS, - BRANCH_UPDATES, - BRANCH_VERSIONS, - BRANCH_PACKAGE_CHANGES, - __BRANCH_MAX, -}; - -static const struct blobmsg_policy branches_policy[__BRANCH_MAX] = { - [BRANCH_ENABLED] = { .name = "enabled", .type = BLOBMSG_TYPE_BOOL }, - [BRANCH_GIT_BRANCH] = { .name = "git_branch", .type = BLOBMSG_TYPE_STRING }, - [BRANCH_BRANCH_OFF_REV] = { .name = "branch_off_rev", .type = BLOBMSG_TYPE_INT32 }, - [BRANCH_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, - [BRANCH_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, - [BRANCH_PATH_PACKAGES] = { .name = "path_packages", .type = BLOBMSG_TYPE_STRING }, - [BRANCH_SNAPSHOT] = { .name = "snapshot", .type = BLOBMSG_TYPE_BOOL }, - [BRANCH_REPOS] = { .name = "repos", .type = BLOBMSG_TYPE_ARRAY }, - [BRANCH_TARGETS] = { .name = "targets", .type = BLOBMSG_TYPE_TABLE }, - [BRANCH_UPDATES] = { .name = "updates", .type = BLOBMSG_TYPE_STRING }, - [BRANCH_VERSIONS] = { .name = "versions", .type = BLOBMSG_TYPE_ARRAY }, - [BRANCH_PACKAGE_CHANGES] = { .name = "package_changes", .type = BLOBMSG_TYPE_ARRAY }, -}; - -enum { - PACKAGE_CHANGES_SOURCE, - PACKAGE_CHANGES_TARGET, - PACKAGE_CHANGES_REVISION, - PACKAGE_CHANGES_MANDATORY, - __PACKAGE_CHANGES_MAX, -}; - -static const struct blobmsg_policy package_changes_policy[__PACKAGE_CHANGES_MAX] = { - [PACKAGE_CHANGES_SOURCE] = { .name = "source", .type = BLOBMSG_TYPE_STRING }, - [PACKAGE_CHANGES_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING }, - [PACKAGE_CHANGES_REVISION] = { .name = "revision", .type = BLOBMSG_TYPE_INT32 }, - [PACKAGE_CHANGES_MANDATORY] = { .name = "mandatory", .type = BLOBMSG_TYPE_BOOL }, -}; - -/* - * shared policy for target.json and server image request reply - */ -enum { - TARGET_ARCH_PACKAGES, - TARGET_BINDIR, - TARGET_DEVICE_PACKAGES, - TARGET_ENQUEUED_AT, - TARGET_IMAGES, - TARGET_DETAIL, - TARGET_MANIFEST, - TARGET_METADATA_VERSION, - TARGET_REQUEST_HASH, - TARGET_QUEUE_POSITION, - TARGET_STATUS, - TARGET_STDERR, - TARGET_STDOUT, - TARGET_TARGET, - TARGET_TITLES, - TARGET_VERSION_CODE, - TARGET_VERSION_NUMBER, - __TARGET_MAX, -}; - -static const struct blobmsg_policy target_policy[__TARGET_MAX] = { - [TARGET_ARCH_PACKAGES] = { .name = "arch_packages", .type = BLOBMSG_TYPE_STRING }, - [TARGET_BINDIR] = { .name = "bin_dir", .type = BLOBMSG_TYPE_STRING }, - [TARGET_DEVICE_PACKAGES] = { .name = "device_packages", .type = BLOBMSG_TYPE_ARRAY }, - [TARGET_ENQUEUED_AT] = { .name = "enqueued_at", .type = BLOBMSG_TYPE_STRING }, - [TARGET_IMAGES] = { .name = "images", .type = BLOBMSG_TYPE_ARRAY }, - [TARGET_MANIFEST] = { .name = "manifest", .type = BLOBMSG_TYPE_TABLE }, - [TARGET_DETAIL] = { .name = "detail", .type = BLOBMSG_TYPE_STRING }, - [TARGET_METADATA_VERSION] = { .name = "metadata_version", .type = BLOBMSG_TYPE_INT32 }, - [TARGET_REQUEST_HASH] = { .name = "request_hash", .type = BLOBMSG_TYPE_STRING }, - [TARGET_QUEUE_POSITION] = { .name = "queue_position", .type = BLOBMSG_TYPE_INT32 }, - [TARGET_STATUS] = { .name = "status", .type = BLOBMSG_TYPE_STRING }, - [TARGET_STDERR] = { .name = "stderr", .type = BLOBMSG_TYPE_STRING }, - [TARGET_STDOUT] = { .name = "stdout", .type = BLOBMSG_TYPE_STRING }, - [TARGET_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING }, - [TARGET_TITLES] = { .name = "titles", .type = BLOBMSG_TYPE_ARRAY }, - [TARGET_VERSION_CODE] = { .name = "version_code", .type = BLOBMSG_TYPE_STRING }, - [TARGET_VERSION_NUMBER] = { .name = "version_number", .type = BLOBMSG_TYPE_STRING }, -}; - -/* - * policy for images object in target - */ -enum { - IMAGES_FILESYSTEM, - IMAGES_NAME, - IMAGES_SHA256, - IMAGES_TYPE, - __IMAGES_MAX, -}; - -static const struct blobmsg_policy images_policy[__IMAGES_MAX] = { - [IMAGES_FILESYSTEM] = { .name = "filesystem", .type = BLOBMSG_TYPE_STRING }, - [IMAGES_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, - [IMAGES_SHA256] = { .name = "sha256", .type = BLOBMSG_TYPE_STRING }, - [IMAGES_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING }, -}; - -/* - * generic policy for HTTP JSON reply - */ -enum { - REPLY_ARRAY, - REPLY_OBJECT, - __REPLY_MAX, -}; - -static const struct blobmsg_policy reply_policy[__REPLY_MAX] = { - [REPLY_ARRAY] = { .name = "reply", .type = BLOBMSG_TYPE_ARRAY }, - [REPLY_OBJECT] = { .name = "reply", .type = BLOBMSG_TYPE_TABLE }, -}; - -/* - * policy for HTTP headers received from server - */ -enum { - H_LEN, - H_RANGE, - H_UNKNOWN_PACKAGE, - H_QUEUE_POSITION, - __H_MAX -}; - -static const struct blobmsg_policy header_policy[__H_MAX] = { - [H_LEN] = { .name = "content-length", .type = BLOBMSG_TYPE_STRING }, - [H_RANGE] = { .name = "content-range", .type = BLOBMSG_TYPE_STRING }, - [H_UNKNOWN_PACKAGE] = { .name = "x-unknown-package", .type = BLOBMSG_TYPE_STRING }, - [H_QUEUE_POSITION] = { .name = "x-queue-position", .type = BLOBMSG_TYPE_INT32 }, -}; - -/* - * load serverurl from UCI - */ -static int load_config() { - struct uci_context *uci_ctx; - struct uci_package *uci_attendedsysupgrade; - struct uci_section *uci_s; - char *url; - - uci_ctx = uci_alloc_context(); - if (!uci_ctx) - return -1; - - uci_ctx->flags &= ~UCI_FLAG_STRICT; - - if (uci_load(uci_ctx, "attendedsysupgrade", &uci_attendedsysupgrade) || - !uci_attendedsysupgrade) { - fprintf(stderr, "Failed to load attendedsysupgrade config\n"); - return -1; - } - uci_s = uci_lookup_section(uci_ctx, uci_attendedsysupgrade, "server"); - if (!uci_s) { - fprintf(stderr, "Failed to read server config section\n"); - return -1; - } - url = uci_lookup_option_string(uci_ctx, uci_s, "url"); - if (!url) { - fprintf(stderr, "Failed to read server url from config\n"); - return -1; - } - if (strncmp(url, "https://", strlen("https://")) && - strncmp(url, "http://", strlen("http://"))) { - fprintf(stderr, "Server url invalid (needs to be http://... or https://...)\n"); - return -1; - } - - serverurl = strdup(url); - - uci_s = uci_lookup_section(uci_ctx, uci_attendedsysupgrade, "client"); - if (!uci_s) { - fprintf(stderr, "Failed to read client config\n"); - return -1; - } - upgrade_packages = atoi(uci_lookup_option_string(uci_ctx, uci_s, "upgrade_packages")); - - uci_free_context(uci_ctx); - - return 0; -} - -/* - * libdpkg - Debian packaging suite library routines - * vercmp.c - comparison of version numbers - * - * Copyright (C) 1995 Ian Jackson - */ - -/* assume ascii; warning: evaluates x multiple times! */ -#define order(x) ((x) == '~' ? -1 \ - : isdigit((x)) ? 0 \ - : !(x) ? 0 \ - : isalpha((x)) ? (x) \ - : (x) + 256) - -static int verrevcmp(const char *val, const char *ref) -{ - if (!val) - val = ""; - if (!ref) - ref = ""; - - while (*val || *ref) { - int first_diff = 0; - - while ((*val && !isdigit(*val)) || (*ref && !isdigit(*ref))) { - int vc = order(*val), rc = order(*ref); - if (vc != rc) - return vc - rc; - val++; - ref++; - } - - while (*val == '0') - val++; - while (*ref == '0') - ref++; - while (isdigit(*val) && isdigit(*ref)) { - if (!first_diff) - first_diff = *val - *ref; - val++; - ref++; - } - if (isdigit(*val)) - return 1; - if (isdigit(*ref)) - return -1; - if (first_diff) - return first_diff; - } - return 0; -} - -static int avl_verrevcmp(const void *k1, const void *k2, void *ptr) -{ - const char *d1 = (const char *)k1, *d2 = (const char*)k2; - - return verrevcmp(d1, d2); -} - -/* - * replace '-rc' by '~' in string - */ -static inline void release_replace_rc(char *ver) -{ - char *tmp; - - tmp = strstr(ver, "-rc"); - if (tmp && strlen(tmp) > 3) { - *tmp = '~'; - memmove(tmp + 1, tmp + 3, strlen(tmp + 3) + 1); - } -} - -/* - * OpenWrt release version string comperator - * replaces '-rc' by '~' to fix ordering of release(s) (candidates) - * using the void release_replace_rc(char *ver) function above. - */ -static int openwrt_release_verrevcmp(const char *ver1, const char *ver2) -{ - char mver1[16], mver2[16]; - - strncpy(mver1, ver1, sizeof(mver1) - 1); - mver1[sizeof(mver1) - 1] = '\0'; - strncpy(mver2, ver2, sizeof(mver2) - 1); - mver2[sizeof(mver2) - 1] = '\0'; - - release_replace_rc(mver1); - release_replace_rc(mver2); - - return verrevcmp(mver1, mver2); -} - -/* - * Select package_changes from branch to global list - */ -static void grab_changes(struct branch *br, unsigned int rev) -{ - struct package_changes *c, *n; - -#ifdef AUC_DEBUG - if (debug) - fprintf(stderr, "grabbing changes for branch %s from revision %u\n", br->name, rev); -#endif - - list_for_each_entry(c, &br->package_changes, list) { - if (c->revision == 0 || c->revision > rev) { - n = malloc(sizeof(struct package_changes)); - memcpy(n, c, sizeof(struct package_changes)); - INIT_LIST_HEAD(&n->list); - list_add_tail(&n->list, &selected_package_changes); - } - } -} - -/** - * UBUS response callbacks - */ -/* - * rpc-sys packagelist - * append array of package names to blobbuf given in req->priv - */ -#define ANSI_ESC "\x1b" -#define ANSI_COLOR_RESET ANSI_ESC "[0m" -#define ANSI_COLOR_RED ANSI_ESC "[1;31m" -#define ANSI_COLOR_GREEN ANSI_ESC "[1;32m" -#define ANSI_COLOR_BLUE ANSI_ESC "[1;34m" -#define ANSI_CURSOR_SAFE "[s" -#define ANSI_CURSOR_RESTORE "[u" -#define ANSI_ERASE_LINE "[K" - -#define PKG_UPGRADE 0x1 -#define PKG_DOWNGRADE 0x2 -#define PKG_NOT_FOUND 0x4 -#define PKG_ERROR 0x8 - -static bool ask_user(const char *message) -{ - char user_input; - fflush(stdin); - fprintf(stderr, "%s [N/y] ", message); - user_input = getchar(); - fflush(stdin); - if ((user_input == 'y') || (user_input == 'Y')) - return true; - - return false; -} - -static inline bool is_builtin_pkg(const char *pkgname) -{ - return !strcmp(pkgname, "libc") || - !strcmp(pkgname, "librt") || - !strcmp(pkgname, "libpthread") || - !strcmp(pkgname, "kernel"); -} - -static const char *apply_package_changes(const char *pkgname, bool interactive) -{ - struct package_changes *pkc; - const char *mpkgname = pkgname; - - list_for_each_entry(pkc, &selected_package_changes, list) { - /* package_change additions are dealt with later */ - if (!pkc->source) - continue; - - if (strcmp(pkc->source, mpkgname)) - continue; - - if (!pkc->mandatory && interactive) { - if (pkc->target) - fprintf(stderr, "Package %s should be replaced by %s.\n", pkc->source, pkc->target); - else - fprintf(stderr, "Package %s should be removed.\n", pkc->source); - - if (dont_ask) - pkc->mandatory = true; - else - pkc->mandatory = ask_user("Apply change"); - } - - if (!pkc->mandatory) - continue; - - mpkgname = pkc->target; - - if (!mpkgname) - break; - } - return mpkgname; -} - -static void pkglist_check_cb(struct ubus_request *req, int type, struct blob_attr *msg) -{ - int *status = (int *)req->priv; - struct blob_attr *tb[__PACKAGES_MAX], *cur; - struct avl_pkg *pkg; - int rem; - int cmpres; - const char *pkgname; - struct package_changes *pkc; - - blobmsg_parse(packages_policy, __PACKAGES_MAX, tb, blobmsg_data(msg), blobmsg_len(msg)); - - if (!tb[PACKAGES_PACKAGES]) - return; - - blobmsg_for_each_attr(cur, tb[PACKAGES_PACKAGES], rem) { - pkgname = blobmsg_name(cur); - if (is_builtin_pkg(pkgname)) - continue; - - pkgname = apply_package_changes(pkgname, true); - if (!pkgname) { - fprintf(stderr, " %s: %s%s -> (not installed)%s\n", - blobmsg_name(cur), ANSI_COLOR_BLUE, - blobmsg_get_string(cur), ANSI_COLOR_RESET); - continue; - } - - pkg = avl_find_element(&pkg_tree, pkgname, pkg, avl); - if (!pkg) { - fprintf(stderr, "installed package %s%s%s cannot be found in remote list!\n", - ANSI_COLOR_RED, pkgname, ANSI_COLOR_RESET); - *status |= PKG_NOT_FOUND; - continue; - } - - if (pkgname != blobmsg_name(cur)) { - fprintf(stderr, " %s%s: %s -> %s: %s%s\n", ANSI_COLOR_BLUE, - blobmsg_name(cur), - blobmsg_get_string(cur), pkgname, pkg->version, - ANSI_COLOR_RESET); - *status |= PKG_UPGRADE; - continue; - } - - cmpres = verrevcmp(blobmsg_get_string(cur), pkg->version); - if (cmpres < 0) - *status |= PKG_UPGRADE; - - if (cmpres > 0) - *status |= PKG_DOWNGRADE; - - if (cmpres -#ifdef AUC_DEBUG - || debug -#endif - ) - fprintf(stderr, " %s: %s%s -> %s%s\n", blobmsg_name(cur), - (!cmpres)?"":(cmpres > 0)?ANSI_COLOR_RED:ANSI_COLOR_GREEN, - blobmsg_get_string(cur), pkg->version, - (cmpres)?ANSI_COLOR_RESET:""); - } - - list_for_each_entry(pkc, &selected_package_changes, list) { - /* deal only with package_change additions now */ - if (pkc->source) - continue; - - pkg = avl_find_element(&pkg_tree, pkc->target, pkg, avl); - if (!pkg) { - fprintf(stderr, "new package %s%s%s cannot be found in remote list!\n", - ANSI_COLOR_RED, pkc->target, ANSI_COLOR_RESET); - *status |= PKG_NOT_FOUND; - continue; - } - fprintf(stderr, " %s: %s(not installed) -> %s%s\n", pkc->target, ANSI_COLOR_BLUE, - pkg->version, ANSI_COLOR_RESET); - } -} - -/* - * rpc-sys packagelist - * append array of package names to blobbuf given in req->priv - */ -static void pkglist_req_cb(struct ubus_request *req, int type, struct blob_attr *msg) { - struct blob_buf *buf = (struct blob_buf *)req->priv; - struct blob_attr *tb[__PACKAGES_MAX]; - struct blob_attr *cur; - int rem; - struct avl_pkg *pkg; - void *table; - const char *pkgname; - struct package_changes *pkc; - - blobmsg_parse(packages_policy, __PACKAGES_MAX, tb, blob_data(msg), blob_len(msg)); - - if (!tb[PACKAGES_PACKAGES]) { - fprintf(stderr, "No packagelist received\n"); - return; - } - - table = blobmsg_open_table(buf, "packages_versions"); - - blobmsg_for_each_attr(cur, tb[PACKAGES_PACKAGES], rem) { - pkgname = blobmsg_name(cur); - if (is_builtin_pkg(pkgname)) - continue; - - pkgname = apply_package_changes(pkgname, false); - pkg = avl_find_element(&pkg_tree, pkgname, pkg, avl); - if (!pkg) - continue; - - blobmsg_add_string(buf, pkgname, pkg->version); - } - - list_for_each_entry(pkc, &selected_package_changes, list) { - /* add new packages to request */ - if (pkc->source) - continue; - - pkg = avl_find_element(&pkg_tree, pkc->target, pkg, avl); - if (!pkg) - continue; - - blobmsg_add_string(buf, pkc->target, pkg->version); - } - blobmsg_close_table(buf, table); -}; - -/* - * system board - * append append board information to blobbuf given in req->priv - * populate board and release global strings - */ -static void board_cb(struct ubus_request *req, int type, struct blob_attr *msg) { - struct blob_buf *buf = (struct blob_buf *)req->priv; - struct blob_attr *tb[__BOARD_MAX]; - struct blob_attr *rel[__RELEASE_MAX]; - - blobmsg_parse(board_policy, __BOARD_MAX, tb, blob_data(msg), blob_len(msg)); - - - if (!tb[BOARD_RELEASE]) { - fprintf(stderr, "No release received\n"); - rc=-ENODATA; - return; - } - - blobmsg_parse(release_policy, __RELEASE_MAX, rel, - blobmsg_data(tb[BOARD_RELEASE]), blobmsg_data_len(tb[BOARD_RELEASE])); - - if (!rel[RELEASE_TARGET] || - !rel[RELEASE_DISTRIBUTION] || - !rel[RELEASE_VERSION] || - !rel[RELEASE_REVISION]) { - fprintf(stderr, "No release information received\n"); - rc=-ENODATA; - return; - } - - target = strdup(blobmsg_get_string(rel[RELEASE_TARGET])); - distribution = strdup(blobmsg_get_string(rel[RELEASE_DISTRIBUTION])); - version = strdup(blobmsg_get_string(rel[RELEASE_VERSION])); - revision = strdup(blobmsg_get_string(rel[RELEASE_REVISION])); - - if (!strcmp(target, "x86/64") || !strcmp(target, "x86/generic")) { - /* - * ugly work-around ahead: - * ignore board name on generic x86 targets, as image name is always 'generic' - */ - board_name = strdup("generic"); - } else { - if (!tb[BOARD_BOARD_NAME]) { - fprintf(stderr, "No board name received\n"); - rc=-ENODATA; - return; - } - board_name = strdup(blobmsg_get_string(tb[BOARD_BOARD_NAME])); - } - - if (tb[BOARD_ROOTFS_TYPE]) - rootfs_type = strdup(blobmsg_get_string(tb[BOARD_ROOTFS_TYPE])); - - blobmsg_add_string(buf, "target", target); - blobmsg_add_string(buf, "version", version); - blobmsg_add_string(buf, "revision", revision); -} - -/* - * rpc-sys upgrade_test - * check if downloaded file is accepted by sysupgrade - */ -static void upgtest_cb(struct ubus_request *req, int type, struct blob_attr *msg) { - int *valid = (int *)req->priv; - struct blob_attr *tb[__UPGTEST_MAX]; - - blobmsg_parse(upgtest_policy, __UPGTEST_MAX, tb, blob_data(msg), blob_len(msg)); - - if (!tb[UPGTEST_CODE]) { - fprintf(stderr, "No sysupgrade test return code received\n"); - return; - } - - *valid = (blobmsg_get_u32(tb[UPGTEST_CODE]) == 0)?1:0; - - if (tb[UPGTEST_STDERR]) - fprintf(stderr, "%s", blobmsg_get_string(tb[UPGTEST_STDERR])); - else if (*valid == 0) - fprintf(stderr, "image verification failed\n"); - else - fprintf(stderr, "image verification succeeded\n"); -}; - -/** - * uclient stuff - */ -static int open_output_file(const char *path, uint64_t resume_offset) -{ - char *filename = NULL; - int flags; - int ret; - - if (cur_resume) - flags = O_RDWR; - else - flags = O_WRONLY | O_EXCL; - - flags |= O_CREAT; - - filename = uclient_get_url_filename(path, "firmware.bin"); - - fprintf(stderr, "Writing to '%s'\n", filename); - ret = open(filename, flags, 0644); - if (ret < 0) - goto free; - - if (resume_offset && - lseek(ret, resume_offset, SEEK_SET) < 0) { - fprintf(stderr, "Failed to seek %"PRIu64" bytes in output file\n", resume_offset); - close(ret); - ret = -1; - goto free; - } - - out_offset = resume_offset; - out_bytes += resume_offset; - -free: - free(filename); - return ret; -} - -struct jsonblobber { - json_tokener *tok; - struct blob_buf *outbuf; -}; - -static void request_done(struct uclient *cl) -{ - struct jsonblobber *jsb = (struct jsonblobber *)cl->priv; - if (jsb) { - json_tokener_free(jsb->tok); - free(jsb); - }; - - uclient_disconnect(cl); - uloop_end(); -} - -static void header_done_cb(struct uclient *cl) -{ - struct blob_attr *tb[__H_MAX]; - struct jsonblobber *jsb = (struct jsonblobber *)cl->priv; - struct blob_buf *outbuf = NULL; - - if (jsb) - outbuf = jsb->outbuf; - - uint64_t resume_offset = 0, resume_end, resume_size; - - if (uclient_http_redirect(cl)) { - fprintf(stderr, "Redirected to %s on %s\n", cl->url->location, cl->url->host); - - return; - } - - if (cl->status_code == 204 && cur_resume) { - /* Resume attempt failed, try normal download */ - cur_resume = false; - //init_request(cl); - return; - } - - DPRINTF("status code: %d\n", cl->status_code); - DPRINTF("headers:\n%s\n", blobmsg_format_json_indent(cl->meta, true, 0)); - blobmsg_parse(header_policy, __H_MAX, tb, blob_data(cl->meta), blob_len(cl->meta)); - - switch (cl->status_code) { - case 400: - request_done(cl); - rc=-ESRCH; - break; - case 422: - fprintf(stderr, "unknown package '%s' requested.\n", - blobmsg_get_string(tb[H_UNKNOWN_PACKAGE])); - rc=-ENOPKG; - request_done(cl); - break; - case 201: - case 202: - retry = true; - if (!outbuf) - break; - - blobmsg_add_u32(outbuf, "status", cl->status_code); - - if (tb[H_QUEUE_POSITION]) - blobmsg_add_u32(outbuf, "queue_position", blobmsg_get_u32(tb[H_QUEUE_POSITION])); - - break; - case 200: - retry = false; - if (cl->priv) - break; - - if (tb[H_LEN]) - out_len = strtoul(blobmsg_get_string(tb[H_LEN]), NULL, 10); - - output_fd = open_output_file(cl->url->location, resume_offset); - if (output_fd < 0) { - perror("Cannot open output file"); - request_done(cl); - } - break; - case 500: - /* server may reply JSON object */ - break; - - default: - DPRINTF("HTTP error %d\n", cl->status_code); - request_done(cl); - break; - } -} - -static void read_data_cb(struct uclient *cl) -{ - char buf[256]; - int len; - json_object *jsobj; - struct blob_buf *outbuf = NULL; - json_tokener *tok = NULL; - struct jsonblobber *jsb = (struct jsonblobber *)cl->priv; - - if (!jsb) { - while (1) { - len = uclient_read(cl, buf, sizeof(buf)); - if (!len) - return; - - out_bytes += len; - write(output_fd, buf, len); - } - return; - } - - outbuf = jsb->outbuf; - tok = jsb->tok; - - while (1) { - len = uclient_read(cl, buf, sizeof(buf)); - if (!len) - break; - - out_bytes += len; - - jsobj = json_tokener_parse_ex(tok, buf, len); - - if (json_tokener_get_error(tok) == json_tokener_continue) - continue; - - if (json_tokener_get_error(tok) != json_tokener_success) - break; - - if (jsobj) - { - blobmsg_add_json_element(outbuf, "reply", jsobj); - - json_object_put(jsobj); - break; - } - } -} - -static void eof_cb(struct uclient *cl) -{ - if (!cl->data_eof && !uptodate) { - fprintf(stderr, "Connection reset prematurely\n"); - } - request_done(cl); -} - -static void handle_uclient_error(struct uclient *cl, int code) -{ - const char *type = "Unknown error"; - - switch(code) { - case UCLIENT_ERROR_CONNECT: - type = "Connection failed"; - break; - case UCLIENT_ERROR_TIMEDOUT: - type = "Connection timed out"; - break; - case UCLIENT_ERROR_SSL_INVALID_CERT: - type = "Invalid SSL certificate"; - break; - case UCLIENT_ERROR_SSL_CN_MISMATCH: - type = "Server hostname does not match SSL certificate"; - break; - default: - break; - } - - fprintf(stderr, "Connection error: %s\n", type); - - request_done(cl); -} - -static const struct uclient_cb check_cb = { - .header_done = header_done_cb, - .data_read = read_data_cb, - .data_eof = eof_cb, - .error = handle_uclient_error, -}; - -static int server_request(const char *url, struct blob_buf *inbuf, struct blob_buf *outbuf) { - struct jsonblobber *jsb = NULL; - int rc = -ENOENT; - char *post_data; - out_offset = 0; - out_bytes = 0; - out_len = 0; - -#ifdef AUC_DEBUG - if (debug) - fprintf(stderr, "Requesting URL: %s\n", url); -#endif - - if (outbuf) { - jsb = malloc(sizeof(struct jsonblobber)); - jsb->outbuf = outbuf; - jsb->tok = json_tokener_new(); - }; - - if (!ucl) { - ucl = uclient_new(url, NULL, &check_cb); - uclient_http_set_ssl_ctx(ucl, ssl_ops, ssl_ctx, 1); - ucl->timeout_msecs = REQ_TIMEOUT * 1000; - } else { - uclient_set_url(ucl, url, NULL); - } - - ucl->priv = jsb; - - rc = uclient_connect(ucl); - if (rc) - return rc; - - rc = uclient_http_set_request_type(ucl, inbuf?"POST":"GET"); - if (rc) - return rc; - - uclient_http_reset_headers(ucl); - uclient_http_set_header(ucl, "User-Agent", user_agent); - if (inbuf) { - uclient_http_set_header(ucl, "Content-Type", "application/json"); - post_data = blobmsg_format_json(inbuf->head, true); - uclient_write(ucl, post_data, strlen(post_data)); - } - rc = uclient_request(ucl); - if (rc) - return rc; - - uloop_run(); - - return 0; -} - -/** - * ustream-ssl - */ -static int init_ustream_ssl(void) { - glob_t gl; - int i; - - dlh = dlopen("libustream-ssl.so", RTLD_LAZY | RTLD_LOCAL); - if (!dlh) - return -ENOENT; - - ssl_ops = dlsym(dlh, "ustream_ssl_ops"); - if (!ssl_ops) - return -ENOENT; - - ssl_ctx = ssl_ops->context_new(false); - - glob("/etc/ssl/certs/*.crt", 0, NULL, &gl); - if (!gl.gl_pathc) - return -ENOKEY; - - for (i = 0; i < gl.gl_pathc; i++) - ssl_ops->context_add_ca_crt_file(ssl_ctx, gl.gl_pathv[i]); - - return 0; -} - -static char* alloc_replace_var(char *in, const char *var, const char *replace) -{ - char *tmp = in; - char *res = NULL; - char *eptr; - - while ((tmp = strchr(tmp, '{'))) { - ++tmp; - eptr = strchr(tmp, '}'); - if (!eptr) - return NULL; - - if (!strncmp(tmp, var, (unsigned int)(eptr - tmp))) { - asprintf(&res, "%.*s%s%s", - (unsigned int)(tmp - in) - 1, in, replace, eptr + 1); - break; - } - } - - if (!res) - res = strdup(in); - - return res; -} - -static int request_target(struct branch_version *bver, char *url) -{ - static struct blob_buf boardbuf; - struct blob_attr *tbr[__REPLY_MAX], *tb[__TARGET_MAX]; - - blobmsg_buf_init(&boardbuf); - - if ((rc = server_request(url, NULL, &boardbuf))) { - blob_buf_free(&boardbuf); - return rc; - } - - blobmsg_parse(reply_policy, __REPLY_MAX, tbr, blob_data(boardbuf.head), blob_len(boardbuf.head)); - - if (!tbr[REPLY_OBJECT]) - return -ENODATA; - - blobmsg_parse(target_policy, __TARGET_MAX, tb, blobmsg_data(tbr[REPLY_OBJECT]), blobmsg_len(tbr[REPLY_OBJECT])); - - if (!tb[TARGET_METADATA_VERSION] || - !tb[TARGET_ARCH_PACKAGES] || - !tb[TARGET_IMAGES] || - !tb[TARGET_TARGET]) { - blob_buf_free(&boardbuf); - return -ENODATA; - } - - if (blobmsg_get_u32(tb[TARGET_METADATA_VERSION]) != 1) { - blob_buf_free(&boardbuf); - return -EPFNOSUPPORT; - } - - if (strcmp(blobmsg_get_string(tb[TARGET_TARGET]), target)) - return -EINVAL; - - if (strcmp(blobmsg_get_string(tb[TARGET_ARCH_PACKAGES]), bver->branch->arch_packages)) - return -EINVAL; - - if (tb[TARGET_VERSION_CODE]) - bver->version_code = strdup(blobmsg_get_string(tb[TARGET_VERSION_CODE])); - - if (tb[TARGET_VERSION_NUMBER]) - bver->version_number = strdup(blobmsg_get_string(tb[TARGET_VERSION_NUMBER])); - - blob_buf_free(&boardbuf); - return 0; -}; - -static char* validate_target(struct blob_attr *branch) -{ - struct blob_attr *cur; - int rem; - - blobmsg_for_each_attr(cur, branch, rem) - if (!strcmp(blobmsg_name(cur), target)) - return strdup(blobmsg_get_string(cur)); - - return NULL; -} - -static void process_branch(struct blob_attr *branch, bool only_active) -{ - struct blob_attr *tb[__BRANCH_MAX], *pkc[__PACKAGE_CHANGES_MAX]; - struct blob_attr *curver, *curpkc; - int remver, rempkc; - struct branch *br; - struct package_changes *pkce; - char *tmp, *board_json_file; - const char *brname; - - blobmsg_parse(branches_policy, __BRANCH_MAX, tb, blobmsg_data(branch), blobmsg_len(branch)); - - /* mandatory fields */ - if (!(tb[BRANCH_ENABLED] && blobmsg_get_bool(tb[BRANCH_ENABLED]) && - tb[BRANCH_NAME] && tb[BRANCH_PATH] && tb[BRANCH_PATH_PACKAGES] && - tb[BRANCH_VERSIONS] && tb[BRANCH_TARGETS])) - return; - - brname = blobmsg_get_string(tb[BRANCH_NAME]); - if (only_active && strncmp(brname, version, strlen(brname))) - return; - - br = calloc(1, sizeof(struct branch)); - avl_init(&br->versions, avl_verrevcmp, false, NULL); - INIT_LIST_HEAD(&br->package_changes); - - /* check if target is offered in branch and get arch_packages */ - br->arch_packages = validate_target(tb[BRANCH_TARGETS]); - if (!br->arch_packages) { - free(br); - return; - } - - if (tb[BRANCH_GIT_BRANCH]) - br->git_branch = strdup(blobmsg_get_string(tb[BRANCH_GIT_BRANCH])); - - if (tb[BRANCH_BRANCH_OFF_REV]) - br->branch_off_rev = blobmsg_get_u32(tb[BRANCH_BRANCH_OFF_REV]); - else - br->branch_off_rev = 0; - - if (tb[BRANCH_SNAPSHOT]) - br->snapshot = blobmsg_get_bool(tb[BRANCH_SNAPSHOT]); - else - br->snapshot = false; - - br->name = strdup(blobmsg_get_string(tb[BRANCH_NAME])); - br->path_packages = alloc_replace_var(blobmsg_get_string(tb[BRANCH_PATH_PACKAGES]), "branch", br->name); - if (!br->path_packages) { - free(br->name); - free(br->arch_packages); - free(br); - return; - } - - /* parse package changes */ - blobmsg_for_each_attr(curpkc, tb[BRANCH_PACKAGE_CHANGES], rempkc) { - if (blobmsg_type(curpkc) != BLOBMSG_TYPE_TABLE) - continue; - - blobmsg_parse(package_changes_policy, __PACKAGE_CHANGES_MAX, pkc, blobmsg_data(curpkc), blobmsg_len(curpkc)); - if (!pkc[PACKAGE_CHANGES_REVISION] || (!pkc[PACKAGE_CHANGES_SOURCE] && !pkc[PACKAGE_CHANGES_TARGET])) - continue; - - pkce = calloc(1, sizeof(struct package_changes)); - if (!pkce) - break; - - if (pkc[PACKAGE_CHANGES_SOURCE]) - pkce->source = strdup(blobmsg_get_string(pkc[PACKAGE_CHANGES_SOURCE])); - - if (pkc[PACKAGE_CHANGES_TARGET]) - pkce->target = strdup(blobmsg_get_string(pkc[PACKAGE_CHANGES_TARGET])); - - pkce->revision = blobmsg_get_u32(pkc[PACKAGE_CHANGES_REVISION]); - - if (pkc[PACKAGE_CHANGES_MANDATORY]) - pkce->mandatory = blobmsg_get_bool(pkc[PACKAGE_CHANGES_MANDATORY]); - - list_add_tail(&pkce->list, &br->package_changes); - } - - /* add each version of the branch */ - blobmsg_for_each_attr(curver, tb[BRANCH_VERSIONS], remver) { - if (blobmsg_type(curver) != BLOBMSG_TYPE_STRING) - continue; - - struct branch_version *bver = calloc(1, sizeof(struct branch_version)); - bver->snapshot = !!strcasestr(blobmsg_get_string(curver), "snapshot"); - bver->path = alloc_replace_var(blobmsg_get_string(tb[BRANCH_PATH]), "version", blobmsg_get_string(curver)); - if (!bver->path) { - free(bver); - continue; - } - bver->version = strdup(blobmsg_get_string(curver)); - if (!bver->version) { - free(bver->path); - free(bver); - continue; - } - bver->branch = br; - if (asprintf(&board_json_file, "%s/%s/%s/%s/%s/%s/%s%s", serverurl, API_JSON, - API_JSON_VERSION, bver->path, API_TARGETS, target, board_name, - API_JSON_EXT) < 0) { - free(bver->version); - free(bver->path); - free(bver); - continue; - } - tmp = board_json_file; - while ((tmp = strchr(tmp, ','))) - *tmp = '_'; - - if (request_target(bver, board_json_file)) { - free(board_json_file); - free(bver->version); - free(bver->path); - free(bver); - continue; - } - free(board_json_file); - bver->avl.key = bver->version; - avl_insert(&br->versions, &bver->avl); - } - - br->avl.key = br->name; - avl_insert(&branches, &br->avl); -} - -static int request_branches(bool only_active) -{ - static struct blob_buf brbuf; - struct blob_attr *cur; - struct blob_attr *tb[__REPLY_MAX]; - int rem; - char url[256]; - struct blob_attr *data; - - blobmsg_buf_init(&brbuf); - snprintf(url, sizeof(url), "%s/%s/%s/%s%s", serverurl, API_JSON, - API_JSON_VERSION, API_BRANCHES, API_JSON_EXT); - - if ((rc = server_request(url, NULL, &brbuf))) { - blob_buf_free(&brbuf); - return rc; - }; - - blobmsg_parse(reply_policy, __REPLY_MAX, tb, blob_data(brbuf.head), blob_len(brbuf.head)); - - /* newer server API replies OBJECT, older API replies ARRAY... */ - if ((!tb[REPLY_ARRAY] && !tb[REPLY_OBJECT])) - return -ENODATA; - - if (tb[REPLY_OBJECT]) - data = tb[REPLY_OBJECT]; - else - data = tb[REPLY_ARRAY]; - - blobmsg_for_each_attr(cur, data, rem) - process_branch(cur, only_active); - - blob_buf_free(&brbuf); - - return 0; -} - -static void free_branches() -{ - struct branch *br, *tmp; - struct branch_version *bver, *tmp2; - struct package_changes *pkce, *tmp3; - - avl_for_each_element_safe(&branches, br, avl, tmp) { - free(br->name); - free(br->path_packages); - free(br->arch_packages); - - avl_for_each_element_safe(&br->versions, bver, avl, tmp2) { - avl_delete(&br->versions, &bver->avl); - free(bver->version); - free(bver->version_code); - free(bver->version_number); - free(bver->path); - free(bver); - } - - list_for_each_entry_safe(pkce, tmp3, &br->package_changes, list) { - list_del(&pkce->list); - free(pkce->source); - free(pkce->target); - free(pkce); - } - - avl_delete(&branches, &br->avl); - } -} - -static struct branch *get_current_branch() -{ - struct branch *br, *abr = NULL; - - avl_for_each_element(&branches, br, avl) { - /* if branch name doesn't match version *prefix*, skip */ - if (!strncasecmp(br->name, version, strlen(br->name))) { - abr = br; - break; - } - } - - return abr; -} - -static int revision_from_version_code(const char *version_code) -{ - int res; - - if (sscanf(version_code, "r%d-", &res) == 1) - return res; - - return -1; -} - -static struct branch_version *select_branch(char *name, char *select_version) -{ - struct branch *br; - struct branch_version *bver, *abver = NULL; - - if (!name) - name = version; - - avl_for_each_element(&branches, br, avl) { - /* if branch name doesn't match version *prefix*, skip */ - if (strncasecmp(br->name, name, strlen(br->name))) - continue; - - avl_for_each_element(&br->versions, bver, avl) { - if (select_version) { - if (!strcasecmp(bver->version, select_version)) { - abver = bver; - break; - } - } else { - if (!strcasecmp(name, "snapshot")) { - /* we are on the main snapshot branch */ - if (br->snapshot && bver->snapshot) { - abver = bver; - break; - } - } else { - /* skip main snapshot branch */ - if (br->snapshot) - continue; - - if (strcasestr(version, "snapshot")) { - /* we are on a stable snapshot branch or coming from main snapshot branch */ - if (bver->snapshot) { - abver = bver; - break; - } - } else { - if (bver->snapshot) - continue; - - if (!abver || (openwrt_release_verrevcmp(abver->version, bver->version) < 0)) - abver = bver; - } - } - } - } - if (abver) - break; - } - - return abver; -} - -static int add_upg_packages(struct blob_attr *reply, char *arch) -{ - struct blob_attr *tbr[__REPLY_MAX]; - struct blob_attr *tba[__PACKAGES_MAX]; - struct blob_attr *packages; - struct blob_attr *cur; - int rem; - struct avl_pkg *avpk; - - blobmsg_parse(reply_policy, __REPLY_MAX, tbr, blob_data(reply), blob_len(reply)); - - if (!tbr[REPLY_OBJECT]) - return -ENODATA; - - if (arch) { - blobmsg_parse(packages_policy, __PACKAGES_MAX, tba, blobmsg_data(tbr[REPLY_OBJECT]), blobmsg_len(tbr[REPLY_OBJECT])); - if (!tba[PACKAGES_ARCHITECTURE] || - !tba[PACKAGES_PACKAGES]) - return -ENODATA; - - if (strcmp(blobmsg_get_string(tba[PACKAGES_ARCHITECTURE]), arch)) - return -EBADMSG; - - packages = tba[PACKAGES_PACKAGES]; - } else { - packages = tbr[REPLY_OBJECT]; - } - - blobmsg_for_each_attr(cur, packages, rem) { - avpk = calloc(1, sizeof(struct avl_pkg)); - if (!avpk) - return -ENOMEM; - - avpk->name = strdup(blobmsg_name(cur)); - if (!avpk->name) { - free(avpk); - return -ENOMEM; - } - - avpk->version = strdup(blobmsg_get_string(cur)); - if (!avpk->version) { - free(avpk->name); - free(avpk); - return -ENOMEM; - } - - avpk->avl.key = avpk->name; - if (avl_insert(&pkg_tree, &avpk->avl)) { - -#ifdef AUC_DEBUG - if (debug) - fprintf(stderr, "failed to insert package %s (%s)!\n", blobmsg_name(cur), blobmsg_get_string(cur)); -#endif - - if (avpk->name) - free(avpk->name); - - if (avpk->version) - free(avpk->version); - - free(avpk); - } - } - - return 0; -} - -static int request_packages(struct branch_version *bver) -{ - static struct blob_buf pkgbuf, archpkgbuf; - char url[256]; - int ret; - - fprintf(stderr, "Requesting package lists...\n"); - - blobmsg_buf_init(&archpkgbuf); - snprintf(url, sizeof(url), "%s/%s/%s/%s/%s/%s/%s%s", serverurl, API_JSON, - API_JSON_VERSION, bver->path, API_TARGETS, target, API_INDEX, API_JSON_EXT); - if ((rc = server_request(url, NULL, &archpkgbuf))) { - blob_buf_free(&archpkgbuf); - return rc; - }; - - ret = add_upg_packages(archpkgbuf.head, bver->branch->arch_packages); - blob_buf_free(&archpkgbuf); - - if (ret) - return ret; - - blobmsg_buf_init(&pkgbuf); - snprintf(url, sizeof(url), "%s/%s/%s/%s/%s/%s-%s%s", serverurl, API_JSON, - API_JSON_VERSION, bver->path, API_PACKAGES, bver->branch->arch_packages, - API_INDEX, API_JSON_EXT); - if ((rc = server_request(url, NULL, &pkgbuf))) { - blob_buf_free(&archpkgbuf); - blob_buf_free(&pkgbuf); - return rc; - }; - - ret = add_upg_packages(pkgbuf.head, NULL); - blob_buf_free(&pkgbuf); - - return ret; -} - - -static int check_installed_packages(void) -{ - static struct blob_buf allpkg; - uint32_t id; - int status = 0; - - blob_buf_init(&allpkg, 0); - blobmsg_add_u8(&allpkg, "all", 1); - blobmsg_add_string(&allpkg, "dummy", "foo"); - if (ubus_lookup_id(ctx, "rpc-sys", &id) || - ubus_invoke(ctx, id, "packagelist", allpkg.head, pkglist_check_cb, &status, 3000)) { - fprintf(stderr, "cannot request packagelist from rpcd\n"); - status |= PKG_ERROR; - } - - return status; -} - -static int req_add_selected_packages(struct blob_buf *req) -{ - static struct blob_buf allpkg; - uint32_t id; - - blob_buf_init(&allpkg, 0); - blobmsg_add_u8(&allpkg, "all", 0); - blobmsg_add_string(&allpkg, "dummy", "foo"); - if (ubus_lookup_id(ctx, "rpc-sys", &id) || - ubus_invoke(ctx, id, "packagelist", allpkg.head, pkglist_req_cb, req, 3000)) { - fprintf(stderr, "cannot request packagelist from rpcd\n"); - return -EFAULT; - } - - return 0; -} - -#if defined(__amd64__) || defined(__i386__) -static int system_is_efi(void) -{ - const char efidname[] = "/sys/firmware/efi/efivars"; - int fd = open(efidname, O_DIRECTORY | O_PATH); - - if (fd != -1) { - close(fd); - return 1; - } else { - return 0; - } -} -#else -static inline int system_is_efi(void) { return 0; } -#endif - -static int get_image_by_type(struct blob_attr *images, const char *typestr, const char *fstype, char **image_name, char **image_sha256) -{ - struct blob_attr *tb[__IMAGES_MAX]; - struct blob_attr *cur; - int rem, ret = -ENOENT; - - blobmsg_for_each_attr(cur, images, rem) { - blobmsg_parse(images_policy, __IMAGES_MAX, tb, blobmsg_data(cur), blobmsg_len(cur)); - if (!tb[IMAGES_FILESYSTEM] || - !tb[IMAGES_NAME] || - !tb[IMAGES_TYPE] || - !tb[IMAGES_SHA256]) - continue; - - if (fstype && strcmp(blobmsg_get_string(tb[IMAGES_FILESYSTEM]), fstype)) - continue; - - if (!strcmp(blobmsg_get_string(tb[IMAGES_TYPE]), typestr)) { - *image_name = strdup(blobmsg_get_string(tb[IMAGES_NAME])); - *image_sha256 = strdup(blobmsg_get_string(tb[IMAGES_SHA256])); - ret = 0; - break; - } - } - - return ret; -} - -static int select_image(struct blob_attr *images, const char *target_fstype, char **image_name, char **image_sha256) -{ - const char *combined_type; - const char *fstype = rootfs_type; - int ret = -ENOENT; - - if (target_fstype) - fstype = target_fstype; - - if (system_is_efi()) - combined_type = "combined-efi"; - else - combined_type = "combined"; - - DPRINTF("images: %s\n", blobmsg_format_json_indent(images, true, 0)); - - if (fstype) { - ret = get_image_by_type(images, "sysupgrade", fstype, image_name, image_sha256); - if (!ret) - return 0; - - ret = get_image_by_type(images, combined_type, fstype, image_name, image_sha256); - if (!ret) - return 0; - - ret = get_image_by_type(images, "sdcard", fstype, image_name, image_sha256); - if (!ret) - return 0; - } - - /* fallback to squashfs unless fstype requested explicitly */ - if (!target_fstype) { - ret = get_image_by_type(images, "sysupgrade", "squashfs", image_name, image_sha256); - if (!ret) - return 0; - - ret = get_image_by_type(images, combined_type, "squashfs", image_name, image_sha256); - if (!ret) - return 0; - - ret = get_image_by_type(images, "sdcard", fstype, image_name, image_sha256); - } - - return ret; -} - -static bool validate_sha256(char *filename, char *sha256str) -{ - char *cmd = calloc(strlen(SHA256SUM) + 1 + strlen(filename) + 1, sizeof(char)); - size_t reslen = (64 + 2 + strlen(filename) + 1) * sizeof(char); - char *resstr = malloc(reslen); - FILE *f; - bool ret = false; - - strcpy(cmd, SHA256SUM); - strcat(cmd, " "); - strcat(cmd, filename); - - f = popen(cmd, "r"); - if (!f) - goto sha256free; - - if (fread(resstr, reslen, 1, f) < 1) - goto sha256close; - - if (!strncmp(sha256str, resstr, 64)) - ret = true; - -sha256close: - fflush(f); - pclose(f); -sha256free: - free(cmd); - free(resstr); - - return ret; -} - -static inline bool status_delay(const char *status) -{ - return !strcmp(API_STATUS_QUEUED, status) || - !strcmp(API_STATUS_STARTED, status); -} - -static void usage(const char *arg0) -{ - fprintf(stdout, "%s: Attended sysUpgrade CLI client\n", arg0); - fprintf(stdout, "Usage: auc [-b ] [-B ] [-c] %s[-f] [-h] [-r] [-y]\n", -#ifdef AUC_DEBUG -"[-d] " -#else -"" -#endif - ); - fprintf(stdout, " -b \tuse specific release branch\n"); - fprintf(stdout, " -B \tuse specific release version\n"); - fprintf(stdout, " -c\t\tonly check if system is up-to-date\n"); -#ifdef AUC_DEBUG - fprintf(stdout, " -d\t\tenable debugging output\n"); -#endif - fprintf(stdout, " -f\t\tuse force\n"); - fprintf(stdout, " -h\t\toutput help\n"); - fprintf(stdout, " -n\t\tdry-run (don't download or upgrade)\n"); - fprintf(stdout, " -r\t\tcheck only for release upgrades\n"); - fprintf(stdout, " -F \toverride filesystem type\n"); - fprintf(stdout, " -y\t\tdon't wait for user confirmation\n"); - fprintf(stdout, "\n"); - fprintf(stdout, "Please report issues to improve the server:\n"); - fprintf(stdout, "%s\n", server_issues); -} - - -/* this main function is too big... todo: split */ -int main(int args, char *argv[]) { - static struct blob_buf checkbuf, infobuf, reqbuf, imgbuf, upgbuf; - struct branch *current_branch, *running_branch; - struct branch_version *target_version; - int running_revision, covered_revision = 0; - uint32_t id; - int valid; - char url[256]; - char *sanetized_board_name, *image_name, *image_sha256, *tmp; - char *cmd_target_branch = NULL, *cmd_target_version = NULL, *cmd_target_fstype = NULL; - struct blob_attr *tbr[__REPLY_MAX]; - struct blob_attr *tb[__TARGET_MAX] = {}; /* make sure tb is NULL initialized even if blobmsg_parse isn't called */ - struct stat imgstat; - bool check_only = false; - bool retry_delay = false; - bool upg_check = false; - bool dry_run = false; - int revcmp = 0; - int addargs; - unsigned char argc = 1; - bool force = false, use_get = false, in_queue = false, release_only = false; - - snprintf(user_agent, sizeof(user_agent), "%s/%s", argv[0], AUC_VERSION); - fprintf(stdout, "%s\n", user_agent); - - while (argcversion_number, target_version->version_code); - - if (running_branch->snapshot && !target_version->branch->snapshot) - revcmp = (running_revision < target_version->branch->branch_off_rev)?-1:1; - else if (!running_branch->snapshot && target_version->branch->snapshot) - revcmp = -1; - else - revcmp = verrevcmp(version, target_version->version_number); - - if (revcmp < 0) - upg_check |= PKG_UPGRADE; - else if (revcmp > 0) - upg_check |= PKG_DOWNGRADE; - - if (release_only && !(upg_check & PKG_UPGRADE)) { - fprintf(stderr, "Nothing to be updated. Use '-f' to force.\n"); - rc = 0; - goto freebranches; - } - - if (target_version->branch == running_branch) - grab_changes(running_branch, running_revision); - else if (revcmp > 0) - fprintf(stderr, "WARNING: Downgrade to older branch may not work as expected!\n"); - else avl_for_element_range(running_branch, target_version->branch, current_branch, avl) { - if (current_branch == running_branch) - grab_changes(running_branch, running_revision); - else - grab_changes(current_branch, covered_revision); - - if (current_branch->branch_off_rev > 0) - covered_revision = current_branch->branch_off_rev; - } - - if ((rc = request_packages(target_version))) - goto freebranches; - - upg_check |= check_installed_packages(); - if (upg_check & PKG_ERROR) { - rc = -ENOPKG; - goto freebranches; - } - - if (!upg_check && !force) { - fprintf(stderr, "Nothing to be updated. Use '-f' to force.\n"); - rc=0; - goto freebranches; - }; - - if (!force && (upg_check & PKG_DOWNGRADE)) { - fprintf(stderr, "Refusing to downgrade. Use '-f' to force.\n"); - rc = -ENOTRECOVERABLE; - goto freebranches; - }; - - if (!force && (upg_check & PKG_NOT_FOUND)) { - fprintf(stderr, "Not all installed packages found in remote lists. Use '-f' to force.\n"); - rc = -ENOTRECOVERABLE; - goto freebranches; - }; - - if (check_only) - goto freebranches; - - if (!dont_ask) { - if (!ask_user("Are you sure you want to continue the upgrade process?")) { - rc = 0; - goto freebranches; - } - } - - blobmsg_add_string(&reqbuf, "version", target_version->version); - blobmsg_add_string(&reqbuf, "version_code", target_version->version_code); - blobmsg_add_string(&reqbuf, "target", target); - - if (cmd_target_fstype || rootfs_type) - blobmsg_add_string(&reqbuf, "filesystem", cmd_target_fstype?cmd_target_fstype:rootfs_type); - - sanetized_board_name = strdup(board_name); - tmp = sanetized_board_name; - while ((tmp = strchr(tmp, ','))) - *tmp = '_'; - - blobmsg_add_string(&reqbuf, "profile", sanetized_board_name); - blobmsg_add_u8(&reqbuf, "diff_packages", 1); - - req_add_selected_packages(&reqbuf); - - snprintf(url, sizeof(url), "%s/%s", serverurl, API_REQUEST); - - use_get = false; - do { - retry = false; - - DPRINTF("requesting from %s\n%s%s", url, use_get?"":blobmsg_format_json_indent(reqbuf.head, true, 0), use_get?"":"\n"); - - rc = server_request(url, use_get?NULL:&reqbuf, &imgbuf); - if (rc) - break; - - blobmsg_parse(reply_policy, __REPLY_MAX, tbr, blob_data(imgbuf.head), blob_len(imgbuf.head)); - if (!tbr[REPLY_OBJECT]) - break; - - blobmsg_parse(target_policy, __TARGET_MAX, tb, blobmsg_data(tbr[REPLY_OBJECT]), blobmsg_len(tbr[REPLY_OBJECT])); - - /* for compatibility with old server version, also support status in 200 reply */ - if (tb[TARGET_STATUS]) { - tmp = blobmsg_get_string(tb[TARGET_STATUS]); - if (status_delay(tmp)) - retry = 1; - } - - if (tb[TARGET_REQUEST_HASH]) { - if (retry) { - if (!retry_delay) - fputs("Requesting build", stderr); - - retry_delay = 2; - if (tb[TARGET_QUEUE_POSITION]) { - fprintf(stderr, "%s%s (position in queue: %d)", - ANSI_ESC, in_queue?ANSI_CURSOR_RESTORE:ANSI_CURSOR_SAFE, - blobmsg_get_u32(tb[TARGET_QUEUE_POSITION])); - in_queue = true; - } else { - if (in_queue) - fprintf(stderr, "%s%s%s%s", - ANSI_ESC, ANSI_CURSOR_RESTORE, - ANSI_ESC, ANSI_ERASE_LINE); - fputc('.', stderr); - in_queue = false; - } - } else { - retry_delay = 0; - } - if (!use_get) { - snprintf(url, sizeof(url), "%s/%s/%s", serverurl, - API_REQUEST, - blobmsg_get_string(tb[TARGET_REQUEST_HASH])); - DPRINTF("polling via GET %s\n", url); - } - use_get = true; - } else if (retry_delay) { - retry_delay = 0; - } - -#ifdef AUC_DEBUG - if (debug && tb[TARGET_STDOUT]) - fputs(blobmsg_get_string(tb[TARGET_STDOUT]), stdout); - - if (debug && tb[TARGET_STDERR]) - fputs(blobmsg_get_string(tb[TARGET_STDERR]), stderr); -#endif - - if (retry) { - blob_buf_free(&imgbuf); - blobmsg_buf_init(&imgbuf); - sleep(retry_delay); - } - } while(retry); - - free(sanetized_board_name); - - if (!tb[TARGET_IMAGES] || !tb[TARGET_BINDIR]) { - if (!rc) - rc=-EBADMSG; - goto freebranches; - } - - if ((rc = select_image(tb[TARGET_IMAGES], cmd_target_fstype, &image_name, &image_sha256))) - goto freebranches; - - snprintf(url, sizeof(url), "%s/%s/%s/%s", serverurl, API_STORE, - blobmsg_get_string(tb[TARGET_BINDIR]), - image_name); - - if (dry_run) { - fprintf(stderr, "\nImage available at %s\n", url); - rc = 0; - goto freebranches; - } - - fprintf(stderr, "\nDownloading image from %s\n", url); - rc = server_request(url, NULL, NULL); - if (rc) - goto freebranches; - - filename = uclient_get_url_filename(url, "firmware.bin"); - - if (stat(filename, &imgstat)) { - fprintf(stderr, "image download failed\n"); - rc=-EPIPE; - goto freebranches; - } - - if ((intmax_t)imgstat.st_size != out_len) { - fprintf(stderr, "file size mismatch\n"); - unlink(filename); - rc=-EMSGSIZE; - goto freebranches; - } - - if (!validate_sha256(filename, image_sha256)) { - fprintf(stderr, "sha256 mismatch\n"); - unlink(filename); - rc=-EBADMSG; - goto freebranches; - } - - if (strcmp(filename, "firmware.bin")) { - if (rename(filename, "firmware.bin")) { - fprintf(stderr, "can't rename to firmware.bin\n"); - unlink(filename); - rc=-errno; - goto freebranches; - } - } - - valid = 0; - if (ubus_lookup_id(ctx, "rpc-sys", &id) || - ubus_invoke(ctx, id, "upgrade_test", NULL, upgtest_cb, &valid, 15000)) { - rc=-EFAULT; - goto freebranches; - } - - if (!valid) { - rc=-EINVAL; - goto freebranches; - } - - fprintf(stdout, "invoking sysupgrade\n"); - blobmsg_add_u8(&upgbuf, "keep", 1); - ubus_invoke(ctx, id, "upgrade_start", upgbuf.head, NULL, NULL, 120000); - sleep(10); - -freebranches: - free_branches(); - if (rc && tb[TARGET_STDOUT] -#ifdef AUC_DEBUG - && !debug -#endif - ) - fputs(blobmsg_get_string(tb[TARGET_STDOUT]), stdout); - if (rc && tb[TARGET_STDERR] -#ifdef AUC_DEBUG - && !debug -#endif - ) - fputs(blobmsg_get_string(tb[TARGET_STDERR]), stderr); - - if (tb[TARGET_DETAIL]) { - fputs(blobmsg_get_string(tb[TARGET_DETAIL]), stderr); - fputc('\n', stderr); - } - -freeboard: - if (rootfs_type) - free(rootfs_type); - - free(board_name); - free(target); - free(distribution); - free(version); - -freebufs: - blob_buf_free(&checkbuf); - blob_buf_free(&infobuf); - blob_buf_free(&reqbuf); - blob_buf_free(&imgbuf); - blob_buf_free(&upgbuf); - -freessl: - if (ssl_ctx) - ssl_ops->context_free(ssl_ctx); - -freeconfig: - free(serverurl); - -freeubus: - uloop_done(); - ubus_free(ctx); - - if (ucl) - uclient_free(ucl); - - if (dlh) - dlclose(dlh); - - if (rc) - fprintf(stderr, "%s (%d)\n", strerror(-1 * rc), -1 * rc); - - return rc; -} -- 2.30.2