diff options
Diffstat (limited to 'busybox/procps/sysctl.c')
-rw-r--r-- | busybox/procps/sysctl.c | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/busybox/procps/sysctl.c b/busybox/procps/sysctl.c new file mode 100644 index 000000000..359dcc041 --- /dev/null +++ b/busybox/procps/sysctl.c | |||
@@ -0,0 +1,352 @@ | |||
1 | |||
2 | /* | ||
3 | * Sysctl 1.01 - A utility to read and manipulate the sysctl parameters | ||
4 | * | ||
5 | * | ||
6 | * "Copyright 1999 George Staikos | ||
7 | * This file may be used subject to the terms and conditions of the | ||
8 | * GNU General Public License Version 2, or any later version | ||
9 | * at your option, as published by the Free Software Foundation. | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details." | ||
14 | * | ||
15 | * Changelog: | ||
16 | * v1.01: | ||
17 | * - added -p <preload> to preload values from a file | ||
18 | * v1.01.1 | ||
19 | * - busybox applet aware by <solar@gentoo.org> | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <unistd.h> | ||
26 | #include <sys/stat.h> | ||
27 | #include <sys/types.h> | ||
28 | #include <dirent.h> | ||
29 | #include <string.h> | ||
30 | #include <errno.h> | ||
31 | #include <fcntl.h> | ||
32 | #include "busybox.h" | ||
33 | |||
34 | /* | ||
35 | * Function Prototypes | ||
36 | */ | ||
37 | static int sysctl_read_setting(const char *setting, int output); | ||
38 | static int sysctl_write_setting(const char *setting, int output); | ||
39 | static int sysctl_preload_file(const char *filename, int output); | ||
40 | static int sysctl_display_all(const char *path, int output, int show_table); | ||
41 | |||
42 | /* | ||
43 | * Globals... | ||
44 | */ | ||
45 | static const char PROC_PATH[] = "/proc/sys/"; | ||
46 | static const char DEFAULT_PRELOAD[] = "/etc/sysctl.conf"; | ||
47 | |||
48 | /* error messages */ | ||
49 | static const char ERR_UNKNOWN_PARAMETER[] = "error: Unknown parameter '%s'\n"; | ||
50 | static const char ERR_MALFORMED_SETTING[] = "error: Malformed setting '%s'\n"; | ||
51 | static const char ERR_NO_EQUALS[] = | ||
52 | "error: '%s' must be of the form name=value\n"; | ||
53 | static const char ERR_INVALID_KEY[] = "error: '%s' is an unknown key\n"; | ||
54 | static const char ERR_UNKNOWN_WRITING[] = | ||
55 | "error: unknown error %d setting key '%s'\n"; | ||
56 | static const char ERR_UNKNOWN_READING[] = | ||
57 | "error: unknown error %d reading key '%s'\n"; | ||
58 | static const char ERR_PERMISSION_DENIED[] = | ||
59 | "error: permission denied on key '%s'\n"; | ||
60 | static const char ERR_OPENING_DIR[] = "error: unable to open directory '%s'\n"; | ||
61 | static const char ERR_PRELOAD_FILE[] = | ||
62 | "error: unable to open preload file '%s'\n"; | ||
63 | static const char WARN_BAD_LINE[] = | ||
64 | "warning: %s(%d): invalid syntax, continuing...\n"; | ||
65 | |||
66 | |||
67 | static void dwrite_str(int fd, const char *buf) | ||
68 | { | ||
69 | write(fd, buf, strlen(buf)); | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * sysctl_main()... | ||
74 | */ | ||
75 | int sysctl_main(int argc, char **argv) | ||
76 | { | ||
77 | int retval = 0; | ||
78 | int output = 1; | ||
79 | int write_mode = 0; | ||
80 | int switches_allowed = 1; | ||
81 | |||
82 | if (argc < 2) | ||
83 | bb_show_usage(); | ||
84 | |||
85 | argv++; | ||
86 | |||
87 | for (; argv && *argv && **argv; argv++) { | ||
88 | if (switches_allowed && **argv == '-') { /* we have a switch */ | ||
89 | switch ((*argv)[1]) { | ||
90 | case 'n': | ||
91 | output = 0; | ||
92 | break; | ||
93 | case 'w': | ||
94 | write_mode = 1; | ||
95 | switches_allowed = 0; | ||
96 | break; | ||
97 | case 'p': | ||
98 | argv++; | ||
99 | return | ||
100 | sysctl_preload_file(((argv && *argv | ||
101 | && **argv) ? *argv : | ||
102 | DEFAULT_PRELOAD), output); | ||
103 | case 'a': | ||
104 | case 'A': | ||
105 | switches_allowed = 0; | ||
106 | return sysctl_display_all(PROC_PATH, output, | ||
107 | ((*argv)[1] == 'a') ? 0 : 1); | ||
108 | case 'h': | ||
109 | case '?': | ||
110 | bb_show_usage(); | ||
111 | default: | ||
112 | bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv); | ||
113 | bb_show_usage(); | ||
114 | } | ||
115 | } else { | ||
116 | switches_allowed = 0; | ||
117 | if (write_mode) | ||
118 | retval = sysctl_write_setting(*argv, output); | ||
119 | else | ||
120 | sysctl_read_setting(*argv, output); | ||
121 | } | ||
122 | } | ||
123 | return retval; | ||
124 | } /* end sysctl_main() */ | ||
125 | |||
126 | |||
127 | |||
128 | /* | ||
129 | * sysctl_preload_file | ||
130 | * preload the sysctl's from a conf file | ||
131 | * - we parse the file and then reform it (strip out whitespace) | ||
132 | */ | ||
133 | #define PRELOAD_BUF 256 | ||
134 | |||
135 | int sysctl_preload_file(const char *filename, int output) | ||
136 | { | ||
137 | int lineno = 0; | ||
138 | char oneline[PRELOAD_BUF]; | ||
139 | char buffer[PRELOAD_BUF]; | ||
140 | char *name, *value, *ptr; | ||
141 | FILE *fp = NULL; | ||
142 | |||
143 | if (!filename || ((fp = fopen(filename, "r")) == NULL)) { | ||
144 | bb_error_msg_and_die(ERR_PRELOAD_FILE, filename); | ||
145 | } | ||
146 | |||
147 | while (fgets(oneline, sizeof(oneline) - 1, fp)) { | ||
148 | oneline[sizeof(oneline) - 1] = 0; | ||
149 | lineno++; | ||
150 | trim(oneline); | ||
151 | ptr = (char *) oneline; | ||
152 | |||
153 | if (*ptr == '#' || *ptr == ';') | ||
154 | continue; | ||
155 | |||
156 | if (bb_strlen(ptr) < 2) | ||
157 | continue; | ||
158 | |||
159 | name = strtok(ptr, "="); | ||
160 | if (!name || !*name) { | ||
161 | bb_error_msg(WARN_BAD_LINE, filename, lineno); | ||
162 | continue; | ||
163 | } | ||
164 | |||
165 | trim(name); | ||
166 | |||
167 | value = strtok(NULL, "\n\r"); | ||
168 | if (!value || !*value) { | ||
169 | bb_error_msg(WARN_BAD_LINE, filename, lineno); | ||
170 | continue; | ||
171 | } | ||
172 | |||
173 | while ((*value == ' ' || *value == '\t') && *value != 0) | ||
174 | value++; | ||
175 | strcpy(buffer, name); | ||
176 | strcat(buffer, "="); | ||
177 | strcat(buffer, value); | ||
178 | sysctl_write_setting(buffer, output); | ||
179 | } | ||
180 | fclose(fp); | ||
181 | return 0; | ||
182 | } /* end sysctl_preload_file() */ | ||
183 | |||
184 | |||
185 | /* | ||
186 | * Write a single sysctl setting | ||
187 | */ | ||
188 | int sysctl_write_setting(const char *setting, int output) | ||
189 | { | ||
190 | int retval = 0; | ||
191 | const char *name = setting; | ||
192 | const char *value; | ||
193 | const char *equals; | ||
194 | char *tmpname, *outname, *cptr; | ||
195 | int fd = -1; | ||
196 | |||
197 | if (!name) /* probably dont' want to display this err */ | ||
198 | return 0; | ||
199 | |||
200 | if (!(equals = strchr(setting, '='))) { | ||
201 | bb_error_msg(ERR_NO_EQUALS, setting); | ||
202 | return -1; | ||
203 | } | ||
204 | |||
205 | value = equals + sizeof(char); /* point to the value in name=value */ | ||
206 | |||
207 | if (!*name || !*value || name == equals) { | ||
208 | bb_error_msg(ERR_MALFORMED_SETTING, setting); | ||
209 | return -2; | ||
210 | } | ||
211 | |||
212 | bb_xasprintf(&tmpname, "%s%.*s", PROC_PATH, (equals - name), name); | ||
213 | outname = bb_xstrdup(tmpname + strlen(PROC_PATH)); | ||
214 | |||
215 | while ((cptr = strchr(tmpname, '.')) != NULL) | ||
216 | *cptr = '/'; | ||
217 | |||
218 | while ((cptr = strchr(outname, '/')) != NULL) | ||
219 | *cptr = '.'; | ||
220 | |||
221 | if ((fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { | ||
222 | switch (errno) { | ||
223 | case ENOENT: | ||
224 | bb_error_msg(ERR_INVALID_KEY, outname); | ||
225 | break; | ||
226 | case EACCES: | ||
227 | bb_perror_msg(ERR_PERMISSION_DENIED, outname); | ||
228 | break; | ||
229 | default: | ||
230 | bb_error_msg(ERR_UNKNOWN_WRITING, errno, outname); | ||
231 | break; | ||
232 | } | ||
233 | retval = -1; | ||
234 | } else { | ||
235 | dwrite_str(fd, value); | ||
236 | close(fd); | ||
237 | if (output) { | ||
238 | dwrite_str(STDOUT_FILENO, outname); | ||
239 | dwrite_str(STDOUT_FILENO, " = "); | ||
240 | } | ||
241 | dwrite_str(STDOUT_FILENO, value); | ||
242 | dwrite_str(STDOUT_FILENO, "\n"); | ||
243 | } | ||
244 | |||
245 | /* cleanup */ | ||
246 | free(tmpname); | ||
247 | free(outname); | ||
248 | return retval; | ||
249 | } /* end sysctl_write_setting() */ | ||
250 | |||
251 | |||
252 | /* | ||
253 | * Read a sysctl setting | ||
254 | * | ||
255 | */ | ||
256 | int sysctl_read_setting(const char *setting, int output) | ||
257 | { | ||
258 | int retval = 0; | ||
259 | char *tmpname, *outname, *cptr; | ||
260 | char inbuf[1025]; | ||
261 | const char *name = setting; | ||
262 | FILE *fp; | ||
263 | |||
264 | if (!setting || !*setting) | ||
265 | bb_error_msg(ERR_INVALID_KEY, setting); | ||
266 | |||
267 | tmpname = concat_path_file(PROC_PATH, name); | ||
268 | outname = bb_xstrdup(tmpname + strlen(PROC_PATH)); | ||
269 | |||
270 | while ((cptr = strchr(tmpname, '.')) != NULL) | ||
271 | *cptr = '/'; | ||
272 | while ((cptr = strchr(outname, '/')) != NULL) | ||
273 | *cptr = '.'; | ||
274 | |||
275 | if ((fp = fopen(tmpname, "r")) == NULL) { | ||
276 | switch (errno) { | ||
277 | case ENOENT: | ||
278 | bb_error_msg(ERR_INVALID_KEY, outname); | ||
279 | break; | ||
280 | case EACCES: | ||
281 | bb_error_msg(ERR_PERMISSION_DENIED, outname); | ||
282 | break; | ||
283 | default: | ||
284 | bb_error_msg(ERR_UNKNOWN_READING, errno, outname); | ||
285 | break; | ||
286 | } | ||
287 | retval = -1; | ||
288 | } else { | ||
289 | while (fgets(inbuf, sizeof(inbuf) - 1, fp)) { | ||
290 | if (output) { | ||
291 | dwrite_str(STDOUT_FILENO, outname); | ||
292 | dwrite_str(STDOUT_FILENO, " = "); | ||
293 | } | ||
294 | dwrite_str(STDOUT_FILENO, inbuf); | ||
295 | } | ||
296 | fclose(fp); | ||
297 | } | ||
298 | |||
299 | free(tmpname); | ||
300 | free(outname); | ||
301 | return retval; | ||
302 | } /* end sysctl_read_setting() */ | ||
303 | |||
304 | |||
305 | |||
306 | /* | ||
307 | * Display all the sysctl settings | ||
308 | * | ||
309 | */ | ||
310 | int sysctl_display_all(const char *path, int output, int show_table) | ||
311 | { | ||
312 | int retval = 0; | ||
313 | int retval2; | ||
314 | DIR *dp; | ||
315 | struct dirent *de; | ||
316 | char *tmpdir; | ||
317 | struct stat ts; | ||
318 | |||
319 | if (!(dp = opendir(path))) { | ||
320 | bb_perror_msg(ERR_OPENING_DIR, path); | ||
321 | retval = -1; | ||
322 | } else { | ||
323 | while ((de = readdir(dp)) != NULL) { | ||
324 | tmpdir = concat_subpath_file(path, de->d_name); | ||
325 | if(tmpdir == NULL) | ||
326 | continue; | ||
327 | if ((retval2 = stat(tmpdir, &ts)) != 0) | ||
328 | bb_perror_msg(tmpdir); | ||
329 | else { | ||
330 | if (S_ISDIR(ts.st_mode)) { | ||
331 | sysctl_display_all(tmpdir, output, show_table); | ||
332 | } else | ||
333 | retval |= | ||
334 | sysctl_read_setting(tmpdir + bb_strlen(PROC_PATH), | ||
335 | output); | ||
336 | |||
337 | } | ||
338 | free(tmpdir); | ||
339 | } /* end while */ | ||
340 | closedir(dp); | ||
341 | } | ||
342 | |||
343 | return retval; | ||
344 | } /* end sysctl_display_all() */ | ||
345 | |||
346 | #ifdef STANDALONE_SYSCTL | ||
347 | int main(int argc, char **argv) | ||
348 | { | ||
349 | return sysctl_main(argc, argv); | ||
350 | } | ||
351 | const char *bb_applet_name = "sysctl"; | ||
352 | #endif | ||