linux_stat 0.4.0 → 0.6.2

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.
@@ -0,0 +1,75 @@
1
+ module LinuxStat
2
+ module PrettifyBytes
3
+ class << self
4
+ # Converts a number to decimal byte units and outputs with the metric prefix
5
+ # For example,
6
+ #
7
+ # LinuxStat::PrettifyBytes.convert_decimal(1000) # => "1.0 kilobyte"
8
+ # LinuxStat::PrettifyBytes.convert_decimal(1000 ** 3) # => "1.0 gigabyte"
9
+ # LinuxStat::PrettifyBytes.convert_decimal(1024 ** 3) # => "1.07 gigabytes"
10
+ def convert_decimal(n)
11
+ @@d_units ||= %W(#{''} kilo mega giga tera peta exa zetta)
12
+ .map.with_index { |x, i| [x, 1000.**(i + 1)] }
13
+ unit = @@d_units.find { |x| n < x[1] } || ['yotta'.freeze, 10 ** 27]
14
+
15
+ converted = n.fdiv(unit[1] / 1000).round(2)
16
+ "#{pad_left(converted)} #{unit[0]}byte#{?s.freeze if converted != 1}"
17
+ end
18
+
19
+ # Converts a number to binary byte units and outputs with the IEC prefix
20
+ # For example,
21
+ #
22
+ # LinuxStat::PrettifyBytes.convert_binary(1000) # => "1000.0 bytes"
23
+ # LinuxStat::PrettifyBytes.convert_binary(1000 ** 3) # => "953.67 mebibytes"
24
+ # LinuxStat::PrettifyBytes.convert_binary(1024 ** 3) # => "1.0 gibibyte"
25
+ def convert_binary(n)
26
+ @@b_units ||= %W(#{''} kibi mebi gibi tebi pebi exbi zebi)
27
+ .map.with_index { |x, i| [x, 1024.**(i + 1)] }
28
+ unit = @@b_units.find { |x| n < x[1] } || ['yobi'.freeze, 10 ** 27]
29
+
30
+ converted = n.fdiv(unit[1] / 1024).round(2)
31
+ "#{pad_left(converted)} #{unit[0]}byte#{?s.freeze if converted != 1}"
32
+ end
33
+
34
+ # Converts a number to decimal byte units
35
+ # For example,
36
+ #
37
+ # LinuxStat::PrettifyBytes.convert_short_decimal(1000) # => "1.0 kB"
38
+ # LinuxStat::PrettifyBytes.convert_short_decimal(1000 ** 3) # => "1.0 GB"
39
+ # LinuxStat::PrettifyBytes.convert_short_decimal(1024 ** 3) # => "1.07 GB"
40
+ def convert_short_decimal(n)
41
+ @@sd_units ||= %W(#{''} k M G T P E Z)
42
+ .map.with_index { |x, i| [x, 1000.**(i + 1)] }
43
+ unit = @@sd_units.find { |x| n < x[1] } || [?Y.freeze, 10 ** 27]
44
+
45
+ converted = n.fdiv(unit[1] / 1000).round(2)
46
+ "#{pad_left(converted)} #{unit[0]}B"
47
+ end
48
+
49
+ # Converts a number to binary byte units
50
+ # For example,
51
+ #
52
+ # LinuxStat::PrettifyBytes.convert_short_binary(1000) # => "1000 B"
53
+ # LinuxStat::PrettifyBytes.convert_short_binary(1000 ** 3) # => "953.67 MiB"
54
+ # LinuxStat::PrettifyBytes.convert_short_binary(1024 ** 3) # => "1.0 GiB"
55
+ def convert_short_binary(n)
56
+ return "#{n} B" if n < 1024
57
+
58
+ @@sb_units ||= %W(#{''} K M G T P E Z)
59
+ .map.with_index { |x, i| [x, 1024.**(i + 1)] }
60
+ unit = @@sb_units.find { |x| n < x[1] } || [?Y.freeze, 1024 ** 9]
61
+
62
+ converted = n.fdiv(unit[1] / 1024).round(2)
63
+ "#{pad_left(converted)} #{unit[0]}iB"
64
+ end
65
+
66
+ private
67
+ def pad_left(n, mantissa_length = 2)
68
+ n = n.round(mantissa_length)
69
+ exp, mant = n.to_s.split(?..freeze)
70
+ m = mant.length < mantissa_length ? mant + ?0.freeze * (mantissa_length - mant.length) : mant
71
+ exp + ?..freeze + m
72
+ end
73
+ end
74
+ end
75
+ end
@@ -70,10 +70,10 @@ module LinuxStat
70
70
  # By default it is the id of the current process ($$)
71
71
  #
72
72
  # It retuns the memory, virtual memory, and resident memory of the process.
73
- # All values are in Kilobytes.
73
+ # All values are in kilobytes.
74
74
  #
75
75
  # The output is a Hash. For example, a sample output:
76
- # {:memory=>8656, :virtual_memory=>78272, :resident_memory=>14072}
76
+ # {:memory=>8515.584, :virtual_memory=>79781.888, :resident_memory=>13955.072}
77
77
  #
78
78
  # Note:
79
79
  # If you need only memory usage of a process, run LinuxStat::ProcessInfo.memory(pid)
@@ -85,34 +85,22 @@ module LinuxStat
85
85
  #
86
86
  # If the info isn't available it will return an empty Hash.
87
87
  def mem_stat(pid = $$)
88
- stat_file = "/proc/#{pid}/stat".freeze
89
- status_file = "/proc/#{pid}/status".freeze
88
+ statm = "/proc/#{pid}/statm".freeze
90
89
 
91
- stat = if File.readable?(stat_file)
92
- IO.read(stat_file).split
90
+ data = if File.readable?(statm)
91
+ IO.read(statm).split
93
92
  else
94
- []
93
+ return {}
95
94
  end
96
95
 
97
- status = if File.readable?(status_file)
98
- IO.readlines(status_file)
99
- else
100
- []
101
- end
102
-
103
- _rss_anon = status.find { |x| x.start_with?('RssAnon') }
104
- rss_anon = _rss_anon ? _rss_anon.split[1].to_i : nil
105
-
106
- _virtual_memory = stat[22]
107
- vm = _virtual_memory ? _virtual_memory.to_i.fdiv(1024).to_i : nil
108
-
109
- _vm_rss = status.find { |x| x.start_with?('VmRSS') }
110
- vm_rss = _vm_rss ? _vm_rss.split[1].to_i : nil
96
+ _rss_anon = (data[1] && data[2]) ? data[1].to_i.-(data[2].to_i).*(pagesize).fdiv(1000) : nil
97
+ _virtual_memory = data[0] ? data[0].to_i*(pagesize).fdiv(1000) : nil
98
+ _resident_memory = data[1] ? data[1].to_i.*(pagesize).fdiv(1000) : nil
111
99
 
112
100
  {
113
- memory: rss_anon,
114
- virtual_memory: vm,
115
- resident_memory: vm_rss
101
+ memory: _rss_anon,
102
+ virtual_memory: _virtual_memory,
103
+ resident_memory: _resident_memory
116
104
  }
117
105
  end
118
106
 
@@ -121,16 +109,17 @@ module LinuxStat
121
109
  # By default it is the id of the current process ($$)
122
110
  #
123
111
  # It retuns the memory of the process.
124
- # The value is in Kilobytes.
112
+ # The value is in kilobytes.
125
113
  # The output is an Integer. For example, a sample output:
126
- # 8664
114
+ # 8523.776
127
115
  #
128
116
  # If the info isn't available it will return nil.
129
117
  def memory(pid = $$)
130
- _rss_anon = IO.readlines("/proc/#{pid}/status")
131
- .find { |x| x.start_with?('RssAnon') }
118
+ file = "/proc/#{pid}/statm".freeze
119
+ return nil unless File.readable?(file)
132
120
 
133
- _rss_anon ? _rss_anon.split[1].to_i : nil
121
+ data = IO.read(file).split
122
+ (data[1] && data[2]) ? data[1].to_i.-(data[2].to_i).*(pagesize).fdiv(1000) : nil
134
123
  end
135
124
 
136
125
  # virtual_memory(pid = $$)
@@ -138,14 +127,17 @@ module LinuxStat
138
127
  # By default it is the id of the current process ($$)
139
128
  #
140
129
  # It retuns the virtual memory for the process.
141
- # The value is in Kilobytes.
130
+ # The value is in kilobytes.
142
131
  # The output is an Integer. For example, a sample output:
143
- # 78376
132
+ # 79781.888
144
133
  #
145
134
  # If the info isn't available it will return nil.
146
135
  def virtual_memory(pid = $$)
147
- _virtual_memory = IO.read("/proc/#{pid}/stat".freeze).split[22]
148
- _virtual_memory ? _virtual_memory.to_i.fdiv(1024).to_i : nil
136
+ file = "/proc/#{pid}/statm".freeze
137
+ return nil unless File.readable?(file)
138
+
139
+ _virtual_memory = IO.read(file).split[0]
140
+ _virtual_memory ? _virtual_memory.to_i.*(pagesize).fdiv(1000) : nil
149
141
  end
150
142
 
151
143
  # resident_memory(pid = $$)
@@ -153,21 +145,24 @@ module LinuxStat
153
145
  # By default it is the id of the current process ($$)
154
146
  #
155
147
  # It retuns the resident memory for the process.
156
- # The value is in Kilobytes.
148
+ # The value is in kilobytes.
157
149
  # The output is an Integer. For example, a sample output:
158
- # 14012
150
+ # 13996.032
159
151
  #
160
152
  # If the info isn't available it will return nil.
161
153
  def resident_memory(pid = $$)
162
- _vm_rss = IO.readlines("/proc/#{pid}/status")
163
- .find { |x| x.start_with?('VmRSS') }
154
+ file = "/proc/#{pid}/statm".freeze
155
+ return nil unless File.readable?(file)
164
156
 
165
- _vm_rss ? _vm_rss.split[1].to_i : nil
157
+ _vm_rss = IO.read(file).split[1]
158
+ _vm_rss ? _vm_rss.to_i.*(pagesize).fdiv(1000) : nil
166
159
  end
167
160
 
168
- # cpu_stat(pid: $$, sleep: 0.05)
161
+ # cpu_stat(pid: $$, sleep: 1.0 / LinuxStat::Sysconf.sc_clk_tck)
169
162
  # Where pid is the process ID and sleep time is the interval between measurements.
170
- # By default it is the id of the current process ($$), and sleep is 0.05
163
+ #
164
+ # By default it is the id of the current process ($$), and sleep is LinuxStat::Sysconf.sc_clk_tck
165
+ # The smallest amount of available sleep time is 1.0 / LinuxStat::Sysconf.sc_clk_tck.
171
166
  #
172
167
  # Note 1:
173
168
  # Do note that the sleep time can slow down your application.
@@ -197,7 +192,7 @@ module LinuxStat
197
192
  #
198
193
  # The :last_executed_cpu also returns an Integer indicating
199
194
  # the last executed cpu of the process.
200
- def cpu_stat(pid: $$, sleep: 0.05)
195
+ def cpu_stat(pid: $$, sleep: ticks_to_ms)
201
196
  file = "/proc/#{pid}/stat"
202
197
  return {} unless File.readable?(file)
203
198
 
@@ -229,9 +224,11 @@ module LinuxStat
229
224
  }
230
225
  end
231
226
 
232
- # cpu_usage(pid: $$, sleep: 0.05)
227
+ # cpu_usage(pid: $$, sleep: 1.0 / LinuxStat::Sysconf.sc_clk_tck)
233
228
  # Where pid is the process ID and sleep time is the interval between measurements.
234
- # By default it is the id of the current process ($$), and sleep is 0.05
229
+ #
230
+ # By default it is the id of the current process ($$), and sleep is 1.0 / LinuxStat::Sysconf.sc_clk_tck
231
+ # The smallest amount of available sleep time is LinuxStat::Sysconf.sc_clk_tck.
235
232
  #
236
233
  # It retuns the CPU usage in Float.
237
234
  # For example:
@@ -241,7 +238,7 @@ module LinuxStat
241
238
  # But if the info isn't available, it will return nil.
242
239
  #
243
240
  # This method is more efficient than running LinuxStat::ProcessInfo.cpu_stat()
244
- def cpu_usage(pid: $$, sleep: 0.05)
241
+ def cpu_usage(pid: $$, sleep: ticks_to_ms)
245
242
  file = "/proc/#{pid}/stat"
246
243
  return nil unless File.readable?(file)
247
244
 
@@ -281,7 +278,8 @@ module LinuxStat
281
278
  file = "/proc/#{pid}/stat".freeze
282
279
  return nil unless File.readable?(file)
283
280
 
284
- IO.read(file).split[19].to_i
281
+ data = IO.read(file).split[19]
282
+ data ? data.to_i : nil
285
283
  end
286
284
 
287
285
  # last_executed_cpu(pid = $$)
@@ -298,13 +296,77 @@ module LinuxStat
298
296
  file = "/proc/#{pid}/stat".freeze
299
297
  return nil unless File.readable?(file)
300
298
 
301
- IO.read("/proc/#{pid}/stat".freeze).split[38].to_i
299
+ IO.read(file).split[38].to_i
300
+ end
301
+
302
+ # uid(pid = $$)
303
+ # returns the UIDs of the process as an Array of Integers.
304
+ #
305
+ # If the info isn't available it returns an empty Array.
306
+ def uid(pid = $$)
307
+ file = "/proc/#{pid}/status".freeze
308
+ return nil unless File.readable?(file)
309
+
310
+ data = IO.readlines(file.freeze).find { |x|
311
+ x[/Uid.*\d*/]
312
+ }.to_s.split.drop(1)
313
+
314
+ {
315
+ real: data[0].to_i,
316
+ effective: data[1].to_i,
317
+ saved_set: data[2].to_i,
318
+ filesystem_uid: data[3].to_i
319
+ }
320
+ end
321
+
322
+ # gid(pid = $$)
323
+ # returns the GIDs of the process as an Hash containing the following data:
324
+ # :real, :effective, :saved_set, :filesystem_uid
325
+ #
326
+ # If the info isn't available it returns an empty Hash.
327
+ def gid(pid = $$)
328
+ file = "/proc/#{pid}/status".freeze
329
+ return nil unless File.readable?(file)
330
+
331
+ data = IO.readlines(file.freeze).find { |x|
332
+ x[/Gid.*\d*/]
333
+ }.split.drop(1)
334
+
335
+ {
336
+ real: data[0].to_i,
337
+ effective: data[1].to_i,
338
+ saved_set: data[2].to_i,
339
+ filesystem_uid: data[3].to_i
340
+ }
341
+ end
342
+
343
+ # owner(pid = $$)
344
+ # Returns the owner of the process
345
+ # But if the status is not available, it will return an empty frozen String.
346
+ def owner(pid = $$)
347
+ file = "/proc/#{pid}/status".freeze
348
+ return ''.freeze unless File.readable?(file)
349
+
350
+ gid = IO.readlines(file.freeze).find { |x|
351
+ x[/Gid.*\d*/]
352
+ }.split.drop(1)[2].to_i
353
+
354
+ LinuxStat::User.username_by_gid(gid)
302
355
  end
303
356
 
304
357
  private
305
358
  def get_ticks
306
359
  @@ticks ||= Sysconf.sc_clk_tck
307
360
  end
361
+
362
+ # Just to avoid multiple calculations!...
363
+ def ticks_to_ms
364
+ @@ms ||= 1.0 / get_ticks
365
+ end
366
+
367
+ def pagesize
368
+ @@pagesize ||= LinuxStat::Sysconf.pagesize
369
+ end
308
370
  end
309
371
  end
310
372
  end
@@ -0,0 +1,298 @@
1
+ module LinuxStat
2
+ module User
3
+ class << self
4
+ # Returns an array of users as string
5
+ # For example:
6
+ # ["root", "bin", "daemon", "mail", "ftp", "http", "nobody"]
7
+ # But if the status isn't available it will return an empty Array.
8
+ def list
9
+ return [] unless passwd_readable?
10
+ passwd.map { |x| x[/.+?:/][0..-2].freeze }
11
+ end
12
+
13
+ # Returns all the Group ids directories as Hash.
14
+ # For example:
15
+ # {:root=>{:uid=>0, :gid=>0}, :bin=>{:uid=>1, :gid=>1}, :daemon=>{:uid=>2, :gid=>2}, :mail=>{:uid=>8, :gid=>12}, :ftp=>{:uid=>14, :gid=>11}}
16
+ #
17
+ # But if the status isn't available it will return an empty Hash.
18
+ def ids
19
+ return {} unless passwd_readable?
20
+ passwd_splitted.reduce({}) { |h, x|
21
+ h.merge!(x[0].to_sym => {
22
+ uid: x[2].to_i, gid: x[3].to_i
23
+ })
24
+ }
25
+ end
26
+
27
+ # Returns all the user IDs as Hash.
28
+ # For example:
29
+ # LinuxStat::User.uids
30
+ # => {:root=>0, :bin=>1, :daemon=>2, :mail=>8, :ftp=>14}
31
+ #
32
+ # But if the status isn't available it will return an empty Hash.
33
+ def uids
34
+ return {} unless passwd_readable?
35
+ passwd_splitted.reduce({}) { |h, x|
36
+ h.merge!(x[0].to_sym => x[2].to_i)
37
+ }
38
+ end
39
+
40
+ # Returns all the Group identifiers as Hash.
41
+ # For example:
42
+ # LinuxStat::User.gids
43
+ # => {:root=>0, :bin=>1, :daemon=>2, :mail=>12, :ftp=>11}
44
+ #
45
+ # But if the status isn't available it will return an empty Hash.
46
+ def gids
47
+ return {} unless passwd_readable?
48
+ passwd_splitted.reduce({}) { |h, x|
49
+ h.merge!(x[0].to_sym => x[3].to_i)
50
+ }
51
+ end
52
+
53
+ # Returns all the home directories as Hash.
54
+ # For example:
55
+ # LinuxStat::User.home_directories
56
+ # => {:root=>"/root", :bin=>"/", :daemon=>"/", :mail=>"/var/spool/mail", :ftp=>"/srv/ftp", :http=>"/srv/http", :nobody=>"/"}
57
+ #
58
+ # But if the status isn't available it will return an empty Hash.
59
+ def home_directories
60
+ return {} unless passwd_readable?
61
+ passwd.reduce({}) { |h, x|
62
+ splitted = x.split(?:)
63
+ h.merge!(splitted[0].to_sym => splitted[5])
64
+ }
65
+ end
66
+
67
+ # Returns the user ID as integer
68
+ # It directly calls LinuxStat::Sysconf.get_uid and LinuxStat::Sysconf.get_gid
69
+ # and then reads /etc/passwd and matches the values with UID and GID.
70
+ #
71
+ # It doesn't get affected with the assignment of USER environment variable
72
+ # If either /etc/passwd is readable or LinuxStat::Sysconf.get_login() is not empty.
73
+ #
74
+ # But if /etc/passwd isn't readable (which is weird), it will fall back to sysconf.h's get_login()
75
+ # It that's not available, like in docker, falls back to ENV['USER].to_s
76
+ #
77
+ # Note that this is not cached or memoized so use this at your own processing expense.
78
+ # It should return the username under most robust circumstances.
79
+ # But if nothing is available for some reason, it will return an empty String.
80
+ def get_user
81
+ unless passwd_readable?
82
+ _l = LinuxStat::Sysconf.get_login().freeze
83
+ return _l.empty? ? ENV['USER'.freeze].to_s : _l
84
+ end
85
+
86
+ uid, gid = LinuxStat::Sysconf.get_uid, LinuxStat::Sysconf.get_gid
87
+
88
+ username = ''
89
+ passwd.each { |x|
90
+ splitted = x.split(?:).freeze
91
+ if splitted[2].to_i == uid && splitted[3].to_i == gid
92
+ username = splitted[0]
93
+ break
94
+ end
95
+ }
96
+ username
97
+ end
98
+
99
+ # Returns the user ID as integer
100
+ # It directly calls LinuxStat::Sysconf.get_uid
101
+ def get_uid
102
+ LinuxStat::Sysconf.get_uid
103
+ end
104
+
105
+ # Returns the group ID as integer
106
+ # It directly calls LinuxStat::Sysconf.get_uid
107
+ def get_gid
108
+ LinuxStat::Sysconf.get_gid
109
+ end
110
+
111
+ # Returns the effective user ID as integer
112
+ # It directly calls LinuxStat::Sysconf.get_euid
113
+ def get_euid
114
+ LinuxStat::Sysconf.get_euid
115
+ end
116
+
117
+ # Calls LinuxStat::Sysconf.get_login()
118
+ # The username is returned as a String.
119
+ # It doesn't get affected by ENV['USER]
120
+ #
121
+ # But if the name isn't available (say inside a container), it will return an empty String.
122
+ # This is meant for speed but not for reliability.
123
+ # To get more reliable output, you might try LinuxStat::User.get_user()
124
+ def get_login
125
+ LinuxStat::Sysconf.get_login
126
+ end
127
+
128
+ # def usernames_by_uid(gid = get_uid)
129
+ # Where uid is the group id of the user. By default it's the uid of the current user.
130
+ #
131
+ # It returns an Array containing the username corresponding to the uid.
132
+ #
133
+ # For example:
134
+ # LinuxStat::User.usernames_by_uid(1001)
135
+ # => ["userx", "usery"]
136
+ #
137
+ # But if the info isn't available it will return an empty Array.
138
+ def usernames_by_uid(uid = get_uid)
139
+ return [] unless passwd_readable?
140
+
141
+ usernames = []
142
+ passwd_splitted.each { |x|
143
+ usernames << x[0] if x[2].to_i == uid
144
+ }
145
+ usernames
146
+ end
147
+
148
+ # def username_by_gid(gid = get_gid)
149
+ # Where gid is the group id of the user. By default it's the gid of the current user.
150
+ #
151
+ # It returns a String cotaining the username corresponding to the gid
152
+ # But if the info isn't available it will return an empty frozen String.
153
+ def username_by_gid(gid = get_gid)
154
+ return ''.freeze unless passwd_readable?
155
+
156
+ username = ''
157
+ passwd.each do |x|
158
+ splitted = x.split(?:.freeze)
159
+ if splitted[2].to_i == gid
160
+ username = splitted[0]
161
+ break
162
+ end
163
+ end
164
+ username
165
+ end
166
+
167
+ # gid_by_username(username = get_user)
168
+ # Where username is the username to look for, by default it is the current user.
169
+ #
170
+ # It returns the gid by the username.
171
+ # For example:
172
+ # LinuxStat::User.gid_by_username('root')
173
+ # => "0"
174
+ #
175
+ # The return type is Integer.
176
+ # But if user passed doesn't exist or if the info isn't available, it will return nil.
177
+ def gid_by_username(username = get_user)
178
+ return nil unless passwd_readable?
179
+
180
+ gid = nil
181
+ passwd.each do |x|
182
+ splitted = x.split(?:.freeze)
183
+ if splitted[0] == username
184
+ gid = splitted[3].to_i
185
+ break
186
+ end
187
+ end
188
+ gid
189
+ end
190
+
191
+ # uid_by_username(username = get_user)
192
+ # Where username is the username to look for, by default it is the current user.
193
+ #
194
+ # It returns the uid by the username.
195
+ # For example:
196
+ # LinuxStat::User.uid_by_username('root')
197
+ # => 0
198
+ #
199
+ # The return type is Integer.
200
+ # But if user passed doesn't exist or if the info isn't available, it will return nil.
201
+ def uid_by_username(username = get_user)
202
+ return nil unless passwd_readable?
203
+
204
+ uid = nil
205
+ passwd.each do |x|
206
+ splitted = x.split(?:.freeze)
207
+ if splitted[0] == username
208
+ uid = splitted[2].to_i
209
+ break
210
+ end
211
+ end
212
+ uid
213
+ end
214
+
215
+ # home_by_username(user = get_user)
216
+ # Where user is the name of the user.
217
+ # Returns the user's home. By default it returns the home of the current user.
218
+ #
219
+ # If the info isn't available, it will return ENV['HOME].to_s.freeze
220
+ def home_by_username(user = get_user)
221
+ return ENV['HOME'].to_s.freeze unless passwd_readable?
222
+
223
+ home = ''
224
+ passwd.each { |x|
225
+ splitted = x.split(?:)
226
+ if splitted[0] == user
227
+ home = splitted[5]
228
+ break
229
+ end
230
+ }
231
+ home
232
+ end
233
+
234
+ # home_by_uid(id = get_uid)
235
+ # Gets all the users home directory with user id.
236
+ # It returns an Array in this format:
237
+ # LinuxStat::User.homes_by_uid(1001)
238
+ # => ["/home/userx", "/home/usery"]
239
+ #
240
+ # Assuming both the users share same UID.
241
+ #
242
+ # If the info isn't available, it will return an empty Array.
243
+ def homes_by_uid(id = get_uid)
244
+ return [] unless passwd_readable?
245
+
246
+ home = []
247
+ passwd.each do |x|
248
+ splitted = x.split(?:.freeze)
249
+ home << splitted[5] if splitted[2].to_i == id
250
+ end
251
+ home
252
+ end
253
+
254
+ # home_by_gid(id = get_uid)
255
+ # Gets the home of the user corresponding to the GID.
256
+ # It returns a String in this format:
257
+ #
258
+ # Assuming both the users share same UID.
259
+ #
260
+ # If the info isn't available, it will return an empty frozen String.
261
+ def home_by_gid(id = get_gid)
262
+ return ''.freeze unless passwd_readable?
263
+
264
+ home = ''
265
+ passwd.each do |x|
266
+ splitted = x.split(?:.freeze)
267
+
268
+ if splitted[3].to_i == id
269
+ home = splitted[5]
270
+ break
271
+ end
272
+ end
273
+ home
274
+ end
275
+
276
+ alias get_current_user get_user
277
+
278
+ private
279
+ def passwd
280
+ @@passwd_file ||= '/etc/passwd'.freeze
281
+ IO.readlines(@@passwd_file)
282
+ end
283
+
284
+ # Only use this method where we are sure that the whole array is going to be used.
285
+ # In cases like find() or a loop with `break` this is a lot of overhead.
286
+ # In cases like reduce({}) or select, this is not helpful.
287
+ def passwd_splitted
288
+ @@passwd_file ||= '/etc/passwd'.freeze
289
+ IO.readlines(@@passwd_file).map { |x| x.split(?:.freeze) }
290
+ end
291
+
292
+ def passwd_readable?
293
+ @@passwd_file ||= '/etc/passwd'.freeze
294
+ @@passwd_readable ||= File.readable?(@@passwd_file)
295
+ end
296
+ end
297
+ end
298
+ end