PiPedal 1.2.33 initial commit

This commit is contained in:
Robin Davies
2024-08-08 12:53:02 -04:00
parent 0e378997a5
commit a3847c8184
255 changed files with 22008 additions and 1791 deletions
+359 -261
View File
@@ -21,7 +21,6 @@
#include <stdlib.h>
#include <unistd.h>
#include "CommandLineParser.hpp"
#include "PiPedalException.hpp"
#include <filesystem>
#include <stdlib.h>
#include "WriteTemplateFile.hpp"
@@ -37,7 +36,7 @@
#include <uuid/uuid.h>
#include <random>
#include "AudioConfig.hpp"
#include "WifiChannelSelectors.hpp"
#if JACK_HOST
#define INSTALL_JACK_SERVICE 1
@@ -47,7 +46,6 @@
#define UNINSTALL_JACK_SERVICE 1
#define SS(x) (((std::stringstream &)(std::stringstream() << x)).str())
#define TEMPLATE_PATH(filename) ("/etc/pipedal/config/templates/" filename ".service")
@@ -70,9 +68,11 @@ using namespace pipedal;
#define CHMOD_BIN "/usr/bin/chmod"
#define SERVICE_PATH "/usr/lib/systemd/system"
#define NATIVE_SERVICE "pipedald"
#define PIPEDALD_SERVICE "pipedald"
#define ADMIN_SERVICE "pipedaladmind"
#define PIPEDAL_P2PD_SERVICE "pipedal_p2pd"
#define PIPEDAL_NM_P2PD_SERVICE "pipedal_nm_p2pd"
#define NETWORK_MANAGER_SERIVCE "NetworkManager"
#define JACK_SERVICE "jack"
#define REMOVE_OLD_SERVICE 0 // Grandfathering: whether to remove the old shutdown service (now pipedaladmind)
@@ -105,14 +105,14 @@ std::filesystem::path findOnPath(const std::string &command)
}
std::stringstream s;
s << "'" << command << "' is not installed.";
throw PiPedalException(s.str());
throw std::runtime_error(s.str());
}
void EnableService()
{
if (sysExec(SYSTEMCTL_BIN " enable " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
if (sysExec(SYSTEMCTL_BIN " enable " PIPEDALD_SERVICE ".service") != EXIT_SUCCESS)
{
cout << "Error: Failed to enable the " NATIVE_SERVICE " service.\n";
cout << "Error: Failed to enable the " PIPEDALD_SERVICE " service.\n";
}
if (sysExec(SYSTEMCTL_BIN " enable " ADMIN_SERVICE ".service") != EXIT_SUCCESS)
{
@@ -121,17 +121,17 @@ void EnableService()
}
void DisableService()
{
#if INSTALL_JACK_SERVICE || UNINSTALL_JACK_SERVICE
#if INSTALL_JACK_SERVICE || UNINSTALL_JACK_SERVICE
if (silentSysExec(SYSTEMCTL_BIN " disable " JACK_SERVICE ".service") != EXIT_SUCCESS)
{
#if INSTALL_JACK_SERVICE
// cout << "Error: Failed to disable the " JACK_SERVICE " service.";
#endif
#if INSTALL_JACK_SERVICE
// cout << "Error: Failed to disable the " JACK_SERVICE " service.";
#endif
}
#endif
if (sysExec(SYSTEMCTL_BIN " disable " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
#endif
if (sysExec(SYSTEMCTL_BIN " disable " PIPEDALD_SERVICE ".service") != EXIT_SUCCESS)
{
cout << "Error: Failed to disable the " NATIVE_SERVICE " service.\n";
cout << "Error: Failed to disable the " PIPEDALD_SERVICE " service.\n";
}
if (sysExec(SYSTEMCTL_BIN " disable " ADMIN_SERVICE ".service") != EXIT_SUCCESS)
{
@@ -147,9 +147,9 @@ void DisableService()
void StopService(bool excludeShutdownService = false)
{
if (sysExec(SYSTEMCTL_BIN " stop " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
if (sysExec(SYSTEMCTL_BIN " stop " PIPEDALD_SERVICE ".service") != EXIT_SUCCESS)
{
cout << "Error: Failed to stop the " NATIVE_SERVICE " service.\n";
cout << "Error: Failed to stop the " PIPEDALD_SERVICE " service.\n";
}
if (!excludeShutdownService)
{
@@ -167,9 +167,9 @@ void StopService(bool excludeShutdownService = false)
#if INSTALL_JACK_SERVICE || UNINSTALL_JACK_SERVICE
if (silentSysExec(SYSTEMCTL_BIN " stop " JACK_SERVICE ".service") != EXIT_SUCCESS)
{
#if INSTALL_JACK_SERVICE
// cout << PiPedalException("Failed to stop the " JACK_SERVICE " service.");
#endif
#if INSTALL_JACK_SERVICE
// cout << std::runtime_error("Failed to stop the " JACK_SERVICE " service.");
#endif
}
#endif
}
@@ -182,12 +182,12 @@ void StartService(bool excludeShutdownService = false)
{
if (sysExec(SYSTEMCTL_BIN " start " ADMIN_SERVICE ".service") != EXIT_SUCCESS)
{
throw PiPedalException("Failed to start the " ADMIN_SERVICE " service.");
throw std::runtime_error("Failed to start the " ADMIN_SERVICE " service.");
}
}
if (sysExec(SYSTEMCTL_BIN " start " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
if (sysExec(SYSTEMCTL_BIN " start " PIPEDALD_SERVICE ".service") != EXIT_SUCCESS)
{
throw PiPedalException("Failed to start the " NATIVE_SERVICE " service.");
throw std::runtime_error("Failed to start the " PIPEDALD_SERVICE " service.");
}
#if INSTALL_JACK_SERVICE
JackServerSettings serverSettings;
@@ -196,7 +196,7 @@ void StartService(bool excludeShutdownService = false)
{
if (sysExec(SYSTEMCTL_BIN " start " JACK_SERVICE ".service") != EXIT_SUCCESS)
{
throw PiPedalException("Failed to start the " JACK_SERVICE " service.");
throw std::runtime_error("Failed to start the " JACK_SERVICE " service.");
}
}
#endif
@@ -246,7 +246,7 @@ static void RemoveLine(const std::string &path, const std::string lineToRemove)
ifstream f(path);
if (!f.is_open())
{
throw PiPedalException(SS("Can't open " << path));
throw std::runtime_error(SS("Can't open " << path));
}
while (true)
{
@@ -265,7 +265,7 @@ static void RemoveLine(const std::string &path, const std::string lineToRemove)
std::ofstream f(path);
if (!f.is_open())
{
throw PiPedalException(SS("Can't write to " << path));
throw std::runtime_error(SS("Can't write to " << path));
}
for (auto &line : lines)
{
@@ -303,7 +303,7 @@ void InstallPamEnv()
ifstream f(path);
if (!f.is_open())
{
throw PiPedalException(SS("Can't open " << path));
throw std::runtime_error(SS("Can't open " << path));
}
while (true)
{
@@ -328,7 +328,7 @@ void InstallPamEnv()
std::ofstream f(path);
if (!f.is_open())
{
throw PiPedalException(SS("Can't write to " << path));
throw std::runtime_error(SS("Can't write to " << path));
}
for (auto &line : lines)
{
@@ -348,7 +348,7 @@ void InstallLimits()
{
if (sysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS)
{
throw PiPedalException("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";
@@ -365,7 +365,6 @@ void InstallLimits()
}
}
#if JACK_HOST
void MaybeStartJackService()
{
@@ -390,13 +389,13 @@ void InstallAudioService()
#if INSTALL_JACK_SERVICE
if (sysExec(GROUPADD_BIN " -f " JACK_SERVICE_GROUP_NAME) != EXIT_SUCCESS)
{
throw PiPedalException("Failed to create jack service group.");
throw std::runtime_error("Failed to create jack service group.");
}
if (!userExists(JACK_SERVICE_ACCOUNT_NAME))
{
if (sysExec(USERADD_BIN " " JACK_SERVICE_ACCOUNT_NAME " -g " JACK_SERVICE_GROUP_NAME " -m -N -r") != EXIT_SUCCESS)
{
// throw PiPedalException("Failed to create service account.");
// throw std::runtime_error("Failed to create service account.");
}
// lock account for login.
silentSysExec("passwd -l " JACK_SERVICE_ACCOUNT_NAME);
@@ -417,18 +416,32 @@ void InstallAudioService()
MaybeStartJackService();
#endif
}
int SudoExec(char **argv)
int SudoExec(int argc, char**argv)
{
// re-execute with SUDO in order to prompt for SUDO credentials once only.
std::vector<char *> args;
std::string pkexec = "/usr/bin/sudo"; // staged because "ISO C++ forbids converting a string constant to std::vector<char*>::value_type"(!)
args.push_back((char *)(pkexec.c_str()));
std::string sPath = getSelfExePath();
args.push_back(const_cast<char *>(sPath.c_str()));
for (int arg = 1; arg < argc; ++arg)
{
args.push_back(const_cast<char *>(argv[arg]));
}
args.push_back(nullptr);
char **newArgs = &args[0];
int pbPid;
int returnValue = 0;
if ((pbPid = fork()) == 0)
{
execv(argv[0], argv);
exit(-1);
return execv(newArgs[0], newArgs);
}
else
{
@@ -445,38 +458,36 @@ static bool IsP2pServiceEnabled()
return settings.enable_;
}
static void RestartP2pdService()
{
if (IsP2pServiceEnabled())
{
silentSysExec(SYSTEMCTL_BIN " restart " PIPEDAL_P2PD_SERVICE);
}
}
static void UninstallP2pdService()
{
silentSysExec("systemctl stop " PIPEDAL_P2PD_SERVICE);
silentSysExec("systemctl disable " PIPEDAL_P2PD_SERVICE);
}
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();
StopService();
DisableService();
UninstallP2pdService();
#if UNINSTALL_JACK_SERVICE
silentSysExec(SYSTEMCTL_BIN " stop jack");
silentSysExec(SYSTEMCTL_BIN " disable jack");
#endif
try
{
std::filesystem::remove("/usr/bin/systemd/system/" OLD_SHUTDOWN_SERVICE ".service");
@@ -493,6 +504,13 @@ void Uninstall()
{
}
try
{
std::filesystem::remove("/usr/bin/systemd/system/" PIPEDAL_NM_P2PD_SERVICE ".service");
}
catch (...)
{
}
try
{
std::filesystem::remove("/usr/bin/systemd/system/" PIPEDAL_P2PD_SERVICE ".service");
}
@@ -502,7 +520,7 @@ void Uninstall()
try
{
std::filesystem::remove("/usr/bin/systemd/system/" NATIVE_SERVICE ".service");
std::filesystem::remove("/usr/bin/systemd/system/" PIPEDALD_SERVICE ".service");
}
catch (...)
{
@@ -521,12 +539,12 @@ void Uninstall()
}
catch (const std::exception &e)
{
// We should NEVER get here. But the consequences of failure are high (causes permanent apt installs/uninstall problems), so be safe.
// We should NEVER get here. But the consequences of failure are high (causes permanent apt installs/uninstall problems), so be safe.
cout << "ERROR: Unexpected error while uninstalling pipedal. (" << e.what() << ")" << endl;
}
catch (...)
{
// We should NEVER get here. But the consequences of failure are high (causes permanent apt installs/uninstall problems), so be safe.
// We should NEVER get here. But the consequences of failure are high (causes permanent apt installs/uninstall problems), so be safe.
cout << "ERROR: Unexpected error while uninstalling pipedal." << endl;
}
}
@@ -577,15 +595,14 @@ static std::string RandomChars(int nchars)
static void PrepareServiceConfigurationFile(uint16_t portNumber)
{
ServiceConfiguration serviceConfiguration;
try {
serviceConfiguration.Load();
} catch (const std::exception &)
try
{
serviceConfiguration.Load();
}
if (serviceConfiguration.deviceName == "" || serviceConfiguration.uuid == ""
|| portNumber != serviceConfiguration.server_port
)
catch (const std::exception &)
{
}
if (serviceConfiguration.deviceName == "" || serviceConfiguration.uuid == "" || portNumber != serviceConfiguration.server_port)
{
if (serviceConfiguration.deviceName == "")
{
@@ -600,190 +617,230 @@ static void PrepareServiceConfigurationFile(uint16_t portNumber)
}
}
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;
std::filesystem::create_directories(destinationPath.parent_path());
std::filesystem::copy_file(sourcePath,destinationPath,std::filesystem::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)
{
if (sysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS)
{
throw PiPedalException("Failed to create audio service group.");
}
if (sysExec(GROUPADD_BIN " -f " SERVICE_GROUP_NAME) != EXIT_SUCCESS)
{
throw PiPedalException("Failed to create pipedald service group.");
}
InstallAudioService();
auto endpos = endpointAddress.find_last_of(':');
if (endpos == string::npos)
{
throw PiPedalException("Invalid endpoint address: " + endpointAddress);
}
uint16_t port;
auto strPort = endpointAddress.substr(endpos + 1);
cout << "Configuring pipedal" << endl;
try
{
auto lport = std::stoul(strPort);
if (lport == 0 || lport >= std::numeric_limits<uint16_t>::max())
if (sysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS)
{
throw PiPedalException("out of range.");
throw std::runtime_error("Failed to create audio service group.");
}
port = (uint16_t)lport;
std::stringstream s;
s << port;
strPort = s.str(); // normalized.
}
catch (const std::exception &)
{
std::stringstream s;
s << "Invalid port number: " << strPort;
throw PiPedalException(s.str());
}
PrepareServiceConfigurationFile(port);
bool authBindRequired = port < 512;
// Create and configure service account.
if (sysExec(GROUPADD_BIN " -f " SERVICE_GROUP_NAME) != EXIT_SUCCESS)
{
throw PiPedalException("Failed to create service group.");
}
if (!userExists(SERVICE_ACCOUNT_NAME))
{
if (sysExec(USERADD_BIN " " SERVICE_ACCOUNT_NAME " -g " SERVICE_GROUP_NAME " -m --home /var/pipedal/home -N -r") != EXIT_SUCCESS)
if (sysExec(GROUPADD_BIN " -f " SERVICE_GROUP_NAME) != EXIT_SUCCESS)
{
// throw PiPedalException("Failed to create service account.");
throw std::runtime_error("Failed to create pipedald service group.");
}
// lock account for login.
silentSysExec("passwd -l " SERVICE_ACCOUNT_NAME);
}
// Add to audio groups.
sysExec(USERMOD_BIN " -a -G " AUDIO_SERVICE_GROUP_NAME " " SERVICE_ACCOUNT_NAME);
// create and configure /var directory.
std::filesystem::path varDirectory("/var/pipedal");
std::filesystem::create_directory(varDirectory);
{
std::stringstream s;
s << CHGRP_BIN " " SERVICE_GROUP_NAME " " << varDirectory.c_str();
sysExec(s.str().c_str());
}
{
std::stringstream s;
s << CHOWN_BIN << " " << SERVICE_ACCOUNT_NAME << " " << varDirectory.c_str();
sysExec(s.str().c_str());
}
{
std::stringstream s;
s << CHMOD_BIN << " 775 " << varDirectory.c_str();
sysExec(s.str().c_str());
}
{
std::stringstream s;
s << CHMOD_BIN << " g+s " << varDirectory.c_str(); // child files/directories inherit ownership.
sysExec(s.str().c_str());
}
// authbind port.
if (authBindRequired)
{
std::filesystem::create_directories("/etc/authbind/byport");
std::filesystem::path portAuthFile = std::filesystem::path("/etc/authbind/byport") / strPort;
// defensively disable wifi p2p if some leftover config file left it enabled.
try
{
// create it.
std::ofstream f(portAuthFile);
if (!f.is_open())
if (IsP2pServiceEnabled())
{
throw PiPedalException("Failed to create " + portAuthFile.string());
WifiDirectConfigSettings settings;
settings.Load();
settings.enable_ = false;
settings.Save();
}
}
catch (const std::exception &)
{
// own it.
std::stringstream s;
s << CHOWN_BIN << " " SERVICE_ACCOUNT_NAME " " << portAuthFile.c_str();
sysExec(s.str().c_str());
}
InstallAudioService();
auto endpos = endpointAddress.find_last_of(':');
if (endpos == string::npos)
{
// group own it.
throw std::runtime_error("Invalid endpoint address: " + endpointAddress);
}
uint16_t port;
auto strPort = endpointAddress.substr(endpos + 1);
try
{
auto lport = std::stoul(strPort);
if (lport == 0 || lport >= std::numeric_limits<uint16_t>::max())
{
throw std::runtime_error("out of range.");
}
port = (uint16_t)lport;
std::stringstream s;
s << CHGRP_BIN << " " SERVICE_GROUP_NAME " " << portAuthFile.c_str();
s << port;
strPort = s.str(); // normalized.
}
catch (const std::exception &)
{
std::stringstream s;
s << "Invalid port number: " << strPort;
throw std::runtime_error(s.str());
}
PrepareServiceConfigurationFile(port);
bool authBindRequired = port < 512;
// Create and configure service account.
if (sysExec(GROUPADD_BIN " -f " SERVICE_GROUP_NAME) != EXIT_SUCCESS)
{
throw std::runtime_error("Failed to create service group.");
}
if (!userExists(SERVICE_ACCOUNT_NAME))
{
if (sysExec(USERADD_BIN " " SERVICE_ACCOUNT_NAME " -g " SERVICE_GROUP_NAME " -m --home /var/pipedal/home -N -r") != EXIT_SUCCESS)
{
// throw std::runtime_error("Failed to create service account.");
}
// lock account for login.
silentSysExec("passwd -l " SERVICE_ACCOUNT_NAME);
}
// Add to audio groups.
sysExec(USERMOD_BIN " -a -G " AUDIO_SERVICE_GROUP_NAME " " SERVICE_ACCOUNT_NAME);
// create and configure /var directory.
std::filesystem::path varDirectory("/var/pipedal");
std::filesystem::create_directory(varDirectory);
{
std::stringstream s;
s << CHGRP_BIN " " SERVICE_GROUP_NAME " " << varDirectory.c_str();
sysExec(s.str().c_str());
}
{
std::stringstream s;
s << CHMOD_BIN << " 770 " << portAuthFile.c_str();
s << CHOWN_BIN << " " << SERVICE_ACCOUNT_NAME << " " << varDirectory.c_str();
sysExec(s.str().c_str());
}
}
cout << "Creating Systemd file."
<< "\n";
{
std::stringstream s;
s << CHMOD_BIN << " 775 " << varDirectory.c_str();
sysExec(s.str().c_str());
}
{
std::stringstream s;
s << CHMOD_BIN << " g+s " << varDirectory.c_str(); // child files/directories inherit ownership.
sysExec(s.str().c_str());
}
std::map<string, string> map;
int shutdownPort = 3147;
map["DESCRIPTION"] = "PiPedal Web Service";
{
std::stringstream s;
// authbind port.
if (authBindRequired)
{
s << findOnPath("authbind").string() << " --deep ";
std::filesystem::create_directories("/etc/authbind/byport");
std::filesystem::path portAuthFile = std::filesystem::path("/etc/authbind/byport") / strPort;
{
// create it.
std::ofstream f(portAuthFile);
if (!f.is_open())
{
throw std::runtime_error("Failed to create " + portAuthFile.string());
}
}
{
// own it.
std::stringstream s;
s << CHOWN_BIN << " " SERVICE_ACCOUNT_NAME " " << portAuthFile.c_str();
sysExec(s.str().c_str());
}
{
// group own it.
std::stringstream s;
s << CHGRP_BIN << " " SERVICE_GROUP_NAME " " << portAuthFile.c_str();
sysExec(s.str().c_str());
}
{
std::stringstream s;
s << CHMOD_BIN << " 770 " << portAuthFile.c_str();
sysExec(s.str().c_str());
}
}
s
<< (programPrefix / "bin" / NATIVE_SERVICE).string()
<< " /etc/pipedal/config /etc/pipedal/react -port " << endpointAddress << " -systemd";
map["COMMAND"] = s.str();
std::map<string, string> map;
int shutdownPort = 3147;
map["DESCRIPTION"] = "PiPedal Web Service";
{
std::stringstream s;
if (authBindRequired)
{
s << findOnPath("authbind").string() << " --deep ";
}
s
<< (programPrefix / "sbin" / PIPEDALD_SERVICE).string()
<< " /etc/pipedal/config /etc/pipedal/react -port " << endpointAddress << " -systemd";
map["COMMAND"] = s.str();
}
WriteTemplateFile(map, GetServiceFileName(PIPEDALD_SERVICE));
map["DESCRIPTION"] = "PiPedal Admin Service";
{
std::stringstream s;
s
<< (programPrefix / "sbin" / ADMIN_SERVICE).string()
<< " -port " << shutdownPort;
map["COMMAND"] = s.str();
}
WriteTemplateFile(map, GetServiceFileName(ADMIN_SERVICE));
// /usr/bin/pipedal_p2pd --config-file /etc/pipedal/config/template_p2pd.conf
if (UsingNetworkManager())
{
std::string pipedal_nm_p2pd_cmd = SS(
(programPrefix / "sbin" / "pipedal_nm_p2pd").string()
//<< " --config-file " << PIPEDAL_P2PD_CONF_PATH
);
map["COMMAND"] = pipedal_nm_p2pd_cmd;
WriteTemplateFile(map, GetServiceFileName(PIPEDAL_NM_P2PD_SERVICE));
}
else
{
std::string pipedal_p2pd_cmd = SS(
(programPrefix / "sbin" / "pipedal_p2pd").string()
<< " --config-file " << PIPEDAL_P2PD_CONF_PATH);
map["COMMAND"] = pipedal_p2pd_cmd;
WriteTemplateFile(map, GetServiceFileName(PIPEDAL_P2PD_SERVICE));
}
CopyWpaSupplicantConfigFile();
sysExec(SYSTEMCTL_BIN " daemon-reload");
RestartService(false);
EnableService();
}
WriteTemplateFile(map, GetServiceFileName(NATIVE_SERVICE));
map["DESCRIPTION"] = "PiPedal Admin Service";
catch (const std::exception &e)
{
std::stringstream s;
s
<< (programPrefix / "bin" / ADMIN_SERVICE).string()
<< " -port " << shutdownPort;
map["COMMAND"] = s.str();
// don't allow abnormal termination, which leaves the package in a state that's
// difficult to uninstall.
cout << "Error: " << e.what();
}
WriteTemplateFile(map, GetServiceFileName(ADMIN_SERVICE));
// /usr/bin/pipedal_p2pd --config-file /etc/pipedal/config/template_p2pd.conf
std::string pipedal_p2pd_cmd = SS(
(programPrefix / "bin" / "pipedal_p2pd").string()
<< " --config-file " << PIPEDAL_P2PD_CONF_PATH);
map["COMMAND"] = pipedal_p2pd_cmd;
WriteTemplateFile(map, GetServiceFileName(PIPEDAL_P2PD_SERVICE));
sysExec(SYSTEMCTL_BIN " daemon-reload");
cout << "Starting services"
<< "\n";
RestartService(false);
EnableService();
RestartP2pdService();
cout << "Complete"
<< "\n";
}
static std::string GetCurrentWebServicePort()
{
std::filesystem::path servicePath = GetServiceFileName(NATIVE_SERVICE);
std::filesystem::path servicePath = GetServiceFileName(PIPEDALD_SERVICE);
try
{
if (std::filesystem::exists(servicePath))
@@ -792,7 +849,7 @@ static std::string GetCurrentWebServicePort()
ifstream f(servicePath);
if (!f.is_open())
{
throw PiPedalException(SS("Can't open " << servicePath));
throw std::runtime_error(SS("Can't open " << servicePath));
}
while (true)
{
@@ -805,11 +862,11 @@ static std::string GetCurrentWebServicePort()
auto startPos = line.find("-port ");
if (startPos != std::string::npos)
{
startPos = startPos+6;
startPos = startPos + 6;
auto endPos = line.find(" -systemd");
if (endPos != std::string::npos)
{
std::string result = line.substr(startPos,endPos-startPos);
std::string result = line.substr(startPos, endPos - startPos);
return result;
}
}
@@ -818,7 +875,7 @@ static std::string GetCurrentWebServicePort()
}
}
}
catch (const std::exception &/*ignored*/)
catch (const std::exception & /*ignored*/)
{
}
return "";
@@ -909,21 +966,25 @@ static void PrintHelp()
<< "Channel number defaults to 1."
<< "\n\n"
<< HangingIndent() << " --disable-p2p\tDisabled Wi-Fi Direct access."
<< HangingIndent() << " --disable-p2p\tDisable Wi-Fi Direct access."
<< "\n\n"
<< HangingIndent() << " --enable-legacy-ap\t <country_code> <ssid> <wep_password> <channel>\tEnable a legacy Wi-Fi access point."
<< "\n\n"
<< "Enable a legacy Wi-Fi access point. \n\n"
<< "country_code is the 2-letter ISO-3166 country code for "
<< "the country you are in. see below for further notes."
<< "\n\n"
<< "See below for an explanation of when you might want to use a legacy Wi-Fi access point instead of Wifi-Direct access."
<< "an explanation of when you might want to use a legacy Access Point instead of "
<< "a P2P (Wi-Fi Direct) connection. Generally, you should prefer a P2p connection "
<< "to an ordinary Hotspot connection."
<< HangingIndent() << " --list-p2p-channels [<country_code>] \tList valid p2p channels for the current/specified country."
<< "\n\n"
// << HangingIndent() << " --enable-legacy-ap\t <country_code> <ssid> <wep_password> <channel>\tEnable a legacy Wi-Fi access point."
// << "\n\n"
// << "Enable a legacy Wi-Fi access point. \n\n"
// << "country_code is the 2-letter ISO-3166 country code for "
// << "the country you are in. see below for further notes."
// << "\n\n"
// << "See below for an explanation of when you might want to use a legacy Wi-Fi access point instead of Wifi-Direct access."
// << "an explanation of when you might want to use a legacy Access Point instead of "
// << "a P2P (Wi-Fi Direct) connection. Generally, you should prefer a P2p connection "
// << "to an ordinary Hotspot connection."
// << "\n\n"
<< HangingIndent() << " --disable-legacy-ap\tDisabled the legacy Wi-Fi access point."
<< "\n\n"
@@ -962,6 +1023,40 @@ static void PrintHelp()
"therefore preferrable under almost all circumstances.\n\n";
}
static int ListP2PChannels(const std::vector<std::string>&arguments)
{
try {
std::string country;
if (arguments.size() >= 2)
{
throw std::runtime_error("Invalid arguments.");
} if (arguments.size() == 1)
{
country = arguments[0];
} else {
// use the currently selected country by default.
WifiDirectConfigSettings settings;
settings.Load();
if (settings.countryCode_.empty())
{
throw std::runtime_error("A country has not yet been selected. Please provde a country code.");
}
country = settings.countryCode_;
}
auto channelSelectors = getWifiChannelSelectors(country.c_str(),true);
for (const auto &channelSelector: channelSelectors)
{
cout << channelSelector.channelName_ << endl;
}
} catch (const std::exception &e)
{
cout << "ERROR: " << e.what() << endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int main(int argc, char **argv)
{
CommandLineParser parser;
@@ -973,13 +1068,14 @@ int main(int argc, char **argv)
bool enable = false, disable = false, restart = false;
bool enable_ap = false, disable_ap = false;
bool enable_p2p = false, disable_p2p = false;
bool list_p2p_channels = false;
bool get_current_port = false;
bool nopkexec = false;
bool nosudo = false;
bool excludeShutdownService = false;
std::string prefixOption;
std::string portOption;
parser.AddOption("--nopkexec", &nopkexec); // strictly a debugging aid.
parser.AddOption("--nosudo", &nosudo); // strictly a debugging aid. Run without sudo, until we fail because of permissions.
parser.AddOption("--install", &install);
parser.AddOption("--uninstall", &uninstall);
parser.AddOption("--stop", &stop);
@@ -991,10 +1087,12 @@ int main(int argc, char **argv)
parser.AddOption("--help", &help);
parser.AddOption("--prefix", &prefixOption);
parser.AddOption("--port", &portOption);
parser.AddOption("--enable-legacy-ap", &enable_ap);
//parser.AddOption("--enable-legacy-ap", &enable_ap);
parser.AddOption("--disable-ap", &disable_ap);
parser.AddOption("--enable-p2p", &enable_p2p);
parser.AddOption("--disable-p2p", &disable_p2p);
parser.AddOption("--list-p2p-channels", &list_p2p_channels);
parser.AddOption("--get-current-port", &get_current_port); // private. For debug use only.
@@ -1003,20 +1101,25 @@ int main(int argc, char **argv)
{
parser.Parse(argc, (const char **)argv);
int actionCount = get_current_port + install + uninstall + stop + start + enable + disable + enable_ap + disable_ap + restart + enable_p2p + disable_p2p;
int actionCount =
help + get_current_port + install + uninstall + stop + start + enable + disable
+ enable_ap + disable_ap + restart + enable_p2p + disable_p2p
+ list_p2p_channels
;
if (actionCount > 1)
{
throw PiPedalException("Please provide only one action.");
throw std::runtime_error("Please provide only one action.");
}
if (argc == 1 )
if (argc == 1)
{
help = true;
} else if (actionCount == 0)
}
else if (actionCount == 0)
{
throw PiPedalException("No action provided.");
throw std::runtime_error("No action provided.");
}
if ((!enable_p2p) && (!enable_ap))
if ((!enable_p2p) && (!enable_ap) && (!list_p2p_channels))
{
if (parser.Arguments().size() != 0)
{
@@ -1045,7 +1148,11 @@ int main(int argc, char **argv)
if (get_current_port)
{
std::cout << "current port: " << GetCurrentWebServicePort() << std::endl;
return 0;
return EXIT_SUCCESS;
}
if (list_p2p_channels)
{
return ListP2PChannels(parser.Arguments());
}
if (portOption.size() != 0 && !install)
{
@@ -1055,24 +1162,9 @@ int main(int argc, char **argv)
}
auto uid = getuid();
if (uid != 0 && !nopkexec)
if (uid != 0 && !nosudo)
{
// re-execute with PKEXEC in order to prompt for SUDO credentials once only.
std::vector<char *> args;
std::string pkexec = "/usr/bin/pkexec"; // staged because "ISO C++ forbids converting a string constant to std::vector<char*>::value_type"(!)
args.push_back((char *)(pkexec.c_str()));
std::string sPath = getSelfExePath();
args.push_back(const_cast<char *>(sPath.c_str()));
for (int arg = 1; arg < argc; ++arg)
{
args.push_back(const_cast<char *>(argv[arg]));
}
args.push_back(nullptr);
char **rawArgv = &args[0];
return SudoExec(rawArgv);
return SudoExec(argc,argv);
}
try
@@ -1088,12 +1180,12 @@ int main(int argc, char **argv)
{
prefix = std::filesystem::path(argv[0]).parent_path().parent_path();
std::filesystem::path pipedalPath = prefix / "bin/pipedald";
std::filesystem::path pipedalPath = prefix / "sbin" / "pipedald";
if (!std::filesystem::exists(pipedalPath))
{
std::stringstream s;
s << "Can't find pipedald executable at " << pipedalPath << ". Try again using the -prefix option.";
throw PiPedalException(s.str());
throw std::runtime_error(s.str());
}
}
@@ -1137,13 +1229,19 @@ int main(int argc, char **argv)
}
else if (enable_p2p)
{
auto argv = parser.Arguments();
WifiDirectConfigSettings settings;
settings.ParseArguments(argv);
settings.valid_ = true;
settings.enable_ = true;
SetWifiDirectConfig(settings);
RestartService(true); // also have to retart web service so that it gets the correct device name.
try {
auto argv = parser.Arguments();
WifiDirectConfigSettings settings;
settings.ParseArguments(argv);
settings.valid_ = true;
settings.enable_ = true;
SetWifiDirectConfig(settings);
RestartService(true); // also have to retart web service so that it gets the correct device name.
} catch (const std::exception&e)
{
cout << "ERROR: " << e.what() << endl;
return EXIT_FAILURE;
}
}
else if (disable_p2p)
{