rswap 1.0.1 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f04d535d4fc03b09f33e5829d6e86ab69c3968d09e6da856ba7c1227c596edf1
4
- data.tar.gz: 4c54f23bfbdfb56089d1531dbcfde558060940b3f946fc1c3d3a2c21ecf5aa00
3
+ metadata.gz: 170c2218491edad5a598121211b12d3a9d88ef4bb96b273a7de96087ed824975
4
+ data.tar.gz: e995e42df15e3558cf3067c09a764bb2dcc9f1ff47c35377918faf8f3b6c9914
5
5
  SHA512:
6
- metadata.gz: f53bbe6ec09a2d7d03c853fd0560c4af33a455f9735946b4391cd6470ece326d6514bb9246cfaa01fcc7c9444b32ade90387ef28110e40337ccab951635573d0
7
- data.tar.gz: f4b8d03f3d595d50e57f7b900f53c7f693bea09bf219191cfa7f93638042032dd9cb622b402d5fcd1445a1450330a34678a5a589bd8a482b3d29ebd555e416e4
6
+ metadata.gz: af7822e72556e00e23fb099707ac11067de671ebbb6a23a6697211a083c86f0c61da6a46488dbf0d84f61b2e7e436d898b887f19ee434e4e0be6f640fe39ffb0
7
+ data.tar.gz: ed8771a037659acf04e0aa9efb32edeff61e6f21740e48bba047813e33c5e47260cffd92aad4e5a818e354a102156fded3cec896f298ac814fb9ab8b494cac7d
data/lib/rswap/cli.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'rainbow'
4
4
  require 'optparse'
5
- require_relative 'native'
5
+ require_relative 'swap_file'
6
6
 
7
7
  module Rswap
8
8
  class CLI
@@ -13,10 +13,12 @@ module Rswap
13
13
  add [SIZE] Create and enable swap (default: 8GB)
14
14
  on Enable existing swap
15
15
  off Disable existing swap
16
+ remove Remove swap file
16
17
  status Show current state
17
18
 
18
19
  Options:
19
20
  --swapfile PATH Path to swap file (default: /swapfile)
21
+ -h, --help Show this help message
20
22
  USAGE
21
23
 
22
24
  ERR = {
@@ -29,146 +31,142 @@ module Rswap
29
31
  6 => 'remove failed'
30
32
  }.freeze
31
33
 
32
- def self.run(argv)
33
- sf = '/swapfile'
34
+ def self.run(argv = ARGV)
35
+ swapfile = '/swapfile'
34
36
 
35
37
  parser = OptionParser.new do |opts|
36
- opts.on('--swapfile PATH') { |path| sf = path }
38
+ opts.banner = HELP
39
+ opts.on('--swapfile PATH') { |path| swapfile = path }
40
+ opts.on('-h', '--help') { puts opts; exit }
37
41
  end
38
42
 
39
43
  begin
40
- parser.order!(argv)
44
+ parser.parse!(argv)
41
45
  rescue OptionParser::InvalidOption => e
42
46
  puts Rainbow("ERR: #{e.message}").red
47
+ puts parser
43
48
  exit 1
44
49
  end
45
50
 
46
51
  cmd = argv.shift
47
52
  if cmd.nil?
48
- puts HELP
53
+ puts parser
49
54
  exit 1
50
55
  end
51
56
 
52
- c = Rswap::Native::Ctrl.new(sf)
57
+ sf = SwapFile.new(swapfile)
53
58
 
54
59
  case cmd
55
- when 'add' then add(c, argv[0] || '8GB')
56
- when 'on' then on(c)
57
- when 'off' then off(c)
58
- when 'status' then status(c)
60
+ when 'add' then add(sf, argv[0] || '4GB')
61
+ when 'on' then on(sf)
62
+ when 'off' then off(sf)
63
+ when 'remove' then remove(sf) # <-- Added
64
+ when 'status' then status(sf)
59
65
  else
60
- puts Rainbow("ERR: unknown '#{cmd}'").red
61
- puts 'Valid: add, on, off, status'
66
+ puts Rainbow("ERR: unknown command '#{cmd}'").red
67
+ puts 'Valid commands: add, on, off, remove, status' # <-- Updated
62
68
  exit 1
63
69
  end
64
70
  end
65
71
 
66
- def self.add(c, sz)
67
- bytes = parse(sz)
68
- st = c.status
69
- size_h = human(bytes)
72
+ # --- Existing Methods (add, on, off, status) ---
73
+ def self.add(sf, size_str)
74
+ bytes = parse_size(size_str)
75
+ return puts(Rainbow("ERR: invalid size '#{size_str}'").red) if bytes <= 0
70
76
 
71
- case st
72
- in { x: true, s: ^bytes }
73
- puts Rainbow("OK: exists (#{size_h})").green
74
- return
75
- in { x: true, s: cur } if cur != bytes
76
- puts Rainbow("WARN: size mismatch (#{human(cur)} vs #{size_h})").yellow
77
- print 'Remove and recreate? [y/N]: '
78
- return unless $stdin.gets.chomp.downcase == 'y'
77
+ st = sf.status
78
+ size_h = human_size(bytes)
79
79
 
