linux_stat 1.0.0 → 1.1.1

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.
@@ -19,28 +19,28 @@ static VALUE getTick(VALUE obj) {
19
19
  }
20
20
 
21
21
  static VALUE getChildMax(VALUE obj) {
22
- short int val = sysconf(_SC_CHILD_MAX) ;
22
+ long long int val = sysconf(_SC_CHILD_MAX) ;
23
23
  if (val < 0) return Qnil ;
24
24
 
25
25
  return INT2FIX(val) ;
26
26
  }
27
27
 
28
28
  static VALUE getHostnameMax(VALUE obj) {
29
- short int val = sysconf(_SC_HOST_NAME_MAX) ;
29
+ int val = sysconf(_SC_HOST_NAME_MAX) ;
30
30
  if (val < 0) return Qnil ;
31
31
 
32
32
  return INT2FIX(val) ;
33
33
  }
34
34
 
35
35
  static VALUE getLoginNameMax(VALUE obj) {
36
- short int val = sysconf(_SC_LOGIN_NAME_MAX) ;
36
+ int val = sysconf(_SC_LOGIN_NAME_MAX) ;
37
37
  if (val < 0) return Qnil ;
38
38
 
39
39
  return INT2FIX(val) ;
40
40
  }
41
41
 
42
42
  static VALUE getOpenMax(VALUE obj) {
43
- short int val = sysconf(_SC_OPEN_MAX) ;
43
+ int val = sysconf(_SC_OPEN_MAX) ;
44
44
  if (val < 0) return Qnil ;
45
45
 
46
46
  return INT2FIX(val) ;
@@ -54,35 +54,35 @@ static VALUE getPageSize(VALUE obj) {
54
54
  }
55
55
 
56
56
  static VALUE getStreamMax(VALUE obj) {
57
- short int val = sysconf(_SC_STREAM_MAX) ;
57
+ int val = sysconf(_SC_STREAM_MAX) ;
58
58
  if (val < 0) return Qnil ;
59
59
 
60
60
  return INT2FIX(val) ;
61
61
  }
62
62
 
63
63
  static VALUE getTTYNameMax(VALUE obj) {
64
- short int val = sysconf(_SC_TTY_NAME_MAX) ;
64
+ int val = sysconf(_SC_TTY_NAME_MAX) ;
65
65
  if (val < 0) return Qnil ;
66
66
 
67
67
  return INT2FIX(val) ;
68
68
  }
69
69
 
70
70
  static VALUE getPosixVersion(VALUE obj) {
71
- short int val = sysconf(_SC_VERSION) ;
71
+ int val = sysconf(_SC_VERSION) ;
72
72
  if (val < 0) return Qnil ;
73
73
 
74
74
  return INT2FIX(val) ;
75
75
  }
76
76
 
77
77
  static VALUE getLineMax(VALUE obj) {
78
- short int val = sysconf(_SC_LINE_MAX) ;
78
+ int val = sysconf(_SC_LINE_MAX) ;
79
79
  if (val < 0) return Qnil ;
80
80
 
81
81
  return INT2FIX(val) ;
82
82
  }
83
83
 
84
84
  static VALUE getExprNestMax(VALUE obj) {
85
- short int val = sysconf(_SC_EXPR_NEST_MAX) ;
85
+ int val = sysconf(_SC_EXPR_NEST_MAX) ;
86
86
  if (val < 0) return Qnil ;
87
87
 
88
88
  return INT2FIX(val) ;
@@ -15,8 +15,8 @@
15
15
 
16
16
  # Miscellaneous Modules
17
17
  # Independed and LinuxStat's miscellaneous modules
18
- require "linux_stat/version"
19
18
  require 'linux_stat/prettify_bytes'
19
+ require "linux_stat/version"
20
20
 
21
21
  # Independed Modules
22
22
  # Modules that doesn't have any dependency on its own
@@ -25,6 +25,7 @@ require "linux_stat/battery"
25
25
  require "linux_stat/bios"
26
26
  require "linux_stat/memory"
27
27
  require "linux_stat/net"
28
+ require "linux_stat/pci"
28
29
  require "linux_stat/process"
29
30
  require "linux_stat/swap"
30
31
  require "linux_stat/usb"
@@ -17,7 +17,9 @@ module LinuxStat
17
17
  # Returns the total bytes received and transmitted as Hash.
18
18
  #
19
19
  # For example:
20
- # {:received=>56602867, :transmitted=>6940922}
20
+ # LinuxStat::Net.usage
21
+ #
22
+ # => {:received=>56602867, :transmitted=>6940922}
21
23
  #
22
24
  # But if the status isn't available it will return an empty Hash.
23
25
  def total_bytes
@@ -68,7 +70,9 @@ module LinuxStat
68
70
  # The return type is a Hash, containg the current internet usage (received, transmit) in B/s.
69
71
  #
70
72
  # For example:
71
- # {:received=>436060.0, :transmitted=>50350.0}
73
+ # LinuxStat::Net.usage
74
+ #
75
+ # => {:received=>436060.0, :transmitted=>50350.0}
72
76
  #
73
77
  # If the system transmits 100 kb in the interval,
74
78
  #
@@ -3,7 +3,9 @@ module LinuxStat
3
3
  class << self
4
4
  ##
5
5
  # Reads /etc/os-release and returns a Hash. For example:
6
- # {:NAME=>"Arch Linux", :PRETTY_NAME=>"Arch Linux", :ID=>"arch", :BUILD_ID=>"rolling", :ANSI_COLOR=>"38;2;23;147;209", :HOME_URL=>"https://www.archlinux.org/", :DOCUMENTATION_URL=>"https://wiki.archlinux.org/", :SUPPORT_URL=>"https://bbs.archlinux.org/", :BUG_REPORT_URL=>"https://bugs.archlinux.org/", :LOGO=>"archlinux"}
6
+ # LinuxStat::OS.os_release
7
+ #
8
+ # => {:NAME=>"Arch Linux", :PRETTY_NAME=>"Arch Linux", :ID=>"arch", :BUILD_ID=>"rolling", :ANSI_COLOR=>"38;2;23;147;209", :HOME_URL=>"https://www.archlinux.org/", :DOCUMENTATION_URL=>"https://wiki.archlinux.org/", :SUPPORT_URL=>"https://bbs.archlinux.org/", :BUG_REPORT_URL=>"https://bugs.archlinux.org/", :LOGO=>"archlinux"}
7
9
  #
8
10
  # If the info isn't available, it will return an empty Hash.
9
11
  #
@@ -13,13 +15,14 @@ module LinuxStat
13
15
  # Because changing the /etc/lsb-release
14
16
  # isn't expected in runtime.
15
17
  def os_release
16
- # cached (memoized) ; as changing the value in runtime is unexpected
17
18
  @@os_release ||= File.readable?('/etc/os-release') ? release('/etc/os-release') : {}
18
19
  end
19
20
 
20
21
  ##
21
22
  # Reads /etc/lsb-release and returns a Hash. For example:
22
- # {:LSB_VERSION=>"1.4", :DISTRIB_ID=>"Arch", :DISTRIB_RELEASE=>"rolling", :DISTRIB_DESCRIPTION=>"Arch Linux"}
23
+ # LinuxStat::OS.lsb_release
24
+ #
25
+ # => {:LSB_VERSION=>"1.4", :DISTRIB_ID=>"Arch", :DISTRIB_RELEASE=>"rolling", :DISTRIB_DESCRIPTION=>"Arch Linux"}
23
26
  #
24
27
  # If the info isn't available, it will return an empty Hash.
25
28
  #
@@ -28,7 +31,6 @@ module LinuxStat
28
31
  # The information is also cached, and once loaded, won't change in runtime.
29
32
  # Because changing the /etc/lsb-release isn't expected in runtime.
30
33
  def lsb_release
31
- # cached (memoized) ; as changing the value in runtime is unexpected
32
34
  @@lsb_release ||= File.readable?('/etc/lsb-release') ? release('/etc/lsb-release') : {}
33
35
  end
34
36
 
@@ -104,7 +106,9 @@ module LinuxStat
104
106
 
105
107
  ##
106
108
  # Reads /proc/uptime and returns the system uptime:
107
- # {:hour=>10, :minute=>34, :second=>12.59}
109
+ # LinuxStat::OS.uptime
110
+ #
111
+ # => {:hour=>10, :minute=>34, :second=>12.59}
108
112
  #
109
113
  # If the stat isn't available, an empty hash is returned.
110
114
  def uptime
@@ -0,0 +1,363 @@
1
+ module LinuxStat
2
+ module PCI
3
+ class << self
4
+ ##
5
+ # = devices_info(hwdata: true)
6
+ #
7
+ # [ Not to be confused with devices_stat ]
8
+ #
9
+ # Take a look at LinuxStat::PCI.devices_stat for more info.
10
+ #
11
+ # Returns details about the devices found in /proc/bus/pci/devices file.
12
+ #
13
+ # The details doesn't contain a lot of details, it opens just one file.
14
+ #
15
+ # The return value is an Array of multiple Hashes. If there's no info available,
16
+ # it will rather return an empty Array.
17
+ #
18
+ # On Android Termux for example, it can not list the directories because they are
19
+ # not readable the the regular user.
20
+ #
21
+ # It can have information like:
22
+ #
23
+ # id, vendor, device, irq, and kernel_driver
24
+ #
25
+ # An example of the returned sample from a test machine is:
26
+ # LinuxStat::PCI.devices_info
27
+ #
28
+ # => [{:id=>"8086:1904", :vendor=>"8086", :device=>"1904", :irq=>0, :kernel_driver=>"skl_uncore", :hwdata=>{:vendor=>"Intel Corporation", :product=>"Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers"}}]
29
+ #
30
+ # Right, it's an Array of Hashes.
31
+ #
32
+ # It also takes one option. The hwdata, which is true by default.
33
+ #
34
+ # Information about usb devices is found inside /usr/share/hwdata/pci.ids
35
+ #
36
+ # The data contains the vendor and the product, the subvendor and the subproduct.
37
+ #
38
+ # If the option is enabled, it will try read /usr/share/hwdata/pci.ids
39
+ #
40
+ # But the file will be read only once. The consecutive calls to this method
41
+ # won't open the hwdata all the times.
42
+ #
43
+ # But if there's no hwdata, the Hash returned by this method will not contain
44
+ # hwdata key.
45
+ #
46
+ # The data is only populated if it's available. For example, if there's no
47
+ # manufacturer available for the product, the returned Hash will not contain the
48
+ # information about the manufacturer.
49
+ #
50
+ # Also note that if there's no info available or no PCI enabled devices, it will return an empty
51
+ # Hash.
52
+ def devices_info(hwdata: true)
53
+ @@proc_pci_readable ||= File.readable?('/proc/bus/pci/devices')
54
+ return {} unless @@proc_pci_readable
55
+
56
+ IO.readlines('/proc/bus/pci/devices'.freeze).map! { |dev|
57
+ x = dev.split
58
+
59
+ vendor = x[1][0..3]
60
+ device = x[1][4..-1]
61
+ irq = x[2].to_i(16)
62
+ kernel_driver = x[-1]
63
+
64
+ query = if hwdata
65
+ query_hwdata(vendor, device)
66
+ else
67
+ {}
68
+ end
69
+
70
+ ret = {
71
+ id: "#{vendor}:#{device}",
72
+ vendor: vendor, device: device,
73
+ irq: irq,
74
+ kernel_driver: kernel_driver
75
+ }
76
+
77
+ ret.merge!(hwdata: query) unless query.empty?
78
+
79
+ ret
80
+ }
81
+ end
82
+
83
+ ##
84
+ # = devices_stat(hwdata: true)
85
+ #
86
+ # Returns details about the devices found in /sys/bus/pci/devices/
87
+ #
88
+ # The return value is an Array of multiple Hashes. If there's no info available,
89
+ # it will rather return an empty Array.
90
+ #
91
+ # On Android Termux for example, it can not list the directories because they are
92
+ # not readable the the regular user.
93
+ #
94
+ # It can have information like:
95
+ #
96
+ # path, id, vendor, device, subvendor, sub_device,
97
+ # kernel_driver, revision, irq, enable, hwdata.
98
+ #
99
+ # An example of the returned sample from a test machine is:
100
+ # LinuxStat::PCI.devices_stat
101
+ #
102
+ # => [{:path=>"/sys/bus/pci/devices/0000:00:00.0/", :id=>"8086:1904", :vendor=>"8086", :device=>"1904", :sub_vendor=>"1028", :sub_device=>"077d", :kernel_driver=>"skl_uncore", :revision=>"0x08", :irq=>0, :enable=>false, :hwdata=>{:vendor=>"Intel Corporation", :product=>"Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers", :sub_system=>nil}}]
103
+ #
104
+ # Right, it's an Array of Hashes.
105
+ #
106
+ # It also takes one option. The hwdata, which is true by default.
107
+ #
108
+ # Information about usb devices is found inside /usr/share/hwdata/pci.ids
109
+ #
110
+ # The data contains the vendor and the product, the subvendor and the subproduct.
111
+ #
112
+ # If the option is enabled, it will try read /usr/share/hwdata/pci.ids
113
+ #
114
+ # But the file will be read only once. The consecutive calls to this method
115
+ # won't open the hwdata all the times.
116
+ #
117
+ # But if there's no hwdata, the Hash returned by this method will not contain
118
+ # hwdata key.
119
+ #
120
+ # The data is only populated if it's available. For example, if there's no
121
+ # manufacturer available for the product, the returned Hash will not contain the
122
+ # information about the manufacturer.
123
+ #
124
+ # If there's no /sys/bus/pci/devices/, it will call LinuxStat::PCI.devices_info
125
+ #
126
+ # Also note that if there's no info available or no PCI enabled devices, it will return an empty
127
+ # Hash.
128
+ def devices_stat(hwdata: true)
129
+ @@sys_pci_readable ||= File.readable?('/sys/bus/pci/devices/')
130
+ return devices_info(hwdata: hwdata) unless @@sys_pci_readable
131
+
132
+ Dir['/sys/bus/pci/devices/*/'.freeze].sort!.map! { |x|
133
+ _vendor_file = File.join(x, 'vendor'.freeze)
134
+ next unless File.readable?(_vendor_file)
135
+ vendor = IO.read(_vendor_file).to_i(16).to_s(16)
136
+ prepend_0(vendor)
137
+
138
+ _device_file = File.join(x, 'device'.freeze)
139
+ next unless File.readable?(_device_file)
140
+ device = IO.read(_device_file).to_i(16).to_s(16)
141
+ prepend_0(device)
142
+
143
+ _sub_vendor_file = File.join(x, 'subsystem_vendor'.freeze)
144
+ sub_vendor = File.readable?(_sub_vendor_file) ? IO.read(_sub_vendor_file).to_i(16).to_s(16) : nil
145
+ prepend_0(sub_vendor) if sub_vendor
146
+
147
+ _sub_device_file = File.join(x, 'subsystem_device'.freeze)
148
+ sub_device = File.readable?(_sub_device_file) ? IO.read(_sub_device_file).to_i(16).to_s(16) : nil
149
+ prepend_0(sub_device) if sub_device
150
+
151
+ _uevent = File.join(x, 'uevent'.freeze)
152
+ uevent = File.readable?(_uevent) ? IO.foreach(_uevent) : nil
153
+
154
+ kernel_driver = if uevent
155
+ uevent.find { |_x|
156
+ _x.split(?=.freeze)[0].to_s.tap(&:strip!) == 'DRIVER'.freeze
157
+ } &.split(?=) &.[](1) &.tap(&:strip!)
158
+ else
159
+ nil
160
+ end
161
+
162
+ _revision_file = File.join(x, 'revision'.freeze)
163
+ revision = File.readable?(_revision_file) ? IO.read(_revision_file).tap(&:strip!) : ''.freeze
164
+
165
+ _irq_file = File.join(x, 'irq'.freeze)
166
+ irq = File.readable?(_irq_file) ? IO.read(_irq_file).to_i : nil
167
+
168
+ _enable_file = File.join(x, 'enable'.freeze)
169
+ enable = File.readable?(_enable_file) ? IO.read(_enable_file).to_i == 1 : nil
170
+
171
+ query = if hwdata && sub_vendor && sub_device
172
+ query_hwdata(vendor, device, sub_vendor, sub_device)
173
+ elsif hwdata && sub_vendor
174
+ query_hwdata(vendor, device, sub_vendor)
175
+ elsif hwdata
176
+ query_hwdata(vendor, device)
177
+ else
178
+ {}
179
+ end
180
+
181
+ ret = {
182
+ path: x, id: "#{vendor}:#{device}",
183
+ vendor: vendor, device: device
184
+ }
185
+
186
+ ret.merge!(sub_vendor: sub_vendor) if sub_vendor
187
+ ret.merge!(sub_device: sub_device) if sub_device
188
+
189
+ ret.merge!(kernel_driver: kernel_driver) if kernel_driver
190
+ ret.merge!(revision: revision) unless revision.empty?
191
+ ret.merge!(irq: irq) if irq
192
+ ret.merge!(enable: enable) unless enable.nil?
193
+ ret.merge!(hwdata: query) unless query.empty?
194
+
195
+ ret
196
+ }
197
+ end
198
+
199
+ ##
200
+ # Reads /proc/bus/pci/devices, counts and returns the total number of lines.
201
+ #
202
+ # But if the information isn't available, it will look into the contents of
203
+ # /sys/bus/pci/devices, and counts the total number of
204
+ # devices connected to the PCI.
205
+ # It checks for devices with vendor and device id files.
206
+ # If there's no such file, it will not count them as a PCI connected device.
207
+ #
208
+ # The return type is an integer.
209
+ #
210
+ # But if the information isn't available, it will return nil.
211
+ def count
212
+ @@proc_pci_readable ||= File.readable?('/proc/bus/pci/devices')
213
+ @@sys_pci_readable ||= File.readable?('/sys/bus/pci/devices/')
214
+
215
+ if @@proc_pci_readable
216
+ IO.readlines('/proc/bus/pci/devices'.freeze).length
217
+
218
+ elsif @@sys_pci_readable
219
+ Dir['/sys/bus/pci/devices/*/'.freeze].count { |x|
220
+ id_vendor_file = File.join(x, 'vendor'.freeze)
221
+ id_product_file = File.join(x, 'device'.freeze)
222
+ File.readable?(id_vendor_file) && File.readable?(id_product_file)
223
+ }
224
+
225
+ else
226
+ nil
227
+ end
228
+ end
229
+
230
+ ##
231
+ # hwdata_file = file
232
+ #
233
+ # Lets you set the hwdata_file about pci.ids.
234
+ #
235
+ # The hwdata file about pci.ids contains vendor name and product name information about
236
+ # devices. This is then mapped by the other methods that utilizes hwdata/pci.ids.
237
+ #
238
+ # Do note that this method is intended to run only once, at the beginning.
239
+ # If you use any other method that utilizes hwdata/pci.ids, before
240
+ # calling this method, this method will not work.
241
+ def hwdata_file=(file)
242
+ @@hwdata_file ||= file.freeze
243
+ end
244
+
245
+ ##
246
+ # Checks if hwdata_file is already initialized or not.
247
+ # Once it's initialized, calling hwdata_file = 'something/pci.ids' is futile.
248
+ def hwdata_file_set?
249
+ @@hwdata_file ||= false
250
+ !!@@hwdata_file
251
+ end
252
+
253
+ ##
254
+ # Returns the hwdata_file as string.
255
+ #
256
+ # If hwdata_file isn't set, it will return an empty frozen string.
257
+ #
258
+ # Once it's set, it can't be changed.
259
+ def hwdata_file
260
+ @@hwdata_file ||= nil
261
+ @@hwdata_file ? @@hwdata_file : ''.freeze
262
+ end
263
+
264
+ ##
265
+ # Initializes hwdata
266
+ #
267
+ # hwdata can take upto 0.1 to 0.2 seconds to get initialized.
268
+ #
269
+ # Calling this method will load hwdata for future use.
270
+ #
271
+ # Once it's initialized, hwdata_file can't be changed.
272
+ #
273
+ # If this method initializes hwdata, it will return true
274
+ # Othewise this method will return false.
275
+ def initialize_hwdata
276
+ @@hwdata ||= nil
277
+ init = !@@hwdata
278
+ hwdata
279
+ init
280
+ end
281
+
282
+ alias count_devices count
283
+
284
+ private
285
+ def hwdata
286
+ @@hwdata_file ||= "/usr/share/hwdata/pci.ids".freeze
287
+
288
+ @@hwdata ||= if File.readable?(@@hwdata_file)
289
+ ret, vendor_id, device_id, device = {}, nil, nil, nil
290
+ i = -1
291
+
292
+ file_data = IO.readlines(@@hwdata_file, encoding: 'ASCII-8BIT')
293
+ file_data_size = file_data.size
294
+
295
+ while (i += 1) < file_data_size
296
+ x = file_data[i]
297
+
298
+ _lstripped = x.lstrip
299
+ next if _lstripped[0] == ?#.freeze || _lstripped.empty?
300
+
301
+ if x[0..1] == "\t\t".freeze
302
+ next unless device_id
303
+
304
+ x.strip!
305
+ sub_device_id = x[/\A.*?\s/].to_s.strip
306
+ sub_device = x[device_id.length..-1].to_s.strip
307
+
308
+ if ret[vendor_id] &.at(1) &.[](device_id) &.[](1)
309
+ sub_system_id = sub_device[/\A.*?\s/].to_s.strip
310
+ sub_system_device = sub_device[sub_system_id.length..-1].to_s.strip
311
+
312
+ ret[vendor_id][1][device_id][1].merge!(sub_device_id => {sub_system_id => sub_system_device})
313
+ end
314
+
315
+ elsif x[0] == ?\t.freeze
316
+ next unless vendor_id
317
+
318
+ x.strip!
319
+ device_id = x[/\A.*?\s/].to_s.strip
320
+ device = x[device_id.length..-1].to_s.strip
321
+ ret[vendor_id][1][device_id] = [device, {}]
322
+
323
+ else
324
+ x.strip!
325
+ vendor_id = x[/\A.*?\s/].to_s.strip
326
+ vendor = x[vendor_id.length..-1].to_s.strip
327
+ ret[vendor_id] = [vendor, {}]
328
+ end
329
+ end
330
+
331
+ ret.freeze
332
+ else
333
+ {}
334
+ end
335
+ end
336
+
337
+ def prepend_0(n)
338
+ n[0, 0] = ?0.*(4 - n.length).freeze if n.length < 4
339
+ n
340
+ end
341
+
342
+ def query_hwdata(vendor_id, product_id, sub_vendor_id = nil, sub_device_id = nil)
343
+ vendor = hwdata[vendor_id]
344
+
345
+ if vendor
346
+ ret = {
347
+ vendor: vendor[0],
348
+ product: vendor.dig(1, product_id, 0),
349
+ }
350
+
351
+ if sub_vendor_id && sub_device_id
352
+ sub_product = vendor.dig(1, product_id, 1, sub_vendor_id, sub_device_id)
353
+ ret.merge!(sub_system: sub_product) if sub_product
354
+ end
355
+
356
+ ret
357
+ else
358
+ {}
359
+ end
360
+ end
361
+ end
362
+ end
363
+ end