master xplshn/aruu / cmd / linux / sysctl.c
  1/* See LICENSE file for copyright and license details. */
  2
  3
  4#include <fcntl.h>
  5#include <limits.h>
  6#include <stdio.h>
  7#include <stdlib.h>
  8#include <string.h>
  9#include <unistd.h>
 10
 11#include "text.h"
 12#include "util.h"
 13
 14static void
 15replacestr(char *s, int a, int b)
 16{
 17	for (; *s; s++)
 18		if (*s == a)
 19			*s = b;
 20}
 21
 22static int
 23getsysctl(char *variable, char **value)
 24{
 25	char path[PATH_MAX];
 26	char *p;
 27	char *buf, *tmp, c;
 28	int fd;
 29	ssize_t n;
 30	size_t sz, i;
 31
 32	replacestr(variable, '.', '/');
 33
 34	strlcpy(path, "/proc/sys/", sizeof(path));
 35	if (strlcat(path, variable, sizeof(path)) >= sizeof(path)) {
 36		replacestr(variable, '/', '.');
 37		return -1;
 38	}
 39
 40	replacestr(variable, '/', '.');
 41
 42	fd = open(path, O_RDONLY);
 43	if (fd < 0)
 44		return -1;
 45
 46	i = 0;
 47	sz = 1;
 48	buf = NULL;
 49	while (1) {
 50		n = read(fd, &c, 1);
 51		if (n < 0) {
 52			close(fd);
 53			free(buf);
 54			return -1;
 55		}
 56		if (n == 0)
 57			break;
 58		if (i == sz - 1) {
 59			sz *= 2;
 60			tmp = realloc(buf, sz);
 61			if (!tmp) {
 62				close(fd);
 63				free(buf);
 64				return -1;
 65			}
 66			buf = tmp;
 67		}
 68		buf[i++] = c;
 69	}
 70	buf[i] = '\0';
 71
 72	p = strrchr(buf, '\n');
 73	if (p)
 74		*p = '\0';
 75
 76	*value = buf;
 77
 78	close(fd);
 79
 80	return 0;
 81}
 82
 83static int
 84setsysctl(char *variable, char *value)
 85{
 86	char path[PATH_MAX];
 87	int fd;
 88	ssize_t n;
 89
 90	replacestr(variable, '.', '/');
 91
 92	strlcpy(path, "/proc/sys/", sizeof(path));
 93	if (strlcat(path, variable, sizeof(path)) >= sizeof(path)) {
 94		replacestr(variable, '/', '.');
 95		return -1;
 96	}
 97
 98	replacestr(variable, '/', '.');
 99
100	fd = open(path, O_WRONLY);
101	if (fd < 0)
102		return -1;
103
104	n = write(fd, value, strlen(value));
105	if ((size_t)n != strlen(value)) {
106		close(fd);
107		return -1;
108	}
109
110	close(fd);
111
112	return 0;
113}
114
115static int
116parsepair(char *pair)
117{
118	char *p;
119	char *variable;
120	char *value;
121
122	for (p = pair; *p; p++) {
123		if (p[0] == '.' && p[1] == '.') {
124			weprintf("malformed input: %s\n", pair);
125			return -1;
126		}
127	}
128	p = strchr(pair, '=');
129	if (p) {
130		if (p[1] == '\0') {
131			weprintf("malformed input: %s\n", pair);
132			return -1;
133		}
134		*p = '\0';
135		value = &p[1];
136	} else {
137		value = NULL;
138	}
139	variable = pair;
140	if (value) {
141		if (setsysctl(variable, value) < 0) {
142			weprintf("failed to set sysctl for %s\n", variable);
143			return -1;
144		}
145	} else {
146		if (getsysctl(variable, &value) < 0) {
147			weprintf("failed to get sysctl for %s\n", variable);
148			return -1;
149		}
150		printf("%s = %s\n", variable, value);
151		free(value);
152	}
153
154	return 0;
155}
156
157static void
158usage(void)
159{
160	eprintf("usage: %s [-p file] variable[=value]...\n", argv0);
161}
162
163// ?man sysctl: configure kernel parameters
164// ?man arguments: variable[=value]...
165// ?man view and modify kernel parameters at runtime
166int
167main(int argc, char *argv[])
168{
169	FILE *fp;
170	char *buf = NULL, *p;
171	char *file = NULL;
172	size_t size = 0;
173	int i;
174	int r = 0;
175
176	ARGBEGIN {
177	// ?man -p:file: preserve file attributes
178	case 'p':
179		file = EARGF(usage());
180		break;
181	default:
182		usage();
183	} ARGEND;
184
185	if (!file && argc < 1)
186		usage();
187
188	if (!file) {
189		for (i = 0; i < argc; i++)
190			if (parsepair(argv[i]) < 0)
191				r = 1;
192	} else {
193		fp = fopen(file, "r");
194		if (!fp)
195			eprintf("fopen %s:", file);
196		while (agetline(&buf, &size, fp) != -1) {
197			p = buf;
198			for (p = buf; *p == ' ' || *p == '\t'; p++)
199				;
200			if (*p == '#' || *p == '\n')
201				continue;
202			for (p = buf; *p; p++) {
203				if (*p == '\n') {
204					*p = '\0';
205					break;
206				}
207			}
208			p = buf;
209			if (parsepair(p) < 0)
210				r = 1;
211		}
212		if (ferror(fp))
213			eprintf("%s: read error:", file);
214		free(buf);
215		fclose(fp);
216	}
217
218	return r;
219}