@@ -187,6 +187,24 @@ static int prepare_var_script(struct dict *dict, const char *script)
return 0;
}
+static int generate_swversions(struct swupdate_cfg *cfg)
+{
+ FILE *fp;
+ struct sw_version *swver;
+ struct swver *sw_ver_list = &cfg->installed_sw_list;
+
+ fp = fopen(cfg->output_swversions, "w");
+ if (!fp)
+ return -EACCES;
+
+ LIST_FOREACH(swver, sw_ver_list, next) {
+ fprintf(fp, "%s\t\t%s\n", swver->name, swver->version);
+ }
+ fclose(fp);
+
+ return 0;
+}
+
static int update_bootloader_env(struct swupdate_cfg *cfg, const char *script)
{
int ret = 0;
@@ -279,6 +297,44 @@ int install_single_image(struct img_type *img, bool dry_run)
return ret;
}
+static int update_installed_image_version(struct swver *sw_ver_list,
+ struct img_type *img)
+{
+ struct sw_version *swver;
+ struct sw_version *swcomp;
+
+ if (!sw_ver_list)
+ return false;
+
+ LIST_FOREACH(swver, sw_ver_list, next) {
+ /*
+ * If component is already installed, update the version
+ */
+ if (!strncmp(img->id.name, swver->name, sizeof(img->id.name))) {
+ strncpy(swver->version, img->id.version, sizeof(img->id.version));
+ return true;
+ }
+ }
+
+ if (!strlen(img->id.version))
+ return false;
+
+ /*
+ * No previous version of this component is installed. Create a new entry.
+ */
+ swcomp = (struct sw_version *)calloc(1, sizeof(struct sw_version));
+ if (!swcomp) {
+ ERROR("Could not create new version entry.");
+ return false;
+ }
+
+ strlcpy(swcomp->name, img->id.name, sizeof(swcomp->name));
+ strlcpy(swcomp->version, img->id.version, sizeof(swcomp->version));
+ LIST_INSERT_HEAD(sw_ver_list, swcomp, next);
+
+ return true;
+}
+
/*
* streamfd: file descriptor if it is required to extract
* images from the stream (update from file)
@@ -370,6 +426,8 @@ int install_images(struct swupdate_cfg *sw)
close(img->fdin);
+ update_installed_image_version(&sw->installed_sw_list, img);
+
if (dropimg)
free_image(img);
@@ -409,6 +467,16 @@ int install_images(struct swupdate_cfg *sw)
ret |= run_prepost_scripts(&sw->bootscripts, POSTINSTALL);
+ /*
+ * Should we generate a list with installed software?
+ */
+ if (strlen(sw->output_swversions)) {
+ ret |= generate_swversions(sw);
+ if (ret) {
+ ERROR("%s cannot be opened", sw->output_swversions);
+ }
+ }
+
return ret;
}
@@ -111,6 +111,7 @@ static struct option long_options[] = {
{"no-state-marker", no_argument, NULL, 'm'},
{"no-transaction-marker", no_argument, NULL, 'M'},
{"output", required_argument, NULL, 'o'},
+ {"gen-swversions", required_argument, NULL, 's'},
{"preupdate", required_argument, NULL, 'P'},
{"postupdate", required_argument, NULL, 'p'},
{"select", required_argument, NULL, 'e'},
@@ -173,6 +174,7 @@ static void usage(char *programname)
" -M, --no-transaction-marker : disable setting bootloader transaction marker\n"
" -m, --no-state-marker : disable setting update state in bootloader\n"
" -o, --output <filename> : saves the incoming stream\n"
+ " -s, --gen-swversions <filename>: generate sw-versions file after successful installation\n"
" -v, --verbose : be verbose, set maximum loglevel\n"
" --version : print SWUpdate version and exit\n"
#ifdef CONFIG_HW_COMPATIBILITY
@@ -320,6 +322,8 @@ static int read_globals_settings(void *elem, void *data)
"preupdatecmd", sw->preupdatecmd);
GET_FIELD_STRING(LIBCFG_PARSER, elem,
"namespace-vars", sw->namespace_for_vars);
+ GET_FIELD_STRING(LIBCFG_PARSER, elem,
+ "gen-swversions", sw->output_swversions);
if (strlen(sw->namespace_for_vars)) {
if (!swupdate_set_default_namespace(sw->namespace_for_vars))
WARN("Default Namaspace for SWUpdate vars cannot be set, possible side-effects");
@@ -475,7 +479,7 @@ int main(int argc, char **argv)
#endif
memset(main_options, 0, sizeof(main_options));
memset(image_url, 0, sizeof(image_url));
- strcpy(main_options, "vhni:e:gq:l:Lcf:p:P:o:N:R:MmB:");
+ strcpy(main_options, "vhni:e:gq:l:Lcf:p:P:o:s:N:R:MmB:");
#ifdef CONFIG_MTD
strcat(main_options, "b:");
#endif
@@ -623,6 +627,9 @@ int main(int argc, char **argv)
case 'o':
strlcpy(swcfg.output, optarg, sizeof(swcfg.output));
break;
+ case 's':
+ strlcpy(swcfg.output_swversions, optarg, sizeof(swcfg.output_swversions));
+ break;
case 'B':
if (set_bootloader(optarg) != 0) {
ERROR("Bootloader interface '%s' could not be initialized.", optarg);
@@ -49,6 +49,7 @@ struct swupdate_cfg {
bool bootloader_transaction_marker;
bool bootloader_state_marker;
char output[SWUPDATE_GENERAL_STRING_SIZE];
+ char output_swversions[SWUPDATE_GENERAL_STRING_SIZE];
char publickeyfname[SWUPDATE_GENERAL_STRING_SIZE];
char aeskeyfname[SWUPDATE_GENERAL_STRING_SIZE];
char postupdatecmd[SWUPDATE_GENERAL_STRING_SIZE];
After a successful update, --gen-swversions generates a file with the installed software and their versions. The file is compatible with CONFIG_SW_VERSIONS_FILE and could replace that file if the end user want swupdate to maintain that file entirely. Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com> --- Notes: v2: - reverse logic for: if (generate_swversions(sw)) { ERROR("%s cannot be opened", sw->output_swversions); } v3: - Change ERROR to WARN - Handle special cases in update_installed_image_version() - Add gen-swversions config parameter v4: - Moved back to ERROR and return failure if swversions could not be generated v5: - Check if sw_ver_list is NULL in update_installed_image_version core/installer.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++ core/swupdate.c | 9 +++++- include/swupdate.h | 1 + 3 files changed, 77 insertions(+), 1 deletion(-)