aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--Report-web_3.html8
-rw-r--r--Report-web_TABLE.html2
-rw-r--r--apt-panopticommon.lua75
-rwxr-xr-xapt-panopticon-report-email-web.lua88
-rwxr-xr-xapt-panopticon.lua142
-rwxr-xr-xlaggers3
-rwxr-xr-xupdate_apt-panopticon63
8 files changed, 272 insertions, 110 deletions
diff --git a/README.md b/README.md
index 2edc3ca..7e5d6d2 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,7 @@ installed -
55* lua-rrd 55* lua-rrd
56* LuaSocket, on Debian based systems it'll be in the lua-socket package. 56* LuaSocket, on Debian based systems it'll be in the lua-socket package.
57* md5sum and sha256, on Debian based systems they'll be in the coreutils package. 57* md5sum and sha256, on Debian based systems they'll be in the coreutils package.
58* timeout, on Debian based systems it'll be in the coreutils package.
58* rrdtool 59* rrdtool
59* xz, on Debian based systems it'll be in the xz-utils package. 60* xz, on Debian based systems it'll be in the xz-utils package.
60 61
diff --git a/Report-web_3.html b/Report-web_3.html
index 632e6f4..a1ca70d 100644
--- a/Report-web_3.html
+++ b/Report-web_3.html
@@ -7,7 +7,13 @@
7 <p><font color='aqua'><b>TIMEOUT</b></font> or <font color='blue'><b>TIMEOUT</b></font> means the mirror had too many timeouts, and tests where aborted, so there is no result for this test.</p> 7 <p><font color='aqua'><b>TIMEOUT</b></font> or <font color='blue'><b>TIMEOUT</b></font> means the mirror had too many timeouts, and tests where aborted, so there is no result for this test.</p>
8 <p>NOTE: timeouts may be due to a problem on the testing computer, it might be busy with other things, or be having it's own network problems.</p> 8 <p>NOTE: timeouts may be due to a problem on the testing computer, it might be busy with other things, or be having it's own network problems.</p>
9 <p>NOTE: the speed of the server this checking script is running on might be wildly exaggerated, it doesn't have to go through the Internet to download from itself.</p> 9 <p>NOTE: the speed of the server this checking script is running on might be wildly exaggerated, it doesn't have to go through the Internet to download from itself.</p>
10 <p>The DNS round robin (DNS-RR) column shows the IPs for that mirror, or <font color='grey'><b>no</b></font> if it isn't part of the DNS-RR. &nbsp; The IPs link to the testing log for that IP accessed via the DNS-RR. &nbsp; deb.devuan.org is the DNS-RR itself, so it doesn't get tested directly.</p> 10 <p>The DNS round robin (DNS-RR) column shows the IPs for that mirror, or <font color='grey'><b>no</b></font> if it isn't part of the DNS-RR.</p>
11 <p> &nbsp; The IPs link to the testing log for that IP accessed via the DNS-RR.</p>
12 <p> &nbsp; If a mirror <a href='DNS-RR_good.txt'>should be</a> it is marked with '<font color='green'><b>&#x2705;</b></font>',
13 if it <a href='DNS-RR_bad.txt'>should not be</a> it is marked with '<font color='red'>&#x274c;</font>',
14 if it might be but still pending full testing, it is marked with '<font color='red'>&#x2753;</font>'.</p>
15 <p> &nbsp; deb.devuan.org is the DNS-RR itself, so it doesn't get tested directly.
16 </p>
11 <p>The time in the Updated column is how often the mirror updates itself.</p> 17 <p>The time in the Updated column is how often the mirror updates itself.</p>
12 <p>Mirrors with a <font style='background-color:dimgrey'>grey background</font> are not active (though may be usable as part of the DNS-RR).</p> 18 <p>Mirrors with a <font style='background-color:dimgrey'>grey background</font> are not active (though may be usable as part of the DNS-RR).</p>
13 <p><font color='grey'><b>skip</b></font> means that the test hasn't been written yet.</p> 19 <p><font color='grey'><b>skip</b></font> means that the test hasn't been written yet.</p>
diff --git a/Report-web_TABLE.html b/Report-web_TABLE.html
index 6ee14f4..b267094 100644
--- a/Report-web_TABLE.html
+++ b/Report-web_TABLE.html
@@ -1,4 +1,4 @@
1 <table> 1 <table id=results>
2 <tr> 2 <tr>
3 <th></th> 3 <th></th>
4 <th class="TTitem"> 4 <th class="TTitem">
diff --git a/apt-panopticommon.lua b/apt-panopticommon.lua
index 0862b77..e31c22f 100644
--- a/apt-panopticommon.lua
+++ b/apt-panopticommon.lua
@@ -3,14 +3,18 @@ local APT = {}
3-- https://oss.oetiker.ch/rrdtool/prog/rrdlua.en.html 3-- https://oss.oetiker.ch/rrdtool/prog/rrdlua.en.html
4APT.rrd = require 'rrd' 4APT.rrd = require 'rrd'
5 5
6APT.version = '0.3 alpha'
7
6APT.protocols = {"ftp", "http", "https", "rsync"} 8APT.protocols = {"ftp", "http", "https", "rsync"}
7APT.tests = {'raw', 'Integrity', 'Protocol', 'Redirects', 'Updated', 'URLSanity', 'Speed'} 9APT.tests = {'raw', 'Integrity', 'Protocol', 'Redirects', 'Updated', 'URLSanity', 'Speed'}
8APT.releases = {"ascii", "beowulf", "chimaera", "ceres"} 10--APT.releases = {"jessie", "ascii", "beowulf", "chimaera", "daedalus", "ceres"}
11APT.releases = {"beowulf","chimaera", "daedalus", "excalibur", "ceres"}
9APT.subRels = {'backports', 'proposed-updates', 'security', 'updates'} 12APT.subRels = {'backports', 'proposed-updates', 'security', 'updates'}
10APT.notExist = 13APT.notExist =
11{ 14{
12 'chimaera-backports', 15 'excalibur-backports',
13 'chimaera-security', 16 'excalibur-security',
17 'excalibur-updates',
14 'ceres-backports', -- These will never exist, it's our code name for the testing suite. 18 'ceres-backports', -- These will never exist, it's our code name for the testing suite.
15 'ceres-proposed-updates', 19 'ceres-proposed-updates',
16 'ceres-updates', 20 'ceres-updates',
@@ -50,6 +54,12 @@ APT.options =
50 help = "The round robin DNS name.", 54 help = "The round robin DNS name.",
51 value = "deb.devuan.org", 55 value = "deb.devuan.org",
52 }, 56 },
57 roundRobinCname =
58 {
59 typ = "string",
60 help = "The round robin DNS name.",
61 value = "deb.rr.devuan.org",
62 },
53 tests = 63 tests =
54 { 64 {
55 typ = "table", 65 typ = "table",
@@ -125,7 +135,7 @@ APT.parseArgs = function(args)
125 local arg = {} 135 local arg = {}
126 local sendArgs = "" 136 local sendArgs = ""
127 -- A special test to disable IPv6 tests if IPv6 isn't available. 137 -- A special test to disable IPv6 tests if IPv6 isn't available.
128 if 1 == APT.exe('ip -6 addr | grep inet6 | grep " global"'):Do().status then 138 if 1 == APT.exe('ip -6 addr | grep inet6 | grep " global"'):timeout():Do().status then
129 table.insert(args, '--tests=-IPv6') 139 table.insert(args, '--tests=-IPv6')
130 end 140 end
131 if 0 ~= #(args) then 141 if 0 ~= #(args) then
@@ -139,7 +149,7 @@ APT.parseArgs = function(args)
139 end 149 end
140 os.exit() 150 os.exit()
141 elseif "--version" == a then 151 elseif "--version" == a then
142 print("apt-panopticon version 0.2 alpha") 152 print("apt-panopticon version " .. APT.version)
143 os.exit() 153 os.exit()
144 elseif "-v" == a then 154 elseif "-v" == a then
145 APT.verbosity = APT.verbosity + 1 155 APT.verbosity = APT.verbosity + 1
@@ -398,7 +408,7 @@ APT.logOpen = function(host, a2, a3)
398 local name = APT.logName(host, a2, a3)[1] 408 local name = APT.logName(host, a2, a3)[1]
399 if APT.checkFile(name) then return false end 409 if APT.checkFile(name) then return false end
400 APT.logFile, e = io.open(name, "a+") 410 APT.logFile, e = io.open(name, "a+")
401 if nil == APT.logFile then C('opening log file (' .. name .. ') - ' .. e); return false end 411 if nil == APT.logFile then print('CRITICAL - opening log file (' .. name .. ') - ' .. e); return false end
402 if nil ~= APT.logFile then 412 if nil ~= APT.logFile then
403 APT.logFile:write("<html><head>\n") 413 APT.logFile:write("<html><head>\n")
404 APT.logFile:write("</head><body bgcolor='black' text='white' alink='red' link='aqua' vlink='fuchsia'>\n") 414 APT.logFile:write("</head><body bgcolor='black' text='white' alink='red' link='aqua' vlink='fuchsia'>\n")
@@ -415,6 +425,7 @@ APT.logPost = function()
415 if nil ~= APT.logFile then 425 if nil ~= APT.logFile then
416 APT.logFile:write("</body></html> \n") 426 APT.logFile:write("</body></html> \n")
417 APT.logFile:close() 427 APT.logFile:close()
428 APT.logFile = nil
418 end 429 end
419end 430end
420 431
@@ -455,7 +466,7 @@ local log = function(v, t, s, prot, test, host)
455 if nil ~= APT.logFile then 466 if nil ~= APT.logFile then
456 if APT.html then 467 if APT.html then
457 local colour = "white" 468 local colour = "white"
458 if -1 == v then colour = "fuchsia" end -- CRITICAL 469 if -1 == v then colour = "fuchsia"; print(t .. " " .. s) end -- CRITICAL
459 if 0 == v then colour = "red " end -- ERROR 470 if 0 == v then colour = "red " end -- ERROR
460 if 1 == v then colour = "yellow " end -- WARNING 471 if 1 == v then colour = "yellow " end -- WARNING
461 if 2 == v then colour = "blue " end -- TIMEOUT 472 if 2 == v then colour = "blue " end -- TIMEOUT
@@ -482,6 +493,17 @@ local E = APT.E
482local C = APT.C 493local C = APT.C
483 494
484 495
496APT.readCmd = function(cmd)
497 local result = {}
498 local output = io.popen(cmd)
499 if nil ~= output then
500 for l in output:lines() do
501 table.insert(result, l)
502 end
503 end
504 return result
505end
506
485APT.debians = {} 507APT.debians = {}
486APT.mirrors = {} 508APT.mirrors = {}
487 509
@@ -508,7 +530,7 @@ APT.tested = function(prot, test, host)
508end 530end
509 531
510APT.exe = function(c) 532APT.exe = function(c)
511 local exe = {status = 0, result = '', log = true, cmd = c .. ' '} 533 local exe = {status = 0, result = '', log = true, cmd = c .. ' ', command = c}
512 534
513 function exe:log() 535 function exe:log()
514 self.log = true 536 self.log = true
@@ -522,6 +544,16 @@ APT.exe = function(c)
522 end 544 end
523 return self 545 return self
524 end 546 end
547 function exe:timeout(c)
548 -- timeout returns a status of - command status if --preserve-status; "128+9" (actually 137) if --kill-after ends up being done; 124 if it had to TERM; command status if all went well.
549 -- --kill-after means "send KILL after TERM fails.
550 if nil == c then
551 self.cmd = 'timeout --kill-after=10.0 --foreground 42.0s ' .. self.cmd
552 else
553 self.cmd = 'timeout --kill-after=10.0 --foreground ' .. c .. ' ' .. self.cmd
554 end
555 return self
556 end
525 function exe:also(c) 557 function exe:also(c)
526 if nil == c then c = '' else c = ' ' .. c end 558 if nil == c then c = '' else c = ' ' .. c end
527 self.cmd = self.cmd .. ';' .. c .. ' ' 559 self.cmd = self.cmd .. ';' .. c .. ' '
@@ -558,17 +590,28 @@ APT.exe = function(c)
558 I'm getting 7168 or 0. No idea what the fuck that is. 590 I'm getting 7168 or 0. No idea what the fuck that is.
559 local ok, rslt, status = os.execute(s) 591 local ok, rslt, status = os.execute(s)
560 ]] 592 ]]
561 local f = io.popen(self.cmd .. ' ; echo "$?"', 'r') 593 local f = APT.readCmd(self.cmd, 'r')
562 -- The last line will be the command's returned status, collect everything else in result. 594 -- The last line will be the command's returned status, collect everything else in result.
563 self.status = '' -- Otherwise the result starts with 0. 595 self.status = '' -- Otherwise the result starts with 0.
564 for l in f:lines() do 596 self.result = '\n'
565 self.result = self.result .. self.status .. "\n" 597 for i,l in ipairs(f) do
566 self.status = l 598 self.result = self.result .. l .. "\n"
599 end
600 f = APT.readCmd('echo "$?"', 'r')
601 for i,l in ipairs(f) do
602 self.status = tonumber(l)
603 if (137 == self.status) or (124 == self.status) then
604 print("timeout killed " .. self.status .. ' ' .. self.command)
605 E("timeout killed " .. self.status .. ' ' .. self.command)
606 elseif (0 ~= self.status) then
607 print("status |" .. self.status .. '| ' .. self.command)
608 E("status |" .. self.status .. '| ' .. self.command)
609 end
567 end 610 end
568 self.status = tonumber(self.status)
569 return self 611 return self
570 end 612 end
571 function exe:fork() 613 function exe:fork(host)
614 if nil ~= host then self.cmd = self.cmd .. '; r=$?; if [ $r -ge 124 ]; then echo "$r ' .. host .. ' failed forked command ' .. string.gsub(self.cmd, '"', "'") .. '"; fi' end
572 self.cmd = '{ ' .. self.cmd .. '; } &' 615 self.cmd = '{ ' .. self.cmd .. '; } &'
573 if true == self.log then D(" forking - &nbsp; <code>" .. self.cmd .. "</code>") end 616 if true == self.log then D(" forking - &nbsp; <code>" .. self.cmd .. "</code>") end
574 os.execute(self.cmd) 617 os.execute(self.cmd)
@@ -578,7 +621,9 @@ APT.exe = function(c)
578end 621end
579 622
580APT.checkExes = function (exe) 623APT.checkExes = function (exe)
581 local count = io.popen('ps x | grep "' .. exe .. '" | grep -v " grep " | grep -v "flock -n apt-panopticon.lock " | wc -l'):read("*l") 624 local count = 0
625 local ps = io.popen('ps x | grep "' .. exe .. '" | grep -v " grep " | grep -v "flock -n apt-panopticon.lock " | wc -l')
626 if nil ~= ps then count = ps:read("*l") end
582 D(count .. " " .. exe .. " commands still running.") 627 D(count .. " " .. exe .. " commands still running.")
583 return tonumber(count) 628 return tonumber(count)
584end 629end
diff --git a/apt-panopticon-report-email-web.lua b/apt-panopticon-report-email-web.lua
index b21ba8a..2a13975 100755
--- a/apt-panopticon-report-email-web.lua
+++ b/apt-panopticon-report-email-web.lua
@@ -18,11 +18,13 @@ APT.debians = loadfile("results/debians.lua")()
18local revDNS = function(hosts, dom, IP) 18local revDNS = function(hosts, dom, IP)
19 if APT.options.roundRobin.value ~= dom then 19 if APT.options.roundRobin.value ~= dom then
20 if nil ~= hosts[APT.options.roundRobin.value] then 20 if nil ~= hosts[APT.options.roundRobin.value] then
21 if nil ~= hosts[APT.options.roundRobin.value].IPs["deb.roundr.devuan.org"][IP] then 21 if nil ~= hosts[APT.options.roundRobin.value].IPs[APT.options.roundRobinCname.value] then
22 if APT.html then 22 if nil ~= hosts[APT.options.roundRobin.value].IPs[APT.options.roundRobinCname.value][IP] then
23 return "<font color='purple'><b>DNS-RR</b></font>" 23 if APT.html then
24 else 24 return "<font color='purple'><b>DNS-RR</b></font>"
25 return "DNS-RR" 25 else
26 return "DNS-RR"
27 end
26 end 28 end
27 end 29 end
28 end 30 end
@@ -87,6 +89,7 @@ local status = function(hosts, host, results, typ)
87 89
88 if to then 90 if to then
89 result = "TIMEOUT" 91 result = "TIMEOUT"
92 hosts[host].passed = false;
90 if not s then result = result .. "*" end 93 if not s then result = result .. "*" end
91 if APT.html then 94 if APT.html then
92 if s then 95 if s then
@@ -102,6 +105,7 @@ local status = function(hosts, host, results, typ)
102 end 105 end
103 elseif 0 < e then 106 elseif 0 < e then
104 result = "FAILED" 107 result = "FAILED"
108 hosts[host].passed = false;
105 if not s then result = result .. "*" end 109 if not s then result = result .. "*" end
106 if APT.html then 110 if APT.html then
107 if s then 111 if s then
@@ -198,24 +202,28 @@ local DNSrrTest = function(hosts, k)
198 space = ' &nbsp; ' 202 space = ' &nbsp; '
199 no = "<font color='grey'><b>no</b></font>" 203 no = "<font color='grey'><b>no</b></font>"
200 end 204 end
201 if (APT.options.roundRobin.value ~= k) and (nil ~= hosts[APT.options.roundRobin.value]) and (nil ~= hosts[k].IPs) then 205 if (APT.options.roundRobin.value ~= k) and (nil ~= hosts[APT.options.roundRobin.value]) and (nil ~= hosts[k].IPs) and ("no" ~= hosts[k].DNSRR) then
202 APT.allpairs(hosts[k].IPs, 206 APT.allpairs(hosts[k].IPs,
203 function(i, w, k, v) 207 function(i, w, k, v)
204 if nil ~= hosts[APT.options.roundRobin.value].IPs["deb.roundr.devuan.org"][i] then 208-- if nil ~= hosts[APT.options.roundRobin.value].IPs[APT.options.roundRobinCname.value] then
205 local log = logCount(APT.options.roundRobin.value, i) 209-- if nil ~= hosts[APT.options.roundRobin.value].IPs[APT.options.roundRobinCname.value][i] then
206 if "" ~= log then 210 local log = logCount(APT.options.roundRobin.value, i)
207 if "" == dns then dns = " " else dns = dns .. space end 211 local inRR = "<font color='green'><b>&#x2705;</b></font>"
208 dns = dns .. logCount(APT.options.roundRobin.value, i) 212 if nil ~= log:find("<font color='") then inRR = "<font color='red'>&#x274c;</font>" end
209 else 213 if "" ~= log then
210 if "" == dns then dns = " " else dns = dns .. space end 214 if "" == dns then dns = " " else dns = dns .. space end
211 if APT.html then i = "<font color='maroon'><b>" .. i .. "</b></font>" end 215 dns = dns .. inRR .. logCount(APT.options.roundRobin.value, i)
212 dns = dns .. i 216 else
213 end 217 if "" == dns then dns = " " else dns = dns .. space end
214 end 218 if APT.html then i = "<font color='maroon'><b>" .. i .. "</b></font>" end
219 dns = dns .. inRR .. i
220 end
221-- end
222-- end
215 end 223 end
216 ) 224 )
217 if "" == dns then dns = no end
218 end 225 end
226 if "" == dns then dns = no end
219 return dns 227 return dns
220end 228end
221 229
@@ -242,6 +250,7 @@ local makeTable = function(web, hosts)
242 if nil == v.Active then active = 'nil' else active = v.Active end 250 if nil == v.Active then active = 'nil' else active = v.Active end
243 web:write(" <tr style='background-color:dimgrey'><th>" .. k .. "</th> ") 251 web:write(" <tr style='background-color:dimgrey'><th>" .. k .. "</th> ")
244 end 252 end
253 hosts[k].passed = true;
245 local inRR = "<font color='green'><b>&#x2705;</b></font>" 254 local inRR = "<font color='green'><b>&#x2705;</b></font>"
246 local ftp = "<font color='grey'><b>skip</b></font>" 255 local ftp = "<font color='grey'><b>skip</b></font>"
247 local http = status(hosts, k, results, "http") 256 local http = status(hosts, k, results, "http")
@@ -260,14 +269,7 @@ local makeTable = function(web, hosts)
260 local week = '<td>&nbsp;</td><td>&nbsp;</td>' 269 local week = '<td>&nbsp;</td><td>&nbsp;</td>'
261 if nil == rate then rate = '' end 270 if nil == rate then rate = '' end
262 271
263 -- DNS-RR test. 272 if not hosts[k].passed then inRR = "<font color='red'>&#x274c;</font>" end
264-- if nil == http: find('OK') then inRR = "<font color='red'>&#x274c;</font>" end
265-- if nil == https: find('OK') then inRR = "<font color='red'>&#x274c;</font>" end
266-- if nil == protocol: find('OK') then inRR = "<font color='red'>&#x274c;</font>" end
267-- if nil == redirects: find('OK') then inRR = "<font color='red'>&#x274c;</font>" end
268-- if nil == sanity: find('OK') then inRR = "<font color='red'>&#x274c;</font>" end
269-- if nil == integrity: find('OK') then inRR = "<font color='red'>&#x274c;</font>" end
270-- if nil == updated: find('OK') then inRR = "<font color='red'>&#x274c;</font>" end
271 273
272 if (APT.options.roundRobin.value ~= k) and (nil ~= hosts[APT.options.roundRobin.value]) then 274 if (APT.options.roundRobin.value ~= k) and (nil ~= hosts[APT.options.roundRobin.value]) then
273 if 0 == max then 275 if 0 == max then
@@ -319,8 +321,10 @@ local makeTable = function(web, hosts)
319 week = '<td>&nbsp;' .. percentUp .. '% up</td><td>&nbsp;' .. percentUpdated .. '% updated</td>' 321 week = '<td>&nbsp;' .. percentUp .. '% up</td><td>&nbsp;' .. percentUpdated .. '% updated</td>'
320-- if ('100.00' ~= percentUp) or ('100.00' ~= percentUpdated) then inRR = "<font color='red'>&#x274c;</font>" end 322-- if ('100.00' ~= percentUp) or ('100.00' ~= percentUpdated) then inRR = "<font color='red'>&#x274c;</font>" end
321 end 323 end
324 if "yes" ~= hosts[k].DNSRR then inRR = " &nbsp; &nbsp; " end
325 if "maybe" == hosts[k].DNSRR then inRR = "<font color='red'>&#x2753;</font>" end
322 326
323 web:write("<td>" .. ftp .. "&nbsp;</td><td>" .. http .. "&nbsp;</td><td>" .. https .. "&nbsp;</td><td>" .. rsync .. "&nbsp;</td><td>" .. dns .. 327 web:write("<td>" .. ftp .. "&nbsp;</td><td>" .. http .. "&nbsp;</td><td>" .. https .. "&nbsp;</td><td>" .. rsync .. "&nbsp;</td><td>" .. inRR .. " " .. dns ..
324 "&nbsp;</td><td>" .. protocol .. "&nbsp;</td><td>" .. redirects .. "&nbsp;</td><td>" .. sanity .. "&nbsp;</td><td>" .. integrity .. "&nbsp;</td>" .. '<td>' .. rate .. 328 "&nbsp;</td><td>" .. protocol .. "&nbsp;</td><td>" .. redirects .. "&nbsp;</td><td>" .. sanity .. "&nbsp;</td><td>" .. integrity .. "&nbsp;</td>" .. '<td>' .. rate ..
325 '</td><td>' .. updated .. '</td>&nbsp;' .. spd .. "&nbsp;" .. week .."&nbsp;</tr>\n") 329 '</td><td>' .. updated .. '</td>&nbsp;' .. spd .. "&nbsp;" .. week .."&nbsp;</tr>\n")
326 if "" ~= active then 330 if "" ~= active then
@@ -360,15 +364,14 @@ local makeIPlist = function(hosts)
360 if nil ~= hosts[k].IPs then 364 if nil ~= hosts[k].IPs then
361 for l, w in pairs(hosts[k].IPs) do 365 for l, w in pairs(hosts[k].IPs) do
362 if type(w) == "table" then 366 if type(w) == "table" then
363-- TODO - don't hard code deb.roundr.devuan.org.
364 -- Don't output the extra DNS-RR entries that are for admin reasons. 367 -- Don't output the extra DNS-RR entries that are for admin reasons.
365 if ((APT.options.roundRobin.value == k) and ("deb.roundr.devuan.org" == l)) or (APT.options.roundRobin.value ~= k) then 368 if ((APT.options.roundRobin.value == k) and (APT.options.roundRobinCname.value == l)) or (APT.options.roundRobin.value ~= k) then
366 n[l] = {} 369 n[l] = {}
367 for i, u in pairs(w) do 370 for i, u in pairs(w) do
368 if (APT.testing("IPv6") and ("AAAA" == u)) or ("A" == u) then 371 if (APT.testing("IPv6") and ("AAAA" == u)) or ("A" == u) then
369 local inRR = "" 372 local inRR = ""
370 local lc = logCount(k, i) 373 local lc = logCount(k, i)
371 if checkRR then 374 if checkRR and ('no' ~= hosts[k].DNSRR) then
372 -- If there where errors, warnings, or timeouts, then it'll have that wrapped in font tags. 375 -- If there where errors, warnings, or timeouts, then it'll have that wrapped in font tags.
373 inRR = "<font color='green'><b>&#x2705;</b></font>" 376 inRR = "<font color='green'><b>&#x2705;</b></font>"
374 if nil ~= lc:find("<font color='") then 377 if nil ~= lc:find("<font color='") then
@@ -382,7 +385,8 @@ local makeIPlist = function(hosts)
382 if f == nil then C("writing DNS-RR_good.txt file - " .. e) end 385 if f == nil then C("writing DNS-RR_good.txt file - " .. e) end
383 end 386 end
384 end 387 end
385 if "yes" ~= hosts[k].DNSRR then inRR = "" end 388 if "maybe" == hosts[k].DNSRR then inRR = "<font color='red'>&#x2753;</font>" end
389 if "no" == hosts[k].DNSRR then inRR = "" end
386 local log = '[<a href="' .. adr .. k .. '_' .. i .. '">graphs</a>] &nbsp; ' 390 local log = '[<a href="' .. adr .. k .. '_' .. i .. '">graphs</a>] &nbsp; '
387 if "" == log then n[l][i] = u else n[l][log .. inRR .. ' ' .. revDNS(hosts, k, i) .. ' ' .. lc] = u end 391 if "" == log then n[l][i] = u else n[l][log .. inRR .. ' ' .. revDNS(hosts, k, i) .. ' ' .. lc] = u end
388 end 392 end
@@ -392,7 +396,7 @@ local makeIPlist = function(hosts)
392 if (APT.testing("IPv6") and ("AAAA" == w)) or ("A" == w) then 396 if (APT.testing("IPv6") and ("AAAA" == w)) or ("A" == w) then
393 local inRR = "" 397 local inRR = ""
394 local lc = logCount(k, l) 398 local lc = logCount(k, l)
395 if checkRR then 399 if checkRR and ('no' ~= hosts[k].DNSRR) then
396 -- If there where errors, warnings, or timeouts, then it'll have that wrapped in font tags. 400 -- If there where errors, warnings, or timeouts, then it'll have that wrapped in font tags.
397 inRR = "<font color='green'><b>&#x2705;</b></font>" 401 inRR = "<font color='green'><b>&#x2705;</b></font>"
398 if nil ~= lc:find("<font color='") then 402 if nil ~= lc:find("<font color='") then
@@ -406,7 +410,8 @@ local makeIPlist = function(hosts)
406 if f == nil then C("writing DNS-RR_good.txt file - " .. e) end 410 if f == nil then C("writing DNS-RR_good.txt file - " .. e) end
407 end 411 end
408 end 412 end
409 if "yes" ~= hosts[k].DNSRR then inRR = "" end 413 if "maybe" == hosts[k].DNSRR then inRR = "<font color='red'>&#x2753;</font>" end
414 if "no" == hosts[k].DNSRR then inRR = "" end
410 local log = '[<a href="' .. adr .. k .. '_' .. l .. '">graphs</a>] &nbsp; ' 415 local log = '[<a href="' .. adr .. k .. '_' .. l .. '">graphs</a>] &nbsp; '
411 if "" == log then n[l] = w else n[log .. inRR .. ' ' .. revDNS(hosts, k, l) .. ' ' .. lc] = w end 416 if "" == log then n[l] = w else n[log .. inRR .. ' ' .. revDNS(hosts, k, l) .. ' ' .. lc] = w end
412 end 417 end
@@ -512,6 +517,17 @@ local colours =
512 '00880080', 517 '00880080',
513 '00088080', 518 '00088080',
514 '00008880', 519 '00008880',
520 '80000080',
521 '08000080',
522 '00800080',
523 '00080080',
524 '00008080',
525 '00000880',
526 'fff00080',
527 '0fff0080',
528 '00fff080',
529 '000fff80',
530 '0000fff0',
515} 531}
516local g = {} 532local g = {}
517local count = 0 533local count = 0
@@ -526,6 +542,7 @@ for k, v in APT.orderedPairs(mirrors) do
526 if APT.options.roundRobin.value ~= k then 542 if APT.options.roundRobin.value ~= k then
527 local c = colours[count] 543 local c = colours[count]
528 local name = string.format('%32s', k) 544 local name = string.format('%32s', k)
545 if c == nil then c = 'ffffff' end
529 if APT.options.referenceSite.value == k then c = 'ffffff' end 546 if APT.options.referenceSite.value == k then c = 'ffffff' end
530 table.insert(g, 'DEF:speedn' .. count .. '=rrd/' .. k .. '/Speed/Speed.rrd:max:MIN') 547 table.insert(g, 'DEF:speedn' .. count .. '=rrd/' .. k .. '/Speed/Speed.rrd:max:MIN')
531 table.insert(g, 'DEF:speedx' .. count .. '=rrd/' .. k .. '/Speed/Speed.rrd:max:MAX') 548 table.insert(g, 'DEF:speedx' .. count .. '=rrd/' .. k .. '/Speed/Speed.rrd:max:MAX')
@@ -576,7 +593,8 @@ if nil == web then C("opening mirrors file - " .. e) else
576 APT.options.roundRobin.value .. " is the DNS round robin, which points to the mirrors that are part of the DNS-RR. &nbsp; " .. 593 APT.options.roundRobin.value .. " is the DNS round robin, which points to the mirrors that are part of the DNS-RR. &nbsp; " ..
577 "If an IP is part of the DNS-RR, it is marked with '<font color='purple'><b>DNS-RR</b></font>'," .. 594 "If an IP is part of the DNS-RR, it is marked with '<font color='purple'><b>DNS-RR</b></font>'," ..
578 " if it <a href='DNS-RR_good.txt'>should be</a> it is marked with '<font color='green'><b>&#x2705;</b></font>'," .. 595 " if it <a href='DNS-RR_good.txt'>should be</a> it is marked with '<font color='green'><b>&#x2705;</b></font>'," ..
579 " if it <a href='DNS-RR_bad.txt'>should not be</a> it is marked with '<font color='red'>&#x274c;</font>'. &nbsp; " .. 596 " if it <a href='DNS-RR_bad.txt'>should not be</a> it is marked with '<font color='red'>&#x274c;</font>'," ..
597 " if it might be but still pending full testing, it is marked with '<font color='red'>&#x2753;</font>'. &nbsp; " ..
580 "<br>" .. 598 "<br>" ..
581 APT.options.referenceSite.value .. " is the master mirror, all the others copy files from it. &nbsp; " .. 599 APT.options.referenceSite.value .. " is the master mirror, all the others copy files from it. &nbsp; " ..
582 "</p>\n" 600 "</p>\n"
@@ -608,7 +626,7 @@ if nil == web then C("opening mirrors file - " .. e) else
608 "and <a href='https://git.devuan.dev/onefang/apt-panopticon_cgp'>here (Devuan repo)</a>.</p>\n" 626 "and <a href='https://git.devuan.dev/onefang/apt-panopticon_cgp'>here (Devuan repo)</a>.</p>\n"
609 ) 627 )
610 local whn = APT.exe('TZ="GMT" ls -dl1 --time-style="+%s" results/stamp | cut -d " " -f 6-6'):Do().result:sub(2, -2) 628 local whn = APT.exe('TZ="GMT" ls -dl1 --time-style="+%s" results/stamp | cut -d " " -f 6-6'):Do().result:sub(2, -2)
611 web:write( "<p>This run took " .. (os.time() - tonumber("0" .. whn)) .. " seconds.</p>" .. 629 web:write( "<p>This run took " .. (os.time() - tonumber("0" .. whn)) .. " seconds. &nbsp &nbsp apt-panopticon version " .. APT.version .. " </p>" ..
612 "\n</body></html>\n") 630 "\n</body></html>\n")
613 web:close() 631 web:close()
614end 632end
diff --git a/apt-panopticon.lua b/apt-panopticon.lua
index 4019fdf..79bdd19 100755
--- a/apt-panopticon.lua
+++ b/apt-panopticon.lua
@@ -14,7 +14,6 @@ APT.html = true
14 14
15 15
16local defaultURL = {scheme = "http"} 16local defaultURL = {scheme = "http"}
17local releases = {"jessie", "ascii", "beowulf", "ceres"}
18local releaseFiles = 17local releaseFiles =
19{ 18{
20 -- Release file. 19 -- Release file.
@@ -37,16 +36,20 @@ local notExist =
37local referenceDebs = 36local referenceDebs =
38{ 37{
39 -- Debian package. 38 -- Debian package.
40 "merged/pool/DEBIAN/main/d/debian-keyring/debian-keyring_2019.02.25_all.deb", 39 "merged/pool/DEBIAN/main/d/debian-keyring/debian-keyring_2023.12.24_all.deb",
41 -- Debian security package. NOTE this one should always be redirected? 40 -- Debian security package. NOTE this one should always be redirected?
42 "merged/pool/DEBIAN-SECURITY/updates/main/a/apt/apt-transport-https_1.4.10_amd64.deb", 41 "merged/pool/DEBIAN-SECURITY/updates/main/a/apt/apt-transport-https_1.8.2.2_all.deb",
43} 42}
44local referenceDevs = 43local referenceDevs =
45{ 44{
46 -- Devuan package. NOTE this one should not get redirected, but that's more a warning than an error. 45 -- Devuan package. NOTE this one should not get redirected, but that's more a warning than an error.
47 "merged/pool/DEVUAN/main/d/devuan-keyring/devuan-keyring_2017.10.03_all.deb", 46 "merged/pool/DEVUAN/main/d/devuan-keyring/devuan-keyring_2023.10.07_all.deb", -- Devuan keeps changing this since the key expiry incident.
47 "merged/pool/DEVUAN/main/b/base-files/base-files_13devuan4_all.deb",
48} 48}
49 49
50local keyring = "/usr/share/keyrings/devuan-archive-keyring.gpg"
51--local keyring = "/etc/apt/trusted.gpg.d/devuan-keyring-2022-archive.gpg"
52
50local curlStatus = 53local curlStatus =
51{ 54{
52 [1 ] = "Unsupported protocol. This build of curl has no support for this protocol.", 55 [1 ] = "Unsupported protocol. This build of curl has no support for this protocol.",
@@ -170,38 +173,76 @@ local repoExists = function (r)
170end 173end
171 174
172local IP = {} 175local IP = {}
173gatherIPs = function (host) 176gatherIPs = function (host, again)
177 if nil == again then again = '' end
174 if nil == IP[host] then 178 if nil == IP[host] then
175 local IPs 179 local IPs
176 -- Takes about 30 seconds to look up the lot. 180 -- Takes about 30 seconds to look up the lot.
177 -- I tested using dig's -f option, it didn't seem much faster. 181 -- I tested using dig's -f option, it didn't seem much faster.
178 -- The sort -r assumes that deb.devuan.org is the first alphabetically. 182 -- The sort -r assumes that deb.devuan.org is the first alphabetically.
179 local dig = io.popen('dig +keepopen +noall +nottlid +answer ' .. host .. ' A ' .. host .. ' AAAA ' .. host .. ' CNAME ' .. host .. ' SRV | sort -r | uniq') 183 if "" == host then print("Empty host name!") end
180 repeat 184 local dig = APT.readCmd('dig ' .. again .. ' +keepopen +noall +nottlid +answer ' .. host .. ' A ' .. host .. ' AAAA ' .. host .. ' CNAME ' .. host .. ' SRV | sort -r | uniq')
181 IPs = dig:read("*l") 185 for i,IPs in ipairs(dig) do
182 if nil ~= IPs then 186 for k, t, v in IPs:gmatch("([%w_%-%.]*)%.%s*IN%s*(%a*)%s*(.*)") do
183 for k, t, v in IPs:gmatch("([%w_%-%.]*)%.%s*IN%s*(%a*)%s*(.*)") do 187 if "." == v:sub(-1, -1) then v = v:sub(1, -2) end
184 if "." == v:sub(-1, -1) then v = v:sub(1, -2) end 188 if nil == IP[k] then IP[k] = {} end
185 if nil == IP[k] then IP[k] = {} end 189 IP[k][v] = t
186 IP[k][v] = t 190 D(" DNS record " .. host .. " == " .. k .. " type " .. t .. " -> " .. v)
187 D(" DNS record " .. host .. " == " .. k .. " type " .. t .. " -> " .. v) 191 if t == "CNAME" then
188 if t == "CNAME" then 192 if "" == v then
193 if '' ~= again then
194 print("Empty host name! DNS record " .. host .. " == " .. k .. " type " .. t .. " -> " .. v)
195 else
196 return gatherIPs(host, '@9.9.9.11')
197 end
198 else
189 gatherIPs(v) 199 gatherIPs(v)
190 IP[k][v] = IP[v] 200 IP[k][v] = IP[v]
191 elseif v == "SRV" then 201 end
192 print("SVR record found, now what do we do?") 202 elseif v == "SRV" then
203 print("SVR record found, now what do we do?")
204 elseif "" == v then
205 if '' ~= again then
206 print("Empty host name! DNS record " .. host .. " == " .. k .. " type " .. t .. " -> " .. v)
207 else
208 return gatherIPs(host, '@9.9.9.11')
193 end 209 end
194 end 210 end
195 end 211 end
196 until nil == IPs 212 end
197 end 213 end
198 214
199 -- If this is the DNS-RR domain name, gather the IPs for the mirrors that mirror_list.txt says should be in it. 215 -- If this is the DNS-RR domain name, gather the IPs for the mirrors that mirror_list.txt says should be in it.
200 if host == APT.options.roundRobin.value then 216 if host == APT.options.roundRobin.value then
201 for k, m in pairs(APT.mirrors) do 217 for k, m in pairs(APT.mirrors) do
202 if "yes" == m.DNSRR then 218 if ("yes" == m.DNSRR) or ("maybe" == m.DNSRR) then
219 if "" == m.FQDN then
220 print("Empty FQDN name! " .. host)
221 end
203 gatherIPs(m.FQDN) 222 gatherIPs(m.FQDN)
204 IP[host][m.FQDN] = IP[m.FQDN] 223 IP[host][m.FQDN] = IP[m.FQDN]
224 -- Strip them out so we don't test them twice.
225 if (nil ~= IP[m.FQDN]) and (nil ~= IP[host][APT.options.roundRobinCname.value]) then
226 for l, n in pairs(IP[m.FQDN]) do
227 if type(n) == 'table' then
228 for h, p in pairs(n) do
229 for j, o in pairs(IP[host][APT.options.roundRobinCname.value]) do
230 if h == j then IP[host][m.FQDN][l][h] = nil end
231 end
232 o = 0
233 for j in pairs(IP[host][m.FQDN][l]) do o = o + 1 end
234 if 0 == o then IP[host][m.FQDN][l] = nil end
235 end
236 else
237 for j, o in pairs(IP[host][APT.options.roundRobinCname.value]) do
238 if l == j then IP[host][m.FQDN][l] = nil end
239 end
240 end
241 o = 0
242 for j in pairs(IP[host][m.FQDN]) do o = o + 1 end
243 if 0 == o then IP[host][m.FQDN] = nil end
244 end
245 end
205 end 246 end
206 end 247 end
207 end 248 end
@@ -289,7 +330,7 @@ checkHEAD = function (host, URL, r, retry, sanity)
289 'curl -I --retry 0 -s --path-as-is --connect-timeout ' .. APT.options.timeout.value .. ' --max-redirs 0 ' .. APT.IPv46 .. ' ' .. 330 'curl -I --retry 0 -s --path-as-is --connect-timeout ' .. APT.options.timeout.value .. ' --max-redirs 0 ' .. APT.IPv46 .. ' ' ..
290 IP .. ' ' .. '-o /dev/null -D results/"HEADERS_' .. fname .. '" ' .. 331 IP .. ' ' .. '-o /dev/null -D results/"HEADERS_' .. fname .. '" ' ..
291 hdr .. ' -w "#%{http_code} %{ssl_verify_result} %{url_effective}\\n" ' .. PU.scheme .. '://' .. host .. PU.path .. ' >>results/"STATUS_' .. fname .. '"' 332 hdr .. ' -w "#%{http_code} %{ssl_verify_result} %{url_effective}\\n" ' .. PU.scheme .. '://' .. host .. PU.path .. ' >>results/"STATUS_' .. fname .. '"'
292 ):Nice():log():Do().status 333 ):timeout(APT.options.maxtime.value * 2.0):Nice():log():Do().status
293 if 0 < r then 334 if 0 < r then
294 APT.tested(PU.scheme, 'Redirects', host) 335 APT.tested(PU.scheme, 'Redirects', host)
295 else 336 else
@@ -315,7 +356,7 @@ checkHEAD = function (host, URL, r, retry, sanity)
315 if 0 ~= status then 356 if 0 ~= status then
316 local msg = curlStatus[status] 357 local msg = curlStatus[status]
317 if nil == msg then msg = "UNKNOWN CURL STATUS CODE!" end 358 if nil == msg then msg = "UNKNOWN CURL STATUS CODE!" end
318 if (28 == status) or (7 == status) then 359 if (128+9 == status) or (124 == status) or (28 == status) or (7 == status) then
319 T(spcd .. spcd .. "TIMEOUT " .. timeouts + 1 .. ", retry " .. retry + 1 .. ' ' .. APT.lnk(URL), PU.scheme, sanity, host) 360 T(spcd .. spcd .. "TIMEOUT " .. timeouts + 1 .. ", retry " .. retry + 1 .. ' ' .. APT.lnk(URL), PU.scheme, sanity, host)
320 timeouts = timeouts + 1 361 timeouts = timeouts + 1
321 else 362 else
@@ -406,7 +447,7 @@ checkHEAD = function (host, URL, r, retry, sanity)
406 local pth = path:match('^(.*/pool/).*$') 447 local pth = path:match('^(.*/pool/).*$')
407 if nil ~= pth then table.insert(APT.results[PU.scheme].redirects, pu.host .. "/" .. pth) else E(spcd .. spcd .. 'Odd redirect path ' .. path) end 448 if nil ~= pth then table.insert(APT.results[PU.scheme].redirects, pu.host .. "/" .. pth) else E(spcd .. spcd .. 'Odd redirect path ' .. path) end
408 I(spcd .. spcd .. "Now checking redirected host " .. u .. ' &nbsp; for &nbsp; ' .. APT.lnk(URL) .. arw .. APT.lnk(location), host) 449 I(spcd .. spcd .. "Now checking redirected host " .. u .. ' &nbsp; for &nbsp; ' .. APT.lnk(URL) .. arw .. APT.lnk(location), host)
409 APT.exe(downloadLock .. "REDIR-" .. check .. ".log.txt" .. " ./apt-panopticon.lua " .. extraArgs .. ' ' .. pu.host .. "/" .. path .. " " .. file):Nice():log():fork() 450 APT.exe(downloadLock .. "REDIR-" .. check .. ".log.txt" .. " ./apt-panopticon.lua " .. extraArgs .. ' ' .. pu.host .. "/" .. path .. " " .. file):timeout(APT.options.maxtime.value * 2.0):Nice():log():fork(pu.host)
410 D(spcd .. 'logging to ' .. APT.logName(pu.host, nil, file)[2]) 451 D(spcd .. 'logging to ' .. APT.logName(pu.host, nil, file)[2])
411 APT.tested(PU.scheme, 'Redirects', host) 452 APT.tested(PU.scheme, 'Redirects', host)
412 end 453 end
@@ -454,7 +495,7 @@ local checkFiles = function (host, ip, path, file)
454 if checkTimeouts(host, "https", ip .. path .. "/" .. s) then return end 495 if checkTimeouts(host, "https", ip .. path .. "/" .. s) then return end
455 end 496 end
456 end 497 end
457 for i, s in pairs(releases) do 498 for i, s in pairs(APT.releases) do
458 for j, k in pairs(releaseFiles) do 499 for j, k in pairs(releaseFiles) do
459 if repoExists(s .. k) then 500 if repoExists(s .. k) then
460 if checkTimeouts(host, "http", ip .. path .. "/merged/dists/" .. s .. '/' .. k) then return end 501 if checkTimeouts(host, "http", ip .. path .. "/merged/dists/" .. s .. '/' .. k) then return end
@@ -493,7 +534,7 @@ checkHost = function (orig, host, path, ip, file)
493 else 534 else
494 if orig == host then 535 if orig == host then
495 I("Testing mirror " .. orig .. "" .. file) 536 I("Testing mirror " .. orig .. "" .. file)
496 APT.exe("./apt-panopticon.lua " .. sendArgs .. " -o " .. orig .. path .. " " .. file):Nice():log():fork() 537 APT.exe("./apt-panopticon.lua " .. sendArgs .. " -o " .. orig .. path .. " " .. file):timeout(APT.options.maxtime.value * 2.0):Nice():log():fork(orig)
497 D('logging to ' .. APT.logName(ph.host, nil, file)[2]) 538 D('logging to ' .. APT.logName(ph.host, nil, file)[2])
498 else D("checkHost " .. orig .. arw .. host) end 539 else D("checkHost " .. orig .. arw .. host) end
499 end 540 end
@@ -568,7 +609,7 @@ local downloads = function(host, URL, meta, release, list)
568 return 609 return
569 end 610 end
570 else 611 else
571 for i, s in pairs(releases) do 612 for i, s in pairs(APT.releases) do
572 for j, k in pairs(releaseFiles) do 613 for j, k in pairs(releaseFiles) do
573 if repoExists(s .. k) then 614 if repoExists(s .. k) then
574 addDownload(host, URL, f, s, k) 615 addDownload(host, URL, f, s, k)
@@ -577,7 +618,7 @@ local downloads = function(host, URL, meta, release, list)
577 end 618 end
578 end 619 end
579 f:close() 620 f:close()
580 APT.exe(cm):Nice():log():fork() 621 APT.exe(cm):timeout(APT.options.maxtime.value * 2.0):Nice():log():fork(host)
581 D('logging to <a href="' .. log .. '">' .. log .. '</a>, with <a href="' .. files .. '">these files</a>') 622 D('logging to <a href="' .. log .. '">' .. log .. '</a>, with <a href="' .. files .. '">these files</a>')
582end 623end
583 624
@@ -594,7 +635,7 @@ local validateURL = function(m)
594 local p = url.parse("http://" .. m.BaseURL) 635 local p = url.parse("http://" .. m.BaseURL)
595 if nil == p.path then p.path = '' end 636 if nil == p.path then p.path = '' end
596 if nil ~= p.port then p.authority = authority .. ':' .. p.port end 637 if nil ~= p.port then p.authority = authority .. ':' .. p.port end
597 if nil == m.FDQN then W("Something wrong in FDQN from mirror_list.txt! nil", "", "", p.authority) else 638 if nil == m.FQDN then W("Something wrong in FQDN from mirror_list.txt! nil", "", "", p.authority) else
598 if m.FQDN ~= p.authority then W("Something wrong in FDQN from mirror_list.txt! " .. m.FDQN, "", "", p.authority) end 639 if m.FQDN ~= p.authority then W("Something wrong in FDQN from mirror_list.txt! " .. m.FDQN, "", "", p.authority) end
599 end 640 end
600 if nil == m.BaseURL then W("Something wrong in BaseURL from mirror_list.txt! nil", "", "", p.authority) else 641 if nil == m.BaseURL then W("Something wrong in BaseURL from mirror_list.txt! nil", "", "", p.authority) else
@@ -678,7 +719,7 @@ local postParse = function(host, list)
678 if APT.options.referenceSite.value == host then 719 if APT.options.referenceSite.value == host then
679 if nil ~= list then 720 if nil ~= list then
680 local sem = 'results/NEW_' .. list.out .. '_%s.txt' 721 local sem = 'results/NEW_' .. list.out .. '_%s.txt'
681 for i, n in pairs(releases) do 722 for i, n in pairs(APT.releases) do
682 local f = sem:format(n) 723 local f = sem:format(n)
683 if APT.checkFile(f .. '.tmp') then 724 if APT.checkFile(f .. '.tmp') then
684 os.execute('mv ' .. f .. '.tmp ' .. f) 725 os.execute('mv ' .. f .. '.tmp ' .. f)
@@ -691,7 +732,7 @@ local postParse = function(host, list)
691end 732end
692 733
693local parseDebs = function(host) 734local parseDebs = function(host)
694 for i, n in pairs(releases) do 735 for i, n in pairs(APT.releases) do
695 local inFile = 'results/NEW_debs_' .. n .. '.txt' 736 local inFile = 'results/NEW_debs_' .. n .. '.txt'
696 local nfile, e = io.open(inFile, "r") 737 local nfile, e = io.open(inFile, "r")
697 if nil == nfile then W("opening " .. inFile .. " file - " .. e) else 738 if nil == nfile then W("opening " .. inFile .. " file - " .. e) else
@@ -733,7 +774,7 @@ end
733 774
734local parsePackages = function(host) 775local parsePackages = function(host)
735 local list = {inf = 'Packages', parser = parseDebs, out = 'debs', files = {}, nextf = ''} 776 local list = {inf = 'Packages', parser = parseDebs, out = 'debs', files = {}, nextf = ''}
736 for i, n in pairs(releases) do 777 for i, n in pairs(APT.releases) do
737 local inFile = 'results/NEW_' .. list.inf .. '_' .. n .. '.txt' 778 local inFile = 'results/NEW_' .. list.inf .. '_' .. n .. '.txt'
738 local outFile = 'results/NEW_' .. list.out .. '_' .. n .. '.txt' 779 local outFile = 'results/NEW_' .. list.out .. '_' .. n .. '.txt'
739 if APT.options.referenceSite.value == host then 780 if APT.options.referenceSite.value == host then
@@ -755,6 +796,7 @@ local parsePackages = function(host)
755 local Pp, e = io.open('results/' .. host .. '/merged/dists/'.. n .. dir .. 'Packages.parsed', "w+") 796 local Pp, e = io.open('results/' .. host .. '/merged/dists/'.. n .. dir .. 'Packages.parsed', "w+")
756 if nil == Pp then W('opening results/' .. host .. '/merged/dists/'.. n .. dir .. 'Packages.parsed' .. ' file - ' .. e) else 797 if nil == Pp then W('opening results/' .. host .. '/merged/dists/'.. n .. dir .. 'Packages.parsed' .. ' file - ' .. e) else
757 local pp = {} 798 local pp = {}
799-- TODO - FIX - check if this file exists first.
758 for l in io.lines('results/' .. host .. '/merged/dists/'.. n .. dir .. 'Packages') do 800 for l in io.lines('results/' .. host .. '/merged/dists/'.. n .. dir .. 'Packages') do
759 if "Package: " == l:sub(1, 9) then 801 if "Package: " == l:sub(1, 9) then
760 if 0 ~= #pp then 802 if 0 ~= #pp then
@@ -786,12 +828,12 @@ local parsePackages = function(host)
786 ' | grep -E "^\\+" | grep -Ev "^\\+\\+\\+|^---" >>results/NEW_' .. list.out .. '_TMP_' .. n .. '.txt') 828 ' | grep -E "^\\+" | grep -Ev "^\\+\\+\\+|^---" >>results/NEW_' .. list.out .. '_TMP_' .. n .. '.txt')
787 for i, s in pairs(referenceDebs) do 829 for i, s in pairs(referenceDebs) do
788 if 0 == APT.exe('grep -q "' .. s:sub(8, -1) .. '" results/OLD_' .. list.out .. '_' .. n .. '.txt'):log():Do().status then 830 if 0 == APT.exe('grep -q "' .. s:sub(8, -1) .. '" results/OLD_' .. list.out .. '_' .. n .. '.txt'):log():Do().status then
789 print('Reference package is out of date (' .. n .. ') - ' .. s) 831 print('Reference package is out of date from ' .. host .. ' (' .. n .. ') - ' .. s)
790 end 832 end
791 end 833 end
792 for i, s in pairs(referenceDevs) do 834 for i, s in pairs(referenceDevs) do
793 if 0 == APT.exe('grep -q "' .. s:sub(8, -1) .. '" results/OLD_' .. list.out .. '_' .. n .. '.txt'):log():Do().status then 835 if 0 == APT.exe('grep -q "' .. s:sub(8, -1) .. '" results/OLD_' .. list.out .. '_' .. n .. '.txt'):log():Do().status then
794 print('Reference package is out of date (' .. n .. ') - ' .. s) 836 print('Reference package is out of date from ' .. host .. ' (' .. n .. ') - ' .. s)
795 end 837 end
796 end 838 end
797 else 839 else
@@ -839,13 +881,13 @@ local parseRelease = function(host)
839 local list = {inf = 'Release', parser = parsePackages, out = 'Packages', files = {}, nextf = 'debs'} 881 local list = {inf = 'Release', parser = parsePackages, out = 'Packages', files = {}, nextf = 'debs'}
840 local updated = false 882 local updated = false
841 local now = tonumber(os.date('%s')) 883 local now = tonumber(os.date('%s'))
842 for i, n in pairs(releases) do 884 for i, n in pairs(APT.releases) do
843 for l, o in pairs(releaseFiles) do 885 for l, o in pairs(releaseFiles) do
844 if repoExists(i .. o) then 886 if repoExists(i .. o) then
845 postDownload(host, n, o) 887 postDownload(host, n, o)
846 if (".gpg" == o:sub(-4, -1)) and (APT.checkFile('results/' .. host .. '/merged/dists/' .. n .. '/' .. o)) then 888 if (".gpg" == o:sub(-4, -1)) and (APT.checkFile('results/' .. host .. '/merged/dists/' .. n .. '/' .. o)) then
847 if APT.testing("Integrity") then 889 if APT.testing("Integrity") then
848 local status = APT.exe( "gpgv --keyring /usr/share/keyrings/devuan-keyring.gpg results/" .. host .. "/merged/dists/" .. n .. '/' .. o .. 890 local status = APT.exe( "gpgv --keyring " .. keyring .. " results/" .. host .. "/merged/dists/" .. n .. '/' .. o ..
849 " results/" .. host .. "/merged/dists/" .. n .. '/' .. o:sub(1, -5)):Nice():noErr():log():Do().status 891 " results/" .. host .. "/merged/dists/" .. n .. '/' .. o:sub(1, -5)):Nice():noErr():log():Do().status
850 if 0 ~= status then E("GPG check failed for " .. host .. "/merged/dists/" .. n .. '/' .. o, "http", "Integrity", host) end 892 if 0 ~= status then E("GPG check failed for " .. host .. "/merged/dists/" .. n .. '/' .. o, "http", "Integrity", host) end
851-- TODO - should check the PGP sig of InRelease as well. 893-- TODO - should check the PGP sig of InRelease as well.
@@ -922,7 +964,7 @@ end
922 964
923local parseStart = function(host) 965local parseStart = function(host)
924 local list = {inf = '', parser = parseRelease, out = 'Release', files = {}, nextf = 'Packages'} 966 local list = {inf = '', parser = parseRelease, out = 'Release', files = {}, nextf = 'Packages'}
925 for i, n in pairs(releases) do 967 for i, n in pairs(APT.releases) do
926 local outFile = 'results/NEW_' .. list.out .. '_' .. n .. '.txt' 968 local outFile = 'results/NEW_' .. list.out .. '_' .. n .. '.txt'
927 for l, o in pairs(releaseFiles) do 969 for l, o in pairs(releaseFiles) do
928 if repoExists(n .. o) then 970 if repoExists(n .. o) then
@@ -991,6 +1033,7 @@ os.execute('sleep 1') -- Wait for things to start up before checking for them.
991 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to devuan.bio.lmu.de (141.84.43.19) port 80 (#0) 1033 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to devuan.bio.lmu.de (141.84.43.19) port 80 (#0)
992 curl: (22) The requested URL returned error: 404 Not Found 1034 curl: (22) The requested URL returned error: 404 Not Found
993]] 1035]]
1036 local trace = {}
994 local min, max, spd = 999999999999, 0 1037 local min, max, spd = 999999999999, 0
995 local num = '[%d%.]+[kM]?' 1038 local num = '[%d%.]+[kM]?'
996 if APT.checkFile(f) then 1039 if APT.checkFile(f) then
@@ -1022,7 +1065,7 @@ os.execute('sleep 1') -- Wait for things to start up before checking for them.
1022 1065
1023 if (APT.options.referenceSite.value ~= host) and ('' ~= list.nextf) then 1066 if (APT.options.referenceSite.value ~= host) and ('' ~= list.nextf) then
1024 local sem = 'results/NEW_' .. list.nextf .. '_%s.txt' 1067 local sem = 'results/NEW_' .. list.nextf .. '_%s.txt'
1025 for i, n in pairs(releases) do 1068 for i, n in pairs(APT.releases) do
1026 local f = sem:format(n) 1069 local f = sem:format(n)
1027 while not APT.checkFile(f) do 1070 while not APT.checkFile(f) do
1028 D('*&lt;* About to yield coroutine while waiting on - not APT.checkFile(' .. f .. ')') 1071 D('*&lt;* About to yield coroutine while waiting on - not APT.checkFile(' .. f .. ')')
@@ -1066,7 +1109,12 @@ if 0 < #arg then
1066 I("Starting tests for " .. arg[1] .. " with these tests - " .. table.concat(APT.options.tests.value, ", ")) 1109 I("Starting tests for " .. arg[1] .. " with these tests - " .. table.concat(APT.options.tests.value, ", "))
1067 APT.mirrors = loadfile("results/mirrors.lua")() 1110 APT.mirrors = loadfile("results/mirrors.lua")()
1068 APT.results = APT.padResults(APT.results) 1111 APT.results = APT.padResults(APT.results)
1069 if APT.origin or APT.redir then APT.results["IPs"] = gatherIPs(pu.host) end 1112 if APT.origin or APT.redir then
1113 if "" == pu.host then
1114 print("Empty pu.host name! " .. pu.host)
1115 end
1116 APT.results["IPs"] = gatherIPs(pu.host)
1117 end
1070 if nil ~= arg[2] then I(" &nbsp; Using IP " .. arg[2]); ip = arg[2] end 1118 if nil ~= arg[2] then I(" &nbsp; Using IP " .. arg[2]); ip = arg[2] end
1071 if nil ~= arg[3] then I(" &nbsp; Using file " .. arg[3]); end 1119 if nil ~= arg[3] then I(" &nbsp; Using file " .. arg[3]); end
1072 1120
@@ -1081,15 +1129,17 @@ if 0 < #arg then
1081 APT.allpairs(ips, 1129 APT.allpairs(ips,
1082 function(k, v) 1130 function(k, v)
1083 if v == "A" then 1131 if v == "A" then
1084 if APT.testing("IPv4") then APT.exe('./apt-panopticon.lua ' .. sendArgs .. ' -4 ' .. pu.host .. path .. ' ' .. k .. ' ' .. file):Nice():log():fork() end 1132 if APT.testing("IPv4") then APT.exe('./apt-panopticon.lua ' .. sendArgs .. ' -4 ' .. pu.host .. path .. ' ' .. k .. ' ' .. file):timeout(APT.options.maxtime.value * 2.0):Nice():log():fork(pu.host) end
1085 elseif v == "AAAA" then 1133 elseif v == "AAAA" then
1086 if APT.testing("IPv6") then APT.exe('./apt-panopticon.lua ' .. sendArgs .. ' -6 ' .. APT.IPv46 .. ' ' .. pu.host .. path .. ' ' .. k .. ' ' .. file):Nice():log():fork() end 1134 if APT.testing("IPv6") then APT.exe('./apt-panopticon.lua ' .. sendArgs .. ' -6 ' .. APT.IPv46 .. ' ' .. pu.host .. path .. ' ' .. k .. ' ' .. file):timeout(APT.options.maxtime.value * 2.0):Nice():log():fork(pu.host) end
1087 end 1135 end
1088 D('logging to ' .. APT.logName(pu.host, k, file)[2]) 1136 D('logging to ' .. APT.logName(pu.host, k, file)[2])
1089 end 1137 end
1090 ) 1138 )
1091 else 1139 else
1092 E("no IPs for " .. pu.host) 1140 E("no IPs for " .. pu.host)
1141 APT.logPost()
1142 return
1093 end 1143 end
1094 end 1144 end
1095 1145
@@ -1178,16 +1228,15 @@ else
1178 while 1 <= APT.checkExes("apt-panopticon.lua " .. sendArgs) do os.execute("sleep 5") end 1228 while 1 <= APT.checkExes("apt-panopticon.lua " .. sendArgs) do os.execute("sleep 5") end
1179 1229
1180 local APT_args = APT.args 1230 local APT_args = APT.args
1181 local APT_logFile = APT.logFile
1182 local debians = {} 1231 local debians = {}
1183 local srvs = io.popen('ls -1 results/*.lua') 1232 local srvs = APT.readCmd('ls -1 results/*.lua')
1184 for l in srvs:lines() do 1233 for ii,l in ipairs(srvs) do
1185 local hst = l:sub(9, -5) 1234 local hst = l:sub(9, -5)
1186 if nil ~= l:find('_R%.lua') then hst = hst:sub(1, -3) end 1235 if nil ~= l:find('_R%.lua') then hst = hst:sub(1, -3) end
1187 if (hst:find('_') == nil) and (nil == APT.mirrors[hst]) then 1236 if (hst:find('_') == nil) and (nil == APT.mirrors[hst]) then
1188 local ips = loadfile(l)().IPs 1237 local ips = loadfile(l)().IPs
1189 if nil ~= ips then 1238 if nil ~= ips then
1190 debians[hst] = {Country = '', FDQN = hst, Active = 'yes', Rate = '', BaseURL = hst, Protocols = {http = true, https = true}, Bandwidth = '', IPs = ips} 1239 debians[hst] = {Country = '', FQDN = hst, Active = 'yes', Rate = '', BaseURL = hst, Protocols = {http = true, https = true}, Bandwidth = '', IPs = ips}
1191 local baseFiles = {} 1240 local baseFiles = {}
1192 local IPfiles = {} 1241 local IPfiles = {}
1193 for i, a in pairs(ips) do 1242 for i, a in pairs(ips) do
@@ -1198,8 +1247,8 @@ else
1198 end 1247 end
1199 end 1248 end
1200 end 1249 end
1201 local files = io.popen('ls -1 results/LOG_' .. hst .. '_*.html') 1250 local files = APT.readCmd('ls -1 results/LOG_' .. hst .. '_*.html')
1202 for ll in files:lines() do 1251 for iii,ll in ipairs(files) do
1203 local dn = false 1252 local dn = false
1204 for i, a in pairs(ips) do 1253 for i, a in pairs(ips) do
1205 if type(a) == 'table' then 1254 if type(a) == 'table' then
@@ -1220,6 +1269,7 @@ else
1220 end 1269 end
1221 1270
1222 local combine = function(ip, a) 1271 local combine = function(ip, a)
1272 local APT_logFile = APT.logFile
1223 if not APT.logOpen(hst, ip) then 1273 if not APT.logOpen(hst, ip) then
1224 print('PROBLEM OPENING LOG FILE ' .. hst .. ' ' .. ip) 1274 print('PROBLEM OPENING LOG FILE ' .. hst .. ' ' .. ip)
1225 else 1275 else
@@ -1231,8 +1281,8 @@ else
1231 if ln:match('^' .. os.date('!%Y%-%m%-%d ') .. '.*$') then APT.logFile:write(ln .. '\n') end -- %F isn't good enough, coz we have to escape the '-'. 1281 if ln:match('^' .. os.date('!%Y%-%m%-%d ') .. '.*$') then APT.logFile:write(ln .. '\n') end -- %F isn't good enough, coz we have to escape the '-'.
1232 end 1282 end
1233 end 1283 end
1284 APT.logPost()
1234 end 1285 end
1235 APT.logPost()
1236 APT.args = APT_args 1286 APT.args = APT_args
1237 APT.logFile = APT_logFile 1287 APT.logFile = APT_logFile
1238 end 1288 end
diff --git a/laggers b/laggers
new file mode 100755
index 0000000..c5f30ee
--- /dev/null
+++ b/laggers
@@ -0,0 +1,3 @@
1#!/bin/bash
2echo "apt-panopticon processes still running -"
3ps ax -o pid,args --sort args | grep -E 'apt-panopticon\.lua | curl | dig ' | grep -v -E 'flock -n |grep -E |sh -c |timeout -k '
diff --git a/update_apt-panopticon b/update_apt-panopticon
index b70f4c3..dde18a5 100755
--- a/update_apt-panopticon
+++ b/update_apt-panopticon
@@ -1,16 +1,55 @@
1#!/bin/bash 1#!/bin/bash
2 2
3cd /var/www/html/apt-panopticon/apt-panopticon_cgp 3PANOPATH="/var/www/html/apt-panopticon"
4#git pull > /dev/null 4#KEEPDAYS=$((2 * 30))
5#chown -R mirrors:www-data * 5
6cd /var/www/html/apt-panopticon/apt-panopticon 6cd ${PANOPATH}/apt-panopticon_cgp
7#git pull > /dev/null 7if [ -d .git ] ; then
8#chown -R mirrors:www-data * 8 git pull > /dev/null
9 9 chown -R www-data:www-data *
10if [ ! -f apt-panopticon.lock ] ; then 10fi
11 rm ../results; ln -s apt-panopticon/results_old ../results 11cd ${PANOPATH}/apt-panopticon
12 flock -n apt-panopticon.lock ./apt-panopticon.lua && rm apt-panopticon.lock 12if [ -d .git ] ; then
13 rm ../results; ln -s apt-panopticon/results ../results 13 git pull > /dev/null
14 chown -R www-data:www-data *
15fi
16
17# Check if the lock file still exists.
18if [ -f apt-panopticon.lock ] ; then
19 # Check if it's still running.
20 ps ax -eo pid,args | grep "apt-panopticon.lua" | grep -v "grep apt-panopticon.lua" | while read line ; do touch apt-panopticon.running ; exit ; done
21 if [ -f apt-panopticon.running ] ; then
22 echo "Previous apt-panopticon still running, exiting."
23 echo "Previous apt-panopticon still running, exiting."
24 ./laggers
25 rm apt-panopticon.running
26 exit 1
27 fi
28 echo "Crashed apt-panopticon detected, removing stale lock file."
29 echo "Crashed apt-panopticon detected, removing stale lock file."
30 ./laggers
31 rm apt-panopticon.lock
32fi
33
34# Clean up any mess left over from failed runs.
35find results_* -maxdepth 2 ! -name "pkgmaster.devuan.org" -name "*.*" -type d -print0 | xargs -0rt /bin/rm -fr
36
37if [ "z" != "z${KEEPDAYS}" ] ; then
38 # Remove old results.
39 find . -daystart -maxdepth 2 -name "stamp" -type f ! -mtime $((0 - ${KEEPDAYS})) -printf "%h\0" | xargs -0rt /bin/rm -fr
40 find . -daystart -maxdepth 2 -name "results_*.tar.xz" -type f ! -mtime $((0 - ${KEEPDAYS})) -print0 | xargs -0rt /bin/rm -f
41 find . -maxdepth 1 -name "results_*" -type d -empty -print0 | xargs -0rt /bin/rm -fr
14fi 42fi
15 43
16#chown -R mirrors:www-data /var/www/html/SledjHamr/apt-panopticon/results 44rm ../results; ln -s apt-panopticon/results_old ../results
45flock -n apt-panopticon.lock ionice -c3 nice -n 19 timeout --kill-after=20.0 --foreground 8.5m ./apt-panopticon.lua && rm apt-panopticon.lock
46if [ -f apt-panopticon.lock ] ; then
47 echo "apt-panopticon timed out."
48 ./laggers
49fi
50rm ../results; ln -s apt-panopticon/results ../results
51
52chown -R www-data:www-data *
53
54# Clean up any mess left over from THIS failed run.
55find results_* -maxdepth 2 ! -name "pkgmaster.devuan.org" -name "*.*" -type d -print0 | xargs -0rt /bin/rm -fr