diff --git a/package/gluon-core/Makefile b/package/gluon-core/Makefile
index c0600c1f5e3c169b999d598b74024cd2b3b03b2d..1272a929c07a4a4b356e9a3fb60465be519bdd49 100644
--- a/package/gluon-core/Makefile
+++ b/package/gluon-core/Makefile
@@ -14,7 +14,7 @@ define Package/gluon-core
   TITLE:=Base files of Gluon
   DEPENDS:= \
 	+gluon-site +libgluonutil +libiwinfo-lua +lua-platform-info +lua-simple-uci +lua-hash +lua-jsonc \
-	+luci-lib-nixio +vxlan +odhcp6c +firewall +pretty-hostname
+	+luabitop +luaposix +luci-lib-nixio +vxlan +odhcp6c +firewall +pretty-hostname
 endef
 
 define Package/gluon-core/description
diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/001-upgrade b/package/gluon-core/luasrc/lib/gluon/upgrade/001-upgrade
index 5d53398c27b0c8e1e7264442c4b701da80388a5d..f4897d18fe2ba61c2ac9854d4a84cb5416eecc7d 100755
--- a/package/gluon-core/luasrc/lib/gluon/upgrade/001-upgrade
+++ b/package/gluon-core/luasrc/lib/gluon/upgrade/001-upgrade
@@ -1,10 +1,10 @@
 #!/usr/bin/lua
 
-local fs = require 'nixio.fs'
 local sysconfig = require 'gluon.sysconfig'
+local unistd = require 'posix.unistd'
 
 
-if fs.stat('/lib/gluon/version/core') and not sysconfig.gluon_version then
+if unistd.access('/lib/gluon/version/core') and not sysconfig.gluon_version then
   -- This isn't an initial upgrade, so set gluon_version
   sysconfig.gluon_version = ''
 end
diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/005-site-domain b/package/gluon-core/luasrc/lib/gluon/upgrade/005-site-domain
index 04c81292574a2370fd378f40cceb7d1883e8b0df..2014dce63e1167ec1a7abcf2c0fc470fb251afaf 100755
--- a/package/gluon-core/luasrc/lib/gluon/upgrade/005-site-domain
+++ b/package/gluon-core/luasrc/lib/gluon/upgrade/005-site-domain
@@ -1,9 +1,9 @@
 #!/usr/bin/lua
 
-local fs = require 'nixio.fs'
+local unistd = require 'posix.unistd'
 
 
-if not fs.access('/lib/gluon/domains/') then
+if not unistd.access('/lib/gluon/domains/') then
 	return
 end
 
@@ -11,7 +11,7 @@ end
 local uci = require('simple-uci').cursor()
 
 local domain = uci:get('gluon', 'core', 'domain')
-if domain and not fs.access('/lib/gluon/domains/' .. domain .. '.json') then
+if domain and not unistd.access('/lib/gluon/domains/' .. domain .. '.json') then
 	io.stderr:write(string.format("Warning: invalid mesh domain '%s' configured, resetting to default...\n", domain))
 	domain = nil
 end
diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac b/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac
index 2a6a7f222e72f8a5b66ece732c52f3a7bbbedfc2..306a1f4144f15cd7849bf01e44c2be7f2b6303c1 100755
--- a/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac
+++ b/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac
@@ -11,8 +11,6 @@ end
 local util = require 'gluon.util'
 local platform = require 'gluon.platform'
 
