summaryrefslogtreecommitdiffstats
path: root/src/b2qt-update-application/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/b2qt-update-application/main.cpp')
-rw-r--r--src/b2qt-update-application/main.cpp203
1 files changed, 203 insertions, 0 deletions
diff --git a/src/b2qt-update-application/main.cpp b/src/b2qt-update-application/main.cpp
new file mode 100644
index 0000000..157af4f
--- /dev/null
+++ b/src/b2qt-update-application/main.cpp
@@ -0,0 +1,203 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use the contact form at
+** http://qt.digia.com/
+**
+** This file is part of Qt Enterprise Embedded.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** the contact form at http://qt.digia.com/
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QProcess>
+#include <QDebug>
+#include <QFile>
+#include <QDir>
+#include <unistd.h>
+#include <sys/reboot.h>
+#include <QNetworkAccessManager>
+#include <QUrl>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include "update.h"
+#include "filewrapper.h"
+
+#define UPDATE_MOUNTPOINT "/mnt/update"
+
+QStringList mounts;
+
+void cleanup()
+{
+ foreach (const QString &m, mounts) {
+ QProcess::execute("umount", QStringList() << m);
+ }
+ mounts.clear();
+}
+
+void error(const QString &message)
+{
+ fprintf(stderr, "%s\n", message.toLocal8Bit().constData());
+ cleanup();
+ exit(1);
+}
+
+bool execute(const QString &binary, const QStringList &arguments)
+{
+ int rc = QProcess::execute(binary, arguments);
+ if (rc != 0)
+ error("Failed to execute command '" + binary + " " + arguments.join(" "));
+ return rc == 0;
+}
+
+bool mount(const QString &device, const QString &mountpoint, const QString &arguments = QString())
+{
+ QStringList tmp;
+ if (!arguments.isEmpty())
+ tmp << "-o" << arguments;
+
+ if (!execute("mount", QStringList() << tmp << device << mountpoint))
+ return false;
+
+ if (!arguments.contains("remount"))
+ mounts << mountpoint;
+ return true;
+}
+
+QByteArray readAll(const QString &fileName)
+{
+ QFile f(fileName);
+ if (!f.open(QFile::ReadOnly)) {
+ qWarning() << "Could not read" << fileName;
+ return QByteArray();
+ }
+
+ return f.readAll();
+}
+
+bool writeAll(const QString &fileName, const QByteArray &content)
+{
+ QFile f(fileName);
+ if (!f.open(QFile::WriteOnly)) {
+ qWarning() << "Could not write" << fileName;
+ return false;
+ }
+ if (f.write(content) != content.size()) {
+ qWarning() << "write size mismatch";
+ return false;
+ }
+ f.close();
+ return true;
+}
+
+QStringList find_usb_storage()
+{
+ QStringList rc;
+ QDir d("/sys/dev/block");
+
+ foreach (QString s, d.entryList()) {
+ QFileInfo fi(d.absoluteFilePath(s));
+ QString path = fi.canonicalFilePath();
+ if (path.contains("/usb"))
+ rc += path.mid(path.lastIndexOf('/'));
+ }
+ return rc;
+}
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ mount(QString(), "/", "remount,rw");
+ execute("mkdir", QStringList() << "-p" << "/mnt/boot");
+ execute("mkdir", QStringList() << "-p" << "/mnt/root");
+ execute("mkdir", QStringList() << "-p" << UPDATE_MOUNTPOINT);
+ mount("/dev/mmcblk0p1", "/mnt/boot", "ro");
+
+ QByteArray update_state = readAll("/mnt/boot/update/state").trimmed();
+ if (update_state.isEmpty())
+ qFatal("Update state is empty");
+
+ if (update_state == "v")
+ qFatal("Update state is 'valid', this should not happen");
+ else if (update_state == "t")
+ qDebug() << "Update state is 'testing', this should not happen";
+ else if (update_state == "u")
+ qDebug() << "Update state is 'update'";
+ else
+ qDebug() << "Unknown update state:" << update_state;
+
+ QStringList usbsticks = find_usb_storage();
+
+ qDebug() << "Found USB storage devices:" << usbsticks;
+
+ bool update_found = false;
+ foreach (QString s, usbsticks) {
+ if (QProcess::execute("mount", QStringList() << "-o" << "ro" << "/dev/" + s << UPDATE_MOUNTPOINT) == 0) {
+ mounts << UPDATE_MOUNTPOINT;
+ qDebug() << "mount successful";
+
+ if (QFile::exists(UPDATE_MOUNTPOINT "/b2qt-update")) {
+ qDebug() << "update found";
+ update_found = true;
+ break;
+ }
+ execute("umount", QStringList() << UPDATE_MOUNTPOINT);
+ mounts.removeAt(mounts.lastIndexOf(UPDATE_MOUNTPOINT));
+ qDebug() << "no update found";
+ } else {
+ qDebug() << "mount of" << s << "failed";
+ }
+ }
+
+ Update update;
+
+ if (update_found) {
+ FileWrapper *fw = new FileWrapper(UPDATE_MOUNTPOINT "/b2qt-update", &update);
+ if (!fw->open(QFile::ReadOnly))
+ qFatal("Failed to open update");
+ qDebug() << "Starting update from USB";
+ update.setDevice(fw);
+ } else {
+ QByteArray update_source = readAll("/mnt/boot/update/source").trimmed();
+ if (update_source.isEmpty()) {
+ execute("umount", QStringList() << "/mnt/boot"); // FIXME
+ mounts.removeAt(mounts.lastIndexOf("/mnt/boot"));
+ qFatal("Update source is empty");
+ }
+
+ execute("udhcpc", QStringList() << "-i" << "eth0");
+
+ QNetworkAccessManager *manager = new QNetworkAccessManager(0);
+ QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(update_source)));
+ reply->setReadBufferSize(2000000); // 2 MB
+
+ QObject::connect(reply, (void (QNetworkReply::*)(QNetworkReply::NetworkError))&QNetworkReply::error,
+ [](QNetworkReply::NetworkError e){qDebug() << "network error" << e;});
+ QObject::connect(reply, &QNetworkReply::sslErrors,
+ [](QList<QSslError>){ qDebug() << "ssl errors";});
+
+ qDebug() << "Starting update from Internet" << update_source;
+ update.setDevice(reply);
+ }
+
+ app.exec();
+
+ qDebug() << "unmount";
+ cleanup();
+
+ qDebug() << "sync";
+ sync();
+ qDebug() << "reboot; waiting 2 seconds";
+ sleep(2);
+ reboot(RB_AUTOBOOT);
+ return 0;
+}