Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Checks whether the rootfs has UDI or Subiquity snaps #249

Merged
merged 5 commits into from
Jul 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ if EXIST "$(SharedIdb)" xcopy /Y /F "$(SharedIdb)" "$(IntDir)"</Command>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\DistroLauncher\algorithms.h" />
<ClInclude Include="FakeChildProcessImpl.h" />
<ClInclude Include="mock_api.h" />
<ClInclude Include="InstallerControllerTestPolicies.h" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
<ClInclude Include="InstallerControllerTestPolicies.h" />
<ClInclude Include="mock_api.h" />
<ClInclude Include="FakeChildProcessImpl.h" />
<ClInclude Include="..\..\DistroLauncher\algorithms.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
Expand All @@ -116,4 +117,4 @@
<UniqueIdentifier>{c6954f59-9f21-4dd8-a33d-693e8797d882}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,37 @@

TEST(UpgradePolicyTests, StringParsing)
{
ASSERT_FALSE(internal::starts_with(L"", L"hello"));
ASSERT_FALSE(internal::starts_with(L"he", L"hello"));
ASSERT_TRUE(internal::starts_with(L"hello", L"hello"));
ASSERT_TRUE(internal::starts_with(L"hello, world!", L"hello"));
ASSERT_FALSE(internal::starts_with(L"cheers, world!", L"hello"));
ASSERT_FALSE(internal::starts_with(L"HELLO", L"hello"));
ASSERT_FALSE(starts_with(L"", L"hello"));
ASSERT_FALSE(starts_with(L"he", L"hello"));
ASSERT_TRUE(starts_with(L"hello", L"hello"));
ASSERT_TRUE(starts_with(L"hello, world!", L"hello"));
ASSERT_FALSE(starts_with(L"cheers, world!", L"hello"));
ASSERT_FALSE(starts_with(L"HELLO", L"hello"));

ASSERT_FALSE(internal::ends_with(L"", L"world!"));
ASSERT_FALSE(internal::ends_with(L"d!", L"world!"));
ASSERT_TRUE(internal::ends_with(L"world!", L"world!"));
ASSERT_TRUE(internal::ends_with(L"hello, world!", L"world!"));
ASSERT_FALSE(internal::ends_with(L"hello, world?", L"world!"));
ASSERT_FALSE(internal::ends_with(L"this string is completely diferent", L"world!"));
ASSERT_FALSE(internal::ends_with(L"HELLO", L"hello"));
ASSERT_FALSE(ends_with(L"", L"world!"));
ASSERT_FALSE(ends_with(L"d!", L"world!"));
ASSERT_TRUE(ends_with(L"world!", L"world!"));
ASSERT_TRUE(ends_with(L"hello, world!", L"world!"));
ASSERT_FALSE(ends_with(L"hello, world?", L"world!"));
ASSERT_FALSE(ends_with(L"this string is completely diferent", L"world!"));
ASSERT_FALSE(ends_with(L"HELLO", L"hello"));

ASSERT_FALSE(internal::starts_with(L"", L"Ubuntu"));
ASSERT_TRUE(internal::starts_with(L"Ubuntu 22.04.1 LTS", L"Ubuntu"));
ASSERT_TRUE(internal::ends_with(L"Ubuntu 22.04.1 LTS", L"LTS"));
ASSERT_FALSE(starts_with(L"", L"Ubuntu"));
ASSERT_TRUE(starts_with(L"Ubuntu 22.04.1 LTS", L"Ubuntu"));
ASSERT_TRUE(ends_with(L"Ubuntu 22.04.1 LTS", L"LTS"));
}

