blob: b8835c0d89c315b42b71dc6849cf2f39661657dd [file] [log] [blame]
Eric Andersenb9050282003-12-24 06:02:11 +00001
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>
Eric Andersenc7bda1c2004-03-15 08:29:22 +000020 *
Eric Andersenb9050282003-12-24 06:02:11 +000021 */
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 */
Eric Andersenb9050282003-12-24 06:02:11 +000037static int sysctl_read_setting(const char *setting, int output);
38static int sysctl_write_setting(const char *setting, int output);
39static int sysctl_preload_file(const char *filename, int output);
40static int sysctl_display_all(const char *path, int output, int show_table);
41
42/*
43 * Globals...
44 */
Glenn L McGrathab821542003-12-26 02:19:34 +000045static const char PROC_PATH[] = "/proc/sys/";
46static const char DEFAULT_PRELOAD[] = "/etc/sysctl.conf";
Eric Andersenb9050282003-12-24 06:02:11 +000047
48/* error messages */
Glenn L McGrathab821542003-12-26 02:19:34 +000049static const char ERR_UNKNOWN_PARAMETER[] = "error: Unknown parameter '%s'\n";
50static const char ERR_MALFORMED_SETTING[] = "error: Malformed setting '%s'\n";
51static const char ERR_NO_EQUALS[] =
Eric Andersenb9050282003-12-24 06:02:11 +000052 "error: '%s' must be of the form name=value\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000053static const char ERR_INVALID_KEY[] = "error: '%s' is an unknown key\n";
54static const char ERR_UNKNOWN_WRITING[] =
Eric Andersenb9050282003-12-24 06:02:11 +000055 "error: unknown error %d setting key '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000056static const char ERR_UNKNOWN_READING[] =
Eric Andersenb9050282003-12-24 06:02:11 +000057 "error: unknown error %d reading key '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000058static const char ERR_PERMISSION_DENIED[] =
Eric Andersenb9050282003-12-24 06:02:11 +000059 "error: permission denied on key '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000060static const char ERR_OPENING_DIR[] = "error: unable to open directory '%s'\n";
61static const char ERR_PRELOAD_FILE[] =
Eric Andersenb9050282003-12-24 06:02:11 +000062 "error: unable to open preload file '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000063static const char WARN_BAD_LINE[] =
Eric Andersenb9050282003-12-24 06:02:11 +000064 "warning: %s(%d): invalid syntax, continuing...\n";
65
66
Glenn L McGrathab821542003-12-26 02:19:34 +000067static void dwrite_str(int fd, const char *buf)
68{
69 write(fd, buf, strlen(buf));
70}
71
Eric Andersenb9050282003-12-24 06:02:11 +000072/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +000073 * sysctl_main()...
Eric Andersenb9050282003-12-24 06:02:11 +000074 */
75int 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)
Glenn L McGrathab821542003-12-26 02:19:34 +000083 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +000084
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 '?':
Glenn L McGrathab821542003-12-26 02:19:34 +0000110 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +0000111 default:
112 bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv);
Glenn L McGrathab821542003-12-26 02:19:34 +0000113 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +0000114 }
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
Eric Andersenb9050282003-12-24 06:02:11 +0000126
127
128/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000129 * sysctl_preload_file
Eric Andersenb9050282003-12-24 06:02:11 +0000130 * preload the sysctl's from a conf file
131 * - we parse the file and then reform it (strip out whitespace)
132 */
Glenn L McGrathab821542003-12-26 02:19:34 +0000133#define PRELOAD_BUF 256
134
Eric Andersenb9050282003-12-24 06:02:11 +0000135int sysctl_preload_file(const char *filename, int output)
136{
137 int lineno = 0;
Glenn L McGrathab821542003-12-26 02:19:34 +0000138 char oneline[PRELOAD_BUF];
139 char buffer[PRELOAD_BUF];
Eric Andersenb9050282003-12-24 06:02:11 +0000140 char *name, *value, *ptr;
141 FILE *fp = NULL;
142
143 if (!filename || ((fp = fopen(filename, "r")) == NULL)) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000144 bb_error_msg_and_die(ERR_PRELOAD_FILE, filename);
Eric Andersenb9050282003-12-24 06:02:11 +0000145 }
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++;
Glenn L McGrathab821542003-12-26 02:19:34 +0000175 strcpy(buffer, name);
176 strcat(buffer, "=");
177 strcat(buffer, value);
Eric Andersenb9050282003-12-24 06:02:11 +0000178 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 */
188int 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
Glenn L McGrathab821542003-12-26 02:19:34 +0000200 if (!(equals = strchr(setting, '='))) {
Eric Andersenb9050282003-12-24 06:02:11 +0000201 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
Eric Andersena68ea1c2006-01-30 22:48:39 +0000212 tmpname = bb_xasprintf("%s%.*s", PROC_PATH, (int)(equals - name), name);
Glenn L McGrathab821542003-12-26 02:19:34 +0000213 outname = bb_xstrdup(tmpname + strlen(PROC_PATH));
Eric Andersenb9050282003-12-24 06:02:11 +0000214
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 {
Glenn L McGrathab821542003-12-26 02:19:34 +0000235 dwrite_str(fd, value);
Eric Andersenb9050282003-12-24 06:02:11 +0000236 close(fd);
237 if (output) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000238 dwrite_str(STDOUT_FILENO, outname);
239 dwrite_str(STDOUT_FILENO, " = ");
Eric Andersenb9050282003-12-24 06:02:11 +0000240 }
Glenn L McGrathab821542003-12-26 02:19:34 +0000241 dwrite_str(STDOUT_FILENO, value);
242 dwrite_str(STDOUT_FILENO, "\n");
Eric Andersenb9050282003-12-24 06:02:11 +0000243 }
244
245 /* cleanup */
246 free(tmpname);
247 free(outname);
248 return retval;
249} /* end sysctl_write_setting() */
250
251
252/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000253 * Read a sysctl setting
Eric Andersenb9050282003-12-24 06:02:11 +0000254 *
255 */
256int 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
Glenn L McGrathab821542003-12-26 02:19:34 +0000267 tmpname = concat_path_file(PROC_PATH, name);
268 outname = bb_xstrdup(tmpname + strlen(PROC_PATH));
Eric Andersenb9050282003-12-24 06:02:11 +0000269
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) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000291 dwrite_str(STDOUT_FILENO, outname);
292 dwrite_str(STDOUT_FILENO, " = ");
Eric Andersenb9050282003-12-24 06:02:11 +0000293 }
Glenn L McGrathab821542003-12-26 02:19:34 +0000294 dwrite_str(STDOUT_FILENO, inbuf);
Eric Andersenb9050282003-12-24 06:02:11 +0000295 }
296 fclose(fp);
297 }
298
299 free(tmpname);
300 free(outname);
301 return retval;
302} /* end sysctl_read_setting() */
303
304
305
306/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000307 * Display all the sysctl settings
Eric Andersenb9050282003-12-24 06:02:11 +0000308 *
309 */
310int 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 {
Eric Andersenb9050282003-12-24 06:02:11 +0000323 while ((de = readdir(dp)) != NULL) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000324 tmpdir = concat_subpath_file(path, de->d_name);
325 if(tmpdir == NULL)
326 continue;
Eric Andersenb9050282003-12-24 06:02:11 +0000327 if ((retval2 = stat(tmpdir, &ts)) != 0)
328 bb_perror_msg(tmpdir);
329 else {
330 if (S_ISDIR(ts.st_mode)) {
Eric Andersenb9050282003-12-24 06:02:11 +0000331 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
347int main(int argc, char **argv)
348{
349 return sysctl_main(argc, argv);
350}
Glenn L McGrathab821542003-12-26 02:19:34 +0000351const char *bb_applet_name = "sysctl";
Eric Andersenb9050282003-12-24 06:02:11 +0000352#endif