80
- # if active -> disable and remove
81
- c.disable if st[:a]
82
-
83
- if c.remove != 0
84
- puts Rainbow('ERR: failed to remove existing swapfile').red
80
+ if st[:exists]
81
+ if st[:size] == bytes
82
+ puts Rainbow("OK: swap file exists (#{size_h})").green
85
83
  return
84
+ else
85
+ puts Rainbow("WARN: size mismatch (#{human_size(st[:size])} vs #{size_h})").yellow
86
+ print 'Remove and recreate? [y/N]: '
87
+ return unless $stdin.gets.chomp.downcase == 'y'
88
+ sf.disable if st[:active]
89
+ return puts(Rainbow('ERR: failed to remove existing swapfile').red) unless sf.remove == :ok
86
90
  end
87
- else
88
- # Hey
89
91
  end
90
92
 
91
- case [c.create(bytes), c.enable]
92
- in [0, 0]
93
- puts Rainbow("OK: created + enabled (#{size_h})").green
94
- in [0, e]
95
- puts Rainbow("ERR: created but enable failed: #{ERR[e]}").red
96
- in [cr, _]
97
- puts Rainbow("ERR: create failed: #{ERR[cr]}").red
93
+ case [sf.create(bytes), sf.enable]
94
+ in [:ok, :ok] then puts Rainbow("OK: created + enabled (#{size_h})").green
95
+ in [:ok, :failed] then puts Rainbow('ERR: created but enable failed').red
96
+ in [:exists, _] then puts Rainbow('ERR: file exists').red
97
+ in [:failed, _] then puts Rainbow('ERR: create failed').red
98
98
  end
99
99
  end
100
100
 
101
- def self.on(c)
102
- st = c.status
103
-
101
+ def self.on(sf)
102
+ st = sf.status
104
103
  case st
105
- in { x: false }
106
- puts Rainbow('ERR: file not found').red
107
- in { a: true }
108
- puts Rainbow('OK: already active').green
104
+ in { exists: false } then puts Rainbow('ERR: file not found').red
105
+ in { active: true } then puts Rainbow('OK: already active').green
109
106
  else
110
- case c.enable
111
- in 0 then puts Rainbow('OK: enabled').green
112
- in e then puts Rainbow("ERR: #{ERR[e]}").red
113
- end
107
+ sf.enable == :ok ? puts(Rainbow('OK: enabled').green) : puts(Rainbow('ERR: enable failed').red)
114
108
  end
115
109
  end
116
110
 
117
- def self.off(c)
118
- st = c.status
119
-
111
+ def self.off(sf)
112
+ st = sf.status
120
113
  case st
121
- in { x: false }
122
- puts Rainbow('ERR: file not found').red
123
- in { a: false }
124
- puts Rainbow('OK: already off').green
125
- in { a: true, u: usage } if usage && usage > 0
126
- puts Rainbow("WARN: #{human(usage)} in use").yellow
127
- case c.disable
128
- in 0 then puts Rainbow('OK: off').green
129
- in e then puts Rainbow("ERR: #{ERR[e]} (tty: sudo swapoff -a)").red
130
- end
131
- in { a: true }
132
- case c.disable
133
- in 0 then puts Rainbow('OK: off').green
134
- in e then puts Rainbow("ERR: #{ERR[e]} (tty: sudo swapoff -a)").red
135
- end
114
+ in { exists: false } then puts Rainbow('ERR: file not found').red
115
+ in { active: false } then puts Rainbow('OK: already off').green
116
+ in { active: true }
117
+ puts Rainbow("WARN: #{human_size(st[:usage])} in use").yellow if st[:usage] && st[:usage] > 0
118
+ sf.disable == :ok ? puts(Rainbow('OK: disabled').green) : puts(Rainbow('ERR: disable failed (try: sudo swapoff -a)').red)
136
119
  end
137
120
  end
138
121
 
139
- def self.status(c)
140
- st = c.status
122
+ # --- New: remove command ---
123
+ def self.remove(sf)
124
+ st = sf.status
141
125
 
142
- puts Rainbow('--- Swap ---').bright
143
- puts "Path: #{st[:p]}"
144
- puts "Exists: #{st[:x] ? 'yes' : 'no'}"
145
- puts "Size: #{human(st[:s])}" if st[:s] && st[:s] > 0
146
-
147
- case st[:a]
148
- in true then puts "Active: #{Rainbow('yes').green}"
149
- in false then puts "Active: #{Rainbow('no').red}"
150
- else puts "Active: #{Rainbow('no').red}"
126
+ if !st[:exists]
127
+ puts Rainbow('ERR: file not found').red
128
+ return
129
+ elsif st[:active]
130
+ puts Rainbow('WARN: swap is active. Disable first? [y/N]: ').yellow
131
+ print ''
132
+ return unless $stdin.gets.chomp.downcase == 'y'
133
+ return puts Rainbow('ERR: disable failed').red if sf.disable == :failed
151
134
  end
152
135
 
153
- puts "Usage: #{human(st[:u])}" if st[:u] && st[:u] >= 0
136
+ # If we get here, file exists and is not active (or was just disabled)
137
+ case sf.remove
138
+ in :ok then puts Rainbow('OK: removed').green
139
+ in :failed then puts Rainbow('ERR: remove failed').red
140
+ end
154
141
  end
