Persist all configuration settings across upgrades. Restart wifi-p2p if neccessary.

This commit is contained in:
Robin Davies
2024-08-27 14:55:48 -04:00
parent 722ef456bc
commit 06ebfb0bce
15 changed files with 340 additions and 201 deletions
+3 -2
View File
@@ -258,10 +258,11 @@
"program": "${command:cmake.launchTargetPath}", "program": "${command:cmake.launchTargetPath}",
"args": [ "args": [
"--nosudo", // run without sudo (which will fail because of perms, but allow us to debug deeper into install code.) "--nosudo", // run without sudo (which will fail because of perms, but allow us to debug deeper into install code.)
"--prefix", "/usr",
//"--get-current-port" //"--get-current-port"
// "--uninstall" "--install"
//"--enable-p2p" , "CA", "PiPedalTest","12345678","14" //"--enable-p2p" , "CA", "PiPedalTest","12345678","14"
"--list-p2p-channels" //"--list-p2p-channels"
], ],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
+35 -4
View File
@@ -9,11 +9,14 @@
#include "WifiRegs.hpp" #include "WifiRegs.hpp"
#include "ChannelInfo.hpp" #include "ChannelInfo.hpp"
#include "DBusLog.hpp" #include "DBusLog.hpp"
#include <sys/stat.h>
using namespace pipedal; using namespace pipedal;
P2pSettings::P2pSettings(const std::filesystem::path&configDirectoryPath) P2pSettings::P2pSettings(const std::filesystem::path&configDirectoryPath, const std::filesystem::path&varDirectoryPath = "/var/pipedal/config")
: configDirectoryPath(configDirectoryPath),
varDirectoryPath(varDirectoryPath)
{ {
this->configDirectoryPath = configDirectoryPath;
} }
@@ -188,12 +191,40 @@ void P2pSettings::Load()
} }
} }
static void openWithPerms(
std::ofstream &f,
const std::filesystem::path &path,
std::filesystem::perms perms =
std::filesystem::perms::owner_read | std::filesystem::perms::owner_write |
std::filesystem::perms::group_read | std::filesystem::perms::group_write)
{
auto directory = path.parent_path();
std::filesystem::create_directories(directory);
// open and close to make an existing empty file.
// close it.
{
std::ofstream f;
f.open(path);
f.close();
}
// set the perms.
std::filesystem::permissions(
path,
perms,
std::filesystem::perm_options::replace);
// open for re3al.
f.open(path);
}
void P2pSettings::Save() void P2pSettings::Save()
{ {
auto filename = config_filename(); auto filename = config_filename();
try { try {
std::ofstream f(filename); std::ofstream f;
if (!f) openWithPerms(f,filename);
if (!f.is_open())
{ {
throw std::runtime_error("Can't write to file."); throw std::runtime_error("Can't write to file.");
} }
+3 -2
View File
@@ -8,7 +8,7 @@
class P2pSettings { class P2pSettings {
// adapter between nm p2p settings, and legacy p2p // adapter between nm p2p settings, and legacy p2p
public: public:
P2pSettings(const std::filesystem::path&configDirectory = "/etc/pipedal/config"); P2pSettings(const std::filesystem::path&configDirectory = "/etc/pipedal/config", const std::filesystem::path&varDirectory = "/var/pipedal/config");
void Load(); void Load();
void Save(); void Save();
@@ -16,6 +16,7 @@ public:
private: private:
bool valid_ = false; bool valid_ = false;
std::filesystem::path configDirectoryPath; std::filesystem::path configDirectoryPath;
std::filesystem::path varDirectoryPath;
bool auth_changed_ = true; bool auth_changed_ = true;
std::vector<uint8_t> device_type_{ std::vector<uint8_t> device_type_{
0x00,0x01, 0x00,0x50,0xF2,0x04, 0x00,0x02 /*"1-0050F204-2";*/ 0x00,0x01, 0x00,0x50,0xF2,0x04, 0x00,0x02 /*"1-0050F204-2";*/
@@ -59,7 +60,7 @@ public:
}; };
std::filesystem::path config_filename() const { std::filesystem::path config_filename() const {
// "/etc/pipedal/config/wpa_supplicant/wpa_supplicant-pipedal.conf"; } // "/etc/pipedal/config/wpa_supplicant/wpa_supplicant-pipedal.conf"; }
return (configDirectoryPath / "NetworkManagerP2P.json").string(); return (varDirectoryPath / "NetworkManagerP2P.json").string();
}; };
const std::string& bssid() const { return bssid_; } const std::string& bssid() const { return bssid_; }
+30 -23
View File
@@ -1,18 +1,18 @@
/* /*
* MIT License * MIT License
* *
* Copyright (c) 2022 Robin E. R. Davies * Copyright (c) 2022 Robin E. R. Davies
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of * Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in * this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to * the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do * of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions: * so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in all * The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software. * copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -23,6 +23,7 @@
*/ */
#include "ServiceConfiguration.hpp" #include "ServiceConfiguration.hpp"
#include <filesystem>
#include <fstream> #include <fstream>
#include <stdexcept> #include <stdexcept>
#include <grp.h> #include <grp.h>
@@ -35,43 +36,49 @@ using namespace pipedal;
using namespace std; using namespace std;
using namespace config_serializer; using namespace config_serializer;
const char ServiceConfiguration::DEVICEID_FILE_NAME[] = "/var/pipedal/config/service.conf";
const char ServiceConfiguration::DEVICEID_FILE_NAME[] = "/etc/pipedal/config/service.conf";
#define SERIALIZER_ENTRY(MEMBER_NAME) \ #define SERIALIZER_ENTRY(MEMBER_NAME) \
new ConfigSerializer<ServiceConfiguration,decltype(ServiceConfiguration::MEMBER_NAME)>(#MEMBER_NAME, &ServiceConfiguration::MEMBER_NAME, "") new ConfigSerializer<ServiceConfiguration, decltype(ServiceConfiguration::MEMBER_NAME)>(#MEMBER_NAME, &ServiceConfiguration::MEMBER_NAME, "")
static p2p::autoptr_vector<ConfigSerializerBase<ServiceConfiguration>> static p2p::autoptr_vector<ConfigSerializerBase<ServiceConfiguration>>
deviceIdSerializers deviceIdSerializers{
{ SERIALIZER_ENTRY(uuid),
SERIALIZER_ENTRY(uuid), SERIALIZER_ENTRY(deviceName),
SERIALIZER_ENTRY(deviceName), SERIALIZER_ENTRY(server_port)};
SERIALIZER_ENTRY(server_port)
};
ServiceConfiguration::ServiceConfiguration() ServiceConfiguration::ServiceConfiguration()
: base(deviceIdSerializers) : base(deviceIdSerializers)
{ {
filename = "/var/pipedal/config/service.conf";
} }
void ServiceConfiguration::Load() void ServiceConfiguration::Load(std::filesystem::path filename)
{ {
base::Load(DEVICEID_FILE_NAME,false); this->filename = filename;
base::Load(filename, false);
} }
void ServiceConfiguration::Save() void ServiceConfiguration::Save()
{ {
base::Save(DEVICEID_FILE_NAME);
{ {
struct group *group_; auto directory = filename.parent_path();
std::filesystem::create_directories(directory);
// make sure the file has correct permissions.
std::ofstream t;
t.open(filename);
t.close();
struct group *group_;
group_ = getgrnam("pipedal_d"); group_ = getgrnam("pipedal_d");
if (group_ == nullptr) if (group_ == nullptr)
{ {
throw logic_error("Group not found: pipedal_d"); throw logic_error("Group not found: pipedal_d");
} }
std::ignore = chown(DEVICEID_FILE_NAME,-1,group_->gr_gid); std::ignore = chown(DEVICEID_FILE_NAME, -1, group_->gr_gid);
std::ignore = chmod(DEVICEID_FILE_NAME, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); std::ignore = chmod(DEVICEID_FILE_NAME, S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH);
} }
base::Save(filename);
} }
@@ -158,12 +158,12 @@ void WifiDirectConfigSettings::Load()
{ {
this->enable_ = false; this->enable_ = false;
std::string strEnable; std::string strEnable;
if (ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","enabled",&strEnable)) if (ConfigUtil::GetConfigLine("/var/pipedal/config/pipedal_p2pd.conf","enabled",&strEnable))
{ {
this->enable_ = (strEnable == "true" || strEnable == "1"); this->enable_ = (strEnable == "true" || strEnable == "1");
} }
std::string strWlan; std::string strWlan;
if (ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","wlan",&strWlan)) if (ConfigUtil::GetConfigLine("/var/pipedal/config/pipedal_p2pd.conf","wlan",&strWlan))
{ {
this->wlan_ = strWlan; this->wlan_ = strWlan;
} else { } else {
@@ -172,20 +172,20 @@ void WifiDirectConfigSettings::Load()
if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","p2p_device_name",&this->hotspotName_)) if (!ConfigUtil::GetConfigLine("/var/pipedal/config/pipedal_p2pd.conf","p2p_device_name",&this->hotspotName_))
{ {
this->hotspotName_ = "PiPedal"; this->hotspotName_ = "PiPedal";
} }
if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","country_code",&this->countryCode_)) if (!ConfigUtil::GetConfigLine("/var/pipedal/config/pipedal_p2pd.conf","country_code",&this->countryCode_))
{ {
this->countryCode_ = "US"; this->countryCode_ = "US";
} }
if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","p2p_pin",&this->pin_)) if (!ConfigUtil::GetConfigLine("/var/pipedal/config/pipedal_p2pd.conf","p2p_pin",&this->pin_))
{ {
this->pin_ = "12345678"; this->pin_ = "12345678";
} }
if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","wifiChannel",&this->channel_)) if (!ConfigUtil::GetConfigLine("/var/pipedal/config/pipedal_p2pd.conf","wifiChannel",&this->channel_))
{ {
this->channel_ = "6"; this->channel_ = "6";
} }
@@ -26,6 +26,7 @@
#include <string> #include <string>
#include "ConfigSerializer.hpp" #include "ConfigSerializer.hpp"
#include <filesystem>
namespace pipedal { namespace pipedal {
using namespace config_serializer; using namespace config_serializer;
@@ -38,12 +39,16 @@ namespace pipedal {
static const char DEVICEID_FILE_NAME[]; static const char DEVICEID_FILE_NAME[];
void Load(); void Load(
std::filesystem::path path = "/var/pipedal/config/service.conf"
);
void Save(); void Save();
std::string uuid; std::string uuid;
std::string deviceName = "PiPedal"; std::string deviceName = "PiPedal";
uint32_t server_port = 80; uint32_t server_port = 80;
private:
std::filesystem::path filename;
}; };
} }
+20 -14
View File
@@ -1,33 +1,39 @@
{ {
// DO NOT EDIT THIS FILE
//
// THIS FILE CONTAINS DEFAULT VALUES AS SET BY THE INSTALLER, AND IS OVERWRITTEN BY
// UPGRADES.
//
// If you wish to customize any of these values, see /var/pipedal/config/config.json
/* A writable directory in which state files can be stored, preferrably only by the server process. */
"local_storage_path": "/var/pipedal",
/* One or more directories containing LV2 plugins, seperated by ':' */ /* One or more directories containing LV2 plugins, seperated by ':' */
"lv2_path": "/usr/lib/lv2:/usr/local/lib/lv2:/usr/modep/lv2", "lv2_path": "/usr/lib/lv2:/usr/local/lib/lv2:/usr/modep/lv2",
/* A writable directory in which state files can be stored, preferrably only by the server process. */ /* whether to lock a process pages into memor. should be true unless running on a very memory constrained system.
"local_storage_path": "/var/pipedal", Setting to false may cause unpredictable audio dropouts.
/* whether to lock a process pages into memroy. should be true unless running on a very memory constrained system.
Setting to false will cause unpredictable audio dropouts.
*/ */
"mlock": true, "mlock": true,
/* Address on which Piddle listens for websocket connections */
"socketServerAddress": "0.0.0.0:80",
/* Number of threads to use for servicing websockets */ /* Number of threads to use for servicing websockets */
"threads" : 5, "threads" : 5,
/* Address on which the web server listens for http requests. */
"socketServerAddress": "0.0.0.0:80",
/* Whether to log individual http requests. (inadvisable) */
"logHttpRequests": false, "logHttpRequests": false,
/* Log level for the web server */
/* { None=0,Error =1,Warning =2,Info = 3, Debug=4} */ /* { None=0,Error =1,Warning =2,Info = 3, Debug=4} */
"logLevel": 3, "logLevel": 3,
/* Maximum filesize to allow when uploading */ /* Maximum filesize to allow when uploading */
"maxUploadSize": 536870912, "maxUploadSize": 536870912 // 512MiB
/* Provide access point capture redirects on this gateway. -- provides automatic browser launching on Access Point access.
(not implemented)
*/
"accessPointGateway": "172.24.1.0/24",
"accessPointServerAddress": "172.24.1.1"
} }
+1
View File
@@ -571,6 +571,7 @@ add_executable(pipedalconfig
CommandLineParser.hpp CommandLineParser.hpp
PiPedalException.hpp PiPedalException.hpp
ConfigMain.cpp ConfigMain.cpp
PiPedalConfiguration.hpp PiPedalConfiguration.cpp
JackServerSettings.hpp JackServerSettings.cpp JackServerSettings.hpp JackServerSettings.cpp
SystemConfigFile.hpp SystemConfigFile.cpp SystemConfigFile.hpp SystemConfigFile.cpp
WifiChannelSelectors.cpp WifiChannelSelectors.hpp WifiChannelSelectors.cpp WifiChannelSelectors.hpp
+88 -95
View File
@@ -38,6 +38,7 @@
#include <random> #include <random>
#include "AudioConfig.hpp" #include "AudioConfig.hpp"
#include "WifiChannelSelectors.hpp" #include "WifiChannelSelectors.hpp"
#include "PiPedalConfiguration.hpp"
#include <grp.h> #include <grp.h>
#if JACK_HOST #if JACK_HOST
@@ -54,6 +55,8 @@
using namespace std; using namespace std;
using namespace pipedal; using namespace pipedal;
namespace fs = std::filesystem;
#define SERVICE_ACCOUNT_NAME "pipedal_d" #define SERVICE_ACCOUNT_NAME "pipedal_d"
#define SERVICE_GROUP_NAME "pipedal_d" #define SERVICE_GROUP_NAME "pipedal_d"
@@ -80,12 +83,12 @@ using namespace pipedal;
#define REMOVE_OLD_SERVICE 0 // Grandfathering: whether to remove the old shutdown service (now pipedaladmind) #define REMOVE_OLD_SERVICE 0 // Grandfathering: whether to remove the old shutdown service (now pipedaladmind)
#define OLD_SHUTDOWN_SERVICE "pipedalshutdownd" #define OLD_SHUTDOWN_SERVICE "pipedalshutdownd"
std::filesystem::path GetServiceFileName(const std::string &serviceName) fs::path GetServiceFileName(const std::string &serviceName)
{ {
return std::filesystem::path(SERVICE_PATH) / (serviceName + ".service"); return fs::path(SERVICE_PATH) / (serviceName + ".service");
} }
std::filesystem::path findOnPath(const std::string &command) fs::path findOnPath(const std::string &command)
{ {
std::string path = getenv("PATH"); std::string path = getenv("PATH");
std::vector<std::string> paths; std::vector<std::string> paths;
@@ -98,8 +101,8 @@ std::filesystem::path findOnPath(const std::string &command)
pos = path.length(); pos = path.length();
} }
std::string thisPath = path.substr(t, pos - t); std::string thisPath = path.substr(t, pos - t);
std::filesystem::path path = std::filesystem::path(thisPath) / command; fs::path path = fs::path(thisPath) / command;
if (std::filesystem::exists(path)) if (fs::exists(path))
{ {
return path; return path;
} }
@@ -244,7 +247,7 @@ static void RemoveLine(const std::string &path, const std::string lineToRemove)
std::vector<std::string> lines; std::vector<std::string> lines;
try try
{ {
if (std::filesystem::exists(path)) if (fs::exists(path))
{ {
{ {
ifstream f(path); ifstream f(path);
@@ -298,10 +301,10 @@ void InstallPamEnv()
#if INSTALL_JACK_SERVICE #if INSTALL_JACK_SERVICE
std::string newLine = PAM_LINE; std::string newLine = PAM_LINE;
std::vector<std::string> lines; std::vector<std::string> lines;
std::filesystem::path path = "/etc/security/pam_env.conf"; fs::path path = "/etc/security/pam_env.conf";
try try
{ {
if (std::filesystem::exists(path)) if (fs::exists(path))
{ {
{ {
ifstream f(path); ifstream f(path);
@@ -355,9 +358,9 @@ void InstallLimits()
throw std::runtime_error("Failed to create audio service group."); throw std::runtime_error("Failed to create audio service group.");
} }
std::filesystem::path limitsConfig = "/etc/security/limits.d/audio.conf"; fs::path limitsConfig = "/etc/security/limits.d/audio.conf";
if (!std::filesystem::exists(limitsConfig)) if (!fs::exists(limitsConfig))
{ {
ofstream output(limitsConfig); ofstream output(limitsConfig);
output << "# Realtime priority group used by pipedal audio (and also by jack)" output << "# Realtime priority group used by pipedal audio (and also by jack)"
@@ -372,9 +375,9 @@ void InstallLimits()
#if JACK_HOST #if JACK_HOST
void MaybeStartJackService() void MaybeStartJackService()
{ {
std::filesystem::path drcFile = "/etc/jackdrc"; fs::path drcFile = "/etc/jackdrc";
if (std::filesystem::exists(drcFile) && std::filesystem::file_size(drcFile) != 0) if (fs::exists(drcFile) && fs::file_size(drcFile) != 0)
{ {
sysExec(SYSTEMCTL_BIN " start jack"); sysExec(SYSTEMCTL_BIN " start jack");
} }
@@ -466,23 +469,8 @@ void Uninstall()
{ {
try try
{ {
try OnWifiUninstall(true);
{
if (IsP2pServiceEnabled())
{
WifiDirectConfigSettings settings;
settings.Load();
settings.enable_ = false;
settings.Save();
SetWifiDirectConfig(settings);
}
}
catch (const std::exception e)
{
std::cout << "Error: Unable to disable the Wiifi P2P service. " << e.what() << std::endl;
}
OnWifiUninstall();
StopService(); StopService();
DisableService(); DisableService();
@@ -494,7 +482,7 @@ void Uninstall()
try try
{ {
std::filesystem::remove("/usr/bin/systemd/system/" OLD_SHUTDOWN_SERVICE ".service"); fs::remove("/usr/bin/systemd/system/" OLD_SHUTDOWN_SERVICE ".service");
} }
catch (...) catch (...)
{ {
@@ -502,21 +490,21 @@ void Uninstall()
try try
{ {
std::filesystem::remove("/usr/bin/systemd/system/" ADMIN_SERVICE ".service"); fs::remove("/usr/bin/systemd/system/" ADMIN_SERVICE ".service");
} }
catch (...) catch (...)
{ {
} }
try try
{ {
std::filesystem::remove("/usr/bin/systemd/system/" PIPEDAL_NM_P2PD_SERVICE ".service"); fs::remove("/usr/bin/systemd/system/" PIPEDAL_NM_P2PD_SERVICE ".service");
} }
catch (...) catch (...)
{ {
} }
try try
{ {
std::filesystem::remove("/usr/bin/systemd/system/" PIPEDAL_P2PD_SERVICE ".service"); fs::remove("/usr/bin/systemd/system/" PIPEDAL_P2PD_SERVICE ".service");
} }
catch (...) catch (...)
{ {
@@ -524,7 +512,7 @@ void Uninstall()
try try
{ {
std::filesystem::remove("/usr/bin/systemd/system/" PIPEDALD_SERVICE ".service"); fs::remove("/usr/bin/systemd/system/" PIPEDALD_SERVICE ".service");
} }
catch (...) catch (...)
{ {
@@ -532,7 +520,7 @@ void Uninstall()
try try
{ {
std::filesystem::remove("/usr/bin/systemd/system/" JACK_SERVICE ".service"); fs::remove("/usr/bin/systemd/system/" JACK_SERVICE ".service");
} }
catch (...) catch (...)
{ {
@@ -596,13 +584,22 @@ static std::string RandomChars(int nchars)
return s.str(); return s.str();
} }
static std::map<fs::path, fs::perms> sPermissionExceptions
({
{
"/var/pipedal/config/NetworkManagerP2P.json",
fs::perms::owner_read | fs::perms::owner_write | fs::perms::group_read | fs::perms::group_write
}
});
void SetVarPermissions( void SetVarPermissions(
const std::filesystem::path &path, const fs::path &path,
std::filesystem::perms directoryPermissions, fs::perms directoryPermissions,
std::filesystem::perms filePermissions, fs::perms filePermissions,
uid_t uid, gid_t gid) uid_t uid, gid_t gid)
{ {
namespace fs = std::filesystem;
using namespace std::filesystem; using namespace std::filesystem;
try { try {
if (fs::exists(path)) { if (fs::exists(path)) {
@@ -630,17 +627,22 @@ void SetVarPermissions(
} }
} else { } else {
fs::permissions(path,filePermissions, fs::perm_options::replace); if (sPermissionExceptions.contains(path))
{
fs::permissions(path,sPermissionExceptions[path], fs::perm_options::replace);
} else {
fs::permissions(path,filePermissions, fs::perm_options::replace);
}
} }
} else { } else {
std::cout << "Error: Path does not exist: " << path << std::endl; std::cout << "Error: Path does not exist: " << path << std::endl;
} }
} catch (const std::filesystem::filesystem_error& e) { } catch (const fs::filesystem_error& e) {
std::cerr << "Error: " << e.what() << std::endl; std::cerr << "Error: " << e.what() << std::endl;
} }
} }
namespace fs = std::filesystem;
static void FixPermissions() static void FixPermissions()
{ {
@@ -675,7 +677,7 @@ static void FixPermissions()
fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_read | fs::perms::owner_write |
fs::perms::group_read | fs::perms::group_write; fs::perms::group_read | fs::perms::group_write;
std::filesystem::path wpa_config_path{ "/etc/pipedal/config/wpa_supplicant/wpa_supplicant-pipedal.conf"}; fs::path wpa_config_path{ "/etc/pipedal/config/wpa_supplicant/wpa_supplicant-pipedal.conf"};
try { try {
fs::permissions(wpa_config_path,wpa_supplicant_perms, fs::perm_options::replace); fs::permissions(wpa_config_path,wpa_supplicant_perms, fs::perm_options::replace);
@@ -722,21 +724,40 @@ void CopyWpaSupplicantConfigFile()
try { try {
const char NM_SUPPLICANT_CONFIG_PATH[] = "/etc/pipedal/config/wpa_supplicant/wpa_supplicant-pipedal.conf"; const char NM_SUPPLICANT_CONFIG_PATH[] = "/etc/pipedal/config/wpa_supplicant/wpa_supplicant-pipedal.conf";
const char NM_SUPPLICANT_CONFIG_SOURCE_PATH[] = "/etc/pipedal/config/templates/wpa_supplicant-pipedal.conf"; const char NM_SUPPLICANT_CONFIG_SOURCE_PATH[] = "/etc/pipedal/config/templates/wpa_supplicant-pipedal.conf";
std::filesystem::path destinationPath = NM_SUPPLICANT_CONFIG_PATH; fs::path destinationPath = NM_SUPPLICANT_CONFIG_PATH;
std::filesystem::path sourcePath = NM_SUPPLICANT_CONFIG_SOURCE_PATH; fs::path sourcePath = NM_SUPPLICANT_CONFIG_SOURCE_PATH;
std::filesystem::create_directories(destinationPath.parent_path()); fs::create_directories(destinationPath.parent_path());
std::filesystem::copy_file(sourcePath,destinationPath,std::filesystem::copy_options::overwrite_existing); fs::copy_file(sourcePath,destinationPath,fs::copy_options::overwrite_existing);
} catch (const std::exception&e) } catch (const std::exception&e)
{ {
cout << "ERROR: " << e.what() << endl; cout << "ERROR: " << e.what() << endl;
} }
} }
void Install(const std::filesystem::path &programPrefix, const std::string endpointAddress)
void DeployVarConfig()
{
fs::path varConfig = "/var/pipedal/config/config.json";
if (!fs::exists(varConfig))
{
auto directory = varConfig.parent_path();
fs::create_directories(directory);
fs::path templateFile = "/etc/pipedal/config/templates/var_config.json";
try {
fs::copy(templateFile,varConfig);
} catch (const std::exception &e)
{
std::cout << "Error: Failed to create " << varConfig << std::endl;
}
}
}
void Install(const fs::path &programPrefix, const std::string endpointAddress)
{ {
cout << "Configuring pipedal" << endl; cout << "Configuring pipedal" << endl;
try try
{ {
DeployVarConfig();
if (sysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS) if (sysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS)
{ {
throw std::runtime_error("Failed to create audio service group."); throw std::runtime_error("Failed to create audio service group.");
@@ -812,8 +833,8 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
// create and configure /var directory. // create and configure /var directory.
std::filesystem::path varDirectory("/var/pipedal"); fs::path varDirectory("/var/pipedal");
std::filesystem::create_directory(varDirectory); fs::create_directory(varDirectory);
{ {
std::stringstream s; std::stringstream s;
@@ -841,8 +862,8 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
if (authBindRequired) if (authBindRequired)
{ {
std::filesystem::create_directories("/etc/authbind/byport"); fs::create_directories("/etc/authbind/byport");
std::filesystem::path portAuthFile = std::filesystem::path("/etc/authbind/byport") / strPort; fs::path portAuthFile = fs::path("/etc/authbind/byport") / strPort;
{ {
// create it. // create it.
@@ -930,56 +951,28 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
FixPermissions(); FixPermissions();
RestartService(false); RestartService(false);
EnableService(); EnableService();
// Restart WiFi Direct if neccessary.
OnWifiReinstall();
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
// don't allow abnormal termination, which leaves the package in a state that's // don't allow abnormal termination, which leaves the package in a state that's
// difficult to uninstall. // difficult to uninstall.
cout << "Error: " << e.what(); cout << "Error: " << e.what();
cout << " Run 'pipedalconfig --install' again to complete setup of PiPedal." << endl;
} }
} }
static std::string GetCurrentWebServicePort() static std::string GetCurrentWebServicePort()
{ {
std::filesystem::path servicePath = GetServiceFileName(PIPEDALD_SERVICE); PiPedalConfiguration config;
try config.Load("/etc/pipedal/config","");
{
if (std::filesystem::exists(servicePath)) std::ostringstream ss;
{ ss << config.GetSocketServerPort();
{ return ss.str();
ifstream f(servicePath);
if (!f.is_open())
{
throw std::runtime_error(SS("Can't open " << servicePath));
}
while (true)
{
std::string line;
if (f.eof())
break;
std::getline(f, line);
if (line.starts_with("ExecStart="))
{
auto startPos = line.find("-port ");
if (startPos != std::string::npos)
{
startPos = startPos + 6;
auto endPos = line.find(" -systemd");
if (endPos != std::string::npos)
{
std::string result = line.substr(startPos, endPos - startPos);
return result;
}
}
}
}
}
}
}
catch (const std::exception & /*ignored*/)
{
}
return "";
} }
static void PrintHelp() static void PrintHelp()
@@ -1279,17 +1272,17 @@ int main(int argc, char **argv)
} }
if (install) if (install)
{ {
std::filesystem::path prefix; fs::path prefix;
if (prefixOption.length() != 0) if (prefixOption.length() != 0)
{ {
prefix = std::filesystem::path(prefixOption); prefix = fs::path(prefixOption);
} }
else else
{ {
prefix = std::filesystem::path(argv[0]).parent_path().parent_path(); prefix = fs::path(argv[0]).parent_path().parent_path();
std::filesystem::path pipedalPath = prefix / "sbin" / "pipedald"; fs::path pipedalPath = prefix / "sbin" / "pipedald";
if (!std::filesystem::exists(pipedalPath)) if (!fs::exists(pipedalPath))
{ {
std::stringstream s; std::stringstream s;
s << "Can't find pipedald executable at " << pipedalPath << ". Try again using the -prefix option."; s << "Can't find pipedald executable at " << pipedalPath << ". Try again using the -prefix option.";
+70 -2
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2022 Robin Davies // Copyright (c) 2022-2024 Robin Davies
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of // Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in // this software and associated documentation files (the "Software"), to deal in
@@ -20,9 +20,76 @@
#include "pch.h" #include "pch.h"
#include "PiPedalConfiguration.hpp" #include "PiPedalConfiguration.hpp"
#include "json.hpp" #include "json.hpp"
#include "ss.hpp"
#include "ServiceConfiguration.hpp"
using namespace pipedal; using namespace pipedal;
namespace fs = std::filesystem;
void PiPedalConfiguration::Load(const std::filesystem::path &path, const std::filesystem::path &webRoot)
{
docRoot_ = path;
webRoot_ = webRoot;
// load installer defaults.
{
std::filesystem::path configPath = path / "config.json";
std::ifstream f(configPath);
if (!f.is_open())
{
std::stringstream s;
s << "Unable to open " << configPath;
throw PiPedalStateException(s.str());
}
json_reader reader(f);
reader.read(this);
}
// web port comes from service.conf
ServiceConfiguration serviceConfiguration;
serviceConfiguration.Load(fs::path(this->local_storage_path_) / "config" / "service.conf");
this->socketServerAddress_ = SS("0.0.0.0:" << serviceConfiguration.server_port);
// load any user-made settings
{
std::filesystem::path userPath = std::filesystem::path(this->local_storage_path_) / "config" / "config.json";
if (std::filesystem::exists(userPath))
{
std::ifstream f(userPath);
json_reader reader(f);
reader.read(this);
}
}
}
uint16_t PiPedalConfiguration::GetSocketServerPort() const
{
try
{
size_t pos = this->socketServerAddress_.find_last_of(':');
if (pos == std::string::npos)
{
throw std::exception();
}
std::string strPort = socketServerAddress_.substr(pos + 1);
unsigned long port = std::stoul(strPort);
if (port == 0)
{
throw std::exception();
}
if (port > std::numeric_limits<uint16_t>::max())
{
throw std::exception();
}
return (uint16_t)port;
}
catch (const std::exception &)
{
std::stringstream s;
s << "Invalid port number in '" << this->socketServerAddress_ << "'.";
throw PiPedalArgumentException(s.str());
}
}
JSON_MAP_BEGIN(PiPedalConfiguration) JSON_MAP_BEGIN(PiPedalConfiguration)
JSON_MAP_REFERENCE(PiPedalConfiguration, lv2_path) JSON_MAP_REFERENCE(PiPedalConfiguration, lv2_path)
@@ -37,4 +104,5 @@ JSON_MAP_REFERENCE(PiPedalConfiguration, maxUploadSize)
JSON_MAP_REFERENCE(PiPedalConfiguration, accessPointGateway) JSON_MAP_REFERENCE(PiPedalConfiguration, accessPointGateway)
JSON_MAP_REFERENCE(PiPedalConfiguration, accessPointServerAddress) JSON_MAP_REFERENCE(PiPedalConfiguration, accessPointServerAddress)
JSON_MAP_REFERENCE(PiPedalConfiguration, isVst3Enabled) JSON_MAP_REFERENCE(PiPedalConfiguration, isVst3Enabled)
JSON_MAP_REFERENCE(PiPedalConfiguration, end)
JSON_MAP_END() JSON_MAP_END()
+3 -44
View File
@@ -48,6 +48,7 @@ private:
std::string accessPointGateway_; std::string accessPointGateway_;
std::string accessPointServerAddress_; std::string accessPointServerAddress_;
bool isVst3Enabled_ = true; bool isVst3Enabled_ = true;
bool end_ = false; // dummy target for /var/pipedal/config/config.json
public: public:
bool IsVst3Enabled() const { return isVst3Enabled_; } bool IsVst3Enabled() const { return isVst3Enabled_; }
@@ -57,26 +58,8 @@ public:
const std::filesystem::path& GetWebRoot() const { const std::filesystem::path& GetWebRoot() const {
return webRoot_; return webRoot_;
} }
void Load(const std::filesystem::path& path, const std::filesystem::path&webRoot) { void Load(const std::filesystem::path& path, const std::filesystem::path&webRoot);
std::filesystem::path configPath = path / "config.json";
if (!std::filesystem::exists(configPath))
{
throw PiPedalException("File not found.");
}
std::ifstream f(configPath);
if (!f.is_open())
{
std::stringstream s;
s << "Unable to open " << configPath;
throw PiPedalStateException(s.str());
}
json_reader reader(f);
reader.read(this);
docRoot_ = path;
webRoot_ = webRoot;
}
const std::filesystem::path &GetDocRoot() const { return docRoot_; } const std::filesystem::path &GetDocRoot() const { return docRoot_; }
const std::string &GetLv2Path() const { return lv2_path_; } const std::string &GetLv2Path() const { return lv2_path_; }
const std::string &GetLocalStoragePath() const { return local_storage_path_; } const std::string &GetLocalStoragePath() const { return local_storage_path_; }
@@ -108,32 +91,8 @@ public:
return socketServerAddress_.substr(0,pos); return socketServerAddress_.substr(0,pos);
} }
uint16_t GetSocketServerPort() const { uint16_t GetSocketServerPort() const;
try {
size_t pos = this->socketServerAddress_.find_last_of(':');
if (pos == std::string::npos)
{
throw std::exception();
}
std::string strPort = socketServerAddress_.substr(pos+1);
unsigned long port = std::stoul(strPort);
if (port == 0)
{
throw std::exception();
}
if (port > std::numeric_limits<uint16_t>::max())
{
throw std::exception();
}
return (uint16_t) port;
} catch (const std::exception &)
{
std::stringstream s;
s << "Invalid port number in '" << this->socketServerAddress_ << "'.";
throw PiPedalArgumentException(s.str());
}
}
uint32_t GetThreads() const { return threads_; } uint32_t GetThreads() const { return threads_; }
DECLARE_JSON_MAP(PiPedalConfiguration); DECLARE_JSON_MAP(PiPedalConfiguration);
+25 -5
View File
@@ -549,13 +549,18 @@ void UninstallP2p()
restoreP2pDnsmasqConfFile(); restoreP2pDnsmasqConfFile();
restoreNetworkManagerP2pConfig(); restoreNetworkManagerP2pConfig();
sysExec(SYSTEMCTL_BIN " restart dhcpcd"); if (!UsingNetworkManager())
{
sysExec(SYSTEMCTL_BIN " restart dhcpcd");
} else {
sysExec(SYSTEMCTL_BIN " restart NetworkManager"); // bring up wlan0 wifi.
}
WifiDirectConfigSettings wifiDirectConfigSettings; WifiDirectConfigSettings wifiDirectConfigSettings;
wifiDirectConfigSettings.Load(); wifiDirectConfigSettings.Load();
wifiDirectConfigSettings.enable_ = false; wifiDirectConfigSettings.enable_ = false;
wifiDirectConfigSettings.Save(); SetWifiDirectConfig(wifiDirectConfigSettings);
sysExec(SYSTEMCTL_BIN " restart NetworkManager"); // bring up wlan0 wifi.
} }
} }
@@ -675,8 +680,15 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings)
cout << e.what() << endl; cout << e.what() << endl;
} }
} }
void pipedal::OnWifiReinstall() {
void pipedal::OnWifiUninstall() WifiDirectConfigSettings settings;
settings.Load();
if (settings.enable_)
{
SetWifiDirectConfig(settings);
}
}
void pipedal::OnWifiUninstall(bool preserveState)
{ {
// intaller hook // intaller hook
if (IsApdInstalled()) if (IsApdInstalled())
@@ -685,7 +697,15 @@ void pipedal::OnWifiUninstall()
} }
if (IsP2pInstalled()) if (IsP2pInstalled())
{ {
WifiDirectConfigSettings settings;
settings.Load();
UninstallP2p(); UninstallP2p();
// preserve the state for future installs.
if (preserveState)
{
settings.Save();
}
} }
} }
void pipedal::OnWifiInstallComplete() void pipedal::OnWifiInstallComplete()
+3 -1
View File
@@ -29,7 +29,9 @@ namespace pipedal {
void SetWifiConfig(const WifiConfigSettings&settings); void SetWifiConfig(const WifiConfigSettings&settings);
void SetWifiDirectConfig(const WifiDirectConfigSettings&settings); void SetWifiDirectConfig(const WifiDirectConfigSettings&settings);
void OnWifiUninstall(); void OnWifiUninstall(bool preserveState = false);
void OnWifiReinstall();
void OnWifiInstallComplete(); void OnWifiInstallComplete();
bool UsingNetworkManager(); bool UsingNetworkManager();
+2 -2
View File
@@ -133,9 +133,9 @@ int main(int argc, char *argv[])
std::cout << "Usage: pipedald <doc_root> [<web_root>] [options...]\n\n" std::cout << "Usage: pipedald <doc_root> [<web_root>] [options...]\n\n"
<< "Options:\n" << "Options:\n"
<< " -systemd: Log to systemd journals instead of to the console.\n" << " -systemd: Log to systemd journals instead of to the console.\n"
<< " -port: Port to listen on e.g. 0.0.0.0:80\n" << " -port: Port to listen on e.g. 80, or 0.0.0.0:80\n"
<< "Example:\n" << "Example:\n"
<< " pipedald /etc/pipedal/config /etc/pipedal/react -port 0.0.0.0:80 \n" << " pipedald /etc/pipedal/config /etc/pipedal/react -port 80 \n"
"\n" "\n"
"Description:\n\n" "Description:\n\n"
" Configuration is read from <doc_root>/config.json\n" " Configuration is read from <doc_root>/config.json\n"
+45
View File
@@ -0,0 +1,45 @@
{
// This file overrides default settings, as set by the installer in /etc/pipdal/config.json
//
// Changes made in this file will be preserved across upgrades.
//
// To override default settings, uncomment the setting line you want to modify.
//
// You should reboot after modifying any of these settings.
// Paths where PiPedal will look for LV2 Plugins.
// One or more directories, seperated by ':'
// "lv2_path": "/usr/lib/lv2:/usr/local/lib/lv2:/usr/modep/lv2",
// whether to lock process pages into memory. should be true unless running on a very memory constrained system.
// Setting to false may cause unpredictable audio dropouts.
// "mlock": true,
// Number of threads the web server should use.
// "threads" : 5,
// Whether to log individual http requests. (highly inadvisable, as requests are logged to the systemd log)
// "logHttpRequests": false,
// Log level for the web server
// { None=0,Error =1,Warning =2,Info = 3, Debug=4}
// "logLevel": 3,
// Maximum filesize to allow when uploading
// "maxUploadSize": 536870912 // 512MiB
// does nothing. avoids chasing ','s.
"end" : true
}