Stefan Reinauer has submitted this change. ( https://review.coreboot.org/c/em100/+/37072 )
Change subject: Add network update functionality ......................................................................
Add network update functionality
Update chip database and firmware images over the network. If you wish to update your chips database or firmware archive, you can now use em100 -U to do so.
The files configs.tar.xz, firmware.tar.xz and VERSION will be downloaded and stored in $EM100_HOME if it is set. Otherwise $HOME/.em100 will be used as a default. If the directory does not exist when running the command, it will be created before downloading.
These tarballs are the same tarballs that are created with the make tarballs target.
Change-Id: I5c378754da4ce06b63f317eb22fa237d7a616fd8 Signed-off-by: Stefan Reinauer stefan.reinauer@coreboot.org Reviewed-on: https://review.coreboot.org/c/em100/+/37072 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Angel Pons th3fanbus@gmail.com --- M Makefile A curl.c M em100.c M em100.h 4 files changed, 200 insertions(+), 2 deletions(-)
Approvals: build bot (Jenkins): Verified Angel Pons: Looks good to me, approved
diff --git a/Makefile b/Makefile index 5880840..8d8be29 100644 --- a/Makefile +++ b/Makefile @@ -29,13 +29,14 @@
LDFLAGS ?= LDFLAGS += $(shell $(PKG_CONFIG) --libs libusb-1.0) +LDFLAGS += $(shell $(PKG_CONFIG) --libs libcurl)
CC ?= gcc PKG_CONFIG ?= pkg-config
XZ = xz/xz_crc32.c xz/xz_crc64.c xz/xz_dec_bcj.c xz/xz_dec_lzma2.c xz/xz_dec_stream.c SOURCES = em100.c firmware.c fpga.c hexdump.c sdram.c spi.c system.c trace.c usb.c -SOURCES += chips.c tar.c $(XZ) +SOURCES += curl.c chips.c tar.c $(XZ) OBJECTS = $(SOURCES:.c=.o)
all: dep em100 diff --git a/curl.c b/curl.c new file mode 100644 index 0000000..95bb05e --- /dev/null +++ b/curl.c @@ -0,0 +1,188 @@ +/* + * Copyright 2019 Google LLC + * + * 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 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <curl/curl.h> +#include "em100.h" + +/* For higher availability these binaries are hosted on + * Google Drive for convenience. You can create them by yourself + * from the installer tar ball. + * + * TODO: some sort of MD5 check / update check. + */ +const char *firmware_id = "1UmzGZbRkF9duwTLPi467EyfIZ6EhnMKA"; +const char *firmware_name = "firmware.tar.xz"; + +const char *configs_id = "19jT6kNYV1TE6WNx6lUkgH0TYyKbxXcd4"; +const char *configs_name = "configs.tar.xz"; + +const char *version_id = "1YC755W_c4nRN4qVgosegFrvfyWllqb0b"; +const char *version_name = "VERSION"; + +#define TIMEOPT CURLINFO_TOTAL_TIME_T +#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL 3000000 + +static int xferinfo(void *p __unused, + curl_off_t dltotal __unused, curl_off_t dlnow __unused, + curl_off_t ultotal __unused, curl_off_t ulnow __unused) +{ + /* Google Drive API transfers no Content-Length, so + * instead of bloating this with Range: hacks, let's + * just print a spinning wheel. + */ + static int pos = 0; + char cursor[4] = { '/', '-', '\', '|' }; + printf("%c\b", cursor[pos]); + fflush(stdout); + pos = (pos + 1) % 4; + return 0; +} + +static size_t write_data(void *ptr, size_t size, size_t nmemb, + void *stream) +{ + return fwrite(ptr, size, nmemb, (FILE *) stream); +} + +static int curl_get(const char *id, const char *filename, int progress) +{ + FILE *file; + CURLcode res; +#define URL_BUFFER_SIZE 1024 + char url[URL_BUFFER_SIZE] = + "https://drive.google.com/uc?export=download&id="; + + file = fopen(filename, "wb"); + if (!file) { + perror(filename); + return -1; + } + + CURL *curl = curl_easy_init(); + if (!curl) { + printf("CURL failed.\n"); + fclose(file); + return -1; + } + + strncat(url, id, URL_BUFFER_SIZE - 1); + + /* Set URL to GET here */ + curl_easy_setopt(curl, CURLOPT_URL, url); +#ifdef DEBUG + /* Switch on protocol/debug output for testing */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); +#endif + + /* Some servers don't like requests without a user-agent field. */ + curl_easy_setopt(curl, CURLOPT_USERAGENT, "em100-agent/1.0"); + + /* Write callback to write the data to disk */ + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); + + /* Write data to this file handle */ + curl_easy_setopt(curl, CURLOPT_WRITEDATA, file); + + if (progress) { + /* Simple progress indicator function */ + curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo); + + /* Enable progress indicator */ + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); + } + + /* Follow redirections (as used by Google Drive) */ + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION , 1L); + + /* Fetch the file */ + res = curl_easy_perform(curl); + + /* Close file */ + fclose(file); + + /* Clean up */ + curl_easy_cleanup(curl); + + return 0; +} + +void download(const char *name, const char *id) +{ + char *filename = get_em100_file(name); + printf("Downloading %s: ", name); + if (curl_get(id, filename, 1)) + printf("FAILED.\n"); + else + printf("OK\n"); + free(filename); +} + +int update_all_files(void) +{ + long old_time, new_time; + char old_version[256] = "<unknown>", new_version[256] = "<unknown>"; + + /* Read existing version and timestamp */ + char *my_version_name = get_em100_file(version_name); + FILE *old = fopen(my_version_name, "r"); + if (!old) { + free(my_version_name); + /* We probably don't have any files yet. Try to + * download everything. + */ + goto download_all; + } + + if (fscanf(old, "Time: %ld\nVersion: %s\n", + &old_time, old_version) != 2) + printf("Parse error in %s.\n", my_version_name); + + free(my_version_name); + fclose(old); + + /* Read upstream version and timestamp */ + char *tmp_version = get_em100_file(".VERSION.new"); + if (curl_get(version_id, tmp_version, 0)) { + printf("FAILED.\n"); + } + FILE *new = fopen(tmp_version, "r"); + if (!new) { + free(tmp_version); + return 1; + } + if (fscanf(new, "Time: %ld\nVersion: %s\n", + &new_time, new_version) != 2) + printf("Parse error in upstream VERSION.\n"); + fclose(new); + unlink(tmp_version); + free(tmp_version); + + /* Compare time stamps and bail out if we have the latest version */ + if (old_time >= new_time) { + printf("Current version: %s. No newer version available.\n", old_version); + return 0; + } + +download_all: + /* Download everything */ + printf("Update available: %s (installed: %s)\n", new_version, old_version); + download(version_name, version_id); + download(configs_name, configs_id); + download(firmware_name, firmware_id); + + return 0; +} diff --git a/em100.c b/em100.c index 6d7fce6..ad341e8 100644 --- a/em100.c +++ b/em100.c @@ -756,6 +756,7 @@ {"firmware-write", 1, 0, 'g'}, {"device", 1, 0, 'x'}, {"list-devices", 0, 0, 'l'}, + {"update-files", 0, 0, 'U'}, {"terminal",0 ,0, 'T'}, {NULL, 0, 0, 0} }; @@ -784,6 +785,7 @@ " -x|--device BUS:DEV use EM100pro on USB bus/device\n" " -x|--device EMxxxxxx use EM100pro with serial no EMxxxxxx\n" " -l|--list-devices list all connected EM100pro devices\n" + " -U|--update-files update device (chip) and firmware database\n" " -D|--debug: print debug information.\n" " -h|--help: this help text\n\n", name); @@ -807,7 +809,7 @@ unsigned int spi_start_address = 0; const char *voltage = NULL;
- while ((opt = getopt_long(argc, argv, "c:d:a:u:rsvtO:F:f:g:S:V:p:Dx:lhT", + while ((opt = getopt_long(argc, argv, "c:d:a:u:rsvtO:F:f:g:S:V:p:Dx:lUhT", longopts, &idx)) != -1) { switch (opt) { case 'c': @@ -875,6 +877,9 @@ case 'l': em100_list(); return 0; + case 'U': + update_all_files(); + return 0; default: case 'h': usage(argv[0]); diff --git a/em100.h b/em100.h index 8870330..4e3d74c 100644 --- a/em100.h +++ b/em100.h @@ -185,6 +185,10 @@ int tar_ls(TFILE *tfile); int test_tar(void);
+/* Network */ +void download(const char *name, const char *id); +int update_all_files(void); + /* Misc. */
#define MB * 1024 * 1024