937 lines
40 KiB
C++
937 lines
40 KiB
C++
//-----------------------------------------------------------------------------------------//
|
|
// Distributed under the MIT License - https://opensource.org/licenses/MIT
|
|
//-----------------------------------------------------------------------------------------//
|
|
//
|
|
// Copyright © 2019 Sasko Usinov
|
|
//
|
|
// 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 AUTHORS OR COPYRIGHT
|
|
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
//-----------------------------------------------------------------------------------------//
|
|
// Distributed under the MIT License - https://opensource.org/licenses/MIT
|
|
//-----------------------------------------------------------------------------------------//
|
|
|
|
#include "application.h"
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/inotify.h>
|
|
|
|
#include <libexplain/read.h> // explain_read()
|
|
#include <signal.h> // SIGs - SIGINT etc
|
|
#include <limits.h> // readlink()
|
|
|
|
//---------------------------------------------------------------------------------------------------------
|
|
// extern
|
|
//---------------------------------------------------------------------------------------------------------
|
|
std::vector<pci_device_struct> app::pci_list;
|
|
std::vector<boot_entry_struct> app::boot_list;
|
|
std::vector<scsi_device_struct> app::scsi_list;
|
|
std::vector<usb_device_struct> app::usb_list;
|
|
|
|
std::vector<pci_device_struct> app::pci_search_list;
|
|
std::vector<scsi_device_struct> app::scsi_search_list;
|
|
std::vector<usb_device_struct> app::usb_search_list;
|
|
|
|
error_structure app::last_err;
|
|
|
|
sigc::signal <void> app::sigc_clear_device_list;
|
|
sigc::signal <void, std::vector<pci_device_struct> &> app::sigc_load_pci_list;
|
|
sigc::signal <void, std::vector<scsi_device_struct> &> app::sigc_load_scsi_list;
|
|
sigc::signal <void, std::vector<usb_device_struct> &> app::sigc_load_usb_list;
|
|
|
|
sigc::signal <void, const std::string &> app::sigc_file_added;
|
|
sigc::signal <void, const std::string &> app::sigc_file_removed;
|
|
sigc::signal <void, const std::string &> app::sigc_dev_query_end;
|
|
|
|
sigc::connection app::sigc_conn_file_added;
|
|
sigc::connection app::sigc_conn_file_removed;
|
|
|
|
std::string app::data::app_log_dir,
|
|
app::data::app_home_dir,
|
|
app::data::app_settings_dir,
|
|
app::data::app_backup_dir,
|
|
app::data::app_scripts_dir;
|
|
|
|
//---------------------------------------------------------------------------------------------------------
|
|
// ...
|
|
//---------------------------------------------------------------------------------------------------------
|
|
file_watcher_data * app::data::fwd;
|
|
bool app::data::exiting(false);
|
|
std::vector<std::string> app::data::watch_list;
|
|
std::vector<std::thread> app::data::thread_list;
|
|
|
|
api::log_manager write_out,
|
|
write_err;
|
|
|
|
//---------------------------------------------------------------------------------------------------------
|
|
// end extern
|
|
//---------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// Type: namespace
|
|
//-------------------------------------------------------------------------------//
|
|
//
|
|
// ToDo: n/a
|
|
//
|
|
// Notes: This is a thread
|
|
//
|
|
// Returns: n/a
|
|
//
|
|
//--------------------------------------------------------------------------------------------------------------------------------------------//
|
|
void app::t_device_monitor(const std::string & dir_path)
|
|
{
|
|
#define EVENT_SIZE (sizeof(inotify_event))
|
|
#define READ_ERR_TRESHOLD (3)
|
|
|
|
file_watcher_data fwd {(dir_path.c_str())};
|
|
app::data::fwd = {& fwd};
|
|
|
|
fwd.file_descriptor = {inotify_init()};
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// Check to see if we have a valid descriptor
|
|
//-------------------------------------------------------------------------------//
|
|
if (fwd.file_descriptor < 0)
|
|
{
|
|
elog("inotify_init failed.");
|
|
return;
|
|
}
|
|
|
|
fwd.watch_descriptor = {inotify_add_watch(fwd.file_descriptor, fwd.dirpath.c_str(), IN_CREATE | IN_DELETE | IN_MODIFY)};
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// Check to see if we have a valid descriptor
|
|
//-------------------------------------------------------------------------------//
|
|
if (fwd.watch_descriptor < 0)
|
|
{
|
|
elog("inotify_add_watch failed.");
|
|
return;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// ...
|
|
//-------------------------------------------------------------------------------//
|
|
for (;;)
|
|
{
|
|
fwd.idx = 0;
|
|
fwd.length = read(fwd.file_descriptor, fwd.buffer, fwd.size);
|
|
|
|
if (fwd.length < 0)
|
|
{
|
|
static int fail_count = 0;
|
|
|
|
if (!app::data::exiting)
|
|
{
|
|
std::string emsg = std::string(": Error in read(): ") +
|
|
std::to_string(static_cast<size_t>(fwd.length)) + ", " +
|
|
std::string(explain_read(fwd.file_descriptor, fwd.buffer, fwd.size));
|
|
|
|
elog(emsg);
|
|
}
|
|
|
|
sleep (READ_ERR_TRESHOLD);
|
|
|
|
if (++fail_count >= READ_ERR_TRESHOLD)
|
|
{
|
|
elog(": READ_ERR_TRESHOLD reached. Quiting...");
|
|
return;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
while (fwd.idx < fwd.length)
|
|
{
|
|
inotify_event * evn = reinterpret_cast<inotify_event *>(& fwd.buffer[fwd.idx]);
|
|
|
|
if (evn->len)
|
|
{
|
|
if (evn->mask & IN_CREATE)
|
|
{
|
|
if (!(evn->mask & IN_ISDIR))
|
|
sigc_file_added(api::sys::read_link(fwd.dirpath + "/" + std::string(evn->name)));
|
|
}
|
|
|
|
if (evn->mask & IN_DELETE)
|
|
{
|
|
if (!(evn->mask & IN_ISDIR))
|
|
sigc_file_removed(fwd.dirpath + "/" + std::string(evn->name));
|
|
}
|
|
|
|
fwd.idx += EVENT_SIZE + evn->len;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// Type: namespace
|
|
//-------------------------------------------------------------------------------//
|
|
//
|
|
// ToDo: n/a
|
|
//
|
|
// Notes: n/a
|
|
//
|
|
// Returns: n/a
|
|
//
|
|
//--------------------------------------------------------------------------------------------------------------------------------------------//
|
|
void app::load_pci_device_list()
|
|
{
|
|
clog("Processing PCI Devices...");
|
|
|
|
std::vector<std::string> lst {api::vct::to_vector_string_list(api::cns::exec("lspci -knn", app::data::app_log_dir).std_out, 10)};
|
|
|
|
pci_list.clear();
|
|
|
|
for (size_t i = 0; i < lst.size(); i++)
|
|
{
|
|
if (lst[i][0] != C_HTAB)
|
|
{
|
|
pci_device_struct dev_info;
|
|
|
|
dev_info.parent_ref = {api::str::trim(lst[i])};
|
|
dev_info.sysfs_id = {api::str::trim(api::str::range_copy(0, api::str::get_char_index(32, 1, lst[i]) - 1, lst[i]))};
|
|
dev_info.dev_type_id = {api::str::trim(api::str::range_copy(api::str::get_char_index('[', 1, lst[i]) + 1, api::str::get_char_index(':', 2, lst[i]) - 2, lst[i]))};
|
|
dev_info.device_type = {api::str::trim(api::str::range_copy(api::str::get_char_index(32, 1, lst[i]) + 1, api::str::get_char_index('[', 1, lst[i]) - 2, lst[i]))};
|
|
dev_info.device_desc = {api::str::trim(api::str::range_copy(api::str::get_char_index(':', 2, lst[i]) + 1, api::str::get_char_index('[', api::str::char_count('[', lst[i]), lst[i]) - 1, lst[i]))};
|
|
dev_info.dev_desc_vid_did = {api::str::trim(api::str::range_copy(api::str::get_char_index('[', api::str::char_count('[', lst[i]), lst[i]) + 1, api::str::get_char_index(']', api::str::char_count(']', lst[i]), lst[i]) - 1, lst[i]))};
|
|
dev_info.boot_script_path = {app::data::app_scripts_dir + "/disable_" + api::str::replace_char(':', '_', dev_info.dev_desc_vid_did.c_str()) + ".sh"};
|
|
|
|
while (lst[++i].at(0) == C_HTAB)
|
|
{
|
|
dev_info.prop.push_back(api::str::trim(lst[i]));
|
|
|
|
std::string entry = {api::str::to_lower_case("kernel modules:")};
|
|
|
|
if (api::str::to_lower_case(api::str::range_copy(0, std::string(entry).size() - 1, api::str::trim(lst[i]))) == entry)
|
|
dev_info.kernel_module = {api::str::trim(api::str::range_copy(api::str::get_char_index(':', 1, lst[i]) + 1, lst[i].size() - 2, lst[i]))};
|
|
|
|
if (i + 1 >= lst.size())
|
|
break;
|
|
}
|
|
|
|
std::string dev_address = {api::cns::exec("find /sys/bus/pci/devices/*/uevent | grep \"" + dev_info.sysfs_id + "\"", app::data::app_log_dir).std_out};
|
|
dev_info.sysfs_id = {api::str::range_copy(api::str::get_char_index('/', 5, dev_address) + 1, api::str::get_char_index('/', 6, dev_address) - 1, dev_address)};
|
|
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// Check to see if the device is enabled
|
|
//-------------------------------------------------------------------------------//
|
|
std::string status_path = "/sys/bus/pci/devices/" + dev_info.sysfs_id + "/enable";
|
|
|
|
if (api::fs::path_exists(status_path))
|
|
{
|
|
std::string msg = {"Checking Device State: \"" + status_path + "\" for \"" + dev_info.device_desc + "\" - State: "};
|
|
std::string status = {api::str::remove_char('\n', api::str::load_from_file(status_path))};
|
|
msg = {msg + (std::atoi(status.c_str()) ? status + " [Enabled]" : status + " [Disabled]")};
|
|
|
|
clog(msg);
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// Is the device enabled?
|
|
//-------------------------------------------------------------------------------//
|
|
if (!std::atoi(status.c_str()))
|
|
dev_info.device_enabled = false;
|
|
}
|
|
else
|
|
{
|
|
clog("File Path Error: \"" << status_path << "\" does not exist. Can't determine whether the following device is enabled or disabled: " << dev_info.device_desc);
|
|
dev_info.device_enabled = false;
|
|
}
|
|
|
|
--i;
|
|
|
|
pci_list.push_back(dev_info);
|
|
}
|
|
}
|
|
|
|
clog("Done Processing PCI Devices...");
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// Type: namespace
|
|
//-------------------------------------------------------------------------------//
|
|
//
|
|
// ToDo: n/a
|
|
//
|
|
// Notes: n/a
|
|
//
|
|
// Returns: n/a
|
|
//
|
|
//--------------------------------------------------------------------------------------------------------------------------------------------//
|
|
std::vector<std::string> app::get_device_prop(const std::string & sysfs_id)
|
|
{
|
|
clog("Obtaining Device Properties...");
|
|
|
|
std::vector<std::string> lshw {api::vct::to_vector_string_list(api::cns::exec("lshw 2> /dev/null", app::data::app_log_dir).std_out, std::vector<char>() = {10})};
|
|
std::vector<std::string> hwinfo {api::vct::to_vector_string_list(api::cns::exec("hwinfo", app::data::app_log_dir).std_out, std::vector<char>() = {10})};
|
|
std::vector<std::string> out {};
|
|
std::string dev_paths {};
|
|
|
|
if (lshw.size() <= 1)
|
|
{
|
|
out.push_back("\n" + TXT_LINE_PADDING + "Error: \"lshw\" not installed or configured properly.\n\n");
|
|
goto process_hwinfo;
|
|
}
|
|
|
|
if (app::lshw_found())
|
|
{
|
|
for (size_t i = 0; i < lshw.size(); i++)
|
|
{
|
|
if (lshw[i].find(sysfs_id) != std::string::npos)
|
|
{
|
|
out.push_back("[GENERAL]");
|
|
|
|
for (size_t x = i; x > 0; x--) // lshw[0] is valid but we don't need it
|
|
{
|
|
if (lshw[x].find("*-") != std::string::npos)
|
|
{
|
|
for (size_t y = x + 1; y < lshw.size(); y++)
|
|
{
|
|
if (lshw[y].find("*-") != std::string::npos)
|
|
goto process_hwinfo;
|
|
|
|
if (!out.size()) out.push_back(std::string());
|
|
|
|
out.push_back(api::str::to_upper_case(TXT_LINE_PADDING + api::str::trim(lshw[y])));
|
|
|
|
if (lshw[y].find("logical name:") != std::string::npos)
|
|
dev_paths += TXT_LINE_PADDING + api::str::trim(lshw[y]) + "\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
process_hwinfo:
|
|
{
|
|
// If you want to extract data from additional properties, simply add the key/property here
|
|
std::vector<std::string> hwinfo_prop_search_list =
|
|
{
|
|
"DEVNAME=",
|
|
"DEVLINKS=",
|
|
"INTERFACE=",
|
|
"IFINDEX=",
|
|
};
|
|
|
|
if (hwinfo.size() <= 1)
|
|
{
|
|
out.push_back("\n" + TXT_LINE_PADDING + "Error: \"hwinfo\" not installed or configured properly.\n\n");
|
|
return out;
|
|
}
|
|
|
|
if (app::hwinfo_found())
|
|
{
|
|
for (size_t i = 0; i < hwinfo.size(); i++)
|
|
{
|
|
//-------------------------------------------------------------------------------//
|
|
// sysfs_id example: 0000:00:1f.3, or 1-4.3 etc (depends on the system)
|
|
//-------------------------------------------------------------------------------//
|
|
if (hwinfo[i].find(sysfs_id) != std::string::npos && hwinfo[i].find("P: /devices/") != std::string::npos)
|
|
{
|
|
clog("Found new section at index: " << i + 1 << ", sysfs_id: " << sysfs_id);
|
|
|
|
out.push_back(std::string());
|
|
out.push_back("[SECTION-" + std::to_string(i + 1) + "] | " + sysfs_id);
|
|
|
|
for (; i < hwinfo.size(); i++)
|
|
{
|
|
clog("...Processing: " << hwinfo[i]);;
|
|
|
|
std::string trimmed = api::str::trim(hwinfo[i]);
|
|
|
|
if (!trimmed.size())
|
|
{
|
|
clog("Breaking at index " << i + 1);
|
|
break;
|
|
}
|
|
|
|
out.push_back(TXT_LINE_PADDING + api::str::range_copy(0, trimmed.size() - 1, trimmed));
|
|
|
|
for (size_t x = 0; x < hwinfo_prop_search_list.size(); x++)
|
|
{
|
|
if (out[out.size() - 1].find(hwinfo_prop_search_list[x]) != std::string::npos)
|
|
// dev_paths += app::stdapi::str::range_copy(app::stdapi::str::get_char_index('=', 1, out[out.size() - 1]) + 1, out[out.size() - 1].size() - 1, out[out.size() - 1]) + "\n";
|
|
dev_paths += TXT_LINE_PADDING + api::str::trim(api::str::range_copy(0, out[out.size() - 1].size() - 1, out[out.size() - 1])) + "\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!dev_paths.size())
|
|
dev_paths.insert(0, TXT_LINE_PADDING + "No Device Paths found\n");
|
|
|
|
out.insert(out.begin(), dev_paths);
|
|
out.insert(out.begin(), "[DEVICE PATHS & NAMES]");
|
|
|
|
clog("Done Obtaining Device Properties");
|
|
|
|
return out;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// Type: namespace
|
|
//-------------------------------------------------------------------------------//
|
|
//
|
|
// ToDo: n/a
|
|
//
|
|
// Notes: n/a
|
|
//
|
|
// Returns: n/a
|
|
//
|
|
//--------------------------------------------------------------------------------------------------------------------------------------------//
|
|
void app::load_scsi_device_list()
|
|
{
|
|
clog("Processing SCSI Devices...");
|
|
|
|
scsi_list.clear();
|
|
|
|
std::vector<std::string> lshw = {api::vct::to_vector_string_list(api::cns::exec("lshw 2> /dev/null").std_out, std::vector<char>() = {10})};
|
|
|
|
for (size_t i = 0; i < lshw.size(); i++)
|
|
{
|
|
//-------------------------------------------------------------------------------//
|
|
// Do we have a new section?
|
|
//-------------------------------------------------------------------------------//
|
|
if (lshw[i].find("*-scsi") != std::string::npos)
|
|
{
|
|
scsi_device_struct scsi = {};
|
|
|
|
scsi.props.push_back(api::str::remove_char(10, lshw[i]));
|
|
|
|
size_t hba_start_idx = (api::str::get_char_index('*', 1, lshw[i]));
|
|
scsi.scsi_idx = (api::str::range_copy(api::str::get_char_index(':', 1, lshw[i]) + 1, lshw[i].length() - 2, lshw[i]));
|
|
|
|
if (scsi.scsi_idx.find("*") != std::string::npos)
|
|
scsi.scsi_idx = "n/a";
|
|
|
|
i++;
|
|
|
|
for (size_t x = i; x < lshw.size(); x++)
|
|
{
|
|
//-------------------------------------------------------------------------------//
|
|
// bus info:
|
|
//-------------------------------------------------------------------------------//
|
|
if (lshw[x].find("bus info:") != std::string::npos)
|
|
{
|
|
std::string trimmed = api::str::trim(lshw[x]);
|
|
|
|
if (lshw[x].find(",") != std::string::npos)
|
|
scsi.hba_number = api::str::range_copy( api::str::get_char_index('@', 1, trimmed) + 1,
|
|
api::str::get_char_index(',', 1, trimmed) - 1,
|
|
trimmed);
|
|
else
|
|
scsi.hba_number = api::str::range_copy( api::str::get_char_index('@', 1, trimmed) + 1,
|
|
trimmed.size() - 1,
|
|
trimmed);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// product info:
|
|
//-------------------------------------------------------------------------------//
|
|
if ((lshw[x].find("product:") != std::string::npos))
|
|
{
|
|
std::string trimmed = api::str::trim(lshw[x]);
|
|
scsi.product_info = api::str::range_copy(9, trimmed.size() - 1, trimmed);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// product desc:
|
|
//-------------------------------------------------------------------------------//
|
|
if ((lshw[x].find("description:") != std::string::npos))
|
|
{
|
|
std::string trimmed = api::str::trim(lshw[x]);
|
|
scsi.product_desc = api::str::range_copy(13, trimmed.size() - 1, trimmed);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// see where the new section starts
|
|
//-------------------------------------------------------------------------------//
|
|
size_t section_start_idx = api::str::get_char_index('*', 1, lshw[x]);
|
|
|
|
if (section_start_idx == hba_start_idx) // new section found that is a *-scsi
|
|
{
|
|
i--;
|
|
break;
|
|
}
|
|
|
|
if ((section_start_idx < hba_start_idx) && (section_start_idx != std::string::npos)) // new section found that is not *-scsi
|
|
break;
|
|
|
|
scsi.props.push_back(api::str::remove_char(10, lshw[x]));
|
|
}
|
|
|
|
scsi.boot_script_path = app::data::app_scripts_dir + "/disable_" + api::str::replace_char(':', '_', scsi.hba_number) + ".sh";
|
|
|
|
if (!scsi.product_info.size())
|
|
scsi.product_info = scsi.product_desc;
|
|
|
|
scsi_list.push_back(scsi);
|
|
}
|
|
}
|
|
|
|
clog("Done Processing SCSI Devices...");
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// Type: namespace
|
|
//-------------------------------------------------------------------------------//
|
|
//
|
|
// ToDo: n/a
|
|
//
|
|
// Notes: n/a
|
|
//
|
|
// Returns: n/a
|
|
//
|
|
//--------------------------------------------------------------------------------------------------------------------------------------------//
|
|
|
|
void app::load_usb_device_list()
|
|
{
|
|
clog("Processing USB Devices...");
|
|
|
|
usb_list.clear();
|
|
|
|
std::vector<std::string> lsusb = {api::vct::to_vector_string_list(api::cns::exec("lsusb").std_out, std::vector<char>() = {10})};
|
|
std::vector<std::string> hwinfo = {api::vct::to_vector_string_list(api::cns::exec("hwinfo").std_out, std::vector<char>() = {10})};
|
|
|
|
for (size_t i = 0; i < lsusb.size() - 1; i++)
|
|
{
|
|
usb_device_struct usb = {};
|
|
|
|
usb.bus_idx = api::str::trim(api::str::range_copy(4, api::str::get_char_index(' ', 2, lsusb[i]) - 1, lsusb[i]));
|
|
usb.device_idx = api::str::trim(api::str::range_copy(api::str::get_char_index(' ', 3, lsusb[i]) + 1, api::str::get_char_index(':', 1, lsusb[i]) - 1, lsusb[i]));
|
|
usb.vid_did = api::str::trim(api::str::range_copy(api::str::get_char_index(' ', 5, lsusb[i]) + 1, api::str::get_char_index(' ', 6, lsusb[i]) - 1, lsusb[i]));
|
|
usb.vid = api::str::trim(api::str::range_copy(api::str::get_char_index(' ', 5, lsusb[i]) + 1, api::str::get_char_index(':', 2, lsusb[i]) - 1, lsusb[i]));
|
|
usb.did = api::str::trim(api::str::range_copy(api::str::get_char_index(':', 2, lsusb[i]) + 1, api::str::get_char_index(' ', 6, lsusb[i]) - 1, lsusb[i]));
|
|
usb.hub_info = api::str::trim(api::str::range_copy(api::str::get_char_index(' ', 6, lsusb[i]) + 1, lsusb[i].size() - 2, lsusb[i]));
|
|
usb.boot_script_path = api::str::trim(app::data::app_scripts_dir + "/disable_" + api::str::replace_char(':', '_', usb.vid_did.c_str()) + ".sh");
|
|
|
|
usb.device_type = "Unclassified Device [Please Install hwinfo]";
|
|
usb.actual_dev_details = "[Please Install hwinfo]";
|
|
|
|
if (hwinfo.size())
|
|
{
|
|
long idx_ven = api::vct::left_index_of(hwinfo, " Vendor: usb 0x" + usb.vid, " Device: usb 0x" + usb.did);
|
|
|
|
for (; idx_ven >= 0; --idx_ven)
|
|
{
|
|
if (hwinfo[static_cast<unsigned long>(idx_ven)].find(" Model: ") != std::string::npos)
|
|
usb.actual_dev_details = api::str::trim(api::str::range_copy(api::str::get_char_index('"', 1, hwinfo[static_cast<unsigned long>(idx_ven)]) + 1, api::str::get_char_index('"', 2, hwinfo[static_cast<unsigned long>(idx_ven)]) - 1, hwinfo[static_cast<unsigned long>(idx_ven)]));
|
|
|
|
if (!api::str::trim(hwinfo[static_cast<unsigned long>(idx_ven)]).size())
|
|
{
|
|
usb.title = api::str::trim(api::str::range_copy(api::str::get_char_index(':', 1, hwinfo[static_cast<unsigned long>(idx_ven + 1)]) + 1, hwinfo[static_cast<unsigned long>(idx_ven + 1)].size() - 1, hwinfo[static_cast<unsigned long>(idx_ven + 1)]));
|
|
usb.device_type = api::str::range_copy(api::str::get_char_index(':', 1, usb.title) + 2, usb.title.size() - 1, usb.title);
|
|
usb.device_type = api::str::range_copy(api::str::get_char_index(' ', 1, usb.device_type) + 1, usb.device_type.size() - 1, usb.device_type);
|
|
usb.hwi_prop_start_idx = idx_ven + 1;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// Check to see if the device is enabled
|
|
//-------------------------------------------------------------------------------//
|
|
std::string id = api::str::remove_left_chars('0', usb.vid) + "/" + api::str::remove_left_chars('0', usb.did);
|
|
usb.sysfs_id = api::str::trim(api::cns::run("sysfs_id=$(grep -il '" + id + "' /sys/bus/usb/devices/*/uevent | tail -1) && echo $sysfs_id | cut -f6 -d'/'"));
|
|
size_t col_pos = api::str::get_char_index(':', 1, usb.sysfs_id);
|
|
usb.sysfs_id = api::str::range_copy(0, col_pos == API_ERROR_IDX_NOT_FOUND ? usb.sysfs_id.size() - 1 : col_pos - 1, usb.sysfs_id);
|
|
usb.device_enabled = api::fs::path_exists("/sys/bus/usb/drivers/usb/" + usb.sysfs_id);
|
|
usb.vid_did_processed = id;
|
|
|
|
if (usb.hub_info.empty())
|
|
usb.hub_info = "[" + usb.vid_did + " / " + usb.vid_did_processed + "]";
|
|
|
|
if (!usb.device_enabled)
|
|
clog("\"" << usb.hub_info << usb.sysfs_id << " " << usb.vid_did << "\" is disabled");
|
|
|
|
usb_list.push_back(usb);
|
|
|
|
clog("Device Type: " << usb.device_type << ", USB Dev ID: " << usb.vid_did << ", Processed USB Dev ID: " << usb.vid_did_processed << ", Hub Info: " << usb.hub_info << ", Device Info: " << usb.actual_dev_details << ", usb.sysfs_id: " << usb.sysfs_id);
|
|
}
|
|
|
|
clog("Done Processing USB Devices...");
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// Type: namespace
|
|
//-------------------------------------------------------------------------------//
|
|
//
|
|
// ToDo: n/a
|
|
//
|
|
// Notes: n/a
|
|
//
|
|
// Returns: n/a
|
|
//
|
|
//--------------------------------------------------------------------------------------------------------------------------------------------//
|
|
void app::search_for_device(const char * dev_str)
|
|
{
|
|
std::string search_str = {api::str::to_lower_case(dev_str)};
|
|
|
|
app::pci_search_list.clear();
|
|
app::scsi_search_list.clear();
|
|
app::usb_search_list.clear();
|
|
|
|
for (size_t i = 0 ; i < app::pci_list.size(); i++)
|
|
{
|
|
if ( api::str::to_lower_case(app::pci_list[i].sysfs_id.c_str()).find(search_str) != std::string::npos ||
|
|
api::str::to_lower_case(app::pci_list[i].device_type.c_str()).find(search_str) != std::string::npos ||
|
|
api::str::to_lower_case(app::pci_list[i].device_desc.c_str()).find(search_str) != std::string::npos ||
|
|
api::str::to_lower_case(app::pci_list[i].dev_type_id.c_str()) .find(search_str) != std::string::npos ||
|
|
api::str::to_lower_case(app::pci_list[i].kernel_module.c_str()).find(search_str) != std::string::npos ||
|
|
api::str::to_lower_case(app::pci_list[i].dev_desc_vid_did.c_str()).find(search_str) != std::string::npos)
|
|
{
|
|
app::pci_search_list.push_back(app::pci_list[i]);
|
|
|
|
clog(app::pci_search_list[app::pci_search_list.size() - 1].device_desc << ": " << app::pci_search_list[app::pci_search_list.size() - 1].device_enabled);
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0 ; i < app::scsi_list.size(); i++)
|
|
{
|
|
if ( api::str::to_lower_case(app::scsi_list[i].hba_number.c_str()).find(search_str) != std::string::npos ||
|
|
api::str::to_lower_case(app::scsi_list[i].product_info.c_str()).find(search_str) != std::string::npos ||
|
|
api::str::to_lower_case(app::scsi_list[i].product_desc.c_str()).find(search_str) != std::string::npos)
|
|
{
|
|
app::scsi_search_list.push_back(app::scsi_list[i]);
|
|
}
|
|
else
|
|
{
|
|
for (size_t x = 0 ; x < app::scsi_list[i].props.size(); x++)
|
|
{
|
|
if (api::str::to_lower_case(app::scsi_list[i].props[x].c_str()).find(search_str) != std::string::npos)
|
|
{
|
|
app::scsi_search_list.push_back(app::scsi_list[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0 ; i < app::usb_list.size(); i++)
|
|
{
|
|
if ( api::str::to_lower_case(app::usb_list[i].hub_info.c_str()).find(search_str) != std::string::npos ||
|
|
api::str::to_lower_case(app::usb_list[i].actual_dev_details.c_str()).find(search_str) != std::string::npos ||
|
|
api::str::to_lower_case(app::usb_list[i].vid_did.c_str()).find(search_str) != std::string::npos)
|
|
{
|
|
app::usb_search_list.push_back(app::usb_list[i]);
|
|
}
|
|
}
|
|
|
|
sigc_clear_device_list();
|
|
sigc_load_pci_list(app::pci_search_list);
|
|
sigc_load_scsi_list(app::scsi_search_list);
|
|
sigc_load_usb_list(app::usb_search_list);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// Type: namespace
|
|
//-------------------------------------------------------------------------------//
|
|
//
|
|
// ToDo: n/a
|
|
//
|
|
// Notes: n/a
|
|
//
|
|
// Returns: n/a
|
|
//
|
|
//--------------------------------------------------------------------------------------------------------------------------------------------//
|
|
int app::config_env()
|
|
{
|
|
write_out.enable_logging();
|
|
write_err.enable_logging();
|
|
|
|
clog("Initialising main process...");
|
|
|
|
app::data::app_log_dir = api::fs::generate_unique_filename("/tmp", app::about::app_name);
|
|
app::data::app_home_dir = api::sys::get_env("HOME");
|
|
|
|
if (!app::data::app_home_dir.length())
|
|
{
|
|
app::last_err.set_error("Failed to find your HOME dir.\n\nWill not continue.", EXIT_FAILURE);
|
|
return last_err.get_error_code();
|
|
}
|
|
|
|
if (api::fs::path_exists(app::data::app_home_dir + std::string("/.config")))
|
|
{
|
|
if (api::fs::is_directory(app::data::app_home_dir + std::string("/.config")))
|
|
app::data::app_settings_dir = app::data::app_home_dir + std::string("/.config/") + app::about::app_name;
|
|
}
|
|
|
|
if (app::data::app_settings_dir.empty())
|
|
{
|
|
if (api::fs::path_exists(app::data::app_home_dir + std::string("/.local/share")))
|
|
{
|
|
if (api::fs::is_directory(app::data::app_home_dir + std::string("/.local/share")))
|
|
app::data::app_settings_dir = app::data::app_home_dir + std::string("/.local/share/") + app::about::app_name;
|
|
}
|
|
}
|
|
|
|
if (app::data::app_settings_dir.empty())
|
|
app::data::app_settings_dir = app::data::app_home_dir + std::string("/") + app::about::app_name;
|
|
|
|
if (app::data::app_settings_dir.empty())
|
|
{
|
|
app::last_err.set_error("Unable to set a data directory to store settings in.", EXIT_FAILURE);
|
|
return last_err.get_error_code();
|
|
}
|
|
|
|
app::data::app_scripts_dir = app::data::app_settings_dir + "/" + std::string(DIRNAME_SCRIPTS);
|
|
app::data::app_backup_dir = app::data::app_settings_dir + "/" + std::string(DIRNAME_BACKUP);
|
|
|
|
if (system(std::string("mkdir " + app::data::app_log_dir).c_str()))
|
|
{
|
|
app::last_err.set_error(std::string("Failed to create log directory: " + app::data::app_log_dir + "\n\nCannot continue without this. Please check permissions.\n\nQuitting..."), EXIT_FAILURE);
|
|
return last_err.get_error_code();
|
|
}
|
|
|
|
if (!api::fs::path_exists(app::data::app_settings_dir))
|
|
{
|
|
if (system(std::string("mkdir " + app::data::app_settings_dir).c_str()))
|
|
{
|
|
app::last_err.set_error(std::string("Failed to create data directory: " + app::data::app_settings_dir + "\n\nCannot continue without this. Please check permissions.\n\nQuitting..."), EXIT_FAILURE);
|
|
return last_err.get_error_code();
|
|
}
|
|
}
|
|
|
|
if (!api::fs::path_exists(app::data::app_scripts_dir))
|
|
{
|
|
if (system(std::string("mkdir " + app::data::app_scripts_dir).c_str()))
|
|
{
|
|
app::last_err.set_error(std::string("Failed to create data directory: " + app::data::app_scripts_dir + "\n\nCannot continue without this. Please check permissions.\n\nQuitting..."), EXIT_FAILURE);
|
|
return last_err.get_error_code();
|
|
}
|
|
}
|
|
|
|
if (!api::fs::path_exists(app::data::app_backup_dir))
|
|
{
|
|
if (system(std::string("mkdir " + app::data::app_backup_dir).c_str()))
|
|
{
|
|
app::last_err.set_error(std::string("Failed to create backup directory: " + app::data::app_backup_dir + "\n\nCannot continue without this. Please check permissions.\n\nQuitting..."), EXIT_FAILURE);
|
|
return last_err.get_error_code();
|
|
}
|
|
}
|
|
|
|
if (!app::lspci_found())
|
|
{
|
|
app::last_err.set_error("This software requires \"lspci\" in order to run properly (not found).\n\nPlease install it (pciutils).", EXIT_FAILURE);
|
|
return last_err.get_error_code();
|
|
}
|
|
|
|
last_err.set_error("", EXIT_SUCCESS);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// Type: namespace
|
|
//-------------------------------------------------------------------------------//
|
|
//
|
|
// ToDo: n/a
|
|
//
|
|
// Notes: n/a
|
|
//
|
|
// Returns: n/a
|
|
//
|
|
//--------------------------------------------------------------------------------------------------------------------------------------------//
|
|
void app::print_config()
|
|
{
|
|
clog("Log dir: " + app::data::app_log_dir);
|
|
clog("Settings dir: " + app::data::app_settings_dir);
|
|
clog("Scripts dir: " + app::data::app_scripts_dir);
|
|
clog("Backups dir: " + app::data::app_backup_dir);
|
|
clog("User ID: " + std::to_string(getuid()));
|
|
clog("Process ID: " + std::to_string(getpid()));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// namespace
|
|
//-------------------------------------------------------------------------------//
|
|
//
|
|
// ToDo: n/a
|
|
//
|
|
// Notes: Creates a list of dir paths to monitor
|
|
//
|
|
// Returns: n/a
|
|
//
|
|
//------------------------------------------------------------------------------//
|
|
void app::init_watch_list()
|
|
{
|
|
app::data::watch_list.push_back("/dev");
|
|
app::data::watch_list.push_back("/dev/block");
|
|
app::data::watch_list.push_back("/dev/bsg");
|
|
app::data::watch_list.push_back("/dev/bus");
|
|
app::data::watch_list.push_back("/dev/char");
|
|
app::data::watch_list.push_back("/dev/disk");
|
|
app::data::watch_list.push_back("/dev/dri");
|
|
app::data::watch_list.push_back("/dev/fd");
|
|
app::data::watch_list.push_back("/dev/input");
|
|
app::data::watch_list.push_back("/dev/mapper");
|
|
app::data::watch_list.push_back("/dev/net");
|
|
app::data::watch_list.push_back("/dev/pts");
|
|
app::data::watch_list.push_back("/dev/snd");
|
|
app::data::watch_list.push_back("/dev/usb");
|
|
app::data::watch_list.push_back("/dev/v4l/by-id");
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// namespace
|
|
//-------------------------------------------------------------------------------//
|
|
//
|
|
// ToDo: n/a
|
|
//
|
|
// Notes: Shows a graphical notification popup on user's desktop via notify-send
|
|
// if it's installed...
|
|
//
|
|
// Returns: n/a
|
|
//
|
|
//------------------------------------------------------------------------------//
|
|
void app::show_notification(const std::string & title, const std::string & msg, int delay)
|
|
{
|
|
if (!api::sys::get_env("DISPLAY").length())
|
|
return;
|
|
|
|
std::vector<std::string> lst;
|
|
|
|
lst.push_back("notify-send -u normal -t ");
|
|
lst.push_back(std::to_string(delay));
|
|
lst.push_back(" -i info '");
|
|
lst.push_back(title);
|
|
lst.push_back("' '");
|
|
lst.push_back(msg);
|
|
lst.push_back("'");
|
|
|
|
std::system((api::vct::to_string(lst) + " &").c_str());
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------//
|
|
// namespace
|
|
//-------------------------------------------------------------------------------//
|
|
//
|
|
// ToDo: n/a
|
|
//
|
|
// Notes: Tries to obtain device details based on the dev_node
|
|
//
|
|
// Returns: Details about the device
|
|
//
|
|
//-------------------------------------------------------------------------------//
|
|
std::string app::query_device(const std::string & dev_node)
|
|
{
|
|
clog(": Searching for: " << dev_node);
|
|
|
|
if (!app::hwinfo_found())
|
|
return "Err: hwinfo not found.\n\n"
|
|
"To get information about the device you just inserted, you need to install hwinfo.";
|
|
|
|
std::string msg;
|
|
|
|
// If you want to extract data from additional properties
|
|
// simply add the key/property here
|
|
std::vector<std::string> search_list =
|
|
{
|
|
"ID_MODEL=",
|
|
"ID_MODEL_FROM_DATABASE=",
|
|
"ID_TYPE=",
|
|
"ID_USB_DRIVER=",
|
|
"ID_PCI_CLASS_FROM_DATABASE",
|
|
"ID_PCI_SUBCLASS_FROM_DATABASE",
|
|
"ID_VENDOR_FROM_DATABASE",
|
|
"ID_VENDOR="
|
|
};
|
|
|
|
std::vector<std::string> hwinfo = api::vct::to_vector_string_list(api::cns::exec("hwinfo", app::data::app_log_dir).std_out, std::vector<char>() = {10});
|
|
|
|
//------------------------------------------------------------------------------------//
|
|
// Iterate through the content
|
|
//------------------------------------------------------------------------------------//
|
|
for (size_t i = 0; i < hwinfo.size(); i++)
|
|
{
|
|
//------------------------------------------------------------------------------------//
|
|
// Find the first one one that contains the dev_node and start working from there
|
|
//------------------------------------------------------------------------------------//
|
|
if (hwinfo[i].find(dev_node) != std::string::npos)
|
|
{
|
|
for (; i < hwinfo.size(); i++)
|
|
{
|
|
if (!api::str::trim(hwinfo[i]).size())
|
|
break;
|
|
|
|
for (size_t x = 0; x < search_list.size(); x++)
|
|
{
|
|
if (hwinfo[i].find(search_list[x]) != std::string::npos)
|
|
msg += api::str::range_copy(api::str::get_char_index('=', 1, hwinfo[i]) + 1, hwinfo[i].size() - 1, hwinfo[i]);
|
|
}
|
|
}
|
|
|
|
for (; i < hwinfo.size(); i++)
|
|
{
|
|
if (!api::str::trim(hwinfo[i]).size())
|
|
break;
|
|
|
|
if (hwinfo[i].find("name: " + dev_node) != std::string::npos)
|
|
{
|
|
i++;
|
|
|
|
std::vector<std::string> class_paths = api::str::url2list(hwinfo[i]);
|
|
|
|
if (class_paths.size() < 3)
|
|
break;
|
|
|
|
for (; i < hwinfo.size(); i++)
|
|
{
|
|
if (!api::str::trim(hwinfo[i]).size())
|
|
break;
|
|
|
|
if (hwinfo[i].find("name:") != std::string::npos)
|
|
break;
|
|
|
|
if (hwinfo[i].find(class_paths[2]) != std::string::npos && hwinfo[i].find("/net/") != std::string::npos)
|
|
{
|
|
size_t copy_start = 0;
|
|
|
|
for (size_t s = hwinfo[i].length() - 1; s > 0; s--)
|
|
{
|
|
if (hwinfo[i][s] == '/')
|
|
{
|
|
copy_start = s;
|
|
break;
|
|
}
|
|
}
|
|
|
|
msg += "\tNetwork Interface Name: " + api::str::range_copy(++copy_start, hwinfo[i].length() - 1, hwinfo[i]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!api::str::trim(msg).length())
|
|
clog("No info found for: " << dev_node);
|
|
|
|
clog("Exit");
|
|
|
|
return msg;
|
|
}
|