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}