Patch from Ned Ludd, solar at gentoo dot org:
authorEric Andersen <andersen@codepoet.org>
Wed, 24 Dec 2003 06:02:11 +0000 (06:02 -0000)
committerEric Andersen <andersen@codepoet.org>
Wed, 24 Dec 2003 06:02:11 +0000 (06:02 -0000)
I had previously provided you with a patch to help complete busybox's
props suite, but have heard no word back. Sense then I've made use of as
many of busybox's native API settings as I could find and would really
love for you to include support for this. If there is something more I
need to do to get this supported added in please let me know.

include/applets.h
include/usage.h
procps/Config.in
procps/Makefile.in
procps/sysctl.c [new file with mode: 0644]

index 1119a9ea66cfa646d4b2ad61b12f8236461c8e49..e348516ea455331e488c054e3c8799230ddd96ea 100644 (file)
 #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
index bd78a5381f256d4b6ce58b39cff21bdb3f6e983b..c8716d24d19ec91c1c65254c71ee318cc7d6a86b 100644 (file)
   #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 \
index 14808e03487843967498a3bc1d5a9bd176acde47..8d557972cc8d302e52bd08698039eb633ea55c29 100644 (file)
@@ -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
 
index 9d2d27391def83bc6c183e5c9d17fbfa74860cbd..723dd9ffb46015f0e0004fe62fc59b0d3efbef78 100644 (file)
@@ -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 (file)
index 0000000..f1799af
--- /dev/null
@@ -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