155
142
 
156
- def self.human(b)
157
- case b
158
- when nil, 0 then '0B'
159
- when (1024**3..) then sprintf('%.2fGB', b.to_f / 1024**3)
160
- when (1024**2..) then sprintf('%.2fMB', b.to_f / 1024**2)
161
- when (1024..) then sprintf('%.2fKB', b.to_f / 1024)
162
- else "#{b}B"
163
- end
143
+ def self.status(sf)
144
+ st = sf.status
145
+ puts Rainbow('--- Swap ---').bright
146
+ puts "Path: #{st[:path]}"
147
+ puts "Exists: #{st[:exists] ? Rainbow('yes').green : Rainbow('no').red}"
148
+ puts "Size: #{human_size(st[:size])}" if st[:size] && st[:size] > 0
149
+ puts "Active: #{st[:active] ? Rainbow('yes').green : Rainbow('no').red}"
150
+ puts "Usage: #{human_size(st[:usage])}" if st[:usage] && st[:usage] >= 0
151
+ end
152
+
153
+ # --- Utility Methods ---
154
+ def self.human_size(b)
155
+ return '0B' if b.nil? || b.zero?
156
+ return sprintf('%.2fGB', b.to_f / 1024**3) if b >= 1024**3
157
+ return sprintf('%.2fMB', b.to_f / 1024**2) if b >= 1024**2
158
+ return sprintf('%.2fKB', b.to_f / 1024) if b >= 1024
159
+ "#{b}B"
164
160
  end
165
161
 
166
- def self.parse(s)
167
- case s.to_s.upcase
162
+ def self.parse_size(s)
163
+ s = s.to_s.upcase.gsub(/\s+/, '')
164
+ case s
168
165
  when /^([\d.]+)GB?$/ then ($1.to_f * 1024**3).to_i
169
166
  when /^([\d.]+)MB?$/ then ($1.to_f * 1024**2).to_i
170
167
  when /^([\d.]+)KB?$/ then ($1.to_f * 1024).to_i
171
- else s.to_i
168
+ when /^\d+$/ then s.to_i
169
+ else 0
172
170
  end
173
171
  end
174
172
  end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rswap
