summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/applets.h3
-rw-r--r--include/usage.h21
-rw-r--r--procps/Config.in6
-rw-r--r--procps/Makefile.in1
-rw-r--r--procps/sysctl.c372
5 files changed, 403 insertions, 0 deletions
diff --git a/include/applets.h b/include/applets.h
index 1119a9e..e348516 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -553,6 +553,9 @@
#ifdef CONFIG_SYNC
APPLET(sync, sync_main, _BB_DIR_BIN, _BB_SUID_NEVER)
#endif
+#ifdef CONFIG_SYSCTL
+ APPLET(sysctl, sysctl_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+#endif
#ifdef CONFIG_SYSLOGD
APPLET(syslogd, syslogd_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
#endif
diff --git a/include/usage.h b/include/usage.h
index bd78a53..c8716d2 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -2266,6 +2266,27 @@
#define USAGE_IPC_LOG(a)
#endif
+#ifdef CONFIG_SYSCTL
+#define sysctl_trivial_usage \
+ "[OPTIONS]... [VALUE]...\n"
+#define sysctl_full_usage
+ "sysctl - configure kernel parameters at runtime\n\n" \
+ "Options:\n" \
+ "\t-n\tUse this option to disable printing of the key name when printing values.\n" \
+ "\t-e\tUse this option to ignore errors about unknown keys.\n" \
+ "\t-w\tUse this option when you want to change a sysctl setting.\n" \
+ "\t-p\tLoad in sysctl settings from the file specified or /etc/sysctl.conf if none given.\n" \
+ "\t-a\tDisplay all values currently available.\n" \
+ "\t-A\tDisplay all values currently available in table form."
+
+#define sysctl_example_usage
+ "sysctl [-n] [-e] variable ...\n" \
+ "sysctl [-n] [-e] -w variable=value ...\n" \
+ "sysctl [-n] [-e] -a\n" \
+ "sysctl [-n] [-e] -p <file>\t(default /etc/sysctl.conf)\n" \
+ "sysctl [-n] [-e] -A\n"
+#endif
+
#define syslogd_trivial_usage \
"[OPTION]..."
#define syslogd_full_usage \
diff --git a/procps/Config.in b/procps/Config.in
index 14808e0..8d55797 100644
--- a/procps/Config.in
+++ b/procps/Config.in
@@ -72,5 +72,11 @@ config CONFIG_UPTIME
the system has been running, how many users are currently logged
on, and the system load averages for the past 1, 5, and 15 minutes.
+config CONFIG_SYSCTL
+ bool "sysctl"
+ default n
+ help
+ sysctl - configure kernel parameters at runtime
+
endmenu
diff --git a/procps/Makefile.in b/procps/Makefile.in
index 9d2d273..723dd9f 100644
--- a/procps/Makefile.in
+++ b/procps/Makefile.in
@@ -28,6 +28,7 @@ PROCPS-$(CONFIG_KILL) += kill.o
PROCPS-$(CONFIG_PIDOF) += pidof.o
PROCPS-$(CONFIG_PS) += ps.o
PROCPS-$(CONFIG_RENICE) += renice.o
+PROCPS-$(CONFIG_SYSCTL) += sysctl.o
PROCPS-$(CONFIG_TOP) += top.o
PROCPS-$(CONFIG_UPTIME) += uptime.o
diff --git a/procps/sysctl.c b/procps/sysctl.c
new file mode 100644
index 0000000..f1799af
--- /dev/null
+++ b/procps/sysctl.c
@@ -0,0 +1,372 @@
+
+/*
+ * Sysctl 1.01 - A utility to read and manipulate the sysctl parameters
+ *
+ *
+ * "Copyright 1999 George Staikos
+ * This file may be used subject to the terms and conditions of the
+ * GNU General Public License Version 2, or any later version
+ * at your option, as published by the Free Software Foundation.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details."
+ *
+ * Changelog:
+ * v1.01:
+ * - added -p <preload> to preload values from a file
+ * v1.01.1
+ * - busybox applet aware by <solar@gentoo.org>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "busybox.h"
+
+/*
+ * Function Prototypes
+ */
+static int sysctl_usage(void);
+static int sysctl_read_setting(const char *setting, int output);
+static int sysctl_write_setting(const char *setting, int output);
+static int sysctl_preload_file(const char *filename, int output);
+static int sysctl_display_all(const char *path, int output, int show_table);
+
+/*
+ * Globals...
+ */
+static const char *PROC_PATH = "/proc/sys/";
+static const char *DEFAULT_PRELOAD = "/etc/sysctl.conf";
+
+/* error messages */
+static const char *ERR_UNKNOWN_PARAMETER = "error: Unknown parameter '%s'\n";
+static const char *ERR_MALFORMED_SETTING = "error: Malformed setting '%s'\n";
+static const char *ERR_NO_EQUALS =
+ "error: '%s' must be of the form name=value\n";
+static const char *ERR_INVALID_KEY = "error: '%s' is an unknown key\n";
+static const char *ERR_UNKNOWN_WRITING =
+ "error: unknown error %d setting key '%s'\n";
+static const char *ERR_UNKNOWN_READING =
+ "error: unknown error %d reading key '%s'\n";
+static const char *ERR_PERMISSION_DENIED =
+ "error: permission denied on key '%s'\n";
+static const char *ERR_OPENING_DIR = "error: unable to open directory '%s'\n";
+static const char *ERR_PRELOAD_FILE =
+ "error: unable to open preload file '%s'\n";
+static const char *WARN_BAD_LINE =
+ "warning: %s(%d): invalid syntax, continuing...\n";
+
+
+/*
+ * sysctl_main()...
+ */
+int sysctl_main(int argc, char **argv)
+{
+ int retval = 0;
+ int output = 1;
+ int write_mode = 0;
+ int switches_allowed = 1;
+
+ if (argc < 2)
+ return sysctl_usage();
+
+ argv++;
+
+ for (; argv && *argv && **argv; argv++) {
+ if (switches_allowed && **argv == '-') { /* we have a switch */
+ switch ((*argv)[1]) {
+ case 'n':
+ output = 0;
+ break;
+ case 'w':
+ write_mode = 1;
+ switches_allowed = 0;
+ break;
+ case 'p':
+ argv++;
+ return
+ sysctl_preload_file(((argv && *argv
+ && **argv) ? *argv :
+ DEFAULT_PRELOAD), output);
+ case 'a':
+ case 'A':
+ switches_allowed = 0;
+ return sysctl_display_all(PROC_PATH, output,
+ ((*argv)[1] == 'a') ? 0 : 1);
+ case 'h':
+ case '?':
+ return sysctl_usage();
+ default:
+ bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv);
+ return sysctl_usage();
+ }
+ } else {
+ switches_allowed = 0;
+ if (write_mode)
+ retval = sysctl_write_setting(*argv, output);
+ else
+ sysctl_read_setting(*argv, output);
+ }
+ }
+ return retval;
+} /* end sysctl_main() */
+
+/*
+ * Display the sysctl_usage format
+ */
+int sysctl_usage()
+{
+ bb_show_usage();
+ return -1;
+} /* end sysctl_usage() */
+
+
+/*
+ * sysctl_preload_file
+ * preload the sysctl's from a conf file
+ * - we parse the file and then reform it (strip out whitespace)
+ */
+int sysctl_preload_file(const char *filename, int output)
+{
+ int lineno = 0;
+ char oneline[256];
+ char buffer[256];
+ char *name, *value, *ptr;
+ FILE *fp = NULL;
+
+ if (!filename || ((fp = fopen(filename, "r")) == NULL)) {
+ bb_error_msg(ERR_PRELOAD_FILE, filename);
+ return 1;
+ }
+
+ while (fgets(oneline, sizeof(oneline) - 1, fp)) {
+ oneline[sizeof(oneline) - 1] = 0;
+ lineno++;
+ trim(oneline);
+ ptr = (char *) oneline;
+
+ if (*ptr == '#' || *ptr == ';')
+ continue;
+
+ if (bb_strlen(ptr) < 2)
+ continue;
+
+ name = strtok(ptr, "=");
+ if (!name || !*name) {
+ bb_error_msg(WARN_BAD_LINE, filename, lineno);
+ continue;
+ }
+
+ trim(name);
+
+ value = strtok(NULL, "\n\r");
+ if (!value || !*value) {
+ bb_error_msg(WARN_BAD_LINE, filename, lineno);
+ continue;
+ }
+
+ while ((*value == ' ' || *value == '\t') && *value != 0)
+ value++;
+ strncpy(buffer, name, sizeof(buffer));
+ strncat(buffer, "=", sizeof(buffer));
+ strncat(buffer, value, sizeof(buffer));
+ sysctl_write_setting(buffer, output);
+ }
+ fclose(fp);
+ return 0;
+} /* end sysctl_preload_file() */
+
+
+/*
+ * Write a single sysctl setting
+ */
+int sysctl_write_setting(const char *setting, int output)
+{
+ int retval = 0;
+ const char *name = setting;
+ const char *value;
+ const char *equals;
+ char *tmpname, *outname, *cptr;
+ int fd = -1;
+
+ if (!name) /* probably dont' want to display this err */
+ return 0;
+
+ if (!(equals = index(setting, '='))) {
+ bb_error_msg(ERR_NO_EQUALS, setting);
+ return -1;
+ }
+
+ value = equals + sizeof(char); /* point to the value in name=value */
+
+ if (!*name || !*value || name == equals) {
+ bb_error_msg(ERR_MALFORMED_SETTING, setting);
+ return -2;
+ }
+
+ tmpname =
+ (char *) xmalloc((equals - name + 1 + bb_strlen(PROC_PATH)) *
+ sizeof(char));
+ outname = (char *) xmalloc((equals - name + 1) * sizeof(char));
+
+ strcpy(tmpname, PROC_PATH);
+ strncat(tmpname, name, (int) (equals - name));
+ tmpname[equals - name + bb_strlen(PROC_PATH)] = 0;
+ strncpy(outname, name, (int) (equals - name));
+ outname[equals - name] = 0;
+
+ while ((cptr = strchr(tmpname, '.')) != NULL)
+ *cptr = '/';
+
+ while ((cptr = strchr(outname, '/')) != NULL)
+ *cptr = '.';
+
+ if ((fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
+ switch (errno) {
+ case ENOENT:
+ bb_error_msg(ERR_INVALID_KEY, outname);
+ break;
+ case EACCES:
+ bb_perror_msg(ERR_PERMISSION_DENIED, outname);
+ break;
+ default:
+ bb_error_msg(ERR_UNKNOWN_WRITING, errno, outname);
+ break;
+ }
+ retval = -1;
+ } else {
+ write(fd, value, bb_strlen(value));
+ close(fd);
+ if (output) {
+ write(STDOUT_FILENO, outname, bb_strlen(outname));
+ write(STDOUT_FILENO, " = ", 3);
+ }
+ write(STDOUT_FILENO, value, bb_strlen(value));
+ write(STDOUT_FILENO, "\n", 1);
+ }
+
+ /* cleanup */
+ free(tmpname);
+ free(outname);
+ return retval;
+} /* end sysctl_write_setting() */
+
+
+/*
+ * Read a sysctl setting
+ *
+ */
+int sysctl_read_setting(const char *setting, int output)
+{
+ int retval = 0;
+ char *tmpname, *outname, *cptr;
+ char inbuf[1025];
+ const char *name = setting;
+ FILE *fp;
+
+ if (!setting || !*setting)
+ bb_error_msg(ERR_INVALID_KEY, setting);
+
+ tmpname =
+ (char *) xmalloc((bb_strlen(name) + bb_strlen(PROC_PATH) + 1) *
+ sizeof(char));
+ outname = (char *) xmalloc((bb_strlen(name) + 1) * sizeof(char));
+
+ strcpy(tmpname, PROC_PATH);
+ strcat(tmpname, name);
+ strcpy(outname, name);
+
+ while ((cptr = strchr(tmpname, '.')) != NULL)
+ *cptr = '/';
+ while ((cptr = strchr(outname, '/')) != NULL)
+ *cptr = '.';
+
+ if ((fp = fopen(tmpname, "r")) == NULL) {
+ switch (errno) {
+ case ENOENT:
+ bb_error_msg(ERR_INVALID_KEY, outname);
+ break;
+ case EACCES:
+ bb_error_msg(ERR_PERMISSION_DENIED, outname);
+ break;
+ default:
+ bb_error_msg(ERR_UNKNOWN_READING, errno, outname);
+ break;
+ }
+ retval = -1;
+ } else {
+ while (fgets(inbuf, sizeof(inbuf) - 1, fp)) {
+ if (output) {
+ write(STDOUT_FILENO, outname, bb_strlen(outname));
+ write(STDOUT_FILENO, " = ", 3);
+ }
+ write(STDOUT_FILENO, inbuf, bb_strlen(inbuf));
+ }
+ fclose(fp);
+ }
+
+ free(tmpname);
+ free(outname);
+ return retval;
+} /* end sysctl_read_setting() */
+
+
+
+/*
+ * Display all the sysctl settings
+ *
+ */
+int sysctl_display_all(const char *path, int output, int show_table)
+{
+ int retval = 0;
+ int retval2;
+ DIR *dp;
+ struct dirent *de;
+ char *tmpdir;
+ struct stat ts;
+
+ if (!(dp = opendir(path))) {
+ bb_perror_msg(ERR_OPENING_DIR, path);
+ retval = -1;
+ } else {
+ readdir(dp);
+ readdir(dp); /* skip . and .. */
+ while ((de = readdir(dp)) != NULL) {
+ tmpdir =
+ (char *) xmalloc(bb_strlen(path) + bb_strlen(de->d_name) + 2);
+ strcpy(tmpdir, path);
+ strcat(tmpdir, de->d_name);
+ if ((retval2 = stat(tmpdir, &ts)) != 0)
+ bb_perror_msg(tmpdir);
+ else {
+ if (S_ISDIR(ts.st_mode)) {
+ strcat(tmpdir, "/");
+ sysctl_display_all(tmpdir, output, show_table);
+ } else
+ retval |=
+ sysctl_read_setting(tmpdir + bb_strlen(PROC_PATH),
+ output);
+
+ }
+ free(tmpdir);
+ } /* end while */
+ closedir(dp);
+ }
+
+ return retval;
+} /* end sysctl_display_all() */
+
+#ifdef STANDALONE_SYSCTL
+int main(int argc, char **argv)
+{
+ return sysctl_main(argc, argv);
+}
+#endif