When OSv kernel is built to hide most symbols but glibc ones, the
OSv applications like httpserver monitoring API can not function
corretly as they rely on number of internal C++ API.

This patch modifies httpserver monitoring API to stop using kernel
internal C++ API. It does so by replacing some of the calls to internal C++
symbols with new module C-style API symbols: for example, 
sched::with_all_threads()
with new osv_get_all_threads(). In other scenarios, we fall back to
standard glibc API: for example osv::current_mounts() is replaced with
getmntent_r() and related functions.

Finally, we link httpserver monitoring app with core/options.cc and
thus remove need to have those symbols exposed by the kernel.

Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>
---
 modules/httpserver-api/api/fs.cc           | 42 ++++++++++----
 modules/httpserver-api/api/hardware.cc     | 23 +++++---
 modules/httpserver-api/api/network.cc      | 19 ++++--
 modules/httpserver-api/api/os.cc           | 67 +++++++++++++---------
 modules/httpserver-api/global_server.cc    | 34 +++++++----
 modules/httpserver-api/global_server.hh    |  5 ++
 modules/httpserver-api/openssl-init.cc     | 15 +++--
 modules/httpserver-api/ssl_server.cc       |  9 ++-
 modules/httpserver-monitoring-api/Makefile |  6 +-
 9 files changed, 150 insertions(+), 70 deletions(-)

diff --git a/modules/httpserver-api/api/fs.cc b/modules/httpserver-api/api/fs.cc
index 94eec77b..52e58c39 100644
--- a/modules/httpserver-api/api/fs.cc
+++ b/modules/httpserver-api/api/fs.cc
@@ -6,12 +6,12 @@
  */
 
 #include "fs.hh"
-#include "osv/mount.h"
 #include "json/formatter.hh"
 #include "autogen/fs.json.hh"
 #include <string>
 #include <vector>
 #include <sys/statvfs.h>