4
+ class SwapFile
5
+ attr_reader :path
6
+
7
+ def initialize(path = '/swapfile')
8
+ @path = path
9
+ @path = '/mnt/swap/swapfile' if path == '/swapfile' && btrfs?
10
+ end
11
+
12
+ def btrfs?
13
+ fs_type = `stat -f -c %T / 2>/dev/null`.strip
14
+ fs_type == 'btrfs'
15
+ end
16
+
17
+ def find_loop_device(img_path)
18
+ output = `losetup -j #{img_path} 2>/dev/null`.strip
19
+ output.split(':').first if output.include?(':')
20
+ end
21
+
22
+ # --- State Checks ---
23
+ def exists?
24
+ if btrfs? && @path == '/mnt/swap/swapfile'
25
+ File.exist?(@path) && system("mountpoint -q /mnt/swap 2>/dev/null")
26
+ else
27
+ File.exist?(@path)
28
+ end
29
+ rescue
30
+ false
31
+ end
32
+
33
+ def size
34
+ exists? ? File.size(@path) : nil
35
+ rescue
36
+ nil
37
+ end
38
+
39
+ def active?
40
+ exists? && File.read('/proc/swaps').lines.any? { |l| l.include?(@path) }
41
+ rescue
42
+ false
43
+ end
44
+
45
+ # --- Usage ---
46
+ def usage
47
+ return nil unless exists?
48
+ File.read('/proc/swaps').each_line do |l|
49
+ next if l.start_with?('Filename')
50
+ file, _, _, used = l.split
51
+ return used.to_i * 1024 if file == @path
52
+ end
53
+ 0
54
+ rescue
55
+ nil
56
+ end
57
+
58
+ # --- Actions ---
59
+ def create(bytes)
60
+ return :exists if exists?
61
+ mb = bytes.to_f / (1024 * 1024)
62
+
63
+ if btrfs? && @path == '/mnt/swap/swapfile'
64
+ img_path = '/var/swap.img'
65
+ mount_point = '/mnt/swap'
66
+
67
+ # Clean up any existing mounts
68
+ if system("mountpoint -q #{mount_point} 2>/dev/null")
69
+ return :failed unless system("umount -l #{mount_point} 2>/dev/null")
70
+ sleep 2
71
+ end
72
+
73
+ # Clean up any existing loop devices for this image
74
+ if (loop_dev = find_loop_device(img_path))
75
+ return :failed unless system("losetup -d #{loop_dev} 2>/dev/null")
76
+ sleep 1
77
+ end
78
+
79
+ # Add 1GB overhead for ext4 metadata
80
+ total_mb = mb.to_i + 1024
81
+ return :failed unless system("truncate -s #{total_mb}M #{img_path}")
82
+ return :failed unless system("mkfs.ext4 -F #{img_path} 2>/dev/null")
83
+ return :failed unless system("mkdir -p #{mount_point}")
84
+
85
+ # Set up loop device explicitly
86
+ loop_dev = `losetup -f 2>/dev/null`.strip
87
+ return :failed unless loop_dev && !loop_dev.empty?
88
+ return :failed unless system("losetup #{loop_dev} #{img_path} 2>/dev/null")
89
+ return :failed unless system("mount #{loop_dev} #{mount_point} 2>/dev/null")
90
+
91
+ # Verify mount succeeded
92
+ return :failed unless system("mountpoint -q #{mount_point} 2>/dev/null")
93
+
94
+ # Create swap file (use original size)
95
+ return :failed unless system("dd if=/dev/zero of=#{mount_point}/swapfile bs=1M count=#{mb.to_i} 2>/dev/null")
96
+ return :failed unless system("chmod 600 #{mount_point}/swapfile")
97
+
98
+ # Initialize swap
99
+ if system("mkswap #{mount_point}/swapfile 2>/dev/null")
100
+ :ok
101
+ else
102
+ # Clean up on failure
103
+ system("rm -f #{mount_point}/swapfile")
104
+ system("umount -l #{mount_point} 2>/dev/null")
105
+ system("losetup -d #{loop_dev} 2>/dev/null")
106
+ system("rm -f #{img_path}")
107
+ :failed
108
+ end
109
+ else
110
+ # Traditional method
111
+ if system("dd if=/dev/zero of=#{@path} bs=1M count=#{mb.to_i} status=progress 2>/dev/null") &&
112
+ system("chmod 600 #{@path} 2>/dev/null") &&
113
+ system("mkswap #{@path} 2>/dev/null")
114
+ :ok
115
+ else
116
+ system("rm -f #{@path}")
117
+ :failed
118
+ end
119
+ end
120
+ end
121
+
122
+ def enable
123
+ exists? && system("swapon #{@path} 2>/dev/null") ? :ok : :failed
124
+ end
125
+
126
+ def disable
127
+ active? && system("swapoff #{@path} 2>/dev/null") ? :ok : :failed
128
+ end
129
+
130
+ def remove
131
+ if btrfs? && @path == '/mnt/swap/swapfile'
132
+ img_path = '/var/swap.img'
133
+ mount_point = '/mnt/swap'
134
+
135
+ # Disable swap
136
+ system("swapoff #{@path} 2>/dev/null")
137
+
138
+ # Remove swap file (critical)
139
+ return :failed unless system("rm -f #{@path}")
140
+
141
+ # Unmount
142
+ system("umount -l #{mount_point} 2>/dev/null")
143
+
144
+ # Clean up loop device
145
+ if (loop_dev = find_loop_device(img_path))
146
+ system("losetup -d #{loop_dev} 2>/dev/null")
147
+ end
148
+
149
+ # Remove image and mount point
150
+ system("rm -f #{img_path}")
151
+ system("rmdir #{mount_point} 2>/dev/null")
152
+
153
+ :ok
154
+ else
155
+ return :failed unless File.exist?(@path)
156
+ system("swapoff #{@path} 2>/dev/null")
157
+ system("sudo rm -f #{@path}") ? :ok : :failed
158
+ end
159
+ end
160
+
161
+ # --- Status ---
162
+ def status
163
+ { path: @path, exists: exists?, size: size, active: active?, usage: usage }
164
+ end
165
+ end
166
+ end
data/lib/rswap/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # lib/rswap/version.rb
2
2
  module Rswap
3
- VERSION = "1.0.1"
3
+ VERSION = "2.0.0"
4
4
  end
data/lib/rswap.rb CHANGED
@@ -5,7 +5,7 @@ require_relative 'rswap/cli'
5
5
 
6
6
  module Rswap
7
7
  # Entry Point
8
- def self.run(args)
8
+ def self.run(args = ARGV)
9
9
  CLI.run(args)
10
10
  end
11
11
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rswap
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - KennedySilverDollar
@@ -9,20 +9,6 @@ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: ffi
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - "~>"
17
- - !ruby/object:Gem::Version
18
- version: '1.17'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - "~>"
24
- - !ruby/object:Gem::Version
25
- version: '1.17'
26
12
  - !ruby/object:Gem::Dependency
27
13
  name: rainbow
28
14
  requirement: !ruby/object:Gem::Requirement
@@ -51,25 +37,18 @@ dependencies:
51
37
  - - "~>"
52
38
  - !ruby/object:Gem::Version
53
39
  version: '13.0'
54
- description: Create/enable/disable swap files with extreme efficiency
40
+ description: Create/remove/enable/disable swapfiles with extreme efficiency
55
41
  email:
56
42
  - kenshinlights@tutamail.com
57
43
  executables:
58
44
  - rswap
59
- extensions:
60
- - ext/rswap/extconf.rb
45
+ extensions: []
61
46
  extra_rdoc_files: []
62
47
  files:
63
48
  - bin/rswap
64
- - ext/rswap/Makefile
65
- - ext/rswap/extconf.rb
66
- - ext/rswap/mkmf.log
67
- - ext/rswap/native.cpp
68
- - ext/rswap/native.o
69
- - ext/rswap/rswap_native.so
70
49
  - lib/rswap.rb
71
50
  - lib/rswap/cli.rb
72
- - lib/rswap/native.rb
51
+ - lib/rswap/swap_file.rb
73
52
  - lib/rswap/version.rb
74
53
  homepage: https://github.com/KennedySilverDollar/rswap
