serverspec 0.2.22 → 0.2.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/serverspec.rb +22 -0
- data/lib/serverspec/backend/exec.rb +17 -12
- data/lib/serverspec/backend/ssh.rb +6 -1
- data/lib/serverspec/commands/base.rb +45 -37
- data/lib/serverspec/commands/debian.rb +3 -3
- data/lib/serverspec/commands/gentoo.rb +5 -4
- data/lib/serverspec/commands/linux.rb +22 -0
- data/lib/serverspec/commands/redhat.rb +3 -3
- data/lib/serverspec/commands/solaris.rb +22 -16
- data/lib/serverspec/matchers/be_reachable.rb +1 -0
- data/lib/serverspec/version.rb +1 -1
- data/spec/debian/commands_spec.rb +30 -29
- data/spec/gentoo/commands_spec.rb +30 -29
- data/spec/redhat/commands_spec.rb +29 -28
- data/spec/solaris/commands_spec.rb +30 -29
- metadata +99 -90
data/lib/serverspec.rb
CHANGED
@@ -8,6 +8,7 @@ require 'serverspec/setup'
|
|
8
8
|
require 'serverspec/filter'
|
9
9
|
require 'serverspec/subject'
|
10
10
|
require 'serverspec/commands/base'
|
11
|
+
require 'serverspec/commands/linux'
|
11
12
|
require 'serverspec/commands/redhat'
|
12
13
|
require 'serverspec/commands/debian'
|
13
14
|
require 'serverspec/commands/gentoo'
|
@@ -30,3 +31,24 @@ RSpec.configure do |c|
|
|
30
31
|
end
|
31
32
|
end
|
32
33
|
end
|
34
|
+
|
35
|
+
module RSpec
|
36
|
+
module Matchers
|
37
|
+
module DSL
|
38
|
+
class Matcher
|
39
|
+
def failure_message_for_should(&block)
|
40
|
+
if block.to_s =~ /serverspec\/matchers\/.+\.rb/
|
41
|
+
@custom = true
|
42
|
+
end
|
43
|
+
if @custom
|
44
|
+
cache_or_call_cached(:failure_message_for_should, &block)
|
45
|
+
else
|
46
|
+
message = "#{example.metadata[:command]}\n"
|
47
|
+
message += "#{example.metadata[:stdout]}"
|
48
|
+
message
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'open3'
|
2
|
-
|
3
1
|
module Serverspec
|
4
2
|
module Backend
|
5
3
|
class Exec
|
@@ -12,17 +10,17 @@ module Serverspec
|
|
12
10
|
end
|
13
11
|
|
14
12
|
def run_command(cmd, opts={})
|
13
|
+
stdout = `#{cmd} 2>&1`
|
15
14
|
# In ruby 1.9, it is possible to use Open3.capture3, but not in 1.8
|
16
15
|
#stdout, stderr, status = Open3.capture3(cmd)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
ret
|
16
|
+
|
17
|
+
if ! @example.nil?
|
18
|
+
@example.metadata[:command] = cmd
|
19
|
+
@example.metadata[:stdout] = stdout
|
20
|
+
end
|
21
|
+
|
22
|
+
{ :stdout => stdout, :stderr => nil,
|
23
|
+
:exit_status => $?, :exit_signal => nil }
|
26
24
|
end
|
27
25
|
|
28
26
|
def check_zero(cmd, *args)
|
@@ -33,11 +31,12 @@ module Serverspec
|
|
33
31
|
# Default action is to call check_zero with args
|
34
32
|
def method_missing(meth, *args, &block)
|
35
33
|
# Remove example object from *args
|
36
|
-
args.shift
|
34
|
+
@example = args.shift
|
37
35
|
check_zero(meth, *args)
|
38
36
|
end
|
39
37
|
|
40
38
|
def check_installed_by_gem(example, package, version)
|
39
|
+
@example = example
|
41
40
|
ret = run_command(commands.check_installed_by_gem(package))
|
42
41
|
res = ret[:exit_status] == 0
|
43
42
|
if res && version
|
@@ -47,6 +46,7 @@ module Serverspec
|
|
47
46
|
end
|
48
47
|
|
49
48
|
def check_running(example, process)
|
49
|
+
@example = example
|
50
50
|
ret = run_command(commands.check_running(process))
|
51
51
|
if ret[:exit_status] == 1 || ret[:stdout] =~ /stopped/
|
52
52
|
ret = run_command(commands.check_process(process))
|
@@ -55,11 +55,13 @@ module Serverspec
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def check_running_under_supervisor(example, process)
|
58
|
+
@example = example
|
58
59
|
ret = run_command(commands.check_running_under_supervisor(process))
|
59
60
|
ret[:exit_status] == 0 && ret[:stdout] =~ /RUNNING/
|
60
61
|
end
|
61
62
|
|
62
63
|
def check_readable(example, file, by_whom)
|
64
|
+
@example = example
|
63
65
|
mode = sprintf('%04s',run_command(commands.get_mode(file))[:stdout].strip)
|
64
66
|
mode = mode.split('')
|
65
67
|
mode_octal = mode[0].to_i * 512 + mode[1].to_i * 64 + mode[2].to_i * 8 + mode[3].to_i * 1
|
@@ -76,6 +78,7 @@ module Serverspec
|
|
76
78
|
end
|
77
79
|
|
78
80
|
def check_writable(example, file, by_whom)
|
81
|
+
@example = example
|
79
82
|
mode = sprintf('%04s',run_command(commands.get_mode(file))[:stdout].strip)
|
80
83
|
mode = mode.split('')
|
81
84
|
mode_octal = mode[0].to_i * 512 + mode[1].to_i * 64 + mode[2].to_i * 8 + mode[3].to_i * 1
|
@@ -92,6 +95,7 @@ module Serverspec
|
|
92
95
|
end
|
93
96
|
|
94
97
|
def check_executable(example, file, by_whom)
|
98
|
+
@example = example
|
95
99
|
mode = sprintf('%04s',run_command(commands.get_mode(file))[:stdout].strip)
|
96
100
|
mode = mode.split('')
|
97
101
|
mode_octal = mode[0].to_i * 512 + mode[1].to_i * 64 + mode[2].to_i * 8 + mode[3].to_i * 1
|
@@ -108,6 +112,7 @@ module Serverspec
|
|
108
112
|
end
|
109
113
|
|
110
114
|
def check_mounted(example, path, expected_attr, only_with)
|
115
|
+
@example = example
|
111
116
|
ret = run_command(commands.check_mounted(path))
|
112
117
|
if expected_attr.nil? || ret[:exit_status] != 0
|
113
118
|
return ret[:exit_status] == 0
|
@@ -5,7 +5,12 @@ module Serverspec
|
|
5
5
|
class Ssh < Exec
|
6
6
|
def run_command(cmd, opt={})
|
7
7
|
cmd = "sudo #{cmd}" if not RSpec.configuration.ssh.options[:user] == 'root'
|
8
|
-
ssh_exec!(cmd)
|
8
|
+
ret = ssh_exec!(cmd)
|
9
|
+
if ! @example.nil?
|
10
|
+
@example.metadata[:command] = cmd
|
11
|
+
@example.metadata[:stdout] = ret[:stdout]
|
12
|
+
end
|
13
|
+
ret
|
9
14
|
end
|
10
15
|
|
11
16
|
private
|
@@ -1,48 +1,55 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
1
3
|
module Serverspec
|
2
4
|
module Commands
|
3
5
|
class Base
|
4
6
|
class NotImplementedError < Exception; end
|
5
7
|
|
8
|
+
def escape target
|
9
|
+
Shellwords.shellescape(target.to_s())
|
10
|
+
end
|
11
|
+
|
6
12
|
def check_enabled service
|
7
13
|
raise NotImplementedError.new
|
8
14
|
end
|
9
15
|
|
10
16
|
def check_mounted path
|
11
|
-
|
17
|
+
regexp = "on #{path}"
|
18
|
+
"mount | grep -w -- #{escape(regexp)}"
|
12
19
|
end
|
13
20
|
|
14
21
|
def check_reachable host, port, proto, timeout
|
15
22
|
if port.nil?
|
16
|
-
"ping -n #{host} -w #{timeout} -c 2"
|
23
|
+
"ping -n #{escape(host)} -w #{escape(timeout)} -c 2"
|
17
24
|
else
|
18
|
-
"nc -vvvvz#{proto[0].chr} #{host} #{port} -w #{timeout}"
|
25
|
+
"nc -vvvvz#{escape(proto[0].chr)} #{escape(host)} #{escape(port)} -w #{escape(timeout)}"
|
19
26
|
end
|
20
27
|
end
|
21
28
|
|
22
29
|
def check_resolvable name, type
|
23
30
|
if type == "dns"
|
24
|
-
"nslookup -timeout=1 #{name}"
|
31
|
+
"nslookup -timeout=1 #{escape(name)}"
|
25
32
|
elsif type == "hosts"
|
26
|
-
"grep -w #{name} /etc/hosts"
|
33
|
+
"grep -w -- #{escape(name)} /etc/hosts"
|
27
34
|
else
|
28
|
-
"getent hosts #{name}"
|
35
|
+
"getent hosts #{escape(name)}"
|
29
36
|
end
|
30
37
|
end
|
31
38
|
|
32
39
|
def check_file file
|
33
|
-
"test -f #{file}"
|
40
|
+
"test -f #{escape(file)}"
|
34
41
|
end
|
35
42
|
|
36
43
|
def check_directory directory
|
37
|
-
"test -d #{directory}"
|
44
|
+
"test -d #{escape(directory)}"
|
38
45
|
end
|
39
46
|
|
40
47
|
def check_user user
|
41
|
-
"id #{user}"
|
48
|
+
"id #{escape(user)}"
|
42
49
|
end
|
43
50
|
|
44
51
|
def check_group group
|
45
|
-
"getent group | grep -wq #{group}"
|
52
|
+
"getent group | grep -wq -- #{escape(group)}"
|
46
53
|
end
|
47
54
|
|
48
55
|
def check_installed package
|
@@ -50,90 +57,91 @@ module Serverspec
|
|
50
57
|
end
|
51
58
|
|
52
59
|
def check_listening port
|
53
|
-
|
60
|
+
regexp = ":#{port} "
|
61
|
+
"netstat -tunl | grep -- #{escape(regexp)}"
|
54
62
|
end
|
55
63
|
|
56
64
|
def check_running service
|
57
|
-
"service #{service} status"
|
65
|
+
"service #{escape(service)} status"
|
58
66
|
end
|
59
67
|
|
60
68
|
def check_running_under_supervisor service
|
61
|
-
"supervisorctl status #{service}"
|
69
|
+
"supervisorctl status #{escape(service)}"
|
62
70
|
end
|
63
71
|
|
64
72
|
def check_process process
|
65
|
-
"ps aux | grep -w #{process} | grep -qv grep"
|
73
|
+
"ps aux | grep -w -- #{escape(process)} | grep -qv grep"
|
66
74
|
end
|
67
75
|
|
68
76
|
def check_file_contain file, expected_pattern
|
69
|
-
"grep -q
|
77
|
+
"grep -q -- #{escape(expected_pattern)} #{escape(file)}"
|
70
78
|
end
|
71
79
|
|
72
80
|
def check_file_contain_within file, expected_pattern, from=nil, to=nil
|
73
81
|
from ||= '1'
|
74
82
|
to ||= '$'
|
75
83
|
checker = check_file_contain("-", expected_pattern)
|
76
|
-
"sed -n
|
84
|
+
"sed -n #{escape(from)},#{escape(to)}p #{escape(file)} | #{checker}"
|
77
85
|
end
|
78
86
|
|
79
87
|
def check_mode file, mode
|
80
|
-
|
88
|
+
regexp = "^#{mode}$"
|
89
|
+
"stat -c %a #{escape(file)} | grep -- #{escape(regexp)}"
|
81
90
|
end
|
82
91
|
|
83
92
|
def check_owner file, owner
|
84
|
-
|
93
|
+
regexp = "^#{owner}$"
|
94
|
+
"stat -c %U #{escape(file)} | grep -- #{escape(regexp)}"
|
85
95
|
end
|
86
96
|
|
87
97
|
def check_grouped file, group
|
88
|
-
|
98
|
+
regexp = "^#{group}$"
|
99
|
+
"stat -c %G #{escape(file)} | grep -- #{escape(regexp)}"
|
89
100
|
end
|
90
101
|
|
91
102
|
def check_cron_entry user, entry
|
92
103
|
entry_escaped = entry.gsub(/\*/, '\\*')
|
93
|
-
"crontab -u #{user} -l | grep
|
104
|
+
"crontab -u #{escape(user)} -l | grep -- #{escape(entry_escaped)}"
|
94
105
|
end
|
95
106
|
|
96
107
|
def check_link link, target
|
97
|
-
"stat -c %N #{link} | grep #{target}"
|
108
|
+
"stat -c %N #{escape(link)} | grep -- #{escape(target)}"
|
98
109
|
end
|
99
110
|
|
100
111
|
def check_installed_by_gem name
|
101
|
-
|
112
|
+
gem_name = "^#{name} "
|
113
|
+
"gem list --local | grep -- #{escape(gem_name)}"
|
102
114
|
end
|
103
115
|
|
104
116
|
def check_belonging_group user, group
|
105
|
-
"id #{user} | awk '{print $3}' | grep #{group}"
|
117
|
+
"id #{escape(user)} | awk '{print $3}' | grep -- #{escape(group)}"
|
106
118
|
end
|
107
119
|
|
108
120
|
def check_gid group, gid
|
109
|
-
|
121
|
+
regexp = "^#{group}"
|
122
|
+
"getent group | grep -w -- #{escape(regexp)} | cut -f 3 -d ':' | grep -w -- #{escape(gid)}"
|
110
123
|
end
|
111
124
|
|
112
125
|
def check_uid user, uid
|
113
|
-
|
126
|
+
regexp = "^uid=#{uid}("
|
127
|
+
"id #{escape(user)} | grep -- #{escape(regexp)}"
|
114
128
|
end
|
115
129
|
|
116
130
|
def check_login_shell user, path_to_shell
|
117
|
-
"getent passwd #{user} | cut -f 7 -d ':' | grep -w #{path_to_shell}"
|
131
|
+
"getent passwd #{escape(user)} | cut -f 7 -d ':' | grep -w -- #{escape(path_to_shell)}"
|
118
132
|
end
|
119
133
|
|
120
134
|
def check_home_directory user, path_to_home
|
121
|
-
"getent passwd #{user} | cut -f 6 -d ':' | grep -w #{path_to_home}"
|
135
|
+
"getent passwd #{escape(user)} | cut -f 6 -d ':' | grep -w -- #{escape(path_to_home)}"
|
122
136
|
end
|
123
137
|
|
124
138
|
def check_authorized_key user, key
|
125
139
|
key.sub!(/\s+\S*$/, '') if key.match(/^\S+\s+\S+\s+\S*$/)
|
126
|
-
"grep -w
|
140
|
+
"grep -w -- #{escape(key)} ~#{escape(user)}/.ssh/authorized_keys"
|
127
141
|
end
|
128
142
|
|
129
143
|
def check_iptables_rule rule, table=nil, chain=nil
|
130
|
-
|
131
|
-
cmd += " -t #{table}" if table
|
132
|
-
cmd += " -S"
|
133
|
-
cmd += " #{chain}" if chain
|
134
|
-
rule.gsub!(/\-/, '\\-')
|
135
|
-
cmd += " | grep '#{rule}'"
|
136
|
-
cmd
|
144
|
+
raise NotImplementedError.new
|
137
145
|
end
|
138
146
|
|
139
147
|
def check_zfs zfs, property=nil, value=nil
|
@@ -141,7 +149,7 @@ module Serverspec
|
|
141
149
|
end
|
142
150
|
|
143
151
|
def get_mode(file)
|
144
|
-
"stat -c %a #{file}"
|
152
|
+
"stat -c %a #{escape(file)}"
|
145
153
|
end
|
146
154
|
|
147
155
|
def check_ipfilter_rule rule
|
@@ -161,7 +169,7 @@ module Serverspec
|
|
161
169
|
end
|
162
170
|
|
163
171
|
def check_selinux mode
|
164
|
-
|
172
|
+
raise NotImplementedError.new
|
165
173
|
end
|
166
174
|
end
|
167
175
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module Serverspec
|
2
2
|
module Commands
|
3
|
-
class Debian <
|
3
|
+
class Debian < Linux
|
4
4
|
def check_enabled service
|
5
|
-
"ls /etc/rc3.d/ | grep #{service}"
|
5
|
+
"ls /etc/rc3.d/ | grep -- #{escape(service)}"
|
6
6
|
end
|
7
7
|
|
8
8
|
def check_installed package
|
9
|
-
"dpkg -s #{package}"
|
9
|
+
"dpkg -s #{escape(package)}"
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -1,16 +1,17 @@
|
|
1
1
|
module Serverspec
|
2
2
|
module Commands
|
3
|
-
class Gentoo <
|
3
|
+
class Gentoo < Linux
|
4
4
|
def check_enabled service
|
5
|
-
|
5
|
+
regexp = "^\\s*#{service}\\s*|\\s*\\(boot\\|default\\)"
|
6
|
+
"/sbin/rc-update show | grep -- #{escape(regexp)}"
|
6
7
|
end
|
7
8
|
|
8
9
|
def check_installed package
|
9
|
-
"/usr/bin/eix #{package} --installed"
|
10
|
+
"/usr/bin/eix #{escape(package)} --installed"
|
10
11
|
end
|
11
12
|
|
12
13
|
def check_running service
|
13
|
-
"/etc/init.d/#{service} status"
|
14
|
+
"/etc/init.d/#{escape(service)} status"
|
14
15
|
end
|
15
16
|
end
|
16
17
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
module Serverspec
|
4
|
+
module Commands
|
5
|
+
class Linux < Base
|
6
|
+
class NotImplementedError < Exception; end
|
7
|
+
|
8
|
+
def check_iptables_rule rule, table=nil, chain=nil
|
9
|
+
cmd = "iptables"
|
10
|
+
cmd += " -t #{escape(table)}" if table
|
11
|
+
cmd += " -S"
|
12
|
+
cmd += " #{escape(chain)}" if chain
|
13
|
+
cmd += " | grep -- #{escape(rule)}"
|
14
|
+
cmd
|
15
|
+
end
|
16
|
+
|
17
|
+
def check_selinux mode
|
18
|
+
"/usr/sbin/getenforce | grep -i -- #{escape(mode)}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module Serverspec
|
2
2
|
module Commands
|
3
|
-
class RedHat <
|
3
|
+
class RedHat < Linux
|
4
4
|
def check_enabled service
|
5
|
-
"chkconfig --list #{service} | grep 3:on"
|
5
|
+
"chkconfig --list #{escape(service)} | grep 3:on"
|
6
6
|
end
|
7
7
|
|
8
8
|
def check_installed package
|
9
|
-
"rpm -q #{package}"
|
9
|
+
"rpm -q #{escape(package)}"
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -2,54 +2,59 @@ module Serverspec
|
|
2
2
|
module Commands
|
3
3
|
class Solaris < Base
|
4
4
|
def check_enabled service
|
5
|
-
"svcs -l #{service} 2> /dev/null | grep 'enabled true'"
|
5
|
+
"svcs -l #{escape(service)} 2> /dev/null | grep 'enabled true'"
|
6
6
|
end
|
7
7
|
|
8
8
|
def check_installed package
|
9
|
-
"pkg list -H #{package} 2> /dev/null"
|
9
|
+
"pkg list -H #{escape(package)} 2> /dev/null"
|
10
10
|
end
|
11
11
|
|
12
12
|
def check_listening port
|
13
|
-
|
13
|
+
regexp = "\.#{port} "
|
14
|
+
"netstat -an 2> /dev/null | egrep 'LISTEN|Idle' | grep -- #{escape(regexp)}"
|
14
15
|
end
|
15
16
|
|
16
17
|
def check_running service
|
17
|
-
"svcs -l #{service} status 2> /dev/null |grep 'state online'"
|
18
|
+
"svcs -l #{escape(service)} status 2> /dev/null |grep 'state online'"
|
18
19
|
end
|
19
20
|
|
20
21
|
def check_cron_entry user, entry
|
21
22
|
entry_escaped = entry.gsub(/\*/, '\\*')
|
22
|
-
"crontab -l #{user} | grep
|
23
|
+
"crontab -l #{escape(user)} | grep -- #{escape(entry_escaped)}"
|
23
24
|
end
|
24
25
|
|
25
26
|
def check_zfs zfs, property=nil
|
26
27
|
if property.nil?
|
27
|
-
"/sbin/zfs list -H #{zfs}"
|
28
|
+
"/sbin/zfs list -H #{escape(zfs)}"
|
28
29
|
else
|
29
30
|
commands = []
|
30
31
|
property.sort.each do |key, value|
|
31
|
-
|
32
|
+
regexp = "^#{value}$"
|
33
|
+
commands << "/sbin/zfs list -H -o #{escape(key)} #{escape(zfs)} | grep -- #{escape(regexp)}"
|
32
34
|
end
|
33
35
|
commands.join(' && ')
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
37
39
|
def check_ipfilter_rule rule
|
38
|
-
"/sbin/ipfstat -io 2> /dev/null | grep
|
40
|
+
"/sbin/ipfstat -io 2> /dev/null | grep -- #{escape(rule)}"
|
39
41
|
end
|
40
42
|
|
41
43
|
def check_ipnat_rule rule
|
42
|
-
|
44
|
+
regexp = "^#{rule}$"
|
45
|
+
"/sbin/ipnat -l 2> /dev/null | grep -- #{escape(regexp)}"
|
43
46
|
end
|
44
47
|
|
45
48
|
def check_svcprop svc, property, value
|
46
|
-
|
49
|
+
regexp = "^#{value}$"
|
50
|
+
"svcprop -p #{escape(property)} #{escape(svc)} | grep -- #{escape(regexp)}"
|
47
51
|
end
|
48
52
|
|
49
53
|
def check_svcprops svc, property
|
50
54
|
commands = []
|
51
55
|
property.sort.each do |key, value|
|
52
|
-
|
56
|
+
regexp = "^#{value}$"
|
57
|
+
commands << "svcprop -p #{escape(key)} #{escape(svc)} | grep -- #{escape(regexp)}"
|
53
58
|
end
|
54
59
|
commands.join(' && ')
|
55
60
|
end
|
@@ -58,23 +63,24 @@ module Serverspec
|
|
58
63
|
from ||= '1'
|
59
64
|
to ||= '$'
|
60
65
|
checker = check_file_contain("/dev/stdin", expected_pattern)
|
61
|
-
"sed -n
|
66
|
+
"sed -n #{escape(from)},#{escape(to)}p #{escape(file)} | #{checker}"
|
62
67
|
end
|
63
68
|
|
64
69
|
def check_belonging_group user, group
|
65
|
-
"id -Gn #{user} | grep #{group}"
|
70
|
+
"id -Gn #{escape(user)} | grep -- #{escape(group)}"
|
66
71
|
end
|
67
72
|
|
68
73
|
def check_gid group, gid
|
69
|
-
|
74
|
+
regexp = "^#{group}:"
|
75
|
+
"getent group | grep -- #{escape(regexp)} | cut -f 3 -d ':' | grep -w -- #{escape(gid)}"
|
70
76
|
end
|
71
77
|
|
72
78
|
def check_home_directory user, path_to_home
|
73
|
-
"getent passwd #{user} | cut -f 6 -d ':' | grep -w #{path_to_home}"
|
79
|
+
"getent passwd #{escape(user)} | cut -f 6 -d ':' | grep -w -- #{escape(path_to_home)}"
|
74
80
|
end
|
75
81
|
|
76
82
|
def check_login_shell user, path_to_shell
|
77
|
-
"getent passwd #{user} | cut -f 7 -d ':' | grep -w #{path_to_shell}"
|
83
|
+
"getent passwd #{escape(user)} | cut -f 7 -d ':' | grep -w -- #{escape(path_to_shell)}"
|
78
84
|
end
|
79
85
|
end
|
80
86
|
end
|