-local fs = require 'nixio.fs'
-
 
 local try_files = {
   '/sys/class/net/eth0/address'
@@ -52,7 +50,7 @@ end
 
 
 for _, file in ipairs(try_files) do
-  local addr = fs.readfile(file)
+  local addr = util.readfile(file)
 
   if addr then
     sysconfig.primary_mac = util.trim(addr)
diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/020-interfaces b/package/gluon-core/luasrc/lib/gluon/upgrade/020-interfaces
index 47757699f2aaade4777921d95c5431f46bc17b04..a1600a1aa3ea9d1fc1aec9286aabaf549c032d95 100755
--- a/package/gluon-core/luasrc/lib/gluon/upgrade/020-interfaces
+++ b/package/gluon-core/luasrc/lib/gluon/upgrade/020-interfaces
@@ -12,15 +12,15 @@ local util = require 'gluon.util'
 local platform = require 'gluon.platform'
 local site = require 'gluon.site'
 
-local fs = require 'nixio.fs'
 local uci = require('simple-uci').cursor()
+local unistd = require 'posix.unistd'
 
 
 local function iface_exists(ifaces)
 	if not ifaces then return nil end
 
 	for iface in ifaces:gmatch('%S+') do
-		if fs.access('/sys/class/net/' .. iface:gsub('%..*$', '')) then
+		if unistd.access('/sys/class/net/' .. iface:gsub('%..*$', '')) then
 			return ifaces
 		end
 	end
diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/500-opkg b/package/gluon-core/luasrc/lib/gluon/upgrade/500-opkg
index 83e4d912db0b93e8a73c596eaab51d3bef009c8d..461e0207ccc76b8e1bd003144a0c8e874dcbb8f7 100755
--- a/package/gluon-core/luasrc/lib/gluon/upgrade/500-opkg
+++ b/package/gluon-core/luasrc/lib/gluon/upgrade/500-opkg
@@ -1,8 +1,8 @@
 #!/usr/bin/lua
 
-local fs = require 'nixio.fs'
+local unistd = require 'posix.unistd'
 
-if not fs.access('/etc/opkg/distfeeds.conf') then
+if not unistd.access('/etc/opkg/distfeeds.conf') then
 	os.exit(0)
 end
 
@@ -22,8 +22,8 @@ subst['%%A'] = f:read()
 f:close()
 
 subst['%%GS'] = site.site_code()
-subst['%%GV'] = util.trim(fs.readfile('/lib/gluon/gluon-version'))
-subst['%%GR'] = util.trim(fs.readfile('/lib/gluon/release'))
+subst['%%GV'] = util.trim(util.readfile('/lib/gluon/gluon-version'))
+subst['%%GR'] = util.trim(util.readfile('/lib/gluon/release'))
 
 local prefix = subst['%%d'] .. '_'
 
diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/999-version b/package/gluon-core/luasrc/lib/gluon/upgrade/999-version
index 608545b74c731eefe6d5f26ef30a1962f6209ed0..c60a07d2b10bbe3c60023a53a5571ef998720874 100755
--- a/package/gluon-core/luasrc/lib/gluon/upgrade/999-version
+++ b/package/gluon-core/luasrc/lib/gluon/upgrade/999-version
@@ -2,10 +2,9 @@
 
 local sysconfig = require 'gluon.sysconfig'
 
-local fs = require 'nixio.fs'
 local util = require 'gluon.util'
 
 
 -- Save the Gluon version in the sysconfig so we know which version we
 -- upgraded from after the next upgrade
-sysconfig.gluon_version = util.trim(fs.readfile('/lib/gluon/gluon-version'))
+sysconfig.gluon_version = util.trim(util.readfile('/lib/gluon/gluon-version'))
diff --git a/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua b/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua
index 1bb2fa1cabfcc8b9f32d90357bbf59808b1ad698..e8b7550be6df02329c3c492c0f0a5eea89a1600e 100644
--- a/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua
+++ b/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua
@@ -22,11 +22,11 @@ local ipairs = ipairs
 local pairs = pairs
 local table = table
 
-local nixio = require 'nixio'
+local bit = require 'bit'
+local posix_glob = require 'posix.glob'
 local hash = require 'hash'
 local sysconfig = require 'gluon.sysconfig'
 local site = require 'gluon.site'
-local fs = require 'nixio.fs'
 
 
 module 'gluon.util'
@@ -77,14 +77,24 @@ function replace_prefix(file, prefix, add)
 	os.rename(tmp, file)
 end
 
-function exec(command)
-	local pp   = io.popen(command)
-	local data = pp:read("*a")
-	pp:close()
+local function readall(f)
+	if not f then
+		return nil
+	end
 
+	local data = f:read('*a')
+	f:close()
 	return data
 end
 
+function readfile(file)
+	return readall(io.open(file))
+end
+
+function exec(command)
+	return readall(io.popen(command))
+end
+
 function node_id()
 	return string.gsub(sysconfig.primary_mac, ':', '')
 end
@@ -120,20 +130,25 @@ function get_mesh_devices(uconn)
 	return devices
 end
 
+-- Safe glob: returns an empty table when the glob fails because of
+-- a non-existing path
+function glob(pattern)
+	return posix_glob.glob(pattern) or {}
+end
+
 local function find_phy_by_path(path)
-	for phy in fs.glob('/sys/devices/' .. path .. '/ieee80211/phy*') do
-		return phy:match('([^/]+)$')
-	end
+	local phy = glob('/sys/devices/' .. path .. '/ieee80211/phy*')[1]
+		or glob('/sys/devices/platform/' .. path .. '/ieee80211/phy*')[1]
 
-	for phy in fs.glob('/sys/devices/platform/' .. path .. '/ieee80211/phy*') do
+	if phy then
 		return phy:match('([^/]+)$')
 	end
 end
 
 local function find_phy_by_macaddr(macaddr)
 	local addr = macaddr:lower()
-	for file in fs.glob('/sys/class/ieee80211/*/macaddress') do
-		if trim(fs.readfile(file)) == addr then
+	for _, file in ipairs(glob('/sys/class/ieee80211/*/macaddress')) do
+		if trim(readfile(file)) == addr then
 			return file:match('([^/]+)/macaddress$')
 		end
 	end
@@ -181,14 +196,14 @@ function generate_mac(i)
 	m1 = tonumber(m1, 16)
 	m6 = tonumber(m6, 16)
 
-	m1 = nixio.bit.bor(m1, 0x02)  -- set locally administered bit
-	m1 = nixio.bit.band(m1, 0xFE) -- unset the multicast bit
+	m1 = bit.bor(m1, 0x02)  -- set locally administered bit
+	m1 = bit.band(m1, 0xFE) -- unset the multicast bit
 
 	-- It's necessary that the first 45 bits of the MAC address don't
 	-- vary on a single hardware interface, since some chips are using
 	-- a hardware MAC filter. (e.g 'rt305x')
 
-	m6 = nixio.bit.band(m6, 0xF8) -- zero the last three bits (space needed for counting)
+	m6 = bit.band(m6, 0xF8) -- zero the last three bits (space needed for counting)
 	m6 = m6 + i                   -- add virtual interface id
 
 	return string.format('%02x:%s:%s:%s:%s:%02x', m1, m2, m3, m4, m5, m6)