Patch from Ned Ludd, solar at gentoo dot org:

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.
This commit is contained in:
Eric Andersen 2003-12-24 06:02:11 +00:00
parent 5089534be0
commit b90502828c
5 changed files with 403 additions and 0 deletions

View File

@ -553,6 +553,9 @@
#ifdef CONFIG_SYNC #ifdef CONFIG_SYNC
APPLET(sync, sync_main, _BB_DIR_BIN, _BB_SUID_NEVER) APPLET(sync, sync_main, _BB_DIR_BIN, _BB_SUID_NEVER)
#endif #endif
#ifdef CONFIG_SYSCTL
APPLET(sysctl, sysctl_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
#endif
#ifdef CONFIG_SYSLOGD #ifdef CONFIG_SYSLOGD
APPLET(syslogd, syslogd_main, _BB_DIR_SBIN, _BB_SUID_NEVER) APPLET(syslogd, syslogd_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
#endif #endif

View File

@ -2266,6 +2266,27 @@
#define USAGE_IPC_LOG(a) #define USAGE_IPC_LOG(a)
#endif #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 \ #define syslogd_trivial_usage \
"[OPTION]..." "[OPTION]..."
#define syslogd_full_usage \ #define syslogd_full_usage \

View File

@ -72,5 +72,11 @@ config CONFIG_UPTIME
the system has been running, how many users are currently logged 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. 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 endmenu

View File

@ -28,6 +28,7 @@ PROCPS-$(CONFIG_KILL) += kill.o
PROCPS-$(CONFIG_PIDOF) += pidof.o PROCPS-$(CONFIG_PIDOF) += pidof.o
PROCPS-$(CONFIG_PS) += ps.o PROCPS-$(CONFIG_PS) += ps.o
PROCPS-$(CONFIG_RENICE) += renice.o PROCPS-$(CONFIG_RENICE) += renice.o
PROCPS-$(CONFIG_SYSCTL) += sysctl.o
PROCPS-$(CONFIG_TOP) += top.o PROCPS-$(CONFIG_TOP) += top.o
PROCPS-$(CONFIG_UPTIME) += uptime.o PROCPS-$(CONFIG_UPTIME) += uptime.o

372
procps/sysctl.c Normal file
View File

@ -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