From 06ebfb0bce3d8d073b5ba86cf783d960ff20c1cb Mon Sep 17 00:00:00 2001 From: Robin Davies Date: Tue, 27 Aug 2024 14:55:48 -0400 Subject: [PATCH] Persist all configuration settings across upgrades. Restart wifi-p2p if neccessary. --- .vscode/launch.json | 5 +- NetworkManagerP2P/src/NMP2pSettings.cpp | 39 +++- NetworkManagerP2P/src/NMP2pSettings.hpp | 5 +- PiPedalCommon/src/ServiceConfiguration.cpp | 53 ++--- .../src/WifiDirectConfigSettings.cpp | 12 +- .../src/include/ServiceConfiguration.hpp | 7 +- config/config.json | 34 ++-- src/CMakeLists.txt | 1 + src/ConfigMain.cpp | 183 +++++++++--------- src/PiPedalConfiguration.cpp | 72 ++++++- src/PiPedalConfiguration.hpp | 47 +---- src/SetWifiConfig.cpp | 30 ++- src/SetWifiConfig.hpp | 4 +- src/main.cpp | 4 +- src/templates/var_config.json | 45 +++++ 15 files changed, 340 insertions(+), 201 deletions(-) create mode 100644 src/templates/var_config.json diff --git a/.vscode/launch.json b/.vscode/launch.json index cfc3802..cc7a005 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -258,10 +258,11 @@ "program": "${command:cmake.launchTargetPath}", "args": [ "--nosudo", // run without sudo (which will fail because of perms, but allow us to debug deeper into install code.) + "--prefix", "/usr", //"--get-current-port" - // "--uninstall" + "--install" //"--enable-p2p" , "CA", "PiPedalTest","12345678","14" - "--list-p2p-channels" + //"--list-p2p-channels" ], "stopAtEntry": false, "cwd": "${workspaceFolder}", diff --git a/NetworkManagerP2P/src/NMP2pSettings.cpp b/NetworkManagerP2P/src/NMP2pSettings.cpp index 598c733..f1d271d 100644 --- a/NetworkManagerP2P/src/NMP2pSettings.cpp +++ b/NetworkManagerP2P/src/NMP2pSettings.cpp @@ -9,11 +9,14 @@ #include "WifiRegs.hpp" #include "ChannelInfo.hpp" #include "DBusLog.hpp" +#include 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() { auto filename = config_filename(); try { - std::ofstream f(filename); - if (!f) + std::ofstream f; + openWithPerms(f,filename); + + if (!f.is_open()) { throw std::runtime_error("Can't write to file."); } diff --git a/NetworkManagerP2P/src/NMP2pSettings.hpp b/NetworkManagerP2P/src/NMP2pSettings.hpp index 6e8d11a..3980cc2 100644 --- a/NetworkManagerP2P/src/NMP2pSettings.hpp +++ b/NetworkManagerP2P/src/NMP2pSettings.hpp @@ -8,7 +8,7 @@ class P2pSettings { // adapter between nm p2p settings, and legacy p2p 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 Save(); @@ -16,6 +16,7 @@ public: private: bool valid_ = false; std::filesystem::path configDirectoryPath; + std::filesystem::path varDirectoryPath; bool auth_changed_ = true; std::vector device_type_{ 0x00,0x01, 0x00,0x50,0xF2,0x04, 0x00,0x02 /*"1-0050F204-2";*/ @@ -59,7 +60,7 @@ public: }; std::filesystem::path config_filename() const { // "/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_; } diff --git a/PiPedalCommon/src/ServiceConfiguration.cpp b/PiPedalCommon/src/ServiceConfiguration.cpp index ae8abb7..7afb2ce 100644 --- a/PiPedalCommon/src/ServiceConfiguration.cpp +++ b/PiPedalCommon/src/ServiceConfiguration.cpp @@ -1,18 +1,18 @@ /* * MIT License - * + * * Copyright (c) 2022 Robin E. R. Davies - * + * * 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 * the Software without restriction, including without limitation the rights to * 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 * so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -23,6 +23,7 @@ */ #include "ServiceConfiguration.hpp" +#include #include #include #include @@ -35,43 +36,49 @@ using namespace pipedal; using namespace std; using namespace config_serializer; - -const char ServiceConfiguration::DEVICEID_FILE_NAME[] = "/etc/pipedal/config/service.conf"; +const char ServiceConfiguration::DEVICEID_FILE_NAME[] = "/var/pipedal/config/service.conf"; #define SERIALIZER_ENTRY(MEMBER_NAME) \ - new ConfigSerializer(#MEMBER_NAME, &ServiceConfiguration::MEMBER_NAME, "") - + new ConfigSerializer(#MEMBER_NAME, &ServiceConfiguration::MEMBER_NAME, "") static p2p::autoptr_vector> -deviceIdSerializers -{ - SERIALIZER_ENTRY(uuid), - SERIALIZER_ENTRY(deviceName), - SERIALIZER_ENTRY(server_port) -}; - + deviceIdSerializers{ + SERIALIZER_ENTRY(uuid), + SERIALIZER_ENTRY(deviceName), + SERIALIZER_ENTRY(server_port)}; 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() { - 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"); if (group_ == nullptr) { throw logic_error("Group not found: pipedal_d"); } - 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 = chown(DEVICEID_FILE_NAME, -1, group_->gr_gid); + std::ignore = chmod(DEVICEID_FILE_NAME, S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH); + } + + base::Save(filename); } \ No newline at end of file diff --git a/PiPedalCommon/src/WifiDirectConfigSettings.cpp b/PiPedalCommon/src/WifiDirectConfigSettings.cpp index eb9c9ac..049a8ee 100644 --- a/PiPedalCommon/src/WifiDirectConfigSettings.cpp +++ b/PiPedalCommon/src/WifiDirectConfigSettings.cpp @@ -158,12 +158,12 @@ void WifiDirectConfigSettings::Load() { this->enable_ = false; 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"); } 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; } 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"; } - 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"; } - 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"; } - 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"; } diff --git a/PiPedalCommon/src/include/ServiceConfiguration.hpp b/PiPedalCommon/src/include/ServiceConfiguration.hpp index e437ec2..6749454 100644 --- a/PiPedalCommon/src/include/ServiceConfiguration.hpp +++ b/PiPedalCommon/src/include/ServiceConfiguration.hpp @@ -26,6 +26,7 @@ #include #include "ConfigSerializer.hpp" +#include namespace pipedal { using namespace config_serializer; @@ -38,12 +39,16 @@ namespace pipedal { static const char DEVICEID_FILE_NAME[]; - void Load(); + void Load( + std::filesystem::path path = "/var/pipedal/config/service.conf" + ); void Save(); std::string uuid; std::string deviceName = "PiPedal"; uint32_t server_port = 80; + private: + std::filesystem::path filename; }; } \ No newline at end of file diff --git a/config/config.json b/config/config.json index 4541f52..d87a2c3 100644 --- a/config/config.json +++ b/config/config.json @@ -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 ':' */ "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. */ - "local_storage_path": "/var/pipedal", - /* 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. + /* whether to lock a process pages into memor. should be true unless running on a very memory constrained system. + Setting to false may cause unpredictable audio dropouts. */ "mlock": true, - /* Address on which Piddle listens for websocket connections */ - "socketServerAddress": "0.0.0.0:80", - /* Number of threads to use for servicing websockets */ "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, + /* 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, - - /* 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" + "maxUploadSize": 536870912 // 512MiB } \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 91ba6cb..b3b63da 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -571,6 +571,7 @@ add_executable(pipedalconfig CommandLineParser.hpp PiPedalException.hpp ConfigMain.cpp + PiPedalConfiguration.hpp PiPedalConfiguration.cpp JackServerSettings.hpp JackServerSettings.cpp SystemConfigFile.hpp SystemConfigFile.cpp WifiChannelSelectors.cpp WifiChannelSelectors.hpp diff --git a/src/ConfigMain.cpp b/src/ConfigMain.cpp index 59d9dd9..a4a489c 100644 --- a/src/ConfigMain.cpp +++ b/src/ConfigMain.cpp @@ -38,6 +38,7 @@ #include #include "AudioConfig.hpp" #include "WifiChannelSelectors.hpp" +#include "PiPedalConfiguration.hpp" #include #if JACK_HOST @@ -54,6 +55,8 @@ using namespace std; using namespace pipedal; +namespace fs = std::filesystem; + #define SERVICE_ACCOUNT_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 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::vector paths; @@ -98,8 +101,8 @@ std::filesystem::path findOnPath(const std::string &command) pos = path.length(); } std::string thisPath = path.substr(t, pos - t); - std::filesystem::path path = std::filesystem::path(thisPath) / command; - if (std::filesystem::exists(path)) + fs::path path = fs::path(thisPath) / command; + if (fs::exists(path)) { return path; } @@ -244,7 +247,7 @@ static void RemoveLine(const std::string &path, const std::string lineToRemove) std::vector lines; try { - if (std::filesystem::exists(path)) + if (fs::exists(path)) { { ifstream f(path); @@ -298,10 +301,10 @@ void InstallPamEnv() #if INSTALL_JACK_SERVICE std::string newLine = PAM_LINE; std::vector lines; - std::filesystem::path path = "/etc/security/pam_env.conf"; + fs::path path = "/etc/security/pam_env.conf"; try { - if (std::filesystem::exists(path)) + if (fs::exists(path)) { { ifstream f(path); @@ -355,9 +358,9 @@ void InstallLimits() 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); output << "# Realtime priority group used by pipedal audio (and also by jack)" @@ -372,9 +375,9 @@ void InstallLimits() #if JACK_HOST 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"); } @@ -466,23 +469,8 @@ void Uninstall() { try { - try - { - 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(true); - OnWifiUninstall(); StopService(); DisableService(); @@ -494,7 +482,7 @@ void Uninstall() try { - std::filesystem::remove("/usr/bin/systemd/system/" OLD_SHUTDOWN_SERVICE ".service"); + fs::remove("/usr/bin/systemd/system/" OLD_SHUTDOWN_SERVICE ".service"); } catch (...) { @@ -502,21 +490,21 @@ void Uninstall() try { - std::filesystem::remove("/usr/bin/systemd/system/" ADMIN_SERVICE ".service"); + fs::remove("/usr/bin/systemd/system/" ADMIN_SERVICE ".service"); } catch (...) { } 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 (...) { } try { - std::filesystem::remove("/usr/bin/systemd/system/" PIPEDAL_P2PD_SERVICE ".service"); + fs::remove("/usr/bin/systemd/system/" PIPEDAL_P2PD_SERVICE ".service"); } catch (...) { @@ -524,7 +512,7 @@ void Uninstall() try { - std::filesystem::remove("/usr/bin/systemd/system/" PIPEDALD_SERVICE ".service"); + fs::remove("/usr/bin/systemd/system/" PIPEDALD_SERVICE ".service"); } catch (...) { @@ -532,7 +520,7 @@ void Uninstall() try { - std::filesystem::remove("/usr/bin/systemd/system/" JACK_SERVICE ".service"); + fs::remove("/usr/bin/systemd/system/" JACK_SERVICE ".service"); } catch (...) { @@ -596,13 +584,22 @@ static std::string RandomChars(int nchars) return s.str(); } +static std::map sPermissionExceptions +({ + { + "/var/pipedal/config/NetworkManagerP2P.json", + fs::perms::owner_read | fs::perms::owner_write | fs::perms::group_read | fs::perms::group_write + + } +}); + + void SetVarPermissions( - const std::filesystem::path &path, - std::filesystem::perms directoryPermissions, - std::filesystem::perms filePermissions, + const fs::path &path, + fs::perms directoryPermissions, + fs::perms filePermissions, uid_t uid, gid_t gid) { - namespace fs = std::filesystem; using namespace std::filesystem; try { if (fs::exists(path)) { @@ -630,17 +627,22 @@ void SetVarPermissions( } } 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 { 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; } } +namespace fs = std::filesystem; static void FixPermissions() { @@ -675,7 +677,7 @@ static void FixPermissions() fs::perms::owner_read | fs::perms::owner_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 { fs::permissions(wpa_config_path,wpa_supplicant_perms, fs::perm_options::replace); @@ -722,21 +724,40 @@ void CopyWpaSupplicantConfigFile() try { 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"; - std::filesystem::path destinationPath = NM_SUPPLICANT_CONFIG_PATH; - std::filesystem::path sourcePath = NM_SUPPLICANT_CONFIG_SOURCE_PATH; + fs::path destinationPath = NM_SUPPLICANT_CONFIG_PATH; + fs::path sourcePath = NM_SUPPLICANT_CONFIG_SOURCE_PATH; - std::filesystem::create_directories(destinationPath.parent_path()); - std::filesystem::copy_file(sourcePath,destinationPath,std::filesystem::copy_options::overwrite_existing); + fs::create_directories(destinationPath.parent_path()); + fs::copy_file(sourcePath,destinationPath,fs::copy_options::overwrite_existing); } catch (const std::exception&e) { 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; try { + DeployVarConfig(); + if (sysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS) { 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. - std::filesystem::path varDirectory("/var/pipedal"); - std::filesystem::create_directory(varDirectory); + fs::path varDirectory("/var/pipedal"); + fs::create_directory(varDirectory); { std::stringstream s; @@ -841,8 +862,8 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo if (authBindRequired) { - std::filesystem::create_directories("/etc/authbind/byport"); - std::filesystem::path portAuthFile = std::filesystem::path("/etc/authbind/byport") / strPort; + fs::create_directories("/etc/authbind/byport"); + fs::path portAuthFile = fs::path("/etc/authbind/byport") / strPort; { // create it. @@ -930,56 +951,28 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo FixPermissions(); RestartService(false); EnableService(); + + // Restart WiFi Direct if neccessary. + OnWifiReinstall(); + } catch (const std::exception &e) { // don't allow abnormal termination, which leaves the package in a state that's // difficult to uninstall. cout << "Error: " << e.what(); + cout << " Run 'pipedalconfig --install' again to complete setup of PiPedal." << endl; } } static std::string GetCurrentWebServicePort() { - std::filesystem::path servicePath = GetServiceFileName(PIPEDALD_SERVICE); - try - { - if (std::filesystem::exists(servicePath)) - { - { - 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 ""; + PiPedalConfiguration config; + config.Load("/etc/pipedal/config",""); + + std::ostringstream ss; + ss << config.GetSocketServerPort(); + return ss.str(); } static void PrintHelp() @@ -1279,17 +1272,17 @@ int main(int argc, char **argv) } if (install) { - std::filesystem::path prefix; + fs::path prefix; if (prefixOption.length() != 0) { - prefix = std::filesystem::path(prefixOption); + prefix = fs::path(prefixOption); } 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"; - if (!std::filesystem::exists(pipedalPath)) + fs::path pipedalPath = prefix / "sbin" / "pipedald"; + if (!fs::exists(pipedalPath)) { std::stringstream s; s << "Can't find pipedald executable at " << pipedalPath << ". Try again using the -prefix option."; diff --git a/src/PiPedalConfiguration.cpp b/src/PiPedalConfiguration.cpp index 5fec21b..f333d95 100644 --- a/src/PiPedalConfiguration.cpp +++ b/src/PiPedalConfiguration.cpp @@ -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 // this software and associated documentation files (the "Software"), to deal in @@ -20,9 +20,76 @@ #include "pch.h" #include "PiPedalConfiguration.hpp" #include "json.hpp" - +#include "ss.hpp" +#include "ServiceConfiguration.hpp" 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::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_REFERENCE(PiPedalConfiguration, lv2_path) @@ -37,4 +104,5 @@ JSON_MAP_REFERENCE(PiPedalConfiguration, maxUploadSize) JSON_MAP_REFERENCE(PiPedalConfiguration, accessPointGateway) JSON_MAP_REFERENCE(PiPedalConfiguration, accessPointServerAddress) JSON_MAP_REFERENCE(PiPedalConfiguration, isVst3Enabled) +JSON_MAP_REFERENCE(PiPedalConfiguration, end) JSON_MAP_END() diff --git a/src/PiPedalConfiguration.hpp b/src/PiPedalConfiguration.hpp index c2fe24e..282c9f8 100644 --- a/src/PiPedalConfiguration.hpp +++ b/src/PiPedalConfiguration.hpp @@ -48,6 +48,7 @@ private: std::string accessPointGateway_; std::string accessPointServerAddress_; bool isVst3Enabled_ = true; + bool end_ = false; // dummy target for /var/pipedal/config/config.json public: bool IsVst3Enabled() const { return isVst3Enabled_; } @@ -57,26 +58,8 @@ public: const std::filesystem::path& GetWebRoot() const { return 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; + void Load(const std::filesystem::path& path, const std::filesystem::path&webRoot); - webRoot_ = webRoot; - - } const std::filesystem::path &GetDocRoot() const { return docRoot_; } const std::string &GetLv2Path() const { return lv2_path_; } const std::string &GetLocalStoragePath() const { return local_storage_path_; } @@ -108,32 +91,8 @@ public: return socketServerAddress_.substr(0,pos); } - 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::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()); - } + uint16_t GetSocketServerPort() const; - } uint32_t GetThreads() const { return threads_; } DECLARE_JSON_MAP(PiPedalConfiguration); diff --git a/src/SetWifiConfig.cpp b/src/SetWifiConfig.cpp index 565f825..13b0f0a 100644 --- a/src/SetWifiConfig.cpp +++ b/src/SetWifiConfig.cpp @@ -549,13 +549,18 @@ void UninstallP2p() restoreP2pDnsmasqConfFile(); 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.Load(); wifiDirectConfigSettings.enable_ = false; - wifiDirectConfigSettings.Save(); - sysExec(SYSTEMCTL_BIN " restart NetworkManager"); // bring up wlan0 wifi. + SetWifiDirectConfig(wifiDirectConfigSettings); } } @@ -675,8 +680,15 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings) cout << e.what() << endl; } } - -void pipedal::OnWifiUninstall() +void pipedal::OnWifiReinstall() { + WifiDirectConfigSettings settings; + settings.Load(); + if (settings.enable_) + { + SetWifiDirectConfig(settings); + } +} +void pipedal::OnWifiUninstall(bool preserveState) { // intaller hook if (IsApdInstalled()) @@ -685,7 +697,15 @@ void pipedal::OnWifiUninstall() } if (IsP2pInstalled()) { + WifiDirectConfigSettings settings; + settings.Load(); UninstallP2p(); + + // preserve the state for future installs. + if (preserveState) + { + settings.Save(); + } } } void pipedal::OnWifiInstallComplete() diff --git a/src/SetWifiConfig.hpp b/src/SetWifiConfig.hpp index e902b60..820b94b 100644 --- a/src/SetWifiConfig.hpp +++ b/src/SetWifiConfig.hpp @@ -29,7 +29,9 @@ namespace pipedal { void SetWifiConfig(const WifiConfigSettings&settings); void SetWifiDirectConfig(const WifiDirectConfigSettings&settings); - void OnWifiUninstall(); + void OnWifiUninstall(bool preserveState = false); + void OnWifiReinstall(); + void OnWifiInstallComplete(); bool UsingNetworkManager(); diff --git a/src/main.cpp b/src/main.cpp index 4c44ca8..43a845b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -133,9 +133,9 @@ int main(int argc, char *argv[]) std::cout << "Usage: pipedald [] [options...]\n\n" << "Options:\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" - << " 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" "Description:\n\n" " Configuration is read from /config.json\n" diff --git a/src/templates/var_config.json b/src/templates/var_config.json new file mode 100644 index 0000000..8fd1ed3 --- /dev/null +++ b/src/templates/var_config.json @@ -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 +} \ No newline at end of file