diff --git a/Makefile b/Makefile index dd2f1cd..17f620c 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,7 @@ SRC = \ swapoff.c \ swapon.c \ switch_root.c \ + sysctl.c \ truncate.c \ umount.c \ unshare.c \ @@ -92,6 +93,7 @@ MAN8 = \ swapoff.8 \ swapon.8 \ switch_root.8 \ + sysctl.8 \ umount.8 OBJ = $(SRC:.c=.o) $(LIB) diff --git a/README b/README index 7743756..7cf5f95 100644 --- a/README +++ b/README @@ -9,7 +9,7 @@ The following programs are currently implemented: chvt clear ctrlaltdel df dmesg eject fallocate free getty halt id insmod killall5 lsmod lsusb mknod mkswap mount mountpoint pagesize pidof pivot_root ps respawn rmmod stat su swapoff swapon - switch_root truncate umount unshare uptime watch who + switch_root sysctl truncate umount unshare uptime watch who The complement of ubase is sbase[1] which mostly follows POSIX and provides all the portable tools. Together they are intended to form a diff --git a/TODO b/TODO index 409a6df..ec7272e 100644 --- a/TODO +++ b/TODO @@ -6,7 +6,6 @@ Tools * swaplabel(8) * last(1) * losetup(8) - * sysctl * lspci * mkswap [-L] * passwd diff --git a/sysctl.8 b/sysctl.8 new file mode 100644 index 0000000..62dc27a --- /dev/null +++ b/sysctl.8 @@ -0,0 +1,9 @@ +.TH SYSCTL 8 ubase-VERSION +.SH NAME +\fBsysctl\fR - Configure kernel parameters at runtime +.SH SYNOPSIS +\fBsysctl\fR \fIvariable\fR[=\fIvalue\fR]... +.SH DESCRIPTION +\fBsysctl\fR modifies kernel parameters at runtime. The parameters available +are those listed under \fI/proc/sys/\fR. Procfs is required for sysctl support +in Linux. You can use \fBsysctl\fR to both read and write sysctl data. diff --git a/sysctl.c b/sysctl.c new file mode 100644 index 0000000..c6e42ce --- /dev/null +++ b/sysctl.c @@ -0,0 +1,139 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include +#include +#include "util.h" + +static int +getsysctl(char *variable, char **value) +{ + char path[PATH_MAX]; + char *p; + char *buf; + int fd; + ssize_t n; + + for (p = variable; *p; p++) + if (*p == '.') + *p = '/'; + + strlcpy(path, "/proc/sys/", sizeof(path)); + if (strlcat(path, variable, sizeof(path)) >= sizeof(path)) + return -1; + + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + + buf = malloc(1024); + if (!buf) { + close(fd); + return -1; + } + + n = read(fd, buf, 1023); + if (n <= 0) { + close(fd); + free(buf); + return -1; + } + buf[n] = '\0'; + + p = strrchr(buf, '\n'); + if (p) + *p = '\0'; + + *value = buf; + + close(fd); + + return 0; +} + +static int +setsysctl(char *variable, char *value) +{ + char path[PATH_MAX]; + char *p; + int fd; + ssize_t n; + + for (p = variable; *p; p++) + if (*p == '.') + *p = '/'; + + strlcpy(path, "/proc/sys/", sizeof(path)); + if (strlcat(path, variable, sizeof(path)) >= sizeof(path)) + return -1; + + fd = open(path, O_WRONLY); + if (fd < 0) + return -1; + + n = write(fd, value, strlen(value)); + if (n != (ssize_t)strlen(value)) { + close(fd); + return -1; + } + + close(fd); + + return 0; +} + +static void +usage(void) +{ + eprintf("usage: %s variable[=value]...\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + char *variable; + char *value; + char *p; + int i; + + argv0 = argv[0]; + argv++; + argc--; + + if (argc < 1) + usage(); + + for (i = 0; i < argc; i++) { + value = NULL; + variable = argv[i]; + p = strchr(variable, '='); + if (p) { + if (p[1] == '\0') { + weprintf("malformed sysctl: %s\n", argv[i]); + continue; + } + *p = '\0'; + value = &p[1]; + } + if (variable) { + if (value) { + if (setsysctl(variable, value) < 0) { + weprintf("failed to set sysctl for %s\n", variable); + continue; + } + } + else { + if (getsysctl(variable, &value) < 0) { + weprintf("failed to get sysctl for %s\n", variable); + continue; + } + printf("%s = %s\n", variable, value); + free(value); + } + } + } + + return EXIT_SUCCESS; +}