TEST(UpgradePolicyTests, Concat)
{
// Checking default functionality
std::wstring dog = L"dog";
auto example = internal::concat(L"The", L" quick brown fox", L" jumps over the lazy ", std::quoted(dog), '.');
auto example = concat(L"The", L" quick brown fox", L" jumps over the lazy ", std::quoted(dog), '.');

ASSERT_EQ(example, LR"(The quick brown fox jumps over the lazy "dog".)");

// Checking quote nesting
auto nested = internal::concat(L"\n{\n ", std::quoted(L"name"), L": ", std::quoted(L"example"), L",\n ",
std::quoted(L"value"), L": ", std::quoted(example), L"\n}\n");
auto nested = concat(L"\n{\n ", std::quoted(L"name"), L": ", std::quoted(L"example"), L",\n ",
std::quoted(L"value"), L": ", std::quoted(example), L"\n}\n");
auto expected = LR"(
{
"name": "example",
Expand All @@ -61,7 +61,6 @@ TEST(UpgradePolicyTests, Concat)

// Checking path auto-quoting
std::filesystem::path example_file{L"/home/fox/documents/example.json"};
auto with_path =
internal::concat(L"diff ", example_file, L" ", example_file.wstring()); // Only first one to be quoted
auto with_path = concat(L"diff ", example_file, L" ", example_file.wstring()); // Only first one to be quoted
ASSERT_EQ(with_path, LR"(diff "/home/fox/documents/example.json" /home/fox/documents/example.json)");
}
1 change: 1 addition & 0 deletions DistroLauncher/DistroLauncher.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="algorithms.h" />
<ClInclude Include="Application.h" />
<ClInclude Include="ApplicationStrategy.h" />
<ClInclude Include="ChildProcess.h" />
Expand Down
33 changes: 32 additions & 1 deletion DistroLauncher/WSLInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,28 @@ namespace Oobe::internal
return ini_find_value(wslConf, L"boot", L"command", L"/usr/libexec/wsl-systemd");
}

bool hasSnap(std::wstring_view name)
{
namespace fs = std::filesystem;
const auto path = Oobe::WindowsPath(fs::path{L"/var/lib/snapd/snaps/"});
return find_file_if(path, [name](const auto& entry) {
return fs::is_regular_file(entry) && starts_with({entry.path().filename().wstring()}, name);
});
}

bool hasUdiSnap()
{
static bool hasUdi = hasSnap(L"ubuntu-desktop-installer");

return hasUdi;
}

bool hasSubiquitySnap()
{
static bool hasSubiquity = hasSnap(L"subiquity");
return hasSubiquity;
}

} // namespace Oobe::internal

// This was kept under Helpers namespace to avoid touching OOBE.cpp/h files.
Expand All @@ -145,8 +167,17 @@ namespace Helpers
{
bool WslGraphicsSupported()
{
// It's possible that we have only Subiquity instead of the Ubuntu-Desktop-Installer snap.
if (!Oobe::internal::hasUdiSnap()) {
return false;
}

if (!Oobe::internal::isWslgEnabled()) {
return false;
}

// Could WSL 3 or greater exist in the future?
return (Oobe::internal::isWslgEnabled() && Oobe::internal::WslGetDistroSubsystemVersion() > 1);
return Oobe::internal::WslGetDistroSubsystemVersion() > 1;
}

} // namespace Helpers.
Expand Down
9 changes: 9 additions & 0 deletions DistroLauncher/WSLInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ namespace Oobe::internal
/// <https://docs.microsoft.com/en-us/windows/wsl/wsl-config#:~:text=WSL%202%20VM.-,localhostForwarding,-boolean>
bool isLocalhostForwardingEnabled(const std::filesystem::path& wslConfig);

/// Returns true if the ubuntu-desktop-installer snap is found inside the rootfs.
/// It's possible that we have only Subiquity or none instead.
/// That's meant to be called during setup, where filesystem errors are less likely to happen.
bool hasUdiSnap();

/// Returns true if the subiquity snap is found inside the rootfs.
/// It's possible that we have the ubuntu-desktop-installer or none instead.
/// That's meant to be called during setup, where filesystem errors are less likely to happen.
bool hasSubiquitySnap();
}

