Device Manager 4 Linux is a distro agnostic graphical device manager for Linux that lets you disable and enable devices without blacklisting the associated kernel module and without requiring a reboot.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

936 lines
40 KiB

//-----------------------------------------------------------------------------------------//
// 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;
}