75
54
  licenses:
@@ -89,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
68
  - !ruby/object:Gem::Version
90
69
  version: '0'
91
70
  requirements: []
92
- rubygems_version: 3.6.9
71
+ rubygems_version: 4.0.0.dev
93
72
  specification_version: 4
94
- summary: Minimal rswap manager
73
+ summary: Minimal swapfile manager
95
74
  test_files: []
data/ext/rswap/Makefile DELETED
@@ -1,273 +0,0 @@
1
-
2
- SHELL = /bin/sh
3
-
4
- # V=0 quiet, V=1 verbose. other values don't work.
5
- V = 0
6
- V0 = $(V:0=)
7
- Q1 = $(V:1=)
8
- Q = $(Q1:0=@)
9
- ECHO1 = $(V:1=@ :)
10
- ECHO = $(ECHO1:0=@ echo)
11
- NULLCMD = :
12
-
13
- #### Start of system configuration section. ####
14
-
15
- srcdir = .
16
- topdir = /usr/include/ruby-3.4.0
17
- hdrdir = $(topdir)
18
- arch_hdrdir = /usr/include/ruby-3.4.0/x86_64-linux
19
- PATH_SEPARATOR = :
20
- VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
21
- prefix = $(DESTDIR)/usr
22
- rubysitearchprefix = $(rubylibprefix)/$(sitearch)
23
- rubyarchprefix = $(rubylibprefix)/$(arch)
24
- rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
25
- exec_prefix = $(prefix)
26
- vendorarchhdrdir = $(vendorhdrdir)/$(sitearch)
27
- sitearchhdrdir = $(sitehdrdir)/$(sitearch)
28
- rubyarchhdrdir = $(rubyhdrdir)/$(arch)
29
- vendorhdrdir = $(rubyhdrdir)/vendor_ruby
30
- sitehdrdir = $(rubyhdrdir)/site_ruby
31
- rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME)
32
- vendorarchdir = $(vendorlibdir)/$(sitearch)
33
- vendorlibdir = $(vendordir)/$(ruby_version)
34
- vendordir = $(rubylibprefix)/vendor_ruby
35
- sitearchdir = $(sitelibdir)/$(sitearch)
36
- sitelibdir = $(sitedir)/$(ruby_version)
37
- sitedir = $(rubylibprefix)/site_ruby
38
- rubyarchdir = $(rubylibdir)/$(arch)
39
- rubylibdir = $(rubylibprefix)/$(ruby_version)
40
- sitearchincludedir = $(includedir)/$(sitearch)
41
- archincludedir = $(includedir)/$(arch)
42
- sitearchlibdir = $(libdir)/$(sitearch)
43
- archlibdir = $(libdir)/$(arch)
44
- ridir = $(datarootdir)/$(RI_BASE_NAME)
45
- modular_gc_dir = $(DESTDIR)
46
- mandir = $(DESTDIR)/usr/share/man
47
- localedir = $(datarootdir)/locale
48
- libdir = $(exec_prefix)/lib64
49
- psdir = $(docdir)
50
- pdfdir = $(docdir)
51
- dvidir = $(docdir)
52
- htmldir = $(docdir)
53
- infodir = $(DESTDIR)/usr/share/info
54
- docdir = $(datarootdir)/doc/$(PACKAGE)
55
- oldincludedir = $(DESTDIR)/usr/include
56
- includedir = $(prefix)/include
57
- runstatedir = $(localstatedir)/run
58
- localstatedir = $(DESTDIR)/var
59
- sharedstatedir = $(prefix)/com
60
- sysconfdir = $(DESTDIR)/etc
61
- datadir = $(datarootdir)
62
- datarootdir = $(prefix)/share
63
- libexecdir = $(exec_prefix)/libexec
64
- sbindir = $(DESTDIR)/usr/bin
65
- bindir = $(exec_prefix)/bin
66
- archdir = $(rubyarchdir)
67
-
68
-
69
- CC_WRAPPER =
70
- CC = cc
71
- CXX = g++
72
- LIBRUBY = $(LIBRUBY_SO)
73
- LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
74
- LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
75
- LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static $(MAINLIBS)
76
- empty =
77
- OUTFLAG = -o $(empty)
78
- COUTFLAG = -o $(empty)
79
- CSRCFLAG = $(empty)
80
-
81
- RUBY_EXTCONF_H =
82
- cflags = $(hardenflags) $(optflags) $(debugflags) $(warnflags)
83
- cxxflags =
84
- optflags = -O3 -fno-fast-math
85
- debugflags = -ggdb3
86
- warnflags = -Wall -Wextra -Wdeprecated-declarations -Wdiv-by-zero -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wwrite-strings -Wold-style-definition -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable -Wmisleading-indentation -Wundef
87
- cppflags =
88
- CCDLFLAGS = -fPIC
89
- CFLAGS = $(CCDLFLAGS) -fstack-clash-protection -D_FORTIFY_SOURCE=2 -mtune=generic -O2 -pipe -g -ffile-prefix-map=/builddir/ruby-3.4.10=. -fPIC $(ARCH_FLAG)
90
- INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
91
- DEFS =
92
- CPPFLAGS = $(DEFS) $(cppflags)
93
- CXXFLAGS = $(CCDLFLAGS) -fstack-clash-protection -D_FORTIFY_SOURCE=2 -mtune=generic -O2 -pipe -g -ffile-prefix-map=/builddir/ruby-3.4.10=. -std=c++23 -fPIC $(ARCH_FLAG)
94
- ldflags = -L. -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -shared
95
- dldflags = -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -Wl,--compress-debug-sections=zlib
96
- ARCH_FLAG =
97
- DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
98
- LDSHARED = $(CC) -shared
99
- LDSHAREDXX = $(CXX) -shared
100
- POSTLINK = :
101
- AR = ar
102
- LD = ld
103
- EXEEXT =
104
-
105
- RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)
106
- RUBY_SO_NAME = ruby
107
- RUBYW_INSTALL_NAME =
108
- RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version)
109
- RUBYW_BASE_NAME = rubyw
110
- RUBY_BASE_NAME = ruby
111
-
112
- arch = x86_64-linux
113
- sitearch = $(arch)
114
- ruby_version = 3.4.0
115
- ruby = $(bindir)/$(RUBY_BASE_NAME)
116
- RUBY = $(ruby)
117
- BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME)
118
- ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h
119
-
120
- RM = rm -f
121
- RM_RF = rm -fr
122
- RMDIRS = rmdir --ignore-fail-on-non-empty -p
123
- MAKEDIRS = /usr/bin/mkdir -p
124
- INSTALL = /usr/bin/install -c
125
- INSTALL_PROG = $(INSTALL) -m 0755
126
- INSTALL_DATA = $(INSTALL) -m 644
127
- COPY = cp
128
- TOUCH = exit >
129
-
130
- #### End of system configuration section. ####
131
-
132
- preload =
133
- libpath = . $(libdir)
134
- LIBPATH = -L. -L$(libdir)
135
- DEFFILE =
136
-
137
- CLEANFILES = mkmf.log
138
- DISTCLEANFILES =
139
- DISTCLEANDIRS =
140
-
141
- extout =
142
- extout_prefix =
143
- target_prefix =
144
- LOCAL_LIBS =
145
- LIBS = $(LIBRUBYARG_SHARED) -lm -lpthread -lc
146
- ORIG_SRCS = native.cpp
147
- SRCS = $(ORIG_SRCS)
148
- OBJS = native.o
149
- HDRS =
150
- LOCAL_HDRS =
151
- TARGET = rswap_native
152
- TARGET_NAME = rswap_native
153
- TARGET_ENTRY = Init_$(TARGET_NAME)
154
- DLLIB = $(TARGET).so
155
- EXTSTATIC =
156
- STATIC_LIB =
157
-
158
- TIMESTAMP_DIR = .
159
- BINDIR = $(bindir)
160
- RUBYCOMMONDIR = $(sitedir)$(target_prefix)
161
- RUBYLIBDIR = $(sitelibdir)$(target_prefix)
162
- RUBYARCHDIR = $(sitearchdir)$(target_prefix)
163
- HDRDIR = $(sitehdrdir)$(target_prefix)
164
- ARCHHDRDIR = $(sitearchhdrdir)$(target_prefix)
165
- TARGET_SO_DIR =
166
- TARGET_SO = $(TARGET_SO_DIR)$(DLLIB)
167
- CLEANLIBS = $(TARGET_SO) false
168
- CLEANOBJS = $(OBJS) *.bak
169
- TARGET_SO_DIR_TIMESTAMP = $(TIMESTAMP_DIR)/.sitearchdir.time
170
-
171
- all: $(DLLIB)
172
- static: $(STATIC_LIB)
173
- .PHONY: all install static install-so install-rb
174
- .PHONY: clean clean-so clean-static clean-rb
175
-
176
- clean-static::
177
- clean-rb-default::
178
- clean-rb::
179
- clean-so::
180
- clean: clean-so clean-static clean-rb-default clean-rb
181
- -$(Q)$(RM_RF) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time
182
-
183
- distclean-rb-default::
184
- distclean-rb::
185
- distclean-so::
186
- distclean-static::
187
- distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb
188
- -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
189
- -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
190
- -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true
191
-
192
- realclean: distclean
193
- install: install-so install-rb
194
-
195
- install-so: $(DLLIB) $(TARGET_SO_DIR_TIMESTAMP)
196
- $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
197
- clean-static::
198
- -$(Q)$(RM) $(STATIC_LIB)
199
- install-rb: pre-install-rb do-install-rb install-rb-default
200
- install-rb-default: pre-install-rb-default do-install-rb-default
201
- pre-install-rb: Makefile
202
- pre-install-rb-default: Makefile
203
- do-install-rb:
204
- do-install-rb-default:
205
- pre-install-rb-default:
206
- @$(NULLCMD)
207
- $(TARGET_SO_DIR_TIMESTAMP):
208
- $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR)
209
- $(Q) $(TOUCH) $@
210
-
211
- site-install: site-install-so site-install-rb
212
- site-install-so: install-so
213
- site-install-rb: install-rb
214
-
215
- .SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S
216
-
217
- .cc.o:
218
- $(ECHO) compiling $(<)
219
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
220
-
221
- .cc.S:
222
- $(ECHO) translating $(<)
223
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
224
-
225
- .mm.o:
226
- $(ECHO) compiling $(<)
227
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
228
-
229
- .mm.S:
230
- $(ECHO) translating $(<)
231
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
232
-
233
- .cxx.o:
234
- $(ECHO) compiling $(<)
235
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
236
-
237
- .cxx.S:
238
- $(ECHO) translating $(<)
239
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
240
-
241
- .cpp.o:
242
- $(ECHO) compiling $(<)
243
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
244
-
245
- .cpp.S:
246
- $(ECHO) translating $(<)
247
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
248
-
249
- .c.o:
250
- $(ECHO) compiling $(<)
251
- $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
252
-
253
- .c.S:
254
- $(ECHO) translating $(<)
255
- $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
256
-
257
- .m.o:
258
- $(ECHO) compiling $(<)
259
- $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
260
-
261
- .m.S:
262
- $(ECHO) translating $(<)
263
- $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
264
-
265
- $(TARGET_SO): $(OBJS) Makefile
266
- $(ECHO) linking shared-object $(DLLIB)
267
- -$(Q)$(RM) $(@)
268
- $(Q) $(LDSHAREDXX) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
269
- $(Q) $(POSTLINK)
270
-
271
-
272
-
273
- $(OBJS): $(HDRS) $(ruby_headers)
data/ext/rswap/extconf.rb DELETED
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
- # ext/rswap/extconf.rb
3
- require 'mkmf'
4
-
5
- if try_compile('int main(){ return 0; }', '-std=c++23')
6
- $CXXFLAGS << ' -std=c++23'
7
- else
8
- abort 'C++23 compiler required'
9
- end
10
-
11
- # Position independent code for shared library
12
- $CXXFLAGS << ' -fPIC'
13
- $LDFLAGS << ' -shared'
14
-
15
- create_makefile('rswap_native')
data/ext/rswap/mkmf.log DELETED
@@ -1,20 +0,0 @@
1
- LD_LIBRARY_PATH=.:/usr/lib64 ASAN_OPTIONS=detect_leaks=0 "cc -o conftest -I/usr/include/ruby-3.4.0/x86_64-linux -I/usr/include/ruby-3.4.0/ruby/backward -I/usr/include/ruby-3.4.0 -I. -fstack-clash-protection -D_FORTIFY_SOURCE=2 -mtune=generic -O2 -pipe -g -ffile-prefix-map=/builddir/ruby-3.4.10=. -fPIC conftest.c -L. -L/usr/lib64 -L. -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby -lm -lpthread -lc"
2
- checked program was:
3
- /* begin */
4
- 1: #include "ruby.h"
5
- 2:
6
- 3: int main(int argc, char **argv)
7
- 4: {
8
- 5: return !!argv[argc];
9
- 6: }
10
- /* end */
11
-
12
- LD_LIBRARY_PATH=.:/usr/lib64 ASAN_OPTIONS=detect_leaks=0 "cc -I/usr/include/ruby-3.4.0/x86_64-linux -I/usr/include/ruby-3.4.0/ruby/backward -I/usr/include/ruby-3.4.0 -I. -fstack-clash-protection -D_FORTIFY_SOURCE=2 -mtune=generic -O2 -pipe -g -ffile-prefix-map=/builddir/ruby-3.4.10=. -fPIC -std=c++23 -c conftest.c"
13
- cc1: warning: command-line option '-std=c++23' is valid for C++/ObjC++ but not for C
14
- checked program was:
15
- /* begin */
16
- 1: #include "ruby.h"
17
- 2:
18
- 3: int main(){ return 0; }
19
- /* end */
20
-
data/ext/rswap/native.cpp DELETED
@@ -1,134 +0,0 @@
1
- // ext/rswap/native.cpp
2
- // C++ Backend - 8 exported functions
3
- #include <cstdlib>
4
- #include <cstring>
5
- #include <filesystem>
6
- #include <fstream>
7
- #include <memory>
8
- #include <sstream>
9
-
10
- namespace fs = std::filesystem;
11
-
12
- constexpr ssize_t SIZE = 1024 * 1024;
13
-
14
- struct Ctrl {
15
- std::string path;
16
- explicit Ctrl(const char* p) : path(p ? p : "") {}
17
- };
18
-
19
- struct SwapInfo {
20
- bool active = false;
21
- long long used = 0;
22
- };
23
-
24
- // Helper: Parse /proc/swaps for swap status and memory usage
25
- SwapInfo get_swap_info(const std::string& path) {
26
- SwapInfo info;
27
- std::ifstream p("/proc/swaps");
28
- if (!p.is_open()) return info;
29
-
30
- std::string line;
31
- while (std::getline(p, line)) {
32
- if (line.find(path) != std::string::npos) {
33
- std::istringstream s(line);
34
- std::string f, t;
35
- ssize_t sz, used;
36
- int pri;
37
- if (s >> f >> t >> sz >> used >> pri) {
38
- info.active = true;
39
- info.used = static_cast<long long>(used) * 1024;
40
- }
41
- break;
42
- }
43
- }
44
- return info;
45
- }
46
-
47
- // Helper: System command execution
48
- int exec_cmd(const std::string& cmd) {
49
- return std::system(cmd.c_str()) == 0 ? 0 : 2;
50
- }
51
-
52
- extern "C" {
53
-
54
- Ctrl* swap_new(const char* path) {
55
- if (!path) return nullptr;
56
- try {
57
- auto ctrl = std::make_unique<Ctrl>(path);
58
- return ctrl.release();
59
- } catch (...) {
60
- return nullptr;
61
- }
62
- }
63
-
64
- void swap_free(const Ctrl* c) {
65
- delete c;
66
- }
67
-
68
- int swap_create(Ctrl* c, ssize_t bytes) {
69
- if (!c || c->path.empty()) return 1;
70
- if (fs::exists(c->path)) return 5;
71
-
72
- std::string bytes_str = std::to_string(bytes);
73
- std::string mb_str = std::to_string(bytes / SIZE);
74
-
75
- // 1. Create empty file (touch)
76
- // 2. Set NOCOW (+C) for Btrfs filesystems before writing data
77
- // 3. Allocate file space via fallocate (fallback to dd)
78
- // 4. Restrict permissions (chmod 600)
79
- // 5. Format as swap space (mkswap)
80
- std::string cmd =
81
- "touch '" + c->path + "' && "
82
- "chattr +C '" + c->path + "' 2>/dev/null; "
83
- "(fallocate -l " + bytes_str + " '" + c->path + "' 2>/dev/null || "
84
- "dd if=/dev/zero of='" + c->path + "' bs=1M count=" + mb_str + " status=none) && "
85
- "chmod 600 '" + c->path + "' && "
86
- "mkswap '" + c->path + "'";
87
-
88
- return exec_cmd(cmd);
89
- }
90
-
91
- int swap_enable(Ctrl* c) {
92
- if (!c || c->path.empty()) return 1;
93
- return exec_cmd("swapon '" + c->path + "' 2>/dev/null");
94
- }
95
-
96
- int swap_disable(Ctrl* c) {
97
- if (!c || c->path.empty()) return 1;
98
-
99
- auto info = get_swap_info(c->path);
100
- if (!info.active) return 4;
101
-
102
- return exec_cmd("swapoff '" + c->path + "' 2>/dev/null");
103
- }
104
-
105
- int swap_remove(Ctrl* c) {
106
- if (!c || c->path.empty()) return 1;
107
- std::error_code ec;
108
- return fs::remove(c->path, ec) ? 0 : 6;
109
- }
110
-
111
- char* swap_status(Ctrl* c) {
112
- if (!c || c->path.empty()) return strdup("{}");
113
-
114
- auto info = get_swap_info(c->path);
115
- bool exists = fs::exists(c->path);
116
- std::uintmax_t file_sz = exists ? fs::file_size(c->path) : 0;
117
-
118
- std::ostringstream j;
119
- j << "{"
120
- << "\"p\":\"" << c->path << "\","
121
- << "\"x\":" << (exists ? "true" : "false") << ","
122
- << "\"s\":" << (exists ? static_cast<long long>(file_sz) : -1) << ","
123
- << "\"a\":" << (info.active ? "true" : "false") << ","
124
- << "\"u\":" << info.used
125
- << "}";
126
-
127
- return strdup(j.str().c_str());
128
- }
129
-
130
- void swap_free_str(char* s) {
131
- free(s);
132
- }
133
-
134
- } // extern "C"
data/ext/rswap/native.o DELETED
Binary file
Binary file
data/lib/rswap/native.rb DELETED
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'ffi'
4
- require 'json'
5
-
6
- module Rswap
7
- module Native
8
- extend FFI::Library
9
-
10
- lib_dir = File.expand_path('../../ext/rswap', __dir__)
11
- ffi_lib File.join(lib_dir, 'rswap_native.so')
12
-
13
- attach_function :swap_new, [:string], :pointer
14
- attach_function :swap_free, [:pointer], :void
15
- attach_function :swap_create, [:pointer, :ssize_t], :int
16
- attach_function :swap_enable, [:pointer], :int
17
- attach_function :swap_disable, [:pointer], :int
18
- attach_function :swap_remove, [:pointer], :int
19
- attach_function :swap_status, [:pointer], :pointer
20
- attach_function :swap_free_str, [:pointer], :void
21
-
22
- class Ctrl
23
- def initialize(path)
24
- @p = Native.swap_new(path)
25
- raise 'init failed' if @p.null?
26
-
27
- ObjectSpace.define_finalizer(self, self.class.finalizer(@p))
28
- end
29
-
30
- def self.finalizer(p)
31
- proc { Native.swap_free(p) }
32
- end
33
-
34
- def create(sz) = Native.swap_create(@p, sz)
35
- def enable = Native.swap_enable(@p)
36
- def disable = Native.swap_disable(@p)
37
- def remove = Native.swap_remove(@p)
38
-
39
- def status
40
- ptr = Native.swap_status(@p)
41
- return {} if ptr.null?
42
-
43
- begin
44
- json_str = ptr.read_string
45
- JSON.parse(json_str, symbolize_names: true)
46
- ensure
47
- Native.swap_free_str(ptr)
48
- # The C++ side frees up the memory that was accessed via strdup to prevent memory leaks.
49
- end
50
- end
51
- end
52
- end
53
- end