diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 067144761df18780269fb04c690be592a3092aa7..ce7cd633462c6e932d1f51d09b7ebc92e03431cb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -27,6 +27,7 @@ compile: script: - echo "Estágio 'build'" - apt-get update && apt-get install -y build-essential cmake git + libudev-dev - git submodule init - git submodule update --init --recursive - mkdir build diff --git a/CMakeLists.txt b/CMakeLists.txt index 130fd6d2252116db9cf5f64f8065f998ad0fbeb5..8972ebc300e7712476913d069ca5d9739588163a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,6 @@ if ( WIN32 ) add_subdirectory ( lib/dtwinver ) endif () - # headers include_directories ( "include" ) @@ -66,4 +65,7 @@ target_link_libraries ( agent-v${VERSION_MAJOR}.${VERSION_MINOR} ${CPR_LIBRARIES if ( WIN32 ) target_link_libraries ( agent-v${VERSION_MAJOR}.${VERSION_MINOR} dtwinver ) -endif() +else () + # libudev + target_link_libraries ( agent-v${VERSION_MAJOR}.${VERSION_MINOR} udev ) +endif () diff --git a/include/agent/linux/get_disks_info.h b/include/agent/linux/get_disks_info.h new file mode 100644 index 0000000000000000000000000000000000000000..7a74943badb3b553b23684eea70da4936908694d --- /dev/null +++ b/include/agent/linux/get_disks_info.h @@ -0,0 +1,9 @@ +struct disk { + std::string model; + long long size; +}; + +typedef struct disk disk_t; + +void get_scsi_disks(std::list<disk_t>&); +void get_disks_info(std::list<disk_t>&); diff --git a/include/agent/linux/get_distro.h b/include/agent/linux/get_distro.h index ae5556a308e2ecf37fe6e97dc026228da6bdf3a5..e9730beb1d5f67c40d2c26f7adb83dcbf6d2d19b 100644 --- a/include/agent/linux/get_distro.h +++ b/include/agent/linux/get_distro.h @@ -1,7 +1,5 @@ #pragma once #include <sys/utsname.h> -#include <fstream> -#include <cstring> +#include "agent/linux/open_file.h" -int open_file(std::string name, std::ifstream& fstream); std::string get_distro(); diff --git a/include/agent/linux/get_memory_size.h b/include/agent/linux/get_memory_size.h new file mode 100644 index 0000000000000000000000000000000000000000..1dc19d0110fd6ed7e6bfe541a1fc59ef5cc3c6a8 --- /dev/null +++ b/include/agent/linux/get_memory_size.h @@ -0,0 +1,7 @@ +#pragma once +#include <fstream> +#include <string> +#include "agent/linux/open_file.h" +#include <algorithm> + +int get_memory_size(); diff --git a/include/agent/linux/get_processor_model.h b/include/agent/linux/get_processor_model.h new file mode 100644 index 0000000000000000000000000000000000000000..e3008313d95a938b53a86c0b37711efacd8a2adf --- /dev/null +++ b/include/agent/linux/get_processor_model.h @@ -0,0 +1,6 @@ +#pragma once +#include <fstream> +#include <string> +#include "agent/linux/open_file.h" + +std::string get_processor_model(); diff --git a/include/agent/linux/inventory.h b/include/agent/linux/inventory.h index 3d96c0cfd1db85ccc955d72430d8fbba73648015..0f6bfa813eef82a276404c4e99fb4e60909e722e 100644 --- a/include/agent/linux/inventory.h +++ b/include/agent/linux/inventory.h @@ -3,15 +3,14 @@ #include <time.h> #include <iostream> #include "agent/linux/get_date.h" +#include "agent/linux/get_disks_info.h" +#include "agent/linux/get_distro.h" #include "agent/linux/get_macaddr.h" #include "agent/linux/get_machine_type.h" +#include "agent/linux/get_memory_size.h" +#include "agent/linux/get_processor_model.h" #include "agent/linux/get_time.h" #include "agent/linux/get_user_count.h" #include "json/json.h" -int open_file(std::string name, std::ifstream& fstream); - -std::string get_distro(); -std::string get_processor_model(); - Json::Value get_inventory(); diff --git a/include/agent/linux/open_file.h b/include/agent/linux/open_file.h new file mode 100644 index 0000000000000000000000000000000000000000..486377505034a8b1fe6bfc0120007314fa7731f8 --- /dev/null +++ b/include/agent/linux/open_file.h @@ -0,0 +1,5 @@ +#pragma once +#include <fstream> +#include <string> + +int open_file(std::string name, std::ifstream& fstream); diff --git a/src/linux/get_disks_info.cpp b/src/linux/get_disks_info.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dffb40f056c8d991af0c724707ac4fe1bddbefd4 --- /dev/null +++ b/src/linux/get_disks_info.cpp @@ -0,0 +1,117 @@ +/* Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre + * Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + * + * This file is part of simmc-agent + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include <libudev.h> +#include <fstream> +#include <string> +#include <iostream> +#include <list> +#include "agent/linux/get_disks_info.h" + + +void get_scsi_disks(std::list<disk_t>& disks) { // NOLINT(runtime/references) + + struct udev *udev; + struct udev_enumerate *enumerate; + struct udev_list_entry *devices, *dev_list_entry, *links_list_entry; + struct udev_device *dev; + + udev = udev_new(); + if (!udev) { + throw "Could not creat udev\n"; + } + + /* SCSI disk devices MAJOR = {8, 65-71, 128-135} + see https://www.kernel.org/doc/Documentation/devices.txt */ + const char* scsi_majors[] = {"8", "65", "66", "67", "68", "69", "70", "71", + "128", "129", "130", "131", "132", "133", + "134", "135"}; + int i; + + for (i=0; i < 16; i++) { + + /* create a list of the disk devices in the 'block' subsystem and with + MAJOR == one of the possible scsi major numbers. */ + enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_property(enumerate, "MAJOR", scsi_majors[i]); + udev_enumerate_add_match_subsystem(enumerate, "block"); + udev_enumerate_scan_devices(enumerate); + devices = udev_enumerate_get_list_entry(enumerate); + + udev_list_entry_foreach(dev_list_entry, devices) { + /* potential new item */ + disk_t curr = {.model = "", .size = -1}; + + /* get the filename of the /sys entry for the device + and create udev_device object representing it */ + const char *path; + path = udev_list_entry_get_name(dev_list_entry); + dev = udev_device_new_from_syspath(udev, path); + + /* MINOR = (16 * drive_number) + partition_number + partition_number is 0 for the whole drive, which is the one we want + therefore, if mod 16 != 0, skip device */ + const char* minor = udev_device_get_property_value(dev, "MINOR"); + if ((atoi(minor) % 16) != 0) { + udev_device_unref(dev); + continue; + } + + + const char* serial = udev_device_get_property_value(dev, + "ID_SERIAL"); + const char* size = udev_device_get_sysattr_value(dev, "size"); + + if (serial) { + curr.model.assign(std::string(serial)); + } + + /* size in Bytes = size * 512 + size in GB = (size * 2^9)/2^30 = size/2^21 */ + if (size) { + curr.size = atoll(size) >> 21; + } + + /* do not push some anomalous device whose model and size we + couldn't obtain */ + if (size && serial) { + disks.push_front(curr); + } + + udev_device_unref(dev); + } + + /* free the enumerator object */ + udev_enumerate_unref(enumerate); + + } + + udev_unref(udev); +} + + +void get_disks_info(std::list<disk_t>& disks) { // NOLINT(runtime/references) + get_scsi_disks(disks); + + if (disks.empty()) { + throw std::string("No disk info found"); + } +} diff --git a/src/linux/get_distro.cpp b/src/linux/get_distro.cpp index 88a4fc8e4d519ec7df8887e2967ff4c087296c6b..a7c47703b567843b25d4fc332e667f5b3e2696cf 100644 --- a/src/linux/get_distro.cpp +++ b/src/linux/get_distro.cpp @@ -20,22 +20,9 @@ */ #include "agent/linux/get_distro.h" - -int open_file(std::string name, std::ifstream& fstream) { - fstream.open(name); - if (fstream.is_open()) - return 1; - else - return 0; -} +#include "agent/linux/open_file.h" std::string get_distro() { - /* in Linux: distro name + version + release - the year is 2016 and we have 2 "unified" ways to identify distros - and a couple regex to find the distro name files - update: I used to complain about Linux, then I tried coding for - Windows... */ - /* currently recorded distros are * Ubuntu * Debian @@ -147,5 +134,6 @@ std::string get_distro() { throw std::string("Release file empty."); } + throw std::string("No release file found."); } diff --git a/src/linux/get_memory_size.cpp b/src/linux/get_memory_size.cpp new file mode 100644 index 0000000000000000000000000000000000000000..df66e963cf8494f87d5c9259e7073c9e58f3d0a1 --- /dev/null +++ b/src/linux/get_memory_size.cpp @@ -0,0 +1,62 @@ +/* Copyright (C) 2004-2016 Centro de Computacao Cientifica e Software Livre + * Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + * + * This file is part of simmc-agent + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include "agent/linux/get_memory_size.h" + +int get_memory_size() { + + std::ifstream meminfo_file; + std::string line; + std::string memsize; + + if (open_file("/proc/meminfo", meminfo_file)) { + + const std::string key = "MemTotal:"; + std::size_t found; + + while (getline(meminfo_file, line)) { + + found = line.find(key); + + if (found != std::string::npos) { + // remove key and 'kB' at the end + std::string value = line.substr(found + key.length(), + line.length() - + (found+key.length()+3)); + // remove whitespaces + remove_copy(value.begin(), value.end(), + std::back_inserter(memsize), ' '); + // convert to integer before returning + return std::stoi(memsize); + } + } + // If EOF and no info returned + std::string err = "MemTotal not found in /proc/meminfo."; + throw err; + + } else { + + std::string err = "Failed to open /proc/meminfo."; + throw err; + + } + +} diff --git a/src/linux/get_processor_model.cpp b/src/linux/get_processor_model.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65a1ce8758d5b2a03735e013968c090fd3446ce3 --- /dev/null +++ b/src/linux/get_processor_model.cpp @@ -0,0 +1,44 @@ +/* Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre + * Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + * + * This file is part of simmc-agent + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include "agent/linux/get_processor_model.h" + +std::string get_processor_model() { + + std::ifstream cpuinfo_file; + std::string line; + if (open_file("/proc/cpuinfo", cpuinfo_file)) { + const std::string key = "model name"; + std::size_t found; + + while (getline(cpuinfo_file, line)) { + found = line.find(key); + if (found != std::string::npos) { + // remove ':' and space at the beginning + found = line.find(":"); + return (line.substr(found+2)); + } + } + throw std::string("Coudn't find model name in /proc/cpuinfo"); + } + + throw std::string("Coudn't open /proc/cpuinfo"); +} diff --git a/src/linux/inventory.cpp b/src/linux/inventory.cpp index ff41037b0034f5b82d2c1ab089d90d15548d8a7e..95162517dee5f5680a2a1a9d8b3f74c1416028b8 100644 --- a/src/linux/inventory.cpp +++ b/src/linux/inventory.cpp @@ -19,13 +19,11 @@ * USA. */ +#include <list> #include "agent/linux/inventory.h" -std::string get_processor_model() { - return "unknown"; -} - Json::Value get_inventory() { + Json::Value inv; // os info @@ -46,17 +44,62 @@ Json::Value get_inventory() { inv["data"]["os_kernel"] = sysinfo.release; inv["data"]["mirror_timestamp"] = sysinfo.version; + try { + inv["data"]["processor"] = get_processor_model(); + } + catch ( std::string err ) { + inv["data"]["processor"] = Json::nullValue; + inv["error"]["processor"] = err; + } + + try { + inv["data"]["memory"] = get_memory_size(); + } + catch ( std::string err ) { + inv["data"]["memory"] = Json::nullValue; + inv["error"]["memory"] = err; + } + + try { + std::list<disk_t> disks; + get_disks_info(disks); + disk_t curr = disks.front(); + inv["data"]["disk1_model"] = curr.model; + inv["data"]["disk1_size"] = curr.size; + disks.pop_front(); + + if (disks.empty()) { + inv["data"]["disk2_model"] = Json::nullValue; + inv["data"]["disk2_size"] = Json::nullValue; + } else { + curr = disks.front(); + inv["data"]["disk2_model"] = curr.model; + inv["data"]["disk2_size"] = curr.size; + disks.pop_front(); + } + + Json::UInt64 disks_size = disks.size(); + inv["data"]["extra_hds"] = disks_size; + + } + catch ( std::string err ) { + inv["data"]["disk1_model"] = Json::nullValue; + inv["data"]["disk1_size"] = Json::nullValue; + inv["data"]["disk2_model"] = Json::nullValue; + inv["data"]["disk2_size"] = Json::nullValue; + inv["data"]["extra_hds"] = Json::nullValue; + + inv["error"]["disk1_model"] = err; + inv["error"]["disk1_size"] = err; + inv["error"]["disk2_model"] = err; + inv["error"]["disk2_size"] = err; + inv["error"]["extra_hds"] = err; + } + // hw info /* - inv["processor"] = - inv["memory"] = - inv["disk1_model"] = - inv["disk1_size"] = inv["disk1_used"] = - inv["disk2_model"] = - inv["disk2_size"] = inv["disk2_used"] = - inv["extra_hds"] = */ // other diff --git a/src/linux/open_file.cpp b/src/linux/open_file.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10bcd1de77d261255c3edb0c7163943bb914dc13 --- /dev/null +++ b/src/linux/open_file.cpp @@ -0,0 +1,31 @@ +/* Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre + * Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR + * + * This file is part of simmc-agent + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include "agent/linux/open_file.h" + +int open_file(std::string name, std::ifstream& fstream) { + fstream.open(name); + if (fstream.is_open()) + return 1; + else + return 0; +} +