Move source files to /src

This commit is contained in:
Floris Bos 2022-02-14 10:06:21 +01:00
parent 4daff1ba79
commit 033ff07abf
2685 changed files with 9 additions and 7 deletions

View file

@ -0,0 +1,153 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2020 Raspberry Pi Ltd
*/
#include "../dependencies/drivelist/src/drivelist.hpp"
#include <QProcess>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDebug>
/*
* Our third-party drivelist module does not provide a C++ implementation
* for listing drives on Linux (only Javascript)
* So roll our own for Linux using same function/data structure as the drivelist one
*/
namespace Drivelist
{
static void _walkStorageChildren(Drivelist::DeviceDescriptor &d, QStringList &labels, QJsonArray &ca)
{
for (auto j : ca)
{
QJsonObject child = j.toObject();
QString label = child["label"].toString();
QString mp = child["mountpoint"].toString();
if (!label.isEmpty())
{
labels.append(label);
}
if (!mp.isEmpty())
{
d.mountpoints.push_back(mp.toStdString());
d.mountpointLabels.push_back(label.toStdString());
}
QJsonArray subca = child["children"].toArray();
if (subca.count())
{
_walkStorageChildren(d, labels, subca);
}
}
}
std::vector<Drivelist::DeviceDescriptor> ListStorageDevices()
{
std::vector<DeviceDescriptor> deviceList;
QProcess p;
QStringList args = { "--bytes", "--json", "--paths", "--output-all" };
p.start("lsblk", args);
p.waitForFinished(2000);
QByteArray output = p.readAll();
if (p.exitStatus() != QProcess::NormalExit || p.exitCode() || output.isEmpty())
{
qDebug() << "Error executing lsblk";
return deviceList;
}
QJsonDocument d = QJsonDocument::fromJson(output);
QJsonArray a = d.object()["blockdevices"].toArray();
for (auto i : a)
{
DeviceDescriptor d;
QJsonObject bdev = i.toObject();
QString name = bdev["kname"].toString();
QString subsystems = bdev["subsystems"].toString();
if (name.startsWith("/dev/loop") || name.startsWith("/dev/sr") || name.startsWith("/dev/ram") || name.startsWith("/dev/zram") || name.isEmpty())
continue;
d.busType = bdev["busType"].toString().toStdString();
d.device = name.toStdString();
d.raw = true;
d.isVirtual = subsystems == "block";
if (bdev["ro"].isBool())
{
/* With some lsblk versions it is a bool in others a "0" or "1" string */
d.isReadOnly = bdev["ro"].toBool();
d.isRemovable= bdev["rm"].toBool() || bdev["hotplug"].toBool() || d.isVirtual;
}
else
{
d.isReadOnly = bdev["ro"].toString() == "1";
d.isRemovable= bdev["rm"].toString() == "1" || bdev["hotplug"].toString() == "1" || d.isVirtual;
}
if (bdev["size"].isString())
{
d.size = bdev["size"].toString().toULongLong();
}
else
{
d.size = bdev["size"].toDouble();
}
d.isSystem = !d.isRemovable && !d.isVirtual;
d.isUSB = subsystems.contains("usb");
d.isSCSI = subsystems.contains("scsi") && !d.isUSB;
d.blockSize = bdev["phy-sec"].toInt();
d.logicalBlockSize = bdev["log-sec"].toInt();
QStringList dp = {
bdev["label"].toString().trimmed(),
bdev["vendor"].toString().trimmed(),
bdev["model"].toString().trimmed()
};
if (name == "/dev/mmcblk0")
{
dp.removeAll("");
if (dp.empty())
dp.append(QObject::tr("Internal SD card reader"));
}
QString mp = bdev["mountpoint"].toString();
if (!mp.isEmpty())
{
d.mountpoints.push_back(mp.toStdString());
d.mountpointLabels.push_back(bdev["label"].toString().toStdString());
}
QStringList labels;
QJsonArray ca = bdev["children"].toArray();
_walkStorageChildren(d, labels, ca);
if (labels.count()) {
dp.append("("+labels.join(", ")+")");
}
dp.removeAll("");
d.description = dp.join(" ").toStdString();
/* Mark internal NVMe drives as non-system if not mounted
anywhere else than under /media */
if (d.isSystem && subsystems.contains("nvme"))
{
bool isMounted = false;
for (std::string mp : d.mountpoints)
{
if (!QByteArray::fromStdString(mp).startsWith("/media/")) {
isMounted = true;
break;
}
}
if (!isMounted)
{
d.isSystem = false;
}
}
deviceList.push_back(d);
}
return deviceList;
}
}

