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