[PATCH 1/4] swupdate: add support for sendtomongoose IPC command

14 views
Skip to first unread message

Tanguy Raufflet

unread,
Mar 9, 2026, 6:16:58 AM (6 days ago) Mar 9
to swup...@googlegroups.com, kevin.l...@savoirfairelinux.com, Tanguy Raufflet
This IPC command allows sending the status of an update after the
system reboots. This is useful to know if the update was successful or
not. In addition, a custom message can be sent to the mongoose server
and displayed in the "messages" section of the web interface.

Usage:
swupdate-ipc sendtomongoose --success|--failure [--message <text>]

Signed-off-by: Tanguy Raufflet <tanguy....@savoirfairelinux.com>
---
core/network_thread.c | 5 +++
include/network_ipc.h | 1 +
include/util.h | 1 +
mongoose/mongoose_interface.c | 41 +++++++++++++++++++-
tools/swupdate-ipc.c | 71 +++++++++++++++++++++++++++++++++++
5 files changed, 118 insertions(+), 1 deletion(-)

diff --git a/core/network_thread.c b/core/network_thread.c
index 6d4c259a..ccfa9d87 100644
--- a/core/network_thread.c
+++ b/core/network_thread.c
@@ -629,6 +629,11 @@ void *network_thread (void *data)
} else
msg.type = NACK;
break;
+ case SWUPDATE_SYSTEM_STATUS:
+ notify(msg.data.notify.status, msg.data.notify.error,
+ SYSTEM_STATUS_MSG, msg.data.notify.msg);
+ msg.type = ACK;
+ break;
default:
msg.type = NACK;
}
diff --git a/include/network_ipc.h b/include/network_ipc.h
index 8eb64cdf..2b2d3972 100644
--- a/include/network_ipc.h
+++ b/include/network_ipc.h
@@ -40,6 +40,7 @@ typedef enum {
GET_HW_REVISION,
SET_SWUPDATE_VARS,
GET_SWUPDATE_VARS,
+ SWUPDATE_SYSTEM_STATUS,
} msgtype;

