linux_stat 0.4.2 → 0.6.3

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.
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
  $-v = true
3
- %w(bundler/setup linux_stat irb).each(&method(:require))
3
+ %w(linux_stat irb).each(&method(:require))
4
4
  IRB.start(__FILE__)
data/bin/setup CHANGED
@@ -4,5 +4,3 @@ IFS=$'\n\t'
4
4
  set -vx
5
5
 
6
6
  bundle install
7
-
8
- # Do any other automated setup that you need to do here
@@ -1,16 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
+ $-v = true
3
+
2
4
  begin
3
- require 'linux_stat'
5
+ require 'linux_stat' unless defined?(LinuxStat)
4
6
  rescue LoadError
5
- puts "The Gem needs to be installed before this test can be run!"
7
+ abort "The Gem needs to be installed before this test can be run!"
6
8
  end
7
9
 
8
- $-v = true
9
-
10
- # Print time each method takes unless --no-time or -nt option is passed
11
- markdown = ARGV.any? { |x| x[/^\-(\-markdown|md)$/] }
12
- html = ARGV.any? { |x| x[/^\-(\-html|html)$/] }
13
-
14
10
  # Check which conflicting argument (e.g., `-md -html` together) is passed last
15
11
  # Always use the last argument
16
12
  conflicting, hash = [
@@ -38,6 +34,7 @@ end
38
34
 
39
35
  MARKDOWN, HTML = hash[:markdown], hash[:html]
40
36
 
37
+ # Print time each method takes unless --no-time or -nt option is passed
41
38
  PRINT_TIME = (MARKDOWN || HTML) ? false : !ARGV.any? { |x| x[/^\-\-no-time$/] || x[/^\-nt$/] }
42
39
 
43
40
  %w(--markdown -md --no-time -nt --html -html).each(&ARGV.method(:delete))
@@ -99,10 +96,11 @@ execute.sort.each do |c|
99
96
  puts
100
97
  end
101
98
 
102
- meths.length > 0
99
+ if meths.length > 0
103
100
  if MARKDOWN
104
101
  puts "```\n\n"
105
102
  elsif HTML
106
103
  puts "</pre>"
107
104
  end
105
+ end
108
106
  end
@@ -1,7 +1,9 @@
1
1
  #include <sys/statvfs.h>
2
2
  #include "ruby.h"
3
+
3
4
  #pragma GCC optimize ("O3")
4
5
  #pragma clang optimize on
6
+ #pragma once
5
7
 
6
8
  static VALUE statfs(VALUE obj, VALUE dir) {
7
9
  struct statvfs buf ;
@@ -1,6 +1,10 @@
1
1
  #include <unistd.h>
2
2
  #include "ruby.h"
3
3
 
4
+ #pragma GCC optimize ("O3")
5
+ #pragma clang optimize on
6
+ #pragma once
7
+
4
8
  static VALUE getTick(VALUE obj) {
5
9
  return INT2FIX(sysconf(_SC_CLK_TCK)) ;
6
10
  }
@@ -21,7 +25,7 @@ static VALUE getOpenMax(VALUE obj) {
21
25
  return INT2FIX(sysconf(_SC_OPEN_MAX)) ;
22
26
  }
23
27
 
24
- static VALUE getPageSizeMax(VALUE obj) {
28
+ static VALUE getPageSize(VALUE obj) {
25
29
  return INT2FIX(sysconf(_SC_PAGESIZE)) ;
26
30
  }
27
31
 
@@ -37,6 +41,23 @@ static VALUE getPosixVersion(VALUE obj) {
37
41
  return INT2FIX(sysconf(_SC_VERSION)) ;
38
42
  }
39
43
 
44
+ static VALUE getUser(VALUE obj) {
45
+ char *name = getlogin() ;
46
+ return name ? rb_str_new_cstr(name) : rb_str_new_cstr("") ;
47
+ }
48
+
49
+ static VALUE getUID(VALUE obj) {
50
+ return INT2FIX(getuid()) ;
51
+ }
52
+
53
+ static VALUE getGID(VALUE obj) {
54
+ return INT2FIX(getgid()) ;
55
+ }
56
+
57
+ static VALUE getEUID(VALUE obj) {
58
+ return INT2FIX(geteuid()) ;
59
+ }
60
+
40
61
  void Init_sysconf() {
41
62
  VALUE _linux_stat = rb_define_module("LinuxStat") ;
42
63
  VALUE _sysconf = rb_define_module_under(_linux_stat, "Sysconf") ;
@@ -46,8 +67,15 @@ void Init_sysconf() {
46
67
  rb_define_module_function(_sysconf, "hostname_max", getHostnameMax, 0) ;
47
68
  rb_define_module_function(_sysconf, "login_name_max", getLoginNameMax, 0) ;
48
69
  rb_define_module_function(_sysconf, "open_max", getOpenMax, 0) ;
49
- rb_define_module_function(_sysconf, "page_size_max", getPageSizeMax, 0) ;
70
+ rb_define_module_function(_sysconf, "pagesize", getPageSize, 0) ;
50
71
  rb_define_module_function(_sysconf, "stream_max", getStreamMax, 0) ;
51
72
  rb_define_module_function(_sysconf, "tty_name_max", getTTYNameMax, 0) ;
52
73
  rb_define_module_function(_sysconf, "posix_version", getPosixVersion, 0) ;
74
+
75
+ rb_define_module_function(_sysconf, "get_uid", getUID, 0) ;
76
+ rb_define_module_function(_sysconf, "get_gid", getGID, 0) ;
77
+ rb_define_module_function(_sysconf, "get_euid", getEUID, 0) ;
78
+
79
+ rb_define_module_function(_sysconf, "get_user", getUser, 0) ;
80
+ rb_define_module_function(_sysconf, "get_login", getUser, 0) ;
53
81
  }
@@ -1,7 +1,9 @@
1
1
  #include <sys/utsname.h>
2
2
  #include "ruby.h"
3
+
3
4
  #pragma GCC optimize ("O3")
4
5
  #pragma clang optimize on
6
+ #pragma once
5
7
 
6
8
  static struct utsname buf ;
7
9
  static short status ;
@@ -1,20 +1,48 @@
1
+ # ----------------------------------------------------------------------------------------------------- #
2
+ # Don't edit this file unless you know what you are doing. #
3
+ # #
4
+ # A file can have reverse dependency. #
5
+ # For example, linux_stat/utsname is required before #
6
+ # linux_stat/os, which means utsname can be used by LinuxStat::OS and the files below. #
7
+ # #
8
+ # Once wrongly edited, you need to go through each method to know what #
9
+ # file is required by the module functions. Which can be very time consuming. #
10
+ # #
11
+ # If you are writng an independent module, just add them under "Independent" section #
12
+ # If you are writing a dependent module, just append that to the end of the file. #
13
+ # If you are writing something that is miscellaneous, just add it to miscellaneous section #
14
+ # ------------------------------------------------------------------------------------------------------ #
15
+
16
+ # Miscellaneous Modules
17
+ # Independed and LinuxStat's miscellaneous modules
1
18
  require "linux_stat/version"
19
+ require 'linux_stat/prettify_bytes'
20
+
21
+ # Independed Modules
22
+ # Modules that doesn't have any dependency on its own
23
+ # But might be required by other module functions in "Dependent Modules" section
2
24
  require "linux_stat/battery"
3
25
  require "linux_stat/bios"
4
26
  require "linux_stat/cpu"
5
27
  require "linux_stat/memory"
6
28
  require "linux_stat/net"
29
+ require "linux_stat/process"
30
+ require "linux_stat/swap"
31
+
32
+ # Dependent Modules
33
+ # Modules that can have reverse dependency
7
34
 
35
+ # LinuxStat::Uname dependent modules
8
36
  require 'linux_stat/utsname'
9
37
  require "linux_stat/os"
10
38
 
11
- require "linux_stat/process"
12
- require "linux_stat/swap"
13
- require "linux_stat/mounts"
14
-
39
+ # LinuxStat::FS dependent modules
15
40
  require "linux_stat/fs_stat"
16
41
  require "linux_stat/filesystem"
42
+ require "linux_stat/mounts"
17
43
 
44
+ # LinuxStat::Sysconf dependent modules
18
45
  require "linux_stat/sysconf"
19
46
  require "linux_stat/kernel"
47
+ require 'linux_stat/user'
20
48
  require "linux_stat/process_info"
@@ -1,8 +1,9 @@
1
1
  module LinuxStat
2
2
  module CPU
3
3
  class << self
4
- # stat(sleep = 0.075)
4
+ # stat(sleep = 1.0 / LinuxStat::Sysconf.sc_clk_tck)
5
5
  # Where sleep is the delay to gather the data.
6
+ # The minimum possible value at anytime is 1.0 / LinuxStat::Sysconf.sc_clk_tck
6
7
  # This method returns the cpu usage of all threads.
7
8
  #
8
9
  # The first one is aggregated CPU usage reported by the Linux kernel.
@@ -12,7 +13,7 @@ module LinuxStat
12
13
  # {0=>84.38, 1=>100.0, 2=>50.0, 3=>87.5, 4=>87.5}
13
14
  #
14
15
  # If the information is not available, it will return an empty Hash
15
- def stat(sleep = 0.075)
16
+ def stat(sleep = ticks_to_ms)
16
17
  return {} unless stat?
17
18
 
18
19
  data = IO.readlines('/proc/stat').select! { |x| x[/^cpu\d*/] }.map! { |x| x.split.map!(&:to_f) }
@@ -33,20 +34,24 @@ module LinuxStat
33
34
  idle_then, idle_now = idle + iowait, idle2 + iowait2
34
35
  totald = idle_now.+(user2 + nice2 + sys2 + irq2 + softirq2 + steal2) - idle_then.+(user + nice + sys + irq + softirq + steal)
35
36
 
37
+ res = totald.-(idle_now - idle_then).fdiv(totald).*(100).round(2).abs
38
+ res = 0.0 if res.nan?
39
+
36
40
  h.merge!(
37
- x => totald.-(idle_now - idle_then).fdiv(totald).*(100).round(2).abs
41
+ x => res
38
42
  )
39
43
  end
40
44
  end
41
45
 
42
- # total_usage(sleep = 0.075)
46
+ # total_usage(sleep = 1.0 / LinuxStat::Sysconf.sc_clk_tck)
43
47
  # Where sleep is the delay to gather the data.
48
+ # The minimum possible value at anytime is 1.0 / LinuxStat::Sysconf.sc_clk_tck
44
49
  # This method returns the cpu usage of all threads.
45
50
  #
46
51
  # It's like running LinuxStat::CPU.stat[0] but it's much more efficient and calculates just the aggregated usage which is available at the top of the /proc/stat file.
47
52
  #
48
53
  # If the information is not available, it will return nil.
49
- def total_usage(sleep = 0.075)
54
+ def total_usage(sleep = ticks_to_ms)
50
55
  return nil unless stat?
51
56
 
52
57
  data = IO.foreach('/proc/stat').first.split.tap(&:shift).map!(&:to_f)
@@ -113,6 +118,10 @@ module LinuxStat
113
118
  def stat?
114
119
  @@stat_readable ||= File.readable?('/proc/stat')
115
120
  end
121
+
122
+ def ticks_to_ms
123
+ @@ms ||= 1.0 / LinuxStat::Sysconf.sc_clk_tck
124
+ end
116
125
  end
117
126
  end
118
127
  end
@@ -133,8 +133,6 @@ module LinuxStat
133
133
  end
134
134
  end
135
135
 
136
- alias release version
137
-
138
136
  # Reads maximum 1024 bytes from /proc/version and returns the string.
139
137
  # The output is also cached ; as changing the value in runtime is unexpected.
140
138
  def string
@@ -148,6 +146,7 @@ module LinuxStat
148
146
  @@tick ||= LinuxStat::Sysconf.sc_clk_tck
149
147
  end
150
148
 
149
+ alias release version
151
150
  alias clk_tck ticks
152
151
 
153
152
  private
@@ -1,7 +1,8 @@
1
1
  module LinuxStat
2
2
  module Mounts
3
3
  class << self
4
- # Reads /proc/mounts and returns list of devices.
4
+ # Reads /proc/mounts and returns the output splitted with \n.
5
+ # In other words, it's same as running IO.readlines('/proc/mounts').each(&:strip!)
5
6
  #
6
7
  # It returns an Array.
7
8
  # If the info isn't available or /proc/mounts is not readable, it will return an empty Array.
@@ -9,6 +10,14 @@ module LinuxStat
9
10
  mounts
10
11
  end
11
12
 
13
+ # Reads /proc/mounts and returns list of devices.
14
+ #
15
+ # It returns an Array.
16
+ # If the info isn't available or /proc/mounts is not readable, it will return an empty Array.
17
+ def list_devices
18
+ mounts.map { |x| x.split(?\s.freeze).first }
19
+ end
20
+
12
21
  # Reads /proc/mounts and returns partition name of the device mounted at /.
13
22
  #
14
23
  # It returns a String.
@@ -45,6 +54,135 @@ module LinuxStat
45
54
  ret
46
55
  end
47
56
 
57
+ # mount_point(dev = root)
58
+ # Where device = block device.
59
+ # The default argument is the root block device.
60
+ #
61
+ # It helps you find the mountpoint of a block device.
62
+ # For example:
63
+ # LinuxStat::Mounts.mount_point('/dev/sdb1')
64
+ # => "/run/media/sourav/5c2b7af7-d4c3-4ab4-a035-06d18ffc8e6f"
65
+ #
66
+ # The return type is String.
67
+ # But if the status isn't available or the device isn't mounted, it will return an empty String.
68
+ def mount_point(dev = root)
69
+ m = ''
70
+ mounts.each do |x|
71
+ x.strip!
72
+
73
+ unless x.empty?
74
+ _x = x.split
75
+ if _x[0] == dev
76
+ m.replace(_x[1])
77
+ break
78
+ end
79
+ end
80
+ end
81
+ m
82
+ end
83
+
84
+ # list_devices_mount_point()
85
+ #
86
+ # It shows all the block devices corresponding to mount points.
87
+ #
88
+ # For example:
89
+ # LinuxStat::Mounts.list_devices_mount_point
90
+ # => {"proc"=>"/proc", "sys"=>"/sys", "dev"=>"/dev", "run"=>"/run", "/dev/sda2"=>"/", "securityfs"=>"/sys/kernel/security", "tmpfs"=>"/run/user/1000", "devpts"=>"/dev/pts", "cgroup2"=>"/sys/fs/cgroup/unified", "cgroup"=>"/sys/fs/cgroup/perf_event", "pstore"=>"/sys/fs/pstore", "none"=>"/sys/fs/bpf", "systemd-1"=>"/proc/sys/fs/binfmt_misc", "debugfs"=>"/sys/kernel/debug", "mqueue"=>"/dev/mqueue", "hugetlbfs"=>"/dev/hugepages", "tracefs"=>"/sys/kernel/tracing", "configfs"=>"/sys/kernel/config", "fusectl"=>"/sys/fs/fuse/connections", "gvfsd-fuse"=>"/run/user/1000/gvfs", "/dev/sdb1"=>"/run/media/sourav/5c2b7af7-d4c3-4ab4-a035-06d18ffc8e6f", "binfmt_misc"=>"/proc/sys/fs/binfmt_misc"}
91
+ #
92
+ # The return type is Hash.
93
+ # But if the status isn't available or the device isn't mounted, it will return an empty String.
94
+ def list_devices_mount_point
95
+ m = {}
96
+ mounts.each do |x|
97
+ x.strip!
98
+
99
+ unless x.empty?
100
+ _x = x.split
101
+ m.merge!(_x[0] => _x[1])
102
+ end
103
+ end
104
+ m
105
+ end
106
+
107
+ # devices_stat
108
+ # [ Not to confuse this method with device_stat(dev) which shows only one device's info ]
109
+ #
110
+ # It shows all the block devices corresponding to mount points and data from LinuxStat::FS.stat(arg)
111
+ #
112
+ # For example:
113
+ # LinuxStat::Mounts.devices_stat
114
+ # => {"proc"=>{:mountpoint=>"/proc", :total=>0, :free=>0, :available=>0, :used=>0, :percent_used=>NaN, :percent_free=>NaN, :percent_available=>NaN}, "/dev/sdb1"=>{:mountpoint=>"/run/media/sourav/5c2b7af7-d4c3-4ab4-a035-06d18ffc8e6f", :total=>31466008576, :free=>2693931008, :available=>2693931008, :used=>28772077568, :percent_used=>91.44, :percent_free=>8.56, :percent_available=>8.56}}
115
+ #
116
+ # The return type is Hash.
117
+ # But if the status isn't available, it will return an empty Hash.
118
+ def devices_stat
119
+ # Code duplication is fine if it gives maximum performance
120
+ m = {}
121
+ mounts.each do |x|
122
+ x.strip!
123
+
124
+ unless x.empty?
125
+ _x = x.split
126
+ total, free, available, used = fs_info(_x[1])
127
+
128
+ m.merge!(_x[0] => {
129
+ mountpoint: _x[1],
130
+
131
+ total: total,
132
+ free: free,
133
+ available: available,
134
+ used: used,
135
+
136
+ percent_used: used.*(100).fdiv(total).round(2),
137
+ percent_free: free.*(100).fdiv(total).round(2),
138
+ percent_available: available.*(100).fdiv(total).round(2),
139
+ })
140
+ end
141
+ end
142
+ m
143
+ end
144
+
145
+ # device_stat(dev = root)
146
+ # [ Not to confuse this method with devices_stat() which shows all devices ]
147
+ # It shows all the block devices corresponding to mount points and data from LinuxStat::FS.stat(arg)
148
+ #
149
+ # For example:
150
+ # LinuxStat::Mounts.device_stat('/dev/sda2')
151
+ # => {"/dev/sda2"=>{:mountpoint=>"/", :total=>119981191168, :free=>35298562048, :available=>35298562048, :used=>84682629120, :percent_used=>70.58, :percent_free=>29.42, :percent_available=>29.42}}
152
+ #
153
+ # The return type is Hash.
154
+ # But if the status isn't available, it will return an empty Hash.
155
+ def device_stat(dev = root)
156
+ # Code duplication is fine if it gives maximum performance
157
+ m = {}
158
+ mounts.each do |x|
159
+ x.strip!
160
+
161
+ unless x.empty?
162
+ _x = x.split
163
+ next if _x[0] != dev
164
+
165
+ total, free, available, used = fs_info(_x[1])
166
+
167
+ m.merge!({
168
+ mountpoint: _x[1],
169
+
170
+ total: total,
171
+ free: free,
172
+ available: available,
173
+ used: used,
174
+
175
+ percent_used: used.*(100).fdiv(total).round(2),
176
+ percent_free: free.*(100).fdiv(total).round(2),
177
+ percent_available: available.*(100).fdiv(total).round(2),
178
+ })
179
+
180
+ break
181
+ end
182
+ end
183
+ m
184
+ end
185
+
48
186
  private
49
187
  def mount_readable?
50
188
  @@mount_readable ||= File.readable?('/proc/mounts')
@@ -59,6 +197,19 @@ module LinuxStat
59
197
  return [] unless mount_readable?
60
198
  @@root ||= IO.foreach('/proc/mounts').find { |x| x.split[1] == '/'.freeze }.split
61
199
  end
200
+
201
+ def fs_info(dev)
202
+ # => [total, free, available, used]
203
+ s = LinuxStat::FS.stat(dev)
204
+ s.default = 0
205
+
206
+ [
207
+ s[:block_size] * s[:blocks],
208
+ s[:block_size] * s[:block_free],
209
+ s[:block_size] * s[:block_avail_unpriv],
210
+ s[:blocks].-(s[:block_free]) * s[:block_size]
211
+ ]
212
+ end
62
213
  end
63
214
  end
64
215
  end
@@ -1,13 +1,119 @@
1
1
  module LinuxStat
2
2
  module Net
3
3
  class << self
4
+ DEV = '/proc/net/dev'.freeze
4
5
  # Returns the local IP address of the system as a String.
5
6
  # If the information isn't available, it will a frozen empty string.
6
7
  def ipv4_private
7
- require 'socket'
8
+ require 'socket' unless defined?(Socket)
8
9
  ip = Socket.ip_address_list.find(&:ipv4_private?)
9
10
  ip ? ip.ip? ? ip.ip_unpack[0].freeze : ''.freeze : ''.freeze
10
11
  end
12
+
13
+ # Returns the total bytes received and transmitted as Hash.
14
+ # For example:
15
+ # {:received=>56602867, :transmitted=>6940922}
16
+ #
17
+ # But if the status isn't available it will return an empty Hash.
18
+ def total_bytes
19
+ return {} unless File.readable?(DEV)
20
+
21
+ data = IO.readlines(DEV).drop(2)
22
+ indices = find_index_of_bytes
23
+ data.reject! { |x| x.strip.start_with?('lo:') }
24
+ r, t = data.map { |x| x.split.values_at(*indices).map(&:to_i) }.transpose.map(&:sum)
25
+
26
+ {
27
+ received: r,
28
+ transmitted: t
29
+ }
30
+ end
31
+
32
+ # Returns the total bytes received as Integer.
33
+ #
34
+ # But if the status isn't available it will return nil.
35
+ def total_bytes_received
36
+ return nil unless File.readable?(DEV)
37
+
38
+ data = IO.readlines(DEV).drop(2)
39
+ index = find_index_of_bytes[0]
40
+ data.reject! { |x| x.strip.start_with?('lo:') }
41
+ data.map { |x| x.split[index].to_i }.sum
42
+ end
43
+
44
+ # Returns the total bytes transmitted as Integer.
45
+ #
46
+ # But if the status isn't available it will return nil.
47
+ def total_bytes_transmitted
48
+ return nil unless File.readable?(DEV)
49
+
50
+ data = IO.readlines(DEV).drop(2)
51
+ index = find_index_of_bytes[-1]
52
+ data.reject! { |x| x.strip.start_with?('lo:') }
53
+ data.map { |x| x.split[index].to_i }.sum
54
+ end
55
+
56
+ # usage(interval = 0.1)
57
+ # Where interval is the time between polling in seconds. The default is 0.1 seconds.
58
+ #
59
+ # The return type is a Hash, containg the current internet usage (received, transmit) in B/s.
60
+ #
61
+ # For example:
62
+ # {:received=>436060.0, :transmitted=>50350.0}
63
+ #
64
+ # If the system transmits 100 kb in the interval,
65
+ # this method will return 1000 kb/s. That is, it estimates
66
+ # the data it will transmit in one second. Thus, a good and reliable interval is 1 second
67
+ # It will return an empty Hash if the info (/proc/net/dev) isn't available.
68
+ def usage(interval = 0.1)
69
+ return {} unless File.readable?(DEV)
70
+
71
+ data = IO.readlines(DEV).drop(2)
72
+ indices = find_index_of_bytes
73
+ data.reject! { |x| x.strip.start_with?('lo:') }
74
+ r, t = data.map { |x| x.split.values_at(*indices).map(&:to_i) }.transpose.map(&:sum)
75
+
76
+ sleep(interval)
77
+
78
+ data2 = IO.readlines(DEV).drop(2)
79
+ data2.reject! { |x| x.strip.start_with?('lo:') }
80
+ r2, t2 = data2.map { |x| x.split.values_at(*indices).map(&:to_i) }.transpose.map(&:sum)
81
+
82
+ # Measure the difference
83
+ dr, dt = r2.-(r).fdiv(interval), t2.-(t).fdiv(interval)
84
+
85
+ {
86
+ received: dr,
87
+ transmitted: dt
88
+ }
89
+ end
90
+
91
+ alias current_usage usage
92
+
93
+ private
94
+ # Returns the index containing the received and transmitted bytes
95
+ def find_index_of_bytes
96
+ @@index_of_bytes ||= nil
97
+
98
+ unless @@index_of_bytes
99
+ data = IO.foreach(DEV)
100
+
101
+ r, h = data.next.split, {}
102
+
103
+ r.each_with_index { |x, i|
104
+ downcased = x.downcase
105
+ h.merge!(:r => i) if downcased.start_with?('receive')
106
+ h.merge!(:t => i) if downcased.start_with?('transmit')
107
+ }
108
+
109
+ data_0 = data.next.gsub(?|.freeze, ' %'.freeze)
110
+ @@index_of_bytes = []
111
+ data_0.split.each_with_index { |x, i| @@index_of_bytes << i if x == '%bytes'.freeze }
112
+ h[:r] > h[:t] ? @@index_of_bytes.reverse : @@index_of_bytes
113
+ else
114
+ @@index_of_bytes
115
+ end
116
+ end
11
117
  end
12
118
  end
13
119
  end