+#include <mntent.h>
 
 namespace httpserver {
 
@@ -23,9 +23,9 @@ using namespace std;
 using namespace json;
 using namespace fs_json;
 
-static void fill_dfstat(DFStat& dfstat, const osv::mount_desc& mount, const 
struct statvfs& st) {
-    dfstat.filesystem = mount.special;
-    dfstat.mount = mount.path;
+static void fill_dfstat(DFStat& dfstat, mntent* mount, const struct statvfs& 
st) {
+    dfstat.filesystem = mount->mnt_fsname;
+    dfstat.mount = mount->mnt_dir;
     dfstat.btotal = st.f_blocks;
     dfstat.bfree = st.f_bfree;
     dfstat.ftotal = st.f_files;
@@ -46,21 +46,31 @@ void init(routes& routes) {
     getDFStats.set_handler("json",
                            [](const_req req)
     {
-        using namespace osv;
         const std::string onemount = req.param.at("mount");
         struct statvfs st;
         httpserver::json::DFStat dfstat;
         vector<httpserver::json::DFStat> dfstats;
 
-        for (mount_desc mount : osv::current_mounts()) {
-            if ((mount.type == "zfs" || mount.type == "rofs") && (onemount == 
"" || onemount == mount.path)) {
-                if (statvfs(mount.path.c_str(),&st) != 0) {
+        FILE *mounts_fp = setmntent("/proc/mounts", "r");
+        if (!mounts_fp) {
+            throw server_error_exception("failed to get mounts information");
+        }
+
+        struct mntent* mount;
+        mntent mnt;
+        char strings[4096];
+        while ((mount = getmntent_r(mounts_fp, &mnt, strings, 
sizeof(strings)))) {
+            std::string fstype(mount->mnt_type);
+            if ((fstype == "zfs" || fstype == "rofs") && (onemount == "" || 
onemount == mount->mnt_dir)) {
+                if (statvfs(mount->mnt_dir,&st) != 0) {
+                    endmntent(mounts_fp);
                     throw not_found_exception("mount does not exist");
                 }
                 fill_dfstat(dfstat, mount, st);
                 dfstats.push_back(dfstat);
             }
         };
+        endmntent(mounts_fp);
 
         // checking if a specific file system was requested and if we found it
         if (onemount != "" && dfstats.size() == 0) {
@@ -76,14 +86,24 @@ void init(routes& routes) {
             httpserver::json::DFStat dfstat;
             vector<httpserver::json::DFStat> res;
 
-            for (osv::mount_desc mount : osv::current_mounts()) {
-                if (mount.type == "zfs" || mount.type == "rofs") {
-                    if (statvfs(mount.path.c_str(),&st) == 0) {
+            FILE *mounts_fp = setmntent("/proc/mounts", "r");
+            if (!mounts_fp) {
+                throw server_error_exception("failed to get mounts 
information");
+            }
+
+            struct mntent* mount;
+            mntent mnt;
+            char strings[4096];
+            while ((mount = getmntent_r(mounts_fp, &mnt, strings, 
sizeof(strings)))) {
+                std::string fstype(mount->mnt_type);
+                if (fstype == "zfs" || fstype == "rofs") {
+                    if (statvfs(mount->mnt_dir,&st) == 0) {
                         fill_dfstat(dfstat, mount, st);
                         res.push_back(dfstat);
                     }
                 }
             }
+            endmntent(mounts_fp);
             return res;
         });
 
diff --git a/modules/httpserver-api/api/hardware.cc 
b/modules/httpserver-api/api/hardware.cc
index f023e394..fe069913 100644
--- a/modules/httpserver-api/api/hardware.cc
+++ b/modules/httpserver-api/api/hardware.cc
@@ -10,9 +10,8 @@
 #include "autogen/hardware.json.hh"
 #include "processor.hh"
 #include "cpuid.hh"
-#include <osv/sched.hh>
-#include <osv/firmware.hh>
-#include <osv/hypervisor.hh>
+#include <osv/osv_c_wrappers.h>
+#include <sys/sysinfo.h>
 
 namespace httpserver {
 
@@ -30,26 +29,36 @@ extern "C" void 
httpserver_plugin_register_routes(httpserver::routes* routes) {
 }
 #endif
 
+static std::string from_c_string(char *c_str) {
+    if (c_str) {
+        std::string str(c_str);
+        free(c_str);
+        return str;
+    } else {
+        return std::string();
+    }
+}
+
 void init(routes& routes)
 {
     hardware_json_init_path("Hardware management API");
 
     processorFeatures.set_handler([](const_req req)
     {
-        return processor::features_str();
+        return from_c_string(osv_processor_features());
     });
 
     processorCount.set_handler([](const_req req)
     {
-        return sched::cpus.size();
+        return get_nprocs();
     });
 
     firmware_vendor.set_handler([](const_req) {
-        return osv::firmware_vendor();
+        return from_c_string(osv_firmware_vendor());
     });
 
     hypervisor_name.set_handler([](const_req) {
-        return osv::hypervisor_name();
+        return from_c_string(osv_hypervisor_name());
     });
 }
 
diff --git a/modules/httpserver-api/api/network.cc 
b/modules/httpserver-api/api/network.cc
index 7d31faf8..595faf4c 100644
--- a/modules/httpserver-api/api/network.cc
+++ b/modules/httpserver-api/api/network.cc
@@ -10,7 +10,7 @@
 #include "../libtools/network_interface.hh"
 #include "exception.hh"
 #include <vector>
-#include <osv/clock.hh>
+#include <time.h>
 
 namespace httpserver {
 
@@ -57,13 +57,16 @@ void init(routes& routes)
     network_json_init_path("Hardware management API");
     network_json::listIfconfig.set_handler([](const_req req) {
         vector<Interface> res;
-        auto time = duration_cast<microseconds>
-                    (osv::clock::uptime::now().time_since_epoch()).count();
+        timespec time;
+        if (clock_gettime(CLOCK_BOOTTIME, &time)) {
+            return res;
+        }
+        auto time_mc = time.tv_sec * 1000000 + time.tv_nsec / 1000;
         for (unsigned int i = 0; i <= number_of_interfaces(); i++) {
             auto* ifp = get_interface_by_index(i);
 
             if (ifp != nullptr) {
-                res.push_back(get_interface(get_interface_name(ifp), ifp, 
time));
+                res.push_back(get_interface(get_interface_name(ifp), ifp, 
time_mc));
             }
         }
         return res;
@@ -76,8 +79,12 @@ void init(routes& routes)
         if (ifp == nullptr) {
             throw not_found_exception(string("Interface ") + name + " not 
found");
         }
-        auto time = 
duration_cast<microseconds>(osv::clock::uptime::now().time_since_epoch()).count();
-        return get_interface(name, ifp, time);
+        timespec time;
+        if (clock_gettime(CLOCK_BOOTTIME, &time)) {
+            throw not_found_exception("Failed to get time");
+        }
+        auto time_mc = time.tv_sec * 1000000 + time.tv_nsec / 1000;
+        return get_interface(name, ifp, time_mc);
     });
 
     network_json::getRoute.set_handler([](const_req req) {
diff --git a/modules/httpserver-api/api/os.cc b/modules/httpserver-api/api/os.cc
index 036f9162..38a662a7 100644
--- a/modules/httpserver-api/api/os.cc
+++ b/modules/httpserver-api/api/os.cc
@@ -6,23 +6,20 @@
  */
 
 #include <sys/utsname.h>
+#include <sys/time.h>
 #include "os.hh"
-#include "osv/version.hh"
 #include "json/formatter.hh"
 #include "autogen/os.json.hh"
 #include <sys/sysinfo.h>
 #include <time.h>
 #include <osv/shutdown.hh>
 #include <osv/power.hh>
-#include <osv/debug.hh>
-#include <osv/sched.hh>
 #include <api/unistd.h>
 #include <osv/commands.hh>
+#include <osv/osv_c_wrappers.h>
 #include <algorithm>
 #include "../java-base/balloon/balloon_api.hh"
 
-extern char debug_buffer[DEBUG_BUFFER_SIZE];
-
 namespace httpserver {
 
 namespace api {
@@ -39,6 +36,16 @@ extern "C" void 
httpserver_plugin_register_routes(httpserver::routes* routes) {
 }
 #endif
 
+static std::string from_c_string(char *c_str) {
+    if (c_str) {
+        std::string str(c_str);
+        free(c_str);
+        return str;
+    } else {
+        return std::string();
+    }
+}
+
 void init(routes& routes)
 {
     os_json_init_path("OS core API");
@@ -48,7 +55,7 @@ void init(routes& routes)
     });
 
     os_version.set_handler([](const_req req) {
-        return osv::version();
+        return from_c_string(osv_version());
     });
 
     os_vendor.set_handler([](const_req req) {
@@ -103,7 +110,7 @@ void init(routes& routes)
 #endif
 
     os_dmesg.set_handler([](const_req req) {
-        return debug_buffer;
+        return osv_debug_buffer();
     });
 
     os_get_hostname.set_handler([](const_req req)
@@ -122,31 +129,39 @@ void init(routes& routes)
 #endif
 
     os_threads.set_handler([](const_req req) {
-        using namespace std::chrono;
         httpserver::json::Threads threads;
-        threads.time_ms = duration_cast<milliseconds>
-            (osv::clock::wall::now().time_since_epoch()).count();
+        timeval timeofday;
+        if (gettimeofday(&timeofday, nullptr)) {
+            return threads;
+        }
+        threads.time_ms = timeofday.tv_sec * 1000 + timeofday.tv_usec / 1000;
         httpserver::json::Thread thread;
-        sched::with_all_threads([&](sched::thread &t) {
-            thread.id = t.id();
-            thread.status = t.get_status();
-            auto tcpu = t.tcpu();
-            thread.cpu = tcpu ? tcpu->id : -1;
-            thread.cpu_ms = 
duration_cast<milliseconds>(t.thread_clock()).count();
-            thread.switches = t.stat_switches.get();
-            thread.migrations = t.stat_migrations.get();
-            thread.preemptions = t.stat_preemptions.get();
-            thread.name = t.name();
-            thread.priority = t.priority();
-            thread.stack_size = t.get_stack_info().size;
-            thread.status = t.get_status();
-            threads.list.push(thread);
-        });
+        osv_thread *osv_threads;
+        size_t threads_num;
+        if (!osv_get_all_threads(&osv_threads, &threads_num)) {
+            for (size_t i = 0; i < threads_num; i++) {
+                auto &t = osv_threads[i];
+                thread.id = t.id;
+                thread.status = t.status;
+                thread.cpu = t.cpu_id;
+                thread.cpu_ms = t.cpu_ms;
+                thread.switches = t.switches;
+                thread.migrations = t.migrations;
+                thread.preemptions = t.preemptions;
+                thread.name = t.name;
+                free(t.name);
+                thread.priority = t.priority;
+                thread.stack_size = t.stack_size;
+                thread.status = t.status;
+                threads.list.push(thread);
+            }
+            free(osv_threads);
+        }
         return threads;
     });
 
     os_get_cmdline.set_handler([](const_req req) {
-        return osv::getcmdline();
+        return from_c_string(osv_cmdline());
     });
 
 #if !defined(MONITORING)
diff --git a/modules/httpserver-api/global_server.cc 
b/modules/httpserver-api/global_server.cc
index 5cf1c62e..649e62cf 100644
--- a/modules/httpserver-api/global_server.cc
+++ b/modules/httpserver-api/global_server.cc
@@ -8,15 +8,14 @@
 #include "global_server.hh"
 #include "path_holder.hh"
 #include <iostream>
-#include <osv/app.hh>
 #include <fstream>
 #include <dlfcn.h>
 #include <boost/filesystem.hpp>
 #include <boost/foreach.hpp>
 #include "json/api_docs.hh"
-#include <osv/debug.h>
 #include "transformers.hh"
 #include <osv/options.hh>
+#include <osv/osv_c_wrappers.h>
 #if !defined(MONITORING)
 #include "yaml-cpp/yaml.h"
 #else
@@ -41,6 +40,13 @@ global_server& global_server::get()
     return *instance;
 }
 
+void global_server::termination_handler() {
+    get().s->close();
+    for( auto plugin : get().plugins) {
+        dlclose(plugin);
+    }
+}
+
 bool global_server::run(std::map<std::string,std::vector<std::string>>& 
_config)
 {
     if (get().s != nullptr) {
@@ -107,12 +113,7 @@ bool 
global_server::run(std::map<std::string,std::vector<std::string>>& _config)
     auto port = get().config["port"][0];
     get().s = new http::server::server(get().config, &get()._routes);
 
-    osv::this_application::on_termination_request([&] {
-        get().s->close();
-        for( auto plugin : get().plugins) {
-            dlclose(plugin);
-        }
-    });
+    osv_current_app_on_termination_request(termination_handler);
 
     std::cout << "Rest API server running on port " << port << std::endl;
     get().s->run();
@@ -121,6 +122,7 @@ bool 
global_server::run(std::map<std::string,std::vector<std::string>>& _config)
 
 #if !defined(MONITORING)
 void global_server::setup_file_mappings(const YAML::Node& file_mappings_node) {
+    auto debug_enabled = osv_debug_enabled();
     for (auto node : file_mappings_node) {
         const YAML::Node path = node["path"];
         if (path && node["directory"]) {
@@ -130,7 +132,9 @@ void global_server::setup_file_mappings(const YAML::Node& 
file_mappings_node) {
                                          new directory_handler(directory, new 
content_replace(content_replace_node.as<std::string>())) :
                                          new directory_handler(directory);
             _routes.add(GET, url(path.as<std::string>()).remainder("path"), 
handler);
-            debug("httpserver: setup directory mapping: [%s] -> [%s]\n", 
path.as<std::string>().c_str(), directory.c_str());
+            if (debug_enabled) {
+                std::cout << "httpserver: setup directory mapping: [" << 
path.as<std::string>() << "] -> [" << directory << "]" << std::endl;
+            }
         }
         else if (path && node["file"]) {
             const std::string file = node["file"].as<std::string>();
@@ -142,7 +146,9 @@ void global_server::setup_file_mappings(const YAML::Node& 
file_mappings_node) {
             else {
                 _routes.add(GET, 
url(path.as<std::string>()).remainder("path"), handler);
             }
-            debug("httpserver: setup file mapping: [%s] -> [%s]\n", 
path.as<std::string>().c_str(), file.c_str());
+            if (debug_enabled) {
+                std::cout << "httpserver: setup file mapping: [" << 
path.as<std::string>() << "] -> [" << file << "]" << std::endl;
+            }
         }
     }
 }
@@ -165,7 +171,9 @@ void global_server::setup_redirects(const YAML::Node& 
redirects_node) {
                                 return "";
                             });
             _routes.put(GET, path, redirect);
-            debug("httpserver: setup redirect: [%s] -> [%s]\n", path.c_str(), 
target_path.c_str());
+            if (osv_debug_enabled()) {
+                std::cout << "httpserver: setup redirect: [" << path << "] -> 
[" << target_path << "]" << std::endl;
+            }
         }
     }
 }
@@ -242,6 +250,8 @@ void global_server::load_plugin(const std::string& path)
     }
     plugins.push_back(plugin);
     httpserver_plugin_register_routes(&_routes);
-    debug("httpserver: loaded plugin from path: %s\n",path.c_str());
+    if (osv_debug_enabled()) {
+        std::cout << "httpserver: loaded plugin from path: " << path << 
std::endl;
+    }
 }
 }
diff --git a/modules/httpserver-api/global_server.hh 
b/modules/httpserver-api/global_server.hh
index e70b7854..587860fb 100644
--- a/modules/httpserver-api/global_server.hh
+++ b/modules/httpserver-api/global_server.hh
@@ -29,6 +29,11 @@ public:
      */
     static global_server& get();
 
+    /**
+     * cleanup routine: shutdown server and close all plugins
+     */
+    static void termination_handler();
+
     /**
      * get the route object
      * @return a reference to the route object
diff --git a/modules/httpserver-api/openssl-init.cc 
b/modules/httpserver-api/openssl-init.cc
index 8630d019..a1bed2bd 100644
--- a/modules/httpserver-api/openssl-init.cc
+++ b/modules/httpserver-api/openssl-init.cc
@@ -8,7 +8,7 @@
 #include <iostream>
 #include <fstream>
 #include <mutex>
-#include <osv/debug.hh>
+#include <osv/osv_c_wrappers.h>
 #include <assert.h>
 
 #include <openssl/rand.h>
@@ -16,9 +16,16 @@
 
 #include "openssl-init.hh"
 
+static void debug_line(const char *line) {
+    auto debug_enabled = osv_debug_enabled();
+    if (debug_enabled) {
+        std::cout << line << std::endl;
+    }
+}
+
 static void seed_openssl()
 {
-    debug("Seeding OpenSSL...\n");
+    debug_line("Seeding OpenSSL...");
 
     for (;;) {
         char buf[32];
@@ -39,10 +46,10 @@ static void seed_openssl()
         // fedora's openssl-1.0.1h-5.fc20 needs 48 bytes instead
         // of 32, which is what is required by its upstream version
         // (tag OpenSSL_1_0_1h). In general, we should make no assumptions.
-        debug("Still not seeded, retrying\n");
+        debug_line("Still not seeded, retrying");
     }
 
-    debug("OpenSSL seeding done.\n");
+    debug_line("OpenSSL seeding done.");
 }
 
 void ensure_openssl_initialized()
diff --git a/modules/httpserver-api/ssl_server.cc 
b/modules/httpserver-api/ssl_server.cc
index a4f8ada2..a064bd6b 100644
--- a/modules/httpserver-api/ssl_server.cc
+++ b/modules/httpserver-api/ssl_server.cc
@@ -5,11 +5,12 @@
  * BSD license as described in the LICENSE file in the top-level directory.
  */
 
-#include <osv/debug.hh>
+#include <osv/osv_c_wrappers.h>
 
 #include "transport.hh"
 #include "ssl_server.hh"
 #include <openssl/ssl.h>
+#include <iostream>
 
 namespace http {
 
@@ -83,8 +84,10 @@ void ssl_acceptor::do_accept(callback_t callback)
                     [this, socket, callback] (boost::system::error_code ec) {
                         if (ec) {
                             auto remote = 
socket->lowest_layer().remote_endpoint();
-                            debug("handshake with " + 
remote.address().to_string()
-                                + " failed: " + ec.message() + "\n");
+                            if (osv_debug_enabled()) {
+                                std::cout << "handshake with " << 
remote.address().to_string()
+                                << " failed: " << ec.message() << std::endl;
+                            }
                         }
 
                         if (!_tcp_acceptor.is_open()) {
diff --git a/modules/httpserver-monitoring-api/Makefile 
b/modules/httpserver-monitoring-api/Makefile
index e26fc06b..8ac415b7 100644
--- a/modules/httpserver-monitoring-api/Makefile
+++ b/modules/httpserver-monitoring-api/Makefile
@@ -45,7 +45,7 @@ all: $(module_out)/lib$(TARGET).so
                $(src)/scripts/manifest_from_host.sh 
$(module_out)/lib$(TARGET).so > usr.manifest; \
        fi
 
-$(module_out)/lib$(TARGET).so: $(JSON_OBJ_FILES) $(OBJ_FILES)
+$(module_out)/lib$(TARGET).so: $(JSON_OBJ_FILES) $(OBJ_FILES) 
$(module_out)/options.o
        $(call quiet, $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(STATIC_LIBS) -o 
$@ $^ $(DYN_LIBS), LINK $@)
 
 ifneq ($(MAKECMDGOALS),clean)
@@ -64,6 +64,10 @@ $(JSON_OBJ_FILES): $(module_out)/autogen/%.o: autogen/%.cc
        $(call very-quiet, mkdir -p $(module_out)/autogen)
        $(call quiet, $(CXX) $(CXXFLAGS) -c -MMD  -o $@ $<, CXX $@)
 
+$(module_out)/options.o: $(src)/core/options.cc
+       $(call very-quiet, mkdir -p $(module_out))
+       $(call quiet, $(CXX) $(CXXFLAGS) -c -MMD -o $@ $<, CXX $@)
+
 clean:
        $(call quiet, $(RM) -f $(TARGET), CLEAN)
        $(call very-quiet, $(RM) -rf $(module_out))
-- 
2.31.1

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/20220117055538.139407-3-jwkozaczuk%40gmail.com.

Reply via email to