/*
diff --git a/include/util.h b/include/util.h
index d4874f64..8b8d463d 100644
--- a/include/util.h
+++ b/include/util.h
@@ -119,6 +119,7 @@ typedef enum {
typedef enum {
CANCELUPDATE=LASTLOGLEVEL + 1,
CHANGE,
+ SYSTEM_STATUS_MSG,
} NOTIFY_CAUSE;

enum {
diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c
index 729862e6..9970d803 100644
--- a/mongoose/mongoose_interface.c
+++ b/mongoose/mongoose_interface.c
@@ -70,9 +70,16 @@ struct parent_connection_info {
unsigned long id;
};

+struct system_status_state {
+ bool valid;
+ RECOVERY_STATUS status;
+ char message[256];
+};
+
static struct parent_connection_info conn_info = {0};
static bool run_postupdate;
static unsigned int watchdog_conn = 0;
+static struct system_status_state last_system_status = {0};
static struct mg_http_serve_opts s_http_server_opts;
const char *global_auth_domain;
const char *global_auth_file;
@@ -408,7 +415,24 @@ static void *broadcast_message_thread(void __attribute__ ((__unused__)) *data)
if (ret != sizeof(msg))
break;

- if (strlen(msg.data.notify.msg) != 0 &&
+ if (msg.data.notify.level == SYSTEM_STATUS_MSG) {
+ char str[512];
+ char escaped_msg[sizeof(str)];
+ last_system_status.valid = true;
+ last_system_status.status = msg.data.notify.status;
+ strncpy(last_system_status.message, msg.data.notify.msg,
+ sizeof(last_system_status.message) - 1);
+ snescape(escaped_msg, sizeof(escaped_msg), last_system_status.message);
+ snprintf(str, sizeof(str),
+ "{\r\n"
+ "\t\"type\": \"system_status\",\r\n"
+ "\t\"status\": \"%s\",\r\n"
+ "\t\"message\": \"%s\"\r\n"
+ "}\r\n",
+ last_system_status.status == SUCCESS ? "SUCCESS" : "FAILURE",
+ escaped_msg);
+ broadcast(str);
+ } else if (strlen(msg.data.notify.msg) != 0 &&
msg.data.status.current != PROGRESS) {
char text[4096];
char str[4160];
@@ -727,6 +751,21 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
#endif
} else if (ev == MG_EV_ERROR) {
ERROR("%p %s", nc->fd, (char *) ev_data);
+ } else if (ev == MG_EV_WS_OPEN) {
+ if (last_system_status.valid) {
+ char str[512];
+ char escaped_msg[sizeof(str)];
+ snescape(escaped_msg, sizeof(escaped_msg), last_system_status.message);
+ int len = snprintf(str, sizeof(str),
+ "{\r\n"
+ "\t\"type\": \"system_status\",\r\n"
+ "\t\"status\": \"%s\",\r\n"
+ "\t\"message\": \"%s\"\r\n"
+ "}\r\n",
+ last_system_status.status == SUCCESS ? "SUCCESS" : "FAILURE",
+ escaped_msg);
+ mg_ws_send(nc, str, len, WEBSOCKET_OP_TEXT);
+ }
} else if (ev == MG_EV_WS_MSG) {
mg_iobuf_del(&nc->recv, 0, nc->recv.len);
} else if (ev == MG_EV_WAKEUP) {
diff --git a/tools/swupdate-ipc.c b/tools/swupdate-ipc.c
index f3738193..03892e57 100644
--- a/tools/swupdate-ipc.c
+++ b/tools/swupdate-ipc.c
@@ -72,6 +72,15 @@ static void usage_send_to_hawkbit(const char *program) {

}

+static void usage_sendtomongoose(const char *program) {
+ fprintf(stdout, "\t %s --success|--failure [--message <text>]\n", program);
+ fprintf(stdout,
+ "\t\t--success : report a successful post-reboot system update\n"
+ "\t\t--failure : report a failed post-reboot system update\n"
+ "\t\t--message <text> : optional status message, truncated at 255 chars (default: empty)\n"
+ );
+}
+
static void usage_sysrestart(const char *programname)
{
fprintf(stdout, "\t %s [OPTION]\n", programname);
@@ -762,6 +771,67 @@ static int monitor(cmd_t __attribute__((__unused__)) *cmd, int argc, char *argv
return 0;
}

+static struct option sendtomongoose_options[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"success", no_argument, NULL, 's'},
+ {"failure", no_argument, NULL, 'f'},
+ {"message", required_argument, NULL, 'm'},
+ {NULL, 0, NULL, 0}
+};
+
+static int sendtomongoose(cmd_t __attribute__((__unused__)) *cmd, int argc, char *argv[]) {
+ ipc_message msg;
+ int c;
+ bool has_status = false;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.type = SWUPDATE_SYSTEM_STATUS;
+
+ while ((c = getopt_long(argc, argv, "sfm:h",
+ sendtomongoose_options, NULL)) != EOF) {
+ switch (c) {
+ case 's':
+ msg.data.notify.status = SUCCESS;
+ has_status = true;
+ break;
+ case 'f':
+ msg.data.notify.status = FAILURE;
+ has_status = true;
+ break;
+ case 'm':
+ strncpy(msg.data.notify.msg, optarg,
+ sizeof(msg.data.notify.msg) - 1);
+ break;
+ case 'h':
+ usage_sendtomongoose(argv[0]);
+ return 0;
+ default:
+ usage_sendtomongoose(argv[0]);
+ return 1;
+ }
+ }
+
+ if (!has_status) {
+ fprintf(stderr, "Error: --success or --failure is required\n");
+ usage_sendtomongoose(argv[0]);
+ return 1;
+ }
+
+ RECOVERY_STATUS requested_status = msg.data.notify.status;
+ int rc = ipc_send_cmd(&msg);
+ if (rc) {
+ fprintf(stderr, "Failed to send status (rc=%d)\n", rc);
+ return 1;
+ }
+ if (msg.type != ACK) {
+ fprintf(stderr, "Server returned NACK\n");
+ return 1;
+ }
+ fprintf(stdout, "System status '%s' sent to the mongoose server\n",
+ requested_status == SUCCESS ? "SUCCESS" : "FAILURE");
+ return 0;
+}
+
/*
* List of implemented commands
*/
@@ -769,6 +839,7 @@ cmd_t commands[] = {
{"aes", sendaes, usage_aes},
{"setversion",setversions, usage_setversion},
{"sendtohawkbit", sendtohawkbit, usage_send_to_hawkbit},
+ {"sendtomongoose", sendtomongoose, usage_sendtomongoose},
{"hawkbitcfg", hawkbitcfg, usage_hawkbitcfg},
{"gethawkbit", gethawkbitstatus, usage_gethawkbitstatus},
{"sysrestart", sysrestart, usage_sysrestart},
--
2.53.0

Tanguy Raufflet

unread,
Mar 9, 2026, 6:16:58 AM (6 days ago) Mar 9
to swup...@googlegroups.com, kevin.l...@savoirfairelinux.com, Tanguy Raufflet
SWUpdate currently reports whether an update was successfully applied to
a bank, but has no built-in mechanism to report whether the system booted
successfully after the update.

After the update has been written to the disk, many devices will run the
update after a reboot. The update may still be discarded if it doesn't
meet stability or secure boot criteria. In this case, we want to report
to the fleet management webserver if the update was accepted or not.

This series introduces a new IPC command, `sendtomongoose`, that allows
an external process (e.g. an init script or a systemd service) to send
the result of the system boot after an update directly to the mongoose
web server. This result is then reflected in the web interface with
dedicated success/failure status banners, alongside an optional message.

The four patches are:

1. Add the `SWUPDATE_SYSTEM_STATUS` IPC command and the `sendtomongoose`
subcommand to `swupdate-ipc`. This allows sending --success or
--failure with an optional --message after a reboot.

Usage:
swupdate-ipc sendtomongoose --success|--failure [--message <text>]

2. Update the web-app to differentiate between "update applied to bank"
(existing) and "system booted successfully after update" (new). The
existing success/failure banners are clarified, and two new banners
are added for the post-reboot system status.

3. Sync the minified web-app example under examples/www/v2 with the
changes introduced in patch 2.

4. Add documentation for the `sendtomongoose` IPC command

Tanguy Raufflet (4):
swupdate: add support for sendtomongoose IPC command
web-app: update the swupdate status messages
examples: www: v2: update the web app example
docs: swupdate-ipc: document sendtomongoose command

core/network_thread.c | 5 +++
doc/source/swupdate-ipc.rst | 19 ++++++++
examples/www/v2/index.html | 2 +-
examples/www/v2/js/swupdate.min.js | 2 +-
include/network_ipc.h | 1 +
include/util.h | 1 +
mongoose/mongoose_interface.c | 41 ++++++++++++++++-
tools/swupdate-ipc.c | 71 ++++++++++++++++++++++++++++++
web-app/index.html | 10 ++++-
web-app/js/swupdate.js | 24 ++++++++++
10 files changed, 171 insertions(+), 5 deletions(-)

--
2.53.0

Tanguy Raufflet

unread,
Mar 9, 2026, 6:16:58 AM (6 days ago) Mar 9
to swup...@googlegroups.com, kevin.l...@savoirfairelinux.com, Tanguy Raufflet
Add documentation for the new sendtomongoose subcommand. The command
allows sending the post-reboot system boot status to the SWUpdate web
interface via the IPC socket.

Signed-off-by: Tanguy Raufflet <tanguy....@savoirfairelinux.com>
---
doc/source/swupdate-ipc.rst | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)

