Skip to content

Commit 17bbb5b

Browse files
authored
Merge pull request #74 from OpenVoxProject/dhcpcd_fix
Don't run dhcpcd command when it isn't running
2 parents 1b61ffc + 9275bde commit 17bbb5b

File tree

3 files changed

+87
-1
lines changed

3 files changed

+87
-1
lines changed

lib/facter/util/linux.rb

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# frozen_string_literal: true
2+
3+
module Facter
4+
module Util
5+
module Linux
6+
def self.process_running?(process_name)
7+
pidfiles = Dir.glob("{/run,/var/run}/#{process_name}{,*,/}*.pid")
8+
pidfiles.each do |pf|
9+
next unless File.file?(pf)
10+
11+
pid = begin
12+
Integer(Facter::Util::FileHelper.safe_read(pf, '').strip, 10)
13+
rescue StandardError
14+
nil
15+
end
16+
next unless pid&.positive?
17+
18+
begin
19+
# Doesn't actually kill, just detects if the process exists
20+
Process.kill(0, pid)
21+
return true if proc_comm(pid) == process_name || proc_cmdline(pid)&.match?(%r{(^|\s|/)#{process_name}(\s|$)})
22+
rescue Errno::ESRCH
23+
# If we can't confirm identity, still treat it as not running to be safe.
24+
next
25+
rescue Errno::EPERM
26+
# Exists but we can't inspect it; assume it's running.
27+
return true
28+
end
29+
end
30+
31+
# Fallback: Try to find it in /proc
32+
return false unless Dir.exist?('/proc')
33+
34+
Dir.glob('/proc/[0-9]*/comm').any? do |path|
35+
Facter::Util::FileHelper.safe_read(path, nil)&.strip == process_name
36+
end
37+
end
38+
39+
def self.proc_comm(pid)
40+
Facter::Util::FileHelper.safe_read("/proc/#{pid}/comm", nil)&.strip
41+
end
42+
43+
def self.proc_cmdline(pid)
44+
raw = Facter::Util::FileHelper.safe_read("/proc/#{pid}/cmdline", nil)
45+
raw&.tr("\0", ' ')
46+
end
47+
end
48+
end
49+
end

lib/facter/util/linux/dhcp.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# frozen_string_literal: true
22

3+
require 'facter/util/linux'
4+
35
module Facter
46
module Util
57
module Linux
@@ -73,11 +75,18 @@ def search_internal_leases(interface_name)
7375
end
7476

7577
def search_with_dhcpcd_command(interface_name)
76-
@log.debug("Attempt to get DHCP for interface #{interface_name}, from dhcpcd command")
78+
return if interface_name == 'lo'
7779

7880
@dhcpcd_command ||= Facter::Core::Execution.which('dhcpcd')
7981
return unless @dhcpcd_command
8082

83+
unless Facter::Util::Linux.process_running?('dhcpcd')
84+
@log.debug('Skipping dhcpcd -U because dhcpcd daemon is not running')
85+
return
86+
end
87+
88+
@log.debug("Attempt to get DHCP for interface #{interface_name}, from dhcpcd command")
89+
8190
output = Facter::Core::Execution.execute("#{@dhcpcd_command} -U #{interface_name}", logger: @log)
8291
dhcp = output.match(/dhcp_server_identifier='(.*)'/)
8392
dhcp[1] if dhcp

spec/facter/util/linux/dhcp_spec.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@
6868
allow(File).to receive(:readable?).with('/var/lib/NetworkManager/').and_return(false)
6969
allow(File).to receive(:readable?).with('/var/db/').and_return(false)
7070

71+
allow(Dir).to receive(:glob).with('{/run,/var/run}/dhcpcd{,*,/}*.pid').and_return(['/run/dhcpcd.pid'])
72+
allow(File).to receive(:file?).with('/run/dhcpcd.pid').and_return(true)
73+
allow(Facter::Util::FileHelper).to receive(:safe_read).with('/run/dhcpcd.pid', '').and_return('1234')
74+
allow(Process).to receive(:kill).with(0, 1234).and_return(true)
75+
allow(Facter::Util::FileHelper).to receive(:safe_read).with('/proc/1234/comm', nil).and_return('dhcpcd')
76+
7177
allow(Facter::Core::Execution).to receive(:which)
7278
.with('dhcpcd').and_return('/usr/bin/dhcpcd')
7379
allow(Facter::Core::Execution).to receive(:execute)
@@ -100,5 +106,27 @@
100106
expect(dhcp_search.dhcp('ens160', 1, log_spy)).to eq(nil)
101107
end
102108
end
109+
110+
context 'when the dhcpcd command is available, but not running' do
111+
before do
112+
allow(Facter::Util::FileHelper).to receive(:safe_read).with('/run/systemd/netif/leases/1', nil).and_return(nil)
113+
allow(File).to receive(:readable?).with('/var/lib/dhclient/').and_return(false)
114+
allow(File).to receive(:readable?).with('/var/lib/dhcp/').and_return(false)
115+
allow(File).to receive(:readable?).with('/var/lib/dhcp3/').and_return(false)
116+
allow(File).to receive(:readable?).with('/var/lib/NetworkManager/').and_return(false)
117+
allow(File).to receive(:readable?).with('/var/db/').and_return(false)
118+
allow(Dir).to receive(:glob).with('{/run,/var/run}/dhcpcd{,*,/}*.pid').and_return([])
119+
allow(Dir).to receive(:glob).with('/proc/[0-9]*/comm').and_return([])
120+
121+
allow(Facter::Core::Execution).to receive(:which)
122+
.with('dhcpcd').and_return('/usr/bin/dhcpcd')
123+
124+
dhcp_search.instance_eval { @dhcpcd_command = nil }
125+
end
126+
127+
it 'returns nil' do
128+
expect(dhcp_search.dhcp('ens160', 1, log_spy)).to eq(nil)
129+
end
130+
end
103131
end
104132
end

0 commit comments

Comments
 (0)