rswap 1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c78cb324adbac507c04b943c46b09237530558ed55cda541c634ee87270e68ed
4
+ data.tar.gz: d3f9fe2c1c2e8ffe2ec1c23956ca4ef4b56a23883299f6ae3c38927d48f259b9
5
+ SHA512:
6
+ metadata.gz: 2e59db26877c8d3a54e802dbea279e21335fd154c49aadf539dca130a6171a4483da2fe0b5e19b78f95101785cff8ef64b502d2f88a7ab2800ad71a0cb504062
7
+ data.tar.gz: b84789bbd7c4c62fa9d25272a447f900f50787daf699345742e585cdcb39a425ea64c1525152bf0387f6697c52a0bfec4e1ca45e884343347e426a26d9468606
data/bin/rswap ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # bin/rswap - Entry point
3
+
4
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
5
+
6
+ require 'rswap'
7
+
8
+ Rswap.run(ARGV)
@@ -0,0 +1,273 @@
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)
@@ -0,0 +1,15 @@
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')
@@ -0,0 +1,20 @@
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
+
@@ -0,0 +1,134 @@
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"
Binary file
Binary file
data/lib/rswap/cli.rb ADDED
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rainbow'
4
+ require 'optparse'
5
+ require_relative 'native'
6
+
7
+ module Rswap
8
+ class CLI
9
+ HELP = <<~USAGE
10
+ Usage: rswap <command> [options]
11
+
12
+ Commands:
13
+ add [SIZE] Create and enable swap (default: 8GB)
14
+ on Enable existing swap
15
+ off Disable existing swap
16
+ status Show current state
17
+
18
+ Options:
19
+ --swapfile PATH Path to swap file (default: /swapfile)
20
+ USAGE
21
+
22
+ ERR = {
23
+ 0 => 'OK',
24
+ 1 => 'internal error',
25
+ 2 => 'command failed',
26
+ 3 => 'cannot read /proc/swaps',
27
+ 4 => 'already disabled',
28
+ 5 => 'file exists',
29
+ 6 => 'remove failed'
30
+ }.freeze
31
+
32
+ def self.run(argv)
33
+ sf = '/swapfile'
34
+
35
+ parser = OptionParser.new do |opts|
36
+ opts.on('--swapfile PATH') { |path| sf = path }
37
+ end
38
+
39
+ begin
40
+ parser.order!(argv)
41
+ rescue OptionParser::InvalidOption => e
42
+ puts Rainbow("ERR: #{e.message}").red
43
+ exit 1
44
+ end
45
+
46
+ cmd = argv.shift
47
+ if cmd.nil?
48
+ puts HELP
49
+ exit 1
50
+ end
51
+
52
+ c = Rswap::Native::Ctrl.new(sf)
53
+
54
+ 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)
59
+ else
60
+ puts Rainbow("ERR: unknown '#{cmd}'").red
61
+ puts 'Valid: add, on, off, status'
62
+ exit 1
63
+ end
64
+ end
65
+
66
+ def self.add(c, sz)
67
+ bytes = parse(sz)
68
+ st = c.status
69
+ size_h = human(bytes)
70
+
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'
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
85
+ return
86
+ end
87
+ else
88
+ # Hey
89
+ end
90
+
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
98
+ end
99
+ end
100
+
101
+ def self.on(c)
102
+ st = c.status
103
+
104
+ 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
109
+ 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
114
+ end
115
+ end
116
+
117
+ def self.off(c)
118
+ st = c.status
119
+
120
+ 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
136
+ end
137
+ end
138
+
139
+ def self.status(c)
140
+ st = c.status
141
+
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}"
151
+ end
152
+
153
+ puts "Usage: #{human(st[:u])}" if st[:u] && st[:u] >= 0
154
+ end
155
+
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
164
+ end
165
+
166
+ def self.parse(s)
167
+ case s.to_s.upcase
168
+ when /^([\d.]+)GB?$/ then ($1.to_f * 1024**3).to_i
169
+ when /^([\d.]+)MB?$/ then ($1.to_f * 1024**2).to_i
170
+ when /^([\d.]+)KB?$/ then ($1.to_f * 1024).to_i
171
+ else s.to_i
172
+ end
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,53 @@
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
@@ -0,0 +1,4 @@
1
+ # lib/rswap/version.rb
2
+ module Rswap
3
+ VERSION = "1.0.0"
4
+ end
data/lib/rswap.rb ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'rswap/version'
4
+ require_relative 'rswap/cli'
5
+
6
+ module Rswap
7
+ # Entry Point
8
+ def self.run(args)
9
+ CLI.run(args)
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rswap
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - KennedySilverDollar
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
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
+ - !ruby/object:Gem::Dependency
27
+ name: rainbow
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.1'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rake
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '13.0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '13.0'
54
+ description: Create/enable/disable rswap files with extreme efficiency
55
+ email:
56
+ - kenshinlights@tutamail.com
57
+ executables:
58
+ - rswap
59
+ extensions:
60
+ - ext/rswap/extconf.rb
61
+ extra_rdoc_files: []
62
+ files:
63
+ - 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
+ - lib/rswap.rb
71
+ - lib/rswap/cli.rb
72
+ - lib/rswap/native.rb
73
+ - lib/rswap/version.rb
74
+ homepage: https://github.com/KennedySilverDollar/rswap-tool
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: 3.0.0
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubygems_version: 3.6.9
93
+ specification_version: 4
94
+ summary: Minimal rswap manager with C++23 backend
95
+ test_files: []