diff --git a/doc/source/swupdate-ipc.rst b/doc/source/swupdate-ipc.rst
index 4ce75b81..d3d6d3e9 100644
--- a/doc/source/swupdate-ipc.rst
+++ b/doc/source/swupdate-ipc.rst
@@ -29,6 +29,13 @@ sysrestart
----------
send a restart command after a network update

+sendtomongoose
+--------------
+send the post-reboot system boot status to the mongoose web server. This
+allows an external process (e.g. a systemd service) to report whether
+the system booted successfully after an update. The result is reflected
+in the web interface.
+
SYNOPSIS
--------

@@ -69,3 +76,15 @@ sysrestart
waits for a SWUpdate connection instead of exit with error
-s <path>
path to progress IPC socket
+
+sendtomongoose --success|--failure [--message <text>]
+ Report the post-reboot system boot status to SWUpdate's web interface.
+
+--success
+ report a successful post-reboot system update
+
+--failure
+ report a failed post-reboot system update
+
+--message <text>
+ optional status message, truncated at 255 chars (default: empty)
--
2.53.0

Tanguy Raufflet

unread,
Mar 9, 2026, 6:16:58 AM (6 days ago) Mar 9
to swup...@googlegroups.com, kevin.l...@savoirfairelinux.com, Tanguy Raufflet
The default behavior of swupdate is to return a success message when
the update is successfully applied to the bank. However, this does not
necessarily mean that the system will boot successfully after the
update. To avoid confusion, the default description of the success
message has been updated. And two additional messages have been added to
indicate the success or failure of the system update. These messages
can be triggered after rebooting the system with the IPC command
sendtomongoose.