View file

@ -0,0 +1,9 @@
[Desktop Entry]
Type=Application
Version=1.0
Name=Imager
Comment=Raspberry Pi Imager
Icon=rpi-imager
Exec=rpi-imager
Categories=Utility
StartupNotify=false

View file

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" ?>
<component type="desktop-application">
<id>org.raspberrypi.rpi-imager</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>Apache-2.0</project_license>
<name>Raspberry Pi Imager</name>
<summary>Raspberry Pi imaging utility</summary>
<description>
<p>
Raspberry Pi Imager downloads a .JSON file from the Raspberry Pi
website with a list of all current download options, ensuring you are
always installing the most up-to-date version.
</p>
<p>
Once youve selected an operating system from the available options,
the utility reads the relevant file directly from the Raspberry Pi
website and writes it straight to the SD card. This speeds up the
process quite considerably compared to the standard process of reading
it from the website, writing it to a file on your hard drive, and then,
as a separate step, reading it back from the hard drive and writing it
to the SD card.
</p>
<p>
During this process, Raspberry Pi Imager also caches the downloaded
operating system image that is to say, it saves a local copy on your
computer, so you can program additional SD cards without having to
download the file again.
</p>
</description>
<launchable type="desktop-id">rpi-imager.desktop</launchable>
<screenshots>
<screenshot type="default">
<image>http://downloads.raspberrypi.org/imager/IMAGING-UTILITY-MAIN.png</image>
<caption>Main window</caption>
</screenshot>
<screenshot>
<image>http://downloads.raspberrypi.org/imager/IMAGING-UTILITY-OS.png</image>
<caption>Choose OS</caption>
</screenshot>
<screenshot>
<image>http://downloads.raspberrypi.org/imager/IMAGING-UTILITY-SD.png</image>
<caption>Choose SD</caption>
</screenshot>
<screenshot>
<image>http://downloads.raspberrypi.org/imager/IMAGING-UTILITY-WRITE.png</image>
<caption>Write in progress</caption>
</screenshot>
<screenshot>
<image>http://downloads.raspberrypi.org/imager/IMAGING-UTILITY-DONE.png</image>
<caption>Write done</caption>
</screenshot>
</screenshots>
<url type="homepage">https://github.com/raspberrypi/rpi-imager</url>
<provides>
<binary>rpi-imager</binary>
</provides>
<releases>
<release version="@IMAGER_VERSION_STR@" />
</releases>
<content_rating type="oars-1.1">
<content_attribute id="social-info">moderate</content_attribute>
</content_rating>
</component>

277
src/linux/udisks2api.cpp Normal file
View file

