tools/pci: replace pciutils with pciaccess

The pciutils library has a license which is incompatible with ours, so
switch to pciaccess instead since it's MIT-licensed.

Signed-off-by: Benjamin Fair <benjaminfair@google.com>
Change-Id: Ie40580d9992f7c30d9fdc904f97c89057791b10e
diff --git a/README.md b/README.md
index ea03fc0..7774718 100644
--- a/README.md
+++ b/README.md
@@ -14,15 +14,25 @@
 
 The host-tool depends on ipmi-blob-tool and pciutils.
 
-#### Building pciutils
+#### Building libpciaccess
 
-Check out the [pciutils source](https://github.com/pciutils/pciutils).
+Check out the [xorg-macros source](https://gitlab.freedesktop.org/xorg/util/macros).
 
 Then run these commands in the source directory.
+
 ```
-make SHARED=yes
-make SHARED=yes install
-make install-lib
+./autogen.sh --prefix=/usr
+make install
+```
+
+Check out the [libpciaccess source](https://gitlab.freedesktop.org/xorg/lib/libpciaccess).
+
+Then run these commands in the source directory.
+
+```
+./autogen.sh
+make
+make install
 ```
 
 #### Building ipmi-blob-tool
diff --git a/configure.ac b/configure.ac
index 41dd7f2..94ed8b7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -123,10 +123,10 @@
 # If not building the host-tool, we're building the BMC.
 AS_IF([test "x$enable_build_host_tool" != "xno"], [
     PKG_CHECK_MODULES(
-        [PCILIB],
-        [libpci],
+        [PCIACCESS],
+        [pciaccess >= 0.8.0],
         [],
-        [AC_MSG_ERROR([Could not find libpci... pciutils package required])]
+        [AC_MSG_ERROR([Could not find libpciaccess... pciaccess package required])]
     )
 ])
 
diff --git a/internal/sys.hpp b/internal/sys.hpp
index a399903..7c56818 100644
--- a/internal/sys.hpp
+++ b/internal/sys.hpp
@@ -16,6 +16,7 @@
 #include <cinttypes>
 #include <cstddef>
 #include <cstdint>
+#include <system_error>
 
 namespace internal
 {
@@ -88,6 +89,11 @@
     std::int64_t getSize(const char* pathname) const override;
 };
 
+inline std::system_error errnoException(const std::string& message)
+{
+    return std::system_error(errno, std::generic_category(), message);
+}
+
 /** @brief Default instantiation of sys */
 extern SysImpl sys_impl;
 
diff --git a/tools/Makefile.am b/tools/Makefile.am
index bb2a317..e0a192e 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -7,12 +7,12 @@
 	$(CODE_COVERAGE_CXXFLAGS)
 
 noinst_LTLIBRARIES = libupdater.la
-libupdater_la_LDFLAGS = -static $(CODE_COVERAGE_LIBS) $(IPMIBLOB_LIBS) $(PCILIB_LIBS)
+libupdater_la_LDFLAGS = -static $(CODE_COVERAGE_LIBS) $(IPMIBLOB_LIBS) $(PCIACCESS_LIBS)
 libupdater_la_CXXFLAGS = \
 	-I$(top_srcdir) \
 	$(CODE_COVERAGE_CXXFLAGS) \
 	$(IPMIBLOB_CFLAGS) \
-	$(PCILIB_CFLAGS)
+	$(PCIACCESS_CFLAGS)
 libupdater_la_SOURCES = \
 	updater.cpp \
 	handler.cpp \
diff --git a/tools/main.cpp b/tools/main.cpp
index 0e29295..dd43c11 100644
--- a/tools/main.cpp
+++ b/tools/main.cpp
@@ -217,7 +217,6 @@
 #else
         host_tool::DevMemDevice devmem;
 #endif
-        host_tool::PciUtilImpl pci;
         host_tool::ProgressStdoutIndicator progress;
 
         std::unique_ptr<host_tool::DataInterface> handler;
@@ -250,6 +249,7 @@
         }
         else if (interface == IPMIPCI)
         {
+            auto& pci = host_tool::PciUtilImpl::getInstance();
             handler = std::make_unique<host_tool::P2aDataHandler>(
                 &blob, &devmem, &pci, &progress);
         }
diff --git a/tools/pci.cpp b/tools/pci.cpp
index feb5c60..7fa4d59 100644
--- a/tools/pci.cpp
+++ b/tools/pci.cpp
@@ -18,9 +18,11 @@
 
 extern "C"
 {
-#include <pci/pci.h>
+#include <pciaccess.h>
 } // extern "C"
 
+#include <linux/pci_regs.h>
+
 #include <cstring>
 #include <optional>
 #include <vector>
@@ -31,45 +33,40 @@
 std::vector<PciDevice>
     PciUtilImpl::getPciDevices(std::optional<PciFilter> filter)
 {
-    PciFilter test;
-    bool check = false;
+    struct pci_id_match match = {PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY,
+                                 PCI_MATCH_ANY};
     std::vector<PciDevice> results;
 
     if (filter.has_value())
     {
-        test = filter.value();
-        check = true;
+        match.vendor_id = filter.value().vid;
+        match.device_id = filter.value().did;
     }
 
-    pci_scan_bus(pacc);
-    struct pci_dev* dev;
+    auto it = pci_id_match_iterator_create(&match);
+    struct pci_device* dev;
 
-    for (dev = pacc->devices; dev; dev = dev->next)
+    while ((dev = pci_device_next(it)))
     {
         PciDevice item;
 
-        pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS);
+        pci_device_probe(dev);
 
         item.bus = dev->bus;
         item.dev = dev->dev;
         item.func = dev->func;
         item.vid = dev->vendor_id;
         item.did = dev->device_id;
-        std::memcpy(item.bars, dev->base_addr, sizeof(dev->base_addr));
 
-        if (check)
+        for (int i = 0; i < PCI_STD_NUM_BARS; i++)
         {
-            if (test.vid == dev->vendor_id && test.did == dev->device_id)
-            {
-                results.push_back(item);
-            }
+            item.bars[i] = dev->regions[i].base_addr;
         }
-        else
-        {
-            results.push_back(item);
-        }
+
+        results.push_back(item);
     }
 
+    pci_iterator_destroy(it);
     return results;
 }
 
diff --git a/tools/pci.hpp b/tools/pci.hpp
index 0edc531..f421892 100644
--- a/tools/pci.hpp
+++ b/tools/pci.hpp
@@ -1,14 +1,23 @@
 #pragma once
 
+#include "internal/sys.hpp"
+
 extern "C"
 {
-#include <pci/pci.h>
+#include <pciaccess.h>
 } // extern "C"
 
+#include <linux/pci_regs.h>
+
 #include <cstdint>
+#include <memory>
 #include <optional>
 #include <vector>
 
+#ifndef PCI_STD_NUM_BARS
+#define PCI_STD_NUM_BARS 6
+#endif // !PCI_STD_NUM_BARS
+
 namespace host_tool
 {
 
@@ -25,7 +34,7 @@
     std::uint8_t bus;
     std::uint8_t dev;
     std::uint8_t func;
-    pciaddr_t bars[6];
+    pciaddr_t bars[PCI_STD_NUM_BARS];
 };
 
 /**
@@ -56,21 +65,32 @@
 class PciUtilImpl : public PciUtilInterface
 {
   public:
-    PciUtilImpl()
+    static PciUtilImpl& getInstance()
     {
-        pacc = pci_alloc();
-        pci_init(pacc);
-    }
-    ~PciUtilImpl()
-    {
-        pci_cleanup(pacc);
+        static PciUtilImpl instance;
+        return instance;
     }
 
     std::vector<PciDevice>
         getPciDevices(std::optional<PciFilter> filter = std::nullopt) override;
 
+    PciUtilImpl(const PciUtilImpl&) = delete;
+    PciUtilImpl& operator=(const PciUtilImpl&) = delete;
+
   private:
-    struct pci_access* pacc;
+    PciUtilImpl()
+    {
+        int ret = pci_system_init();
+        if (ret)
+        {
+            throw internal::errnoException("pci_system_init");
+        }
+    }
+
+    ~PciUtilImpl()
+    {
+        pci_system_cleanup();
+    }
 };
 
 } // namespace host_tool