Signed-off-by: Tanguy Raufflet <tanguy....@savoirfairelinux.com>
---
web-app/index.html | 10 ++++++++--
web-app/js/swupdate.js | 24 ++++++++++++++++++++++++
2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/web-app/index.html b/web-app/index.html
index 2e0e9a2d..801e1654 100755
--- a/web-app/index.html
+++ b/web-app/index.html
@@ -83,10 +83,16 @@
Updating may take a few minutes, please don't turn off the power.
</div>
<div id="swu-success" class="alert alert-success" style="display: none;">
- <i class="fas fa-check-circle"></i> Updated successfully.
+ <i class="fas fa-check-circle"></i> Update successfully applied.
+ </div>
+ <div id="swu-success-system" class="alert alert-success" style="display: none;">
+ <i class="fas fa-check-circle"></i> System successfully updated.
</div>
<div id="swu-failure" class="alert alert-danger" style="display: none;">
- <i class="fas fa-times-circle"></i> Update failed.
+ <i class="fas fa-times-circle"></i> Update failed to apply.
+ </div>
+ <div id="swu-failure-system" class="alert alert-danger" style="display: none;">
+ <i class="fas fa-times-circle"></i> System update failed.
</div>
<div id="swu-done" class="alert alert-info" style="display: none;">
<i class="fas fa-sync"></i> Restarting system.
diff --git a/web-app/js/swupdate.js b/web-app/js/swupdate.js
index faeca3d2..4f317829 100755
--- a/web-app/js/swupdate.js
+++ b/web-app/js/swupdate.js
@@ -52,6 +52,8 @@ function updateStatus (status) {
$('#swu-failure').hide()
$('#swu-done').hide()
$('#swu-run').hide()
+ $('#swu-success-system').hide()
+ $('#swu-failure-system').hide()

switch (status) {
case StatusEnum.IDLE:
@@ -75,6 +77,18 @@ function updateStatus (status) {
}
}

+function updateSystemStatus (status) {
+ $('#swu-idle').hide()
+ $('#swu-success-system').hide()
+ $('#swu-failure-system').hide()
+
+ if (status === 'SUCCESS') {
+ $('#swu-success-system').show()
+ } else if (status === 'FAILURE') {
+ $('#swu-failure-system').show()
+ }
+}
+
const updateProgressBarStatus = (function (status) {
let s = ''

@@ -166,6 +180,16 @@ window.onload = function () {
case 'source': {
break
}
+ case 'system_status': {
+ updateSystemStatus(msg.status)
+ if (msg.message) {
+ const p = $('<p></p>')
+ p.text(msg.message)
+ p.addClass('mb-1')
+ $('#messages').append(p)
+ }
+ break
+ }
case 'step': {
const percent = Math.round((100 * (Number(msg.step) - 1) + Number(msg.percent)) / Number(msg.number))
const value = percent + '%' + ' (' + msg.step + ' of ' + msg.number + ')'
--
2.53.0

Tanguy Raufflet

unread,
Mar 9, 2026, 6:16:58 AM (6 days ago) Mar 9
to swup...@googlegroups.com, kevin.l...@savoirfairelinux.com, Tanguy Raufflet
This commit updates the web app example to reflect the latest changes
in the web-app code.

The modifications added allow displaying a specific message status via
IPC to display the status of the system update after a reboot.

Signed-off-by: Tanguy Raufflet <tanguy....@savoirfairelinux.com>
---
examples/www/v2/index.html | 2 +-
examples/www/v2/js/swupdate.min.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/www/v2/index.html b/examples/www/v2/index.html
index db1255cf..3e369e61 100755
--- a/examples/www/v2/index.html
+++ b/examples/www/v2/index.html
@@ -1 +1 @@
-<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><link rel="icon" href="images/favicon.png" type="image/png"><link rel="stylesheet" href="css/bootstrap.min.css"><link rel="stylesheet" href="css/dropzone.min.css"><link rel="stylesheet" href="css/fontawesome.min.css"><link rel="stylesheet" href="css/solid.min.css"><link rel="stylesheet" href="css/swupdate.min.css"><script src="js/jquery.min.js"></script><script src="js/bootstrap.min.js"></script><script src="js/dropzone.min.js"></script><script src="js/swupdate.min.js"></script><title>SWUpdate - Software Update for Embedded Systems</title></head><body><!-- Navigation Header --><nav class="navbar sticky-top navbar-expand-sm navbar-dark bg-primary"><div class="container"><a class="navbar-brand" href="#"><img class="d-inline-block align-top" src="images/logo.png" alt=""> </a><button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarText"><ul class="navbar-nav ms-auto"><li class="nav-item"><a id="swu-restart" class="nav-link" href="#"><i class="fas fa-sync"></i> Restart System</a></li></ul></div></div></nav><!-- Use Bootstrap Grid Container --><div class="container"><!-- Header --><div class="row my-3"><div class="col"><div class="card opacity-75"><div class="card-header pb-0"><h1 class="display-4"><span class="text-primary">SW</span>Update</h1><p class="lead">Software update for embedded systems</p><p>Upload a software image below, or restart the system at the top right corner.</p></div></div></div></div><div class="row my-3"><div class="col"><div class="card opacity-75"><div class="card-header pb-0"><h5><i class="fas fa-wrench"></i> Software Update</h5></div><div class="card-body"><!-- Dropzone Button for drag&drop files --><form class="dropzone border rounded mb-3" id="dropzone" action="./upload" method="post" enctype="multipart/form-data"><div class="dz-default dz-message"><span class="dz-message">Click here, or drag and drop a software update image file to this area.</span></div></form><!-- Status --><div id="swu-idle" class="alert alert-secondary"><i class="fas fa-info-circle"></i> Update not started.</div><div id="swu-run" class="alert alert-warning" style="display: none;"><i class="fas fa-exclamation-triangle"></i> Updating may take a few minutes, please don't turn off the power.</div><div id="swu-success" class="alert alert-success" style="display: none;"><i class="fas fa-check-circle"></i> Updated successfully.</div><div id="swu-failure" class="alert alert-danger" style="display: none;"><i class="fas fa-times-circle"></i> Update failed.</div><div id="swu-done" class="alert alert-info" style="display: none;"><i class="fas fa-sync"></i> Restarting system.</div><!-- Progress --> <i id="swu-progress-spinner" class="spinner-border invisible" role="status"></i> <strong id="swu-progress-run" style="display: none;">Updating:</strong> <span id="swu-progress-name"></span> <span id="swu-progress-value" class="float-right"></span><div class="progress" role="progressbar"><div id="swu-progress-bar" class="progress-bar progress-bar-striped" style="height: 1.5rem"></div></div></div></div></div></div><!-- Messages --><div class="row my-3"><div class="col"><div class="card opacity-75"><div class="card-header" id="headingMessages"><a class="h5 collapsed" data-bs-toggle="collapse" data-bs-target="#collapseMessages" aria-expanded="false" aria-controls="collapseMessages"><i class="fas"></i> Messages</a></div><div id="collapseMessages" class="collapse" aria-labelledby="headingMessages"><div class="card-body" id="messages"></div></div></div></div></div><!-- Restart --><div id="swu-restart-modal" class="modal fade" tabindex="-1"><div class="modal-dialog modal-dialog-centered"><div class="modal-content"><div class="modal-body"><i class="spinner-border" role="status"></i><h5>The system will restart. Please be patient, as restarting takes about one minute.</h5></div></div></div></div></div></body></html>
\ No newline at end of file
+<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><link rel="icon" href="images/favicon.png" type="image/png"><link rel="stylesheet" href="css/bootstrap.min.css"><link rel="stylesheet" href="css/dropzone.min.css"><link rel="stylesheet" href="css/fontawesome.min.css"><link rel="stylesheet" href="css/solid.min.css"><link rel="stylesheet" href="css/swupdate.min.css"><script src="js/jquery.min.js"></script><script src="js/bootstrap.min.js"></script><script src="js/dropzone.min.js"></script><script src="js/swupdate.min.js"></script><title>SWUpdate - Software Update for Embedded Systems</title></head><body><!-- Navigation Header --><nav class="navbar sticky-top navbar-expand-sm navbar-dark bg-primary"><div class="container"><a class="navbar-brand" href="#"><img class="d-inline-block align-top" src="images/logo.png" alt=""> </a><button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarText"><ul class="navbar-nav ms-auto"><li class="nav-item"><a id="swu-restart" class="nav-link" href="#"><i class="fas fa-sync"></i> Restart System</a></li></ul></div></div></nav><!-- Use Bootstrap Grid Container --><div class="container"><!-- Header --><div class="row my-3"><div class="col"><div class="card opacity-75"><div class="card-header pb-0"><h1 class="display-4"><span class="text-primary">SW</span>Update</h1><p class="lead">Software update for embedded systems</p><p>Upload a software image below, or restart the system at the top right corner.</p></div></div></div></div><div class="row my-3"><div class="col"><div class="card opacity-75"><div class="card-header pb-0"><h5><i class="fas fa-wrench"></i> Software Update</h5></div><div class="card-body"><!-- Dropzone Button for drag&drop files --><form class="dropzone border rounded mb-3" id="dropzone" action="./upload" method="post" enctype="multipart/form-data"><div class="dz-default dz-message"><span class="dz-message">Click here, or drag and drop a software update image file to this area.</span></div></form><!-- Status --><div id="swu-idle" class="alert alert-secondary"><i class="fas fa-info-circle"></i> Update not started.</div><div id="swu-run" class="alert alert-warning" style="display: none;"><i class="fas fa-exclamation-triangle"></i> Updating may take a few minutes, please don't turn off the power.</div><div id="swu-success" class="alert alert-success" style="display: none;"><i class="fas fa-check-circle"></i> Update successfully applied.</div><div id="swu-success-system" class="alert alert-success" style="display: none;"><i class="fas fa-check-circle"></i> System successfully updated.</div><div id="swu-failure" class="alert alert-danger" style="display: none;"><i class="fas fa-times-circle"></i> Update failed to apply.</div><div id="swu-failure-system" class="alert alert-danger" style="display: none;"><i class="fas fa-times-circle"></i> System update failed.</div><div id="swu-done" class="alert alert-info" style="display: none;"><i class="fas fa-sync"></i> Restarting system.</div><!-- Progress --> <i id="swu-progress-spinner" class="spinner-border invisible" role="status"></i> <strong id="swu-progress-run" style="display: none;">Updating:</strong> <span id="swu-progress-name"></span> <span id="swu-progress-value" class="float-right"></span><div class="progress" role="progressbar"><div id="swu-progress-bar" class="progress-bar progress-bar-striped" style="height: 1.5rem"></div></div></div></div></div></div><!-- Messages --><div class="row my-3"><div class="col"><div class="card opacity-75"><div class="card-header" id="headingMessages"><a class="h5 collapsed" data-bs-toggle="collapse" data-bs-target="#collapseMessages" aria-expanded="false" aria-controls="collapseMessages"><i class="fas"></i> Messages</a></div><div id="collapseMessages" class="collapse" aria-labelledby="headingMessages"><div class="card-body" id="messages"></div></div></div></div></div><!-- Restart --><div id="swu-restart-modal" class="modal fade" tabindex="-1"><div class="modal-dialog modal-dialog-centered"><div class="modal-content"><div class="modal-body"><i class="spinner-border" role="status"></i><h5>The system will restart. Please be patient, as restarting takes about one minute.</h5></div></div></div></div></div></body></html>
\ No newline at end of file
diff --git a/examples/www/v2/js/swupdate.min.js b/examples/www/v2/js/swupdate.min.js
index deda89e3..5daf51a4 100644
--- a/examples/www/v2/js/swupdate.min.js
+++ b/examples/www/v2/js/swupdate.min.js
@@ -4,4 +4,4 @@
*
* SPDX-License-Identifier: MIT
*/
-const StatusEnum={IDLE:"IDLE",START:"START",RUN:"RUN",SUCCESS:"SUCCESS",FAILURE:"FAILURE",DONE:"DONE"};function isStatusInEnum(s){return s in StatusEnum}function restart(){$.post("restart",{},function(s){showRestart()})}function showRestart(){new bootstrap.Modal("#swu-restart-modal",{backdrop:"static",keyboard:!1}).show(),window.setTimeout(tryReload,3e3)}function tryReload(){$.ajax({cache:!1,timeout:1e3,success:function(s){window.location.reload(!0)},error:function(s,e,t){"timeout"===e?tryReload():window.setTimeout(tryReload,1e3)}})}function updateStatus(s){if(isStatusInEnum(s))switch($("#swu-idle").hide(),$("#swu-success").hide(),$("#swu-failure").hide(),$("#swu-done").hide(),$("#swu-run").hide(),s){case StatusEnum.IDLE:$("#swu-idle").show();break;case StatusEnum.START:case StatusEnum.RUN:$("#swu-run").show();break;case StatusEnum.SUCCESS:$("#swu-success").show();break;case StatusEnum.FAILURE:$("#swu-failure").show();break;case StatusEnum.DONE:$("#swu-done").show()}}const updateProgressBarStatus=function(s){let e="";return function(s){if(isStatusInEnum(s)){switch($("#swu-progress-bar").removeClass("bg-danger bg-success progress-bar-animated"),$("#swu-progress-spinner").addClass("invisible").removeClass("visible"),$("#swu-progress-run").hide(),s){case StatusEnum.START:updateProgressBar(0,"","");break;case StatusEnum.RUN:$("#swu-progress-bar").addClass("progress-bar-animated"),$("#swu-progress-spinner").removeClass("invisible").addClass("visible"),$("#swu-progress-run").show();break;case StatusEnum.SUCCESS:$("#swu-progress-bar").addClass("bg-success");break;case StatusEnum.FAILURE:"START"===e&&"RUN"===e||updateProgressBar(0,"",""),$("#swu-progress-bar").addClass("bg-danger")}e=s}}}();function updateProgressBar(s,e,t){$("#swu-progress-value").text(t),$("#swu-progress-name").text(e),$("#swu-progress-bar").css("width",s+"%").attr("aria-valuenow",s)}Dropzone.options.dropzone={timeout:0,clickable:!0,acceptedFiles:".swu",maxFilesize:0},window.onload=function(){let s;$("#swu-restart").click(restart),s="https:"===window.location.protocol?"wss:":"ws:";const e=new WebSocket(s+"//"+window.location.host+window.location.pathname.replace(/\/[^/]*$/,"")+"/ws");e.onopen=function(s){updateStatus(StatusEnum.IDLE)},e.onclose=function(s){showRestart()},e.onmessage=function(s){const e=JSON.parse(s.data);switch(e.type){case"message":{const s=$("<p></p>");s.text(e.text),s.addClass("mb-1"),e.level<=3&&s.addClass("text-danger"),$("#messages").append(s);break}case"status":updateStatus(e.status),updateProgressBarStatus(e.status);break;case"source":break;case"step":{const s=Math.round((100*(Number(e.step)-1)+Number(e.percent))/Number(e.number)),t=s+"% ("+e.step+" of "+e.number+")";updateProgressBar(s,e.name,t);break}}}};
\ No newline at end of file
+const StatusEnum={IDLE:"IDLE",START:"START",RUN:"RUN",SUCCESS:"SUCCESS",FAILURE:"FAILURE",DONE:"DONE"};function isStatusInEnum(s){return s in StatusEnum}function restart(){$.post("restart",{},function(s){showRestart()})}function showRestart(){new bootstrap.Modal("#swu-restart-modal",{backdrop:"static",keyboard:!1}).show(),window.setTimeout(tryReload,3e3)}function tryReload(){$.ajax({cache:!1,timeout:1e3,success:function(s){window.location.reload(!0)},error:function(s,e,t){"timeout"===e?tryReload():window.setTimeout(tryReload,1e3)}})}function updateStatus(s){if(isStatusInEnum(s))switch($("#swu-idle").hide(),$("#swu-success").hide(),$("#swu-failure").hide(),$("#swu-done").hide(),$("#swu-run").hide(),$("#swu-success-system").hide(),$("#swu-failure-system").hide(),s){case StatusEnum.IDLE:$("#swu-idle").show();break;case StatusEnum.START:case StatusEnum.RUN:$("#swu-run").show();break;case StatusEnum.SUCCESS:$("#swu-success").show();break;case StatusEnum.FAILURE:$("#swu-failure").show();break;case StatusEnum.DONE:$("#swu-done").show()}}function updateSystemStatus(s){$("#swu-idle").hide(),$("#swu-success-system").hide(),$("#swu-failure-system").hide(),"SUCCESS"===s?$("#swu-success-system").show():"FAILURE"===s&&$("#swu-failure-system").show()}const updateProgressBarStatus=function(s){let e="";return function(s){if(isStatusInEnum(s)){switch($("#swu-progress-bar").removeClass("bg-danger bg-success progress-bar-animated"),$("#swu-progress-spinner").addClass("invisible").removeClass("visible"),$("#swu-progress-run").hide(),s){case StatusEnum.START:updateProgressBar(0,"","");break;case StatusEnum.RUN:$("#swu-progress-bar").addClass("progress-bar-animated"),$("#swu-progress-spinner").removeClass("invisible").addClass("visible"),$("#swu-progress-run").show();break;case StatusEnum.SUCCESS:$("#swu-progress-bar").addClass("bg-success");break;case StatusEnum.FAILURE:"START"===e&&"RUN"===e||updateProgressBar(0,"",""),$("#swu-progress-bar").addClass("bg-danger")}e=s}}}();function updateProgressBar(s,e,t){$("#swu-progress-value").text(t),$("#swu-progress-name").text(e),$("#swu-progress-bar").css("width",s+"%").attr("aria-valuenow",s)}Dropzone.options.dropzone={timeout:0,clickable:!0,acceptedFiles:".swu",maxFilesize:0},window.onload=function(){let s;$("#swu-restart").click(restart),s="https:"===window.location.protocol?"wss:":"ws:";const e=new WebSocket(s+"//"+window.location.host+window.location.pathname.replace(/\/[^/]*$/,"")+"/ws");e.onopen=function(s){updateStatus(StatusEnum.IDLE)},e.onclose=function(s){showRestart()},e.onmessage=function(s){const e=JSON.parse(s.data);switch(e.type){case"message":{const s=$("<p></p>");s.text(e.text),s.addClass("mb-1"),e.level<=3&&s.addClass("text-danger"),$("#messages").append(s);break}case"status":updateStatus(e.status),updateProgressBarStatus(e.status);break;case"source":break;case"system_status":if(updateSystemStatus(e.status),e.message){const s=$("<p></p>");s.text(e.message),s.addClass("mb-1"),$("#messages").append(s)}break;case"step":{const s=Math.round((100*(Number(e.step)-1)+Number(e.percent))/Number(e.number)),t=s+"% ("+e.step+" of "+e.number+")";updateProgressBar(s,e.name,t);break}}}};
\ No newline at end of file
--
2.53.0

Stefano Babic

unread,
Mar 9, 2026, 7:02:21 AM (6 days ago) Mar 9
to Tanguy Raufflet, swup...@googlegroups.com, kevin.l...@savoirfairelinux.com
Hi Tanguy,

On 3/9/26 11:10, Tanguy Raufflet wrote:
> SWUpdate currently reports whether an update was successfully applied to
> a bank, but has no built-in mechanism to report whether the system booted
> successfully after the update.
>

Well, this is not true but this is implemented where a feedback must be
sent.

> After the update has been written to the disk, many devices will run the
> update after a reboot. The update may still be discarded if it doesn't
> meet stability or secure boot criteria. In this case, we want to report
> to the fleet management webserver if the update was accepted or not.
>

And for the supported fleet management, this is implemented. SWUpdate's
state machine terminates after the new software has successfully booted.
The mechanism is done together with the bootloader, because this could
also discard the new software without starting it.

So the mechanism is based on bootloader's variable, and the "ustate"
variable is set by SWUpdate and changed by the bootloader in case of
failure. You see that the feed back is sent to the Hawkbit server
without any additional tool / application.

But in case the update must be confirmed, there is the IPC. Typical use
case is an update must be confirmed by the end user, so that it must
confirm that he agree to update the software.

> This series introduces a new IPC command, `sendtomongoose`,

Taking account of above, I do not like to have a specific different
mechanism for any kind of interface SWUpdate provides. The Webserver
hadn't yet this information because it is supposed to run autonomously
on the device, that is there is no backend. The backends are grouped
into the suricatta modules, and the mechanism is already there - as you
were inspired from the "sendtohawkbit" command.

>that allows
> an external process (e.g. an init script or a systemd service) to send
> the result of the system boot after an update directly to the mongoose
> web server. This result is then reflected in the web interface with
> dedicated success/failure status banners, alongside an optional message.

Then the current mechanism must be uniformed and factorized so that is
available for all interfaces, including the Webserver. I do not like any
duplication.

>
> The four patches are:
>
> 1. Add the `SWUPDATE_SYSTEM_STATUS` IPC command and the `sendtomongoose`
> subcommand to `swupdate-ipc`. This allows sending --success or
> --failure with an optional --message after a reboot.
>
> Usage:
> swupdate-ipc sendtomongoose --success|--failure [--message <text>]
>
> 2. Update the web-app to differentiate between "update applied to bank"
> (existing)

existing

> and "system booted successfully after update" (new).

Existing as well, because if system is up again with ustate=INSTALLED or
TEST, it means that the new Software can run.


> The
> existing success/failure banners are clarified, and two new banners
> are added for the post-reboot system status.
>
> 3. Sync the minified web-app example under examples/www/v2 with the
> changes introduced in patch 2.
>
> 4. Add documentation for the `sendtomongoose` IPC command
>

Best regards,
Stefano Babic

> Tanguy Raufflet (4):
> swupdate: add support for sendtomongoose IPC command
> web-app: update the swupdate status messages
> examples: www: v2: update the web app example
> docs: swupdate-ipc: document sendtomongoose command
>
> core/network_thread.c | 5 +++
> doc/source/swupdate-ipc.rst | 19 ++++++++
> examples/www/v2/index.html | 2 +-
> examples/www/v2/js/swupdate.min.js | 2 +-
> include/network_ipc.h | 1 +
> include/util.h | 1 +
> mongoose/mongoose_interface.c | 41 ++++++++++++++++-
> tools/swupdate-ipc.c | 71 ++++++++++++++++++++++++++++++
> web-app/index.html | 10 ++++-
> web-app/js/swupdate.js | 24 ++++++++++
> 10 files changed, 171 insertions(+), 5 deletions(-)
>

--
_______________________________________________________________________
Nabla Software Engineering GmbH
Hirschstr. 111A | 86156 Augsburg | Tel: +49 821 45592596
Geschäftsführer : Stefano Babic | HRB 40522 Augsburg
E-Mail: sba...@nabladev.com

Reply all
Reply to author
Forward
0 new messages