summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-01-18 15:35:38 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-01-18 15:35:38 +0100
commit7e044cf2930cf63b30de8f30b3ea75851eda7d2b (patch)
treeaa1b15a3d84f28d6c57626220d6a849cbde76260
parentf7cc4541626279b07626b9d98beba03a7230b518 (diff)
downloadserenity-7e044cf2930cf63b30de8f30b3ea75851eda7d2b.zip
Add a simple /bin/sysctl that wraps the files in /proc/sys.
-rw-r--r--AK/StringBuilder.cpp6
-rwxr-xr-xKernel/sync.sh1
-rw-r--r--Userland/.gitignore1
-rw-r--r--Userland/Makefile9
-rw-r--r--Userland/sysctl.cpp138
5 files changed, 151 insertions, 4 deletions
diff --git a/AK/StringBuilder.cpp b/AK/StringBuilder.cpp
index 0e155df72c..572a8e8590 100644
--- a/AK/StringBuilder.cpp
+++ b/AK/StringBuilder.cpp
@@ -40,12 +40,14 @@ void StringBuilder::appendf(const char* fmt, ...)
ByteBuffer StringBuilder::to_byte_buffer()
{
m_buffer.trim(m_length);
- return m_buffer;
+ return move(m_buffer);
}
String StringBuilder::build()
{
- return String((const char*)m_buffer.pointer(), m_length);
+ auto string = String((const char*)m_buffer.pointer(), m_length);
+ m_buffer.clear();
+ return string;
}
}
diff --git a/Kernel/sync.sh b/Kernel/sync.sh
index 180586f108..d69fb747b8 100755
--- a/Kernel/sync.sh
+++ b/Kernel/sync.sh
@@ -43,6 +43,7 @@ cp -v ../Userland/touch mnt/bin/touch
cp -v ../Userland/sync mnt/bin/sync
cp -v ../Userland/more mnt/bin/more
cp -v ../Userland/guitest mnt/bin/guitest
+cp -v ../Userland/sysctl mnt/bin/sysctl
cp -v ../Terminal/Terminal mnt/bin/Terminal
sh sync-local.sh
cp -v kernel.map mnt/
diff --git a/Userland/.gitignore b/Userland/.gitignore
index 94dd3a2a12..b977ea519a 100644
--- a/Userland/.gitignore
+++ b/Userland/.gitignore
@@ -22,3 +22,4 @@ touch
sync
more
guitest
+sysctl
diff --git a/Userland/Makefile b/Userland/Makefile
index 7dc23d5970..c34165565d 100644
--- a/Userland/Makefile
+++ b/Userland/Makefile
@@ -19,7 +19,8 @@ OBJS = \
mkdir.o \
touch.o \
more.o \
- guitest.o
+ guitest.o \
+ sysctl.o
APPS = \
id \
@@ -43,7 +44,8 @@ APPS = \
touch \
sync \
more \
- guitest
+ guitest \
+ sysctl
ARCH_FLAGS =
STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc
@@ -129,6 +131,9 @@ more: more.o
guitest: guitest.o
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
+sysctl: sysctl.o
+ $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
+
.cpp.o:
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
diff --git a/Userland/sysctl.cpp b/Userland/sysctl.cpp
new file mode 100644
index 0000000000..13c7e564ab
--- /dev/null
+++ b/Userland/sysctl.cpp
@@ -0,0 +1,138 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <AK/AKString.h>
+#include <AK/StringBuilder.h>
+#include <AK/Vector.h>
+
+static bool flag_show_all = false;
+static int show_all();
+static int handle_var(const char*);
+
+static void usage()
+{
+ printf("usage: sysctl [-a] [variable[=value]]\n");
+}
+
+int main(int argc, char** argv)
+{
+ int opt;
+ while ((opt = getopt(argc, argv, "a")) != -1) {
+ switch (opt) {
+ case 'a':
+ flag_show_all = true;
+ break;
+ default:
+ usage();
+ return 0;
+ }
+ }
+
+ if (flag_show_all)
+ return show_all();
+
+ if (optind >= argc) {
+ usage();
+ return 0;
+ }
+
+ const char* var = argv[optind];
+
+ return handle_var(var);
+}
+
+int show_all()
+{
+ DIR* dirp = opendir("/proc/sys");
+ if (!dirp) {
+ perror("opendir");
+ return 1;
+ }
+ char pathbuf[256];
+
+ while (auto* de = readdir(dirp)) {
+ if (de->d_name[0] == '.')
+ continue;
+ sprintf(pathbuf, "/proc/sys/%s", de->d_name);
+ int fd = open(pathbuf, O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ continue;
+ }
+ char buffer[1024];
+ int nread = read(fd, buffer, sizeof(buffer));
+ close(fd);
+ if (nread < 0) {
+ perror("read");
+ continue;
+ }
+ buffer[nread] = '\0';
+ printf("%s = %s", de->d_name, buffer);
+ if (nread && buffer[nread - 1] != '\n')
+ printf("\n");
+ }
+ closedir(dirp);
+ return 0;
+}
+
+static String read_var(const String& name)
+{
+ StringBuilder builder;
+ builder.append("/proc/sys/");
+ builder.append(name);
+ auto path = builder.build();
+ int fd = open(path.characters(), O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ exit(1);
+ }
+ char buffer[1024];
+ int nread = read(fd, buffer, sizeof(buffer));
+ close(fd);
+ if (nread < 0) {
+ perror("read");
+ exit(1);
+ }
+ return String(buffer, nread, Chomp);
+}
+
+static void write_var(const String& name, const String& value)
+{
+ StringBuilder builder;
+ builder.append("/proc/sys/");
+ builder.append(name);
+ auto path = builder.build();
+ int fd = open(path.characters(), O_WRONLY);
+ if (fd < 0) {
+ perror("open");
+ exit(1);
+ }
+ int nwritten = write(fd, value.characters(), value.length());
+ if (nwritten < 0) {
+ perror("read");
+ exit(1);
+ }
+ close(fd);
+}
+
+int handle_var(const char* var)
+{
+ String spec(var, Chomp);
+ auto parts = spec.split('=');
+ String variable_name = parts[0];
+ bool is_write = parts.size() > 1;
+
+ if (!is_write) {
+ printf("%s = %s\n", variable_name.characters(), read_var(variable_name).characters());
+ return 0;
+ }
+
+ printf("%s = %s", variable_name.characters(), read_var(variable_name).characters());
+ write_var(variable_name, parts[1]);
+ printf(" -> %s\n", read_var(variable_name).characters());
+ return 0;
+}