linux_stat 1.1.1 → 1.3.0
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.
- checksums.yaml +4 -4
- data/README.md +108 -64
- data/ext/sysconf/sysconf.c +11 -0
- data/lib/linux_stat.rb +1 -0
- data/lib/linux_stat/battery.rb +2 -0
- data/lib/linux_stat/bios.rb +2 -0
- data/lib/linux_stat/cpu.rb +2 -0
- data/lib/linux_stat/filesystem.rb +2 -0
- data/lib/linux_stat/kernel.rb +2 -0
- data/lib/linux_stat/memory.rb +9 -7
- data/lib/linux_stat/mounts.rb +5 -3
- data/lib/linux_stat/net.rb +6 -4
- data/lib/linux_stat/os.rb +50 -15
- data/lib/linux_stat/pci.rb +61 -56
- data/lib/linux_stat/prettify_bytes.rb +7 -0
- data/lib/linux_stat/process.rb +48 -23
- data/lib/linux_stat/process_info.rb +7 -0
- data/lib/linux_stat/swap.rb +6 -4
- data/lib/linux_stat/thermal.rb +122 -0
- data/lib/linux_stat/usb.rb +52 -48
- data/lib/linux_stat/user.rb +6 -3
- data/lib/linux_stat/version.rb +1 -1
- metadata +3 -2
@@ -1,4 +1,11 @@
|
|
1
1
|
module LinuxStat
|
2
|
+
# Helps you convert bytes to a unit like:
|
3
|
+
#
|
4
|
+
# 1. kilobyte, megabyte, gigabyte, terabyte, petabyte, exabyte, zettabyte, yottabyte
|
5
|
+
# 2. kibibyte, mebibyte, gibibyte, tebibyte, pebibyte, exbibyte, zebibyte, yobibyte
|
6
|
+
# 3. kB, MB, GB, TB, PB, EB, ZB, YB
|
7
|
+
# 4. kiB, MiB, GiB, TiB, PiB, EiB, ZiB, YiB
|
8
|
+
|
2
9
|
module PrettifyBytes
|
3
10
|
class << self
|
4
11
|
##
|
data/lib/linux_stat/process.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
module LinuxStat
|
2
|
+
# Shows various information about a process that is either
|
3
|
+
# running, sleeping, idle or a zombie.
|
4
|
+
|
2
5
|
module Process
|
3
6
|
class << self
|
4
7
|
##
|
@@ -6,10 +9,17 @@ module LinuxStat
|
|
6
9
|
#
|
7
10
|
# The return type is an Array of Integers.
|
8
11
|
def list
|
9
|
-
Dir['/proc/*']
|
10
|
-
|
11
|
-
|
12
|
-
|
12
|
+
d = Dir['/proc/*'.freeze]
|
13
|
+
ret, i = [], -1
|
14
|
+
count = d.length
|
15
|
+
|
16
|
+
while(i += 1) < count
|
17
|
+
pid = File.split(d[i])[1]
|
18
|
+
pid_i = pid.to_i
|
19
|
+
ret << pid_i if pid_i.to_s == pid
|
20
|
+
end
|
21
|
+
|
22
|
+
ret
|
13
23
|
end
|
14
24
|
|
15
25
|
##
|
@@ -17,28 +27,42 @@ module LinuxStat
|
|
17
27
|
#
|
18
28
|
# The return type is Integer.
|
19
29
|
def count
|
20
|
-
list.
|
30
|
+
list.length
|
21
31
|
end
|
22
32
|
|
23
33
|
##
|
24
34
|
# Returns all the id of processes mapped with their names as a Hash.
|
25
35
|
def names
|
26
|
-
|
36
|
+
h, i = {}, -1
|
37
|
+
|
38
|
+
l = list
|
39
|
+
count = l.length
|
40
|
+
|
41
|
+
while(i += 1) < count
|
42
|
+
x = l[i]
|
43
|
+
|
27
44
|
begin
|
28
|
-
h.merge!( x => IO.foreach(
|
29
|
-
rescue
|
30
|
-
h
|
45
|
+
h.merge!( x => IO.foreach("/proc/#{x}/status").first.split[1])
|
46
|
+
rescue StandardError
|
31
47
|
end
|
32
|
-
|
48
|
+
end
|
49
|
+
h
|
33
50
|
end
|
34
51
|
|
35
52
|
##
|
36
53
|
# Returns all the id of processes mapped with their status as a Hash.
|
37
54
|
def types
|
38
|
-
|
55
|
+
h, i = {}, -1
|
56
|
+
|
57
|
+
l = list
|
58
|
+
count = l.length
|
59
|
+
|
60
|
+
while(i += 1) < count
|
61
|
+
x = l[i]
|
62
|
+
|
39
63
|
begin
|
40
64
|
h.merge!(x =>
|
41
|
-
case IO.
|
65
|
+
case IO.foreach("/proc/#{x}/stat", ' '.freeze).first(3)[-1][0]
|
42
66
|
when ?S.freeze then :sleeping
|
43
67
|
when ?I.freeze then :idle
|
44
68
|
when ?Z.freeze then :zombie
|
@@ -46,10 +70,11 @@ module LinuxStat
|
|
46
70
|
else :unknown
|
47
71
|
end
|
48
72
|
)
|
49
|
-
rescue
|
50
|
-
h
|
73
|
+
rescue StandardError
|
51
74
|
end
|
52
|
-
|
75
|
+
end
|
76
|
+
|
77
|
+
h
|
53
78
|
end
|
54
79
|
|
55
80
|
##
|
@@ -58,8 +83,8 @@ module LinuxStat
|
|
58
83
|
def sleeping
|
59
84
|
list.select { |x|
|
60
85
|
begin
|
61
|
-
IO.
|
62
|
-
rescue
|
86
|
+
IO.foreach("/proc/#{x}/stat", ' '.freeze).first(3)[-1][0] == ?S.freeze
|
87
|
+
rescue StandardError
|
63
88
|
nil
|
64
89
|
end
|
65
90
|
}
|
@@ -71,8 +96,8 @@ module LinuxStat
|
|
71
96
|
def idle
|
72
97
|
list.select { |x|
|
73
98
|
begin
|
74
|
-
IO.
|
75
|
-
rescue
|
99
|
+
IO.foreach("/proc/#{x}/stat", ' '.freeze).first(3)[-1][0] == ?I.freeze
|
100
|
+
rescue StandardError
|
76
101
|
nil
|
77
102
|
end
|
78
103
|
}
|
@@ -84,8 +109,8 @@ module LinuxStat
|
|
84
109
|
def zombie
|
85
110
|
list.select { |x|
|
86
111
|
begin
|
87
|
-
IO.
|
88
|
-
rescue
|
112
|
+
IO.foreach("/proc/#{x}/stat", ' '.freeze).first(3)[-1][0] == ?Z.freeze
|
113
|
+
rescue StandardError
|
89
114
|
nil
|
90
115
|
end
|
91
116
|
}
|
@@ -97,8 +122,8 @@ module LinuxStat
|
|
97
122
|
def running
|
98
123
|
list.select { |x|
|
99
124
|
begin
|
100
|
-
IO.
|
101
|
-
rescue
|
125
|
+
IO.foreach("/proc/#{x}/stat", ' '.freeze).first(3)[-1][0] == ?R.freeze
|
126
|
+
rescue StandardError
|
102
127
|
nil
|
103
128
|
end
|
104
129
|
}
|
@@ -1,4 +1,11 @@
|
|
1
1
|
module LinuxStat
|
2
|
+
# Shows various information about a process that is either
|
3
|
+
# running, sleeping, idle or a zombie.
|
4
|
+
# Most methods can take a PID, but some uses polling to calculate
|
5
|
+
# something, they can accept options instead of arguments.
|
6
|
+
# Consult the documentation on the specific methods
|
7
|
+
# for more details on that.
|
8
|
+
|
2
9
|
module ProcessInfo
|
3
10
|
class << self
|
4
11
|
##
|
data/lib/linux_stat/swap.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module LinuxStat
|
2
|
+
# Shows various Swap devices related information of the current system.
|
3
|
+
|
2
4
|
module Swap
|
3
5
|
class << self
|
4
6
|
##
|
@@ -8,7 +10,7 @@ module LinuxStat
|
|
8
10
|
def list
|
9
11
|
return {} unless swaps_readable?
|
10
12
|
|
11
|
-
file = IO.readlines('/proc/swaps').drop(1)
|
13
|
+
file = IO.readlines('/proc/swaps'.freeze).drop(1)
|
12
14
|
file.reduce({}) do |h, x|
|
13
15
|
name, *stats = x.strip.split
|
14
16
|
h.merge!(name => stats.map! { |v| v.to_i.to_s == v ? v.to_i : v.to_sym })
|
@@ -20,7 +22,7 @@ module LinuxStat
|
|
20
22
|
#
|
21
23
|
# If the info isn't available, it will return an empty Hash.
|
22
24
|
def any?
|
23
|
-
!!IO.foreach('/proc/swaps').
|
25
|
+
!!IO.foreach('/proc/swaps'.freeze).first(2)[1]
|
24
26
|
end
|
25
27
|
|
26
28
|
# Show aggregated used and available swap.
|
@@ -114,7 +116,7 @@ module LinuxStat
|
|
114
116
|
def read_usage
|
115
117
|
return [[], []] unless swaps_readable?
|
116
118
|
|
117
|
-
val = IO.readlines('/proc/swaps').drop(1)
|
119
|
+
val = IO.readlines('/proc/swaps'.freeze).drop(1)
|
118
120
|
return [[], []] if val.empty?
|
119
121
|
|
120
122
|
val.map! { |x|
|
@@ -123,7 +125,7 @@ module LinuxStat
|
|
123
125
|
end
|
124
126
|
|
125
127
|
def swaps_readable?
|
126
|
-
@@swaps_readable ||= File.readable?('/proc/swaps')
|
128
|
+
@@swaps_readable ||= File.readable?('/proc/swaps'.freeze)
|
127
129
|
end
|
128
130
|
end
|
129
131
|
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module LinuxStat
|
2
|
+
# Sensors are available to /sys/class/hwmon
|
3
|
+
# This module just reads the files inside them to get the sensor information.
|
4
|
+
#
|
5
|
+
# https://www.kernel.org/doc/Documentation/thermal/sysfs-api.txt
|
6
|
+
|
7
|
+
module Thermal
|
8
|
+
class << self
|
9
|
+
##
|
10
|
+
# Get temperatures from all sensors.
|
11
|
+
#
|
12
|
+
# The return value is an Array of Hashes.
|
13
|
+
#
|
14
|
+
# It opens various files from /sys/, and it should be
|
15
|
+
# considered very slow.
|
16
|
+
#
|
17
|
+
# Each hash may contain information including:
|
18
|
+
#
|
19
|
+
# path, name, label
|
20
|
+
# temperature, temp_crit, temp_max
|
21
|
+
#
|
22
|
+
# But if the info isn't available, it will return an empty Array.
|
23
|
+
def temperatures
|
24
|
+
query_hwmon('temp'.freeze, :temperature, true)
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Get RPM from all fans.
|
29
|
+
#
|
30
|
+
# The return value is an Array of Hashes.
|
31
|
+
#
|
32
|
+
# It opens various files from /sys/, and it should be
|
33
|
+
# considered very slow.
|
34
|
+
#
|
35
|
+
# Each hash may contain information including:
|
36
|
+
#
|
37
|
+
# path, name, label
|
38
|
+
# rpm, temp_crit, temp_max
|
39
|
+
#
|
40
|
+
# But if the info isn't available, it will return an empty Array.
|
41
|
+
def fans
|
42
|
+
query_hwmon('fan'.freeze, :rpm)
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Counts the number of sensors (fans are not counted)
|
47
|
+
#
|
48
|
+
# The return type is an Integer.
|
49
|
+
def count_sensors
|
50
|
+
return 0 unless hwmon_readable?
|
51
|
+
|
52
|
+
Dir["/sys/class/hwmon/hwmon[0-9]*/temp[0-9]*_input".freeze].size
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Counts the number of fans (sensors are not counted)
|
57
|
+
#
|
58
|
+
# The return type is an Integer.
|
59
|
+
def count_fans
|
60
|
+
return 0 unless hwmon_readable?
|
61
|
+
|
62
|
+
Dir["/sys/class/hwmon/hwmon[0-9]*/fan[0-9]*_input".freeze].size
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def hwmon_readable?
|
67
|
+
@@hwmon_readable ||= File.readable?("/sys/class/hwmon/")
|
68
|
+
end
|
69
|
+
|
70
|
+
def query_hwmon(mon, key, div = false)
|
71
|
+
return [] unless hwmon_readable?
|
72
|
+
|
73
|
+
name = dir = ''.freeze
|
74
|
+
|
75
|
+
files = Dir["/sys/class/hwmon/hwmon[0-9]*/#{mon}[0-9]*_input".freeze]
|
76
|
+
i = -1
|
77
|
+
ret = []
|
78
|
+
|
79
|
+
while x = files[i += 1]
|
80
|
+
splitted = File.split(x)
|
81
|
+
path = File.join(splitted[0..-2])
|
82
|
+
|
83
|
+
n = splitted[-1][/.*_/]
|
84
|
+
|
85
|
+
label_f = "#{path}/#{n}label"
|
86
|
+
label = File.readable?(label_f) ? IO.read(label_f, encoding: 'ASCII-8BIT'.freeze).strip : nil
|
87
|
+
|
88
|
+
temp_crit_f = "#{path}/#{n}crit"
|
89
|
+
temp_crit = File.readable?(temp_crit_f) ? IO.read(temp_crit_f, encoding: 'ASCII-8BIT'.freeze).to_i : nil
|
90
|
+
|
91
|
+
temp_max_f = "#{path}/#{n}max"
|
92
|
+
temp_max = File.readable?(temp_max_f) ? IO.read(temp_max_f, encoding: 'ASCII-8BIT'.freeze).to_i : nil
|
93
|
+
|
94
|
+
value = File.readable?(x) ? IO.read(x).to_i : nil
|
95
|
+
|
96
|
+
if dir != path
|
97
|
+
dir = path
|
98
|
+
name_f = "#{path}/name"
|
99
|
+
name = File.readable?(name_f) ? IO.read(name_f, encoding: 'ASCII-8BIT'.freeze).tap(&:strip!) : ''.freeze
|
100
|
+
end
|
101
|
+
|
102
|
+
if div
|
103
|
+
value /= 1000.0
|
104
|
+
temp_max /= 1000.0 if temp_max
|
105
|
+
temp_crit /= 1000.0 if temp_crit
|
106
|
+
end
|
107
|
+
|
108
|
+
h = {path: path, name: name}
|
109
|
+
|
110
|
+
h.merge!(label: label) if label
|
111
|
+
h.merge!(key => value)
|
112
|
+
h.merge!(temp_crit: temp_crit) if temp_crit
|
113
|
+
h.merge!(temp_crit: temp_max) if temp_max
|
114
|
+
|
115
|
+
ret.push(h)
|
116
|
+
end
|
117
|
+
|
118
|
+
ret
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/lib/linux_stat/usb.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module LinuxStat
|
2
|
+
# Shows various USB device related information of the current system.
|
3
|
+
|
2
4
|
module USB
|
3
5
|
class << self
|
4
6
|
##
|
@@ -49,73 +51,75 @@ module LinuxStat
|
|
49
51
|
return [] unless @@sys_usb_readable
|
50
52
|
|
51
53
|
Dir['/sys/bus/usb/devices/*/'.freeze].sort!.map! { |x|
|
52
|
-
|
53
|
-
|
54
|
-
|
54
|
+
begin
|
55
|
+
id_vendor_file = File.join(x, 'idVendor'.freeze)
|
56
|
+
next unless File.readable?(id_vendor_file)
|
57
|
+
id_vendor = IO.read(id_vendor_file).strip
|
55
58
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
+
id_product_file = File.join(x, 'idProduct'.freeze)
|
60
|
+
next unless File.readable?(id_vendor_file)
|
61
|
+
id_product = IO.read(id_product_file).strip
|
59
62
|
|
60
|
-
|
61
|
-
|
63
|
+
bus_num_file = File.join(x, 'busnum'.freeze)
|
64
|
+
bus_num = File.readable?(bus_num_file) ? IO.read(bus_num_file).strip : ''.freeze
|
62
65
|
|
63
|
-
|
64
|
-
|
66
|
+
dev_num_file = File.join(x, 'devnum'.freeze)
|
67
|
+
dev_num = File.readable?(dev_num_file) ? IO.read(dev_num_file).strip : ''.freeze
|
65
68
|
|
66
|
-
|
67
|
-
|
69
|
+
serial_file = File.join(x, 'serial'.freeze)
|
70
|
+
serial = File.readable?(serial_file) ? IO.read(serial_file).strip : ''.freeze
|
68
71
|
|
69
|
-
|
70
|
-
|
72
|
+
product_file = File.join(x, 'product'.freeze)
|
73
|
+
product = File.readable?(product_file) ? IO.read(product_file).strip : ''.freeze
|
71
74
|
|
72
|
-
|
73
|
-
|
75
|
+
manufacturer_file = File.join(x, 'manufacturer'.freeze)
|
76
|
+
manufacturer = File.readable?(manufacturer_file) ? IO.read(manufacturer_file).strip : ''.freeze
|
74
77
|
|
75
|
-
|
76
|
-
|
78
|
+
removable_file = File.join(x, 'removable'.freeze)
|
79
|
+
removable = File.readable?(removable_file) ? IO.read(removable_file).strip.downcase : ''.freeze
|
77
80
|
|
78
|
-
|
79
|
-
|
81
|
+
authorized_file = File.join(x, 'authorized'.freeze)
|
82
|
+
authorized = File.readable?(authorized_file) ? IO.read(authorized_file).to_i : ''.freeze
|
80
83
|
|
81
|
-
|
82
|
-
|
84
|
+
b_max_power_file = File.join(x, 'bMaxPower'.freeze)
|
85
|
+
b_max_power = File.readable?(b_max_power_file) ? IO.read(b_max_power_file).strip : ''.freeze
|
83
86
|
|
84
|
-
|
85
|
-
|
87
|
+
b_max_packet_size0_file = File.join(x, 'bMaxPacketSize0'.freeze)
|
88
|
+
b_max_packet_size0 = File.readable?(b_max_packet_size0_file) ? IO.read(b_max_packet_size0_file).to_i : ''.freeze
|
86
89
|
|
87
|
-
|
90
|
+
query = hwdata ? query_hwdata(id_vendor, id_product) : {}
|
88
91
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
end
|
92
|
+
is_removable = if removable == 'removable'.freeze
|
93
|
+
true
|
94
|
+
elsif removable == 'unknown'.freeze
|
95
|
+
nil
|
96
|
+
else
|
97
|
+
false
|
98
|
+
end
|
97
99
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
100
|
+
ret = {
|
101
|
+
path: x, id: "#{id_vendor}:#{id_product}",
|
102
|
+
vendor_id: id_vendor, product_id: id_product
|
103
|
+
}
|
102
104
|
|
103
|
-
|
104
|
-
|
105
|
+
ret.merge!(bus_num: bus_num.to_i) unless bus_num.empty?
|
106
|
+
ret.merge!(dev_num: dev_num.to_i) unless dev_num.empty?
|
105
107
|
|
106
|
-
|
108
|
+
ret.merge!(serial: serial) unless serial.empty?
|
107
109
|
|
108
|
-
|
109
|
-
|
110
|
-
|
110
|
+
ret.merge!(hwdata: query) unless query.empty?
|
111
|
+
ret.merge!(product: product) unless product.empty?
|
112
|
+
ret.merge!(manufacturer: manufacturer) unless manufacturer.empty?
|
111
113
|
|
112
|
-
|
113
|
-
|
114
|
+
ret.merge!(removable: is_removable) unless is_removable.nil?
|
115
|
+
ret.merge!(authorized: authorized == 1)
|
114
116
|
|
115
|
-
|
116
|
-
|
117
|
+
ret.merge!(b_max_power: b_max_power) unless b_max_power.empty?
|
118
|
+
ret.merge!(b_max_packet_size0: b_max_packet_size0) if b_max_packet_size0
|
117
119
|
|
118
|
-
|
120
|
+
ret
|
121
|
+
rescue StandardError
|
122
|
+
end
|
119
123
|
}.tap(&:compact!)
|
120
124
|
end
|
121
125
|
|