@ -0,0 +1,277 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2020 Raspberry Pi Ltd
*/
#include "udisks2api.h"
#include <unistd.h>
#include <fcntl.h>
#include <QDBusInterface>
#include <QDBusReply>
#include <QDBusUnixFileDescriptor>
#include <QDebug>
#include <QThread>
UDisks2Api::UDisks2Api(QObject *parent)
: QObject(parent)
{
}
int UDisks2Api::authOpen(const QString &device, const QString &mode)
{
QString devpath = _resolveDevice(device);
if (devpath.isEmpty())
return -1;
QDBusInterface blockdevice("org.freedesktop.UDisks2", devpath,
"org.freedesktop.UDisks2.Block", QDBusConnection::systemBus());
QString drive = blockdevice.property("Drive").value<QDBusObjectPath>().path();
if (!drive.isEmpty() && drive != "/")
{
_unmountDrive(drive);
}
// User may need to enter password in authentication dialog so set long timeout
blockdevice.setTimeout(3600 * 1000);
QVariantMap options = {{"flags", O_EXCL}};
QDBusReply<QDBusUnixFileDescriptor> dbusfd = blockdevice.call("OpenDevice", mode, options);
if (!blockdevice.isValid() || !dbusfd.isValid() || !dbusfd.value().isValid())
return -1;
int fd = ::dup(dbusfd.value().fileDescriptor());
return fd;
}
QString UDisks2Api::_resolveDevice(const QString &device)
{
QDBusInterface manager("org.freedesktop.UDisks2", "/org/freedesktop/UDisks2/Manager",
"org.freedesktop.UDisks2.Manager", QDBusConnection::systemBus());
QVariantMap devspec = {{"path", device}};
QVariantMap options;
QDBusReply<QList<QDBusObjectPath>> list = manager.call("ResolveDevice", devspec, options);
if (!manager.isValid() || !list.isValid() || list.value().isEmpty())
return QString();
return list.value().first().path();
}
void UDisks2Api::_unmountDrive(const QString &driveDbusPath)
{
//qDebug() << "Drive:" << driveDbusPath;
QDBusInterface manager("org.freedesktop.UDisks2", "/org/freedesktop/UDisks2/Manager",
"org.freedesktop.UDisks2.Manager", QDBusConnection::systemBus());
QVariantMap options;
QDBusReply<QList<QDBusObjectPath>> list = manager.call("GetBlockDevices", options);
if (!manager.isValid() || !list.isValid())
return;
for (auto devpath : list.value())
{
QString devpathStr = devpath.path();
QDBusInterface blockdevice("org.freedesktop.UDisks2", devpathStr,
"org.freedesktop.UDisks2.Block", QDBusConnection::systemBus());
QString driveOfDev = blockdevice.property("Drive").value<QDBusObjectPath>().path();
if (driveOfDev != driveDbusPath)
continue;
//qDebug() << "Device:" << devpathStr << "belongs to same drive";
QDBusInterface filesystem("org.freedesktop.UDisks2", devpathStr,
"org.freedesktop.UDisks2.Filesystem", QDBusConnection::systemBus());
QDBusReply<void> reply = filesystem.call("Unmount", options);
if (reply.isValid())
qDebug() << "Unmounted" << devpathStr << "successfully";
}
}
bool UDisks2Api::formatDrive(const QString &device, bool mountAfterwards)
{
QString devpath = _resolveDevice(device);
if (devpath.isEmpty())
return false;
QDBusInterface blockdevice("org.freedesktop.UDisks2", devpath,
"org.freedesktop.UDisks2.Block", QDBusConnection::systemBus());
QString drive = blockdevice.property("Drive").value<QDBusObjectPath>().path();
if (!drive.isEmpty() && drive != "/")
{
_unmountDrive(drive);
}
qDebug() << "Repartitioning drive";
QVariantMap options;
QDBusReply<void> reply = blockdevice.call("Format", "dos", options);
if (!reply.isValid())
{
qDebug() << "Error repartitioning device:" << reply.error().message();
return false;
}
QVariantMap partOptions, formatOptions;
QDBusInterface partitiontable("org.freedesktop.UDisks2", devpath,
"org.freedesktop.UDisks2.PartitionTable", QDBusConnection::systemBus());
/* The all-in-one CreatePartitionAndFormat udisks2 method seems to not always
work properly. Do seperate actions with sleep in between instead */
qDebug() << "Adding partition";
QDBusReply<QDBusObjectPath> newpartition = partitiontable.call("CreatePartition", QVariant((qulonglong) 4*1024*1024), QVariant((qulonglong) 0), "0x0e", "", partOptions);
if (!newpartition.isValid())
{
qDebug() << "Error adding partition:" << newpartition.error().message();
return false;
}
qDebug() << "New partition:" << newpartition.value().path();
QThread::sleep(1);
if (!drive.isEmpty() && drive != "/")
{
/* Unmount one more time, as auto-mount may have tried to mount an old FAT filesystem again if it
* lives at the same sector in the new partition table as before */
_unmountDrive(drive);
}
qDebug() << "Formatting drive as FAT32";
QDBusInterface newblockdevice("org.freedesktop.UDisks2", newpartition.value().path(),
"org.freedesktop.UDisks2.Block", QDBusConnection::systemBus());
newblockdevice.setTimeout(300 * 1000);
QDBusReply<void> fatformatreply = newblockdevice.call("Format", "vfat", formatOptions);
if (!fatformatreply.isValid())
{
qDebug() << "Error from udisks2 while performing FAT32 format:" << fatformatreply.error().message();
return false;
}
if (mountAfterwards)
{
QDBusInterface filesystem("org.freedesktop.UDisks2", newpartition.value().path(),
"org.freedesktop.UDisks2.Filesystem", QDBusConnection::systemBus());
QVariantMap mountOptions;
for (int attempt = 0; attempt < 10; attempt++)
{
qDebug() << "Mounting partition";
// User may need to enter password in authentication dialog if non-removable storage, so set long timeout
filesystem.setTimeout(3600 * 1000);
QDBusReply<QString> mp = filesystem.call("Mount", mountOptions);
if (mp.isValid())
{
qDebug() << "Mounted new file system at:" << mp;
return true;
}
else
{
/* Check if already auto-mounted */
auto mps = mountPoints(filesystem);
if (!mps.isEmpty())
{
qDebug() << "Was already auto-mounted at:" << mps;
return true;
}
else
{
qDebug() << "Error mounting:" << mp.error().message();
}
}
QThread::sleep(1);
}
qDebug() << "Failed to mount new file system.";
return false;
}
return true;
}
QString UDisks2Api::mountDevice(const QString &device)
{
QString devpath = _resolveDevice(device);
if (devpath.isEmpty())
return QString();
QDBusInterface filesystem("org.freedesktop.UDisks2", devpath,
"org.freedesktop.UDisks2.Filesystem", QDBusConnection::systemBus());
QVariantMap mountOptions;
for (int attempt = 0; attempt < 10; attempt++)
{
qDebug() << "Mounting partition";
// User may need to enter password in authentication dialog if non-removable storage, so set long timeout
filesystem.setTimeout(3600 * 1000);
QDBusReply<QString> mp = filesystem.call("Mount", mountOptions);
if (mp.isValid())
{
qDebug() << "Mounted file system at:" << mp;
return mp;
}
else
{
/* Check if already auto-mounted */
auto mps = mountPoints(filesystem);
if (!mps.isEmpty())
{
qDebug() << "Was already auto-mounted at:" << mps;
return mps.first();
}
else
{
qDebug() << "Error mounting:" << mp.error().message();
}
}
QThread::sleep(1);
}
qDebug() << "Failed to mount file system.";
return QString();
}
void UDisks2Api::unmountDrive(const QString &device)
{
QString devpath = _resolveDevice(device);
if (devpath.isEmpty())
return;
_unmountDrive(devpath);
}
QByteArrayList UDisks2Api::mountPoints(const QString &partitionDevice)
{
QString devpath = _resolveDevice(partitionDevice);
if (devpath.isEmpty())
return QByteArrayList();
QDBusInterface filesystem("org.freedesktop.UDisks2", devpath,
"org.freedesktop.UDisks2.Filesystem", QDBusConnection::systemBus());
return mountPoints(filesystem);
}
QByteArrayList UDisks2Api::mountPoints(const QDBusInterface &filesystem)
{
QByteArrayList mps;
QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.UDisks2", filesystem.path(),
"org.freedesktop.DBus.Properties", "Get");
QVariantList args = {"org.freedesktop.UDisks2.Filesystem", "MountPoints"};
msg.setArguments(args);
QDBusMessage reply = QDBusConnection::systemBus().call(msg);
for (auto arg : reply.arguments())
{
arg.value<QDBusVariant>().variant().value<QDBusArgument>() >> mps;
}
for (auto &str : mps)
{
if (!str.isEmpty() && str.back() == '\0')
str.chop(1);
}
return mps;
}

35
src/linux/udisks2api.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef UDISKS2API_H
#define UDISKS2API_H
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2020 Raspberry Pi Ltd
*/
#include <QObject>
#include <QFile>
class QDBusInterface;
class UDisks2Api : public QObject
{
Q_OBJECT
public:
explicit UDisks2Api(QObject *parent = nullptr);
int authOpen(const QString &device, const QString &mode = "rw");
bool formatDrive(const QString &device, bool mountAfterwards = true);
QString mountDevice(const QString &device);
void unmountDrive(const QString &device);
QByteArrayList mountPoints(const QString &partitionDevice);
QByteArrayList mountPoints(const QDBusInterface &filesystem);
protected:
QString _resolveDevice(const QString &device);
void _unmountDrive(const QString &driveDbusPath);
signals:
public slots:
};
#endif // UDISKS2API_H