namespace Oobe
Expand Down
70 changes: 70 additions & 0 deletions DistroLauncher/algorithms.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#pragma once
/*
* Copyright (C) 2022 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

// Common algorithms to be used everywhere in the launcher project with style resembling the std ones.

template <typename CharT>
bool starts_with(const std::basic_string_view<CharT> tested, const std::basic_string_view<CharT> start)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ bugprone-easily-swappable-parameters ⚠️
2 adjacent parameters of starts_with of similar type (const std::basic_string_view<CharT>) are easily swapped by mistake

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is indeed somewhat bug prone, but those are the only parameters the function accept, I don't see other way to do it :D.

{
if (tested.size() < start.size()) {
return false;
}
auto mismatch = std::mismatch(start.cbegin(), start.cend(), tested.cbegin());
return mismatch.first == start.cend();
}

template <typename CharT, std::size_t TestedSize, std::size_t StartSize>
bool starts_with(CharT const (&tested)[TestedSize], CharT const (&start)[StartSize])
{
return starts_with<CharT>(std::basic_string_view<CharT>{tested}, std::basic_string_view<CharT>{start});
}

template <typename CharT>
bool ends_with(const std::basic_string_view<CharT> tested, const std::basic_string_view<CharT> end)
{
if (tested.size() < end.size()) {
return false;
}
auto mismatch = std::mismatch(end.crbegin(), end.crend(), tested.crbegin());
return mismatch.first == end.crend();
}

template <typename CharT, std::size_t TestedSize, std::size_t EndSize>
bool ends_with(const CharT (&tested)[TestedSize], const CharT (&end)[EndSize])
{
return ends_with<CharT>(std::basic_string_view<CharT>{tested}, std::basic_string_view<CharT>{end});
}

template <typename... Args> std::wstring concat(Args&&... args)
{
std::wstringstream buffer;
(buffer << ... << std::forward<Args>(args));
return buffer.str();
}

template <typename Pred> bool find_file_if(const std::filesystem::path& directory, Pred&& pred)
{
namespace fs = std::filesystem;
std::error_code error;
assert(fs::is_directory(directory));
auto listing = fs::directory_iterator{directory, error};
if (error) {
return false;
}
return std::find_if(begin(listing), end(listing), std::forward<Pred>(pred)) != end(listing);
}
1 change: 1 addition & 0 deletions DistroLauncher/stdafx.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <variant>
#include <type_traits>
#include <utility>
#include "algorithms.h"
#include "expected.hpp"
#include "not_null.h"
#include "WslApiLoader.h"
Expand Down
20 changes: 1 addition & 19 deletions DistroLauncher/upgrade_policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,13 @@
namespace internal
{

bool starts_with(const std::wstring_view tested, const std::wstring_view start)
{
if (tested.size() < start.size()) {
return false;
}
auto mismatch = std::mismatch(start.cbegin(), start.cend(), tested.cbegin());
return mismatch.first == start.cend();
}

bool ends_with(const std::wstring_view tested, const std::wstring_view end)
{
if (tested.size() < end.size()) {
return false;
}
auto mismatch = std::mismatch(end.crbegin(), end.crend(), tested.crbegin());
return mismatch.first == end.crend();
}

std::wstring GetUpgradePolicy()
{
std::wstring_view name = DistributionInfo::Name;
if (name == L"Ubuntu") {
return L"lts";
}
if (starts_with(name, L"Ubuntu") && ends_with(name, L"LTS")) {
if (starts_with(name, {L"Ubuntu"}) && ends_with(name, {L"LTS"})) {
return L"never";
}
return L"normal";
Expand Down
10 changes: 0 additions & 10 deletions DistroLauncher/upgrade_policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,8 @@

namespace internal
{
bool starts_with(std::wstring_view tested, std::wstring_view start);
bool ends_with(std::wstring_view tested, std::wstring_view end);

std::wstring GetUpgradePolicy();

template <typename... Args> std::wstring concat(Args&&... args)
{
std::wstringstream buffer;
(buffer << ... << std::forward<Args>(args));
return buffer.str();
}

void SetDefaultUpgradePolicyImpl();

}
Expand Down