blob: bcd229fdd219499cf273a674a828764abcf92e33 [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
Bernhard Reutner-Fischercb448162006-04-12 07:35:12 +00007 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Eric Andersenb9050282003-12-24 06:02:11 +00009 *
10 * Changelog:
11 * v1.01:
12 * - added -p <preload> to preload values from a file
13 * v1.01.1
14 * - busybox applet aware by <solar@gentoo.org>
Eric Andersenc7bda1c2004-03-15 08:29:22 +000015 *
Eric Andersenb9050282003-12-24 06:02:11 +000016 */
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <unistd.h>
21#include <sys/stat.h>
22#include <sys/types.h>
23#include <dirent.h>
24#include <string.h>
25#include <errno.h>
26#include <fcntl.h>
27#include "busybox.h"
28
29/*
30 * Function Prototypes
31 */
Eric Andersenb9050282003-12-24 06:02:11 +000032static int sysctl_read_setting(const char *setting, int output);
33static int sysctl_write_setting(const char *setting, int output);
34static int sysctl_preload_file(const char *filename, int output);
35static int sysctl_display_all(const char *path, int output, int show_table);
36
37/*
38 * Globals...
39 */
Glenn L McGrathab821542003-12-26 02:19:34 +000040static const char PROC_PATH[] = "/proc/sys/";
41static const char DEFAULT_PRELOAD[] = "/etc/sysctl.conf";
Eric Andersenb9050282003-12-24 06:02:11 +000042
43/* error messages */
Glenn L McGrathab821542003-12-26 02:19:34 +000044static const char ERR_UNKNOWN_PARAMETER[] = "error: Unknown parameter '%s'\n";
45static const char ERR_MALFORMED_SETTING[] = "error: Malformed setting '%s'\n";
46static const char ERR_NO_EQUALS[] =
Eric Andersenb9050282003-12-24 06:02:11 +000047 "error: '%s' must be of the form name=value\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000048static const char ERR_INVALID_KEY[] = "error: '%s' is an unknown key\n";
49static const char ERR_UNKNOWN_WRITING[] =
Eric Andersenb9050282003-12-24 06:02:11 +000050 "error: unknown error %d setting key '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000051static const char ERR_UNKNOWN_READING[] =
Eric Andersenb9050282003-12-24 06:02:11 +000052 "error: unknown error %d reading key '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000053static const char ERR_PERMISSION_DENIED[] =
Eric Andersenb9050282003-12-24 06:02:11 +000054 "error: permission denied on key '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000055static const char ERR_PRELOAD_FILE[] =
Eric Andersenb9050282003-12-24 06:02:11 +000056 "error: unable to open preload file '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000057static const char WARN_BAD_LINE[] =
Eric Andersenb9050282003-12-24 06:02:11 +000058 "warning: %s(%d): invalid syntax, continuing...\n";
59
60
Glenn L McGrathab821542003-12-26 02:19:34 +000061static void dwrite_str(int fd, const char *buf)
62{
63 write(fd, buf, strlen(buf));
64}
65
Eric Andersenb9050282003-12-24 06:02:11 +000066/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +000067 * sysctl_main()...
Eric Andersenb9050282003-12-24 06:02:11 +000068 */
69int sysctl_main(int argc, char **argv)
70{
71 int retval = 0;
72 int output = 1;
73 int write_mode = 0;
74 int switches_allowed = 1;
75
76 if (argc < 2)
Glenn L McGrathab821542003-12-26 02:19:34 +000077 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +000078
79 argv++;
80
81 for (; argv && *argv && **argv; argv++) {
82 if (switches_allowed && **argv == '-') { /* we have a switch */
83 switch ((*argv)[1]) {
84 case 'n':
85 output = 0;
86 break;
87 case 'w':
88 write_mode = 1;
89 switches_allowed = 0;
90 break;
91 case 'p':
92 argv++;
93 return
94 sysctl_preload_file(((argv && *argv
95 && **argv) ? *argv :
96 DEFAULT_PRELOAD), output);
97 case 'a':
98 case 'A':
99 switches_allowed = 0;
100 return sysctl_display_all(PROC_PATH, output,
101 ((*argv)[1] == 'a') ? 0 : 1);
102 case 'h':
103 case '?':
Glenn L McGrathab821542003-12-26 02:19:34 +0000104 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +0000105 default:
106 bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv);
Glenn L McGrathab821542003-12-26 02:19:34 +0000107 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +0000108 }
109 } else {
110 switches_allowed = 0;
111 if (write_mode)
112 retval = sysctl_write_setting(*argv, output);
113 else
114 sysctl_read_setting(*argv, output);
115 }
116 }
117 return retval;
118} /* end sysctl_main() */
119
Eric Andersenb9050282003-12-24 06:02:11 +0000120
121
122/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000123 * sysctl_preload_file
Eric Andersenb9050282003-12-24 06:02:11 +0000124 * preload the sysctl's from a conf file
125 * - we parse the file and then reform it (strip out whitespace)
126 */
Glenn L McGrathab821542003-12-26 02:19:34 +0000127#define PRELOAD_BUF 256
128
Eric Andersenb9050282003-12-24 06:02:11 +0000129int sysctl_preload_file(const char *filename, int output)
130{
131 int lineno = 0;
Glenn L McGrathab821542003-12-26 02:19:34 +0000132 char oneline[PRELOAD_BUF];
133 char buffer[PRELOAD_BUF];
Eric Andersenb9050282003-12-24 06:02:11 +0000134 char *name, *value, *ptr;
135 FILE *fp = NULL;
136
137 if (!filename || ((fp = fopen(filename, "r")) == NULL)) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000138 bb_error_msg_and_die(ERR_PRELOAD_FILE, filename);
Eric Andersenb9050282003-12-24 06:02:11 +0000139 }
140
141 while (fgets(oneline, sizeof(oneline) - 1, fp)) {
142 oneline[sizeof(oneline) - 1] = 0;
143 lineno++;
144 trim(oneline);
145 ptr = (char *) oneline;
146
147 if (*ptr == '#' || *ptr == ';')
148 continue;
149
150 if (bb_strlen(ptr) < 2)
151 continue;
152
153 name = strtok(ptr, "=");
154 if (!name || !*name) {
155 bb_error_msg(WARN_BAD_LINE, filename, lineno);
156 continue;
157 }
158
159 trim(name);
160
161 value = strtok(NULL, "\n\r");
162 if (!value || !*value) {
163 bb_error_msg(WARN_BAD_LINE, filename, lineno);
164 continue;
165 }
166
167 while ((*value == ' ' || *value == '\t') && *value != 0)
168 value++;
Glenn L McGrathab821542003-12-26 02:19:34 +0000169 strcpy(buffer, name);
170 strcat(buffer, "=");
171 strcat(buffer, value);
Eric Andersenb9050282003-12-24 06:02:11 +0000172 sysctl_write_setting(buffer, output);
173 }
174 fclose(fp);
175 return 0;
176} /* end sysctl_preload_file() */
177
178
179/*
180 * Write a single sysctl setting
181 */
182int sysctl_write_setting(const char *setting, int output)
183{
184 int retval = 0;
185 const char *name = setting;
186 const char *value;
187 const char *equals;
188 char *tmpname, *outname, *cptr;
189 int fd = -1;
190
191 if (!name) /* probably dont' want to display this err */
192 return 0;
193
Glenn L McGrathab821542003-12-26 02:19:34 +0000194 if (!(equals = strchr(setting, '='))) {
Eric Andersenb9050282003-12-24 06:02:11 +0000195 bb_error_msg(ERR_NO_EQUALS, setting);
196 return -1;
197 }
198
199 value = equals + sizeof(char); /* point to the value in name=value */
200
201 if (!*name || !*value || name == equals) {
202 bb_error_msg(ERR_MALFORMED_SETTING, setting);
203 return -2;
204 }
205
Eric Andersena68ea1c2006-01-30 22:48:39 +0000206 tmpname = bb_xasprintf("%s%.*s", PROC_PATH, (int)(equals - name), name);
Glenn L McGrathab821542003-12-26 02:19:34 +0000207 outname = bb_xstrdup(tmpname + strlen(PROC_PATH));
Eric Andersenb9050282003-12-24 06:02:11 +0000208
209 while ((cptr = strchr(tmpname, '.')) != NULL)
210 *cptr = '/';
211
212 while ((cptr = strchr(outname, '/')) != NULL)
213 *cptr = '.';
214
215 if ((fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
216 switch (errno) {
217 case ENOENT:
218 bb_error_msg(ERR_INVALID_KEY, outname);
219 break;
220 case EACCES:
221 bb_perror_msg(ERR_PERMISSION_DENIED, outname);
222 break;
223 default:
224 bb_error_msg(ERR_UNKNOWN_WRITING, errno, outname);
225 break;
226 }
227 retval = -1;
228 } else {
Glenn L McGrathab821542003-12-26 02:19:34 +0000229 dwrite_str(fd, value);
Eric Andersenb9050282003-12-24 06:02:11 +0000230 close(fd);
231 if (output) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000232 dwrite_str(STDOUT_FILENO, outname);
233 dwrite_str(STDOUT_FILENO, " = ");
Eric Andersenb9050282003-12-24 06:02:11 +0000234 }
Glenn L McGrathab821542003-12-26 02:19:34 +0000235 dwrite_str(STDOUT_FILENO, value);
236 dwrite_str(STDOUT_FILENO, "\n");
Eric Andersenb9050282003-12-24 06:02:11 +0000237 }
238
239 /* cleanup */
240 free(tmpname);
241 free(outname);
242 return retval;
243} /* end sysctl_write_setting() */
244
245
246/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000247 * Read a sysctl setting
Eric Andersenb9050282003-12-24 06:02:11 +0000248 *
249 */
250int sysctl_read_setting(const char *setting, int output)
251{
252 int retval = 0;
253 char *tmpname, *outname, *cptr;
254 char inbuf[1025];
255 const char *name = setting;
256 FILE *fp;
257
258 if (!setting || !*setting)
259 bb_error_msg(ERR_INVALID_KEY, setting);
260
Glenn L McGrathab821542003-12-26 02:19:34 +0000261 tmpname = concat_path_file(PROC_PATH, name);
262 outname = bb_xstrdup(tmpname + strlen(PROC_PATH));
Eric Andersenb9050282003-12-24 06:02:11 +0000263
264 while ((cptr = strchr(tmpname, '.')) != NULL)
265 *cptr = '/';
266 while ((cptr = strchr(outname, '/')) != NULL)
267 *cptr = '.';
268
269 if ((fp = fopen(tmpname, "r")) == NULL) {
270 switch (errno) {
271 case ENOENT:
272 bb_error_msg(ERR_INVALID_KEY, outname);
273 break;
274 case EACCES:
275 bb_error_msg(ERR_PERMISSION_DENIED, outname);
276 break;
277 default:
278 bb_error_msg(ERR_UNKNOWN_READING, errno, outname);
279 break;
280 }
281 retval = -1;
282 } else {
283 while (fgets(inbuf, sizeof(inbuf) - 1, fp)) {
284 if (output) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000285 dwrite_str(STDOUT_FILENO, outname);
286 dwrite_str(STDOUT_FILENO, " = ");
Eric Andersenb9050282003-12-24 06:02:11 +0000287 }
Glenn L McGrathab821542003-12-26 02:19:34 +0000288 dwrite_str(STDOUT_FILENO, inbuf);
Eric Andersenb9050282003-12-24 06:02:11 +0000289 }
290 fclose(fp);
291 }
292
293 free(tmpname);
294 free(outname);
295 return retval;
296} /* end sysctl_read_setting() */
297
298
299
300/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000301 * Display all the sysctl settings
Eric Andersenb9050282003-12-24 06:02:11 +0000302 *
303 */
304int sysctl_display_all(const char *path, int output, int show_table)
305{
306 int retval = 0;
307 int retval2;
308 DIR *dp;
309 struct dirent *de;
310 char *tmpdir;
311 struct stat ts;
312
Bernhard Reutner-Fischercb448162006-04-12 07:35:12 +0000313 if (!(dp = bb_opendir(path))) {
Eric Andersenb9050282003-12-24 06:02:11 +0000314 retval = -1;
315 } else {
Eric Andersenb9050282003-12-24 06:02:11 +0000316 while ((de = readdir(dp)) != NULL) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000317 tmpdir = concat_subpath_file(path, de->d_name);
318 if(tmpdir == NULL)
319 continue;
Eric Andersenb9050282003-12-24 06:02:11 +0000320 if ((retval2 = stat(tmpdir, &ts)) != 0)
321 bb_perror_msg(tmpdir);
322 else {
323 if (S_ISDIR(ts.st_mode)) {
Eric Andersenb9050282003-12-24 06:02:11 +0000324 sysctl_display_all(tmpdir, output, show_table);
325 } else
326 retval |=
327 sysctl_read_setting(tmpdir + bb_strlen(PROC_PATH),
328 output);
329
330 }
331 free(tmpdir);
332 } /* end while */
333 closedir(dp);
334 }
335
336 return retval;
337} /* end sysctl_display_all() */
338
339#ifdef STANDALONE_SYSCTL
340int main(int argc, char **argv)
341{
342 return sysctl_main(argc, argv);
343}
Glenn L McGrathab821542003-12-26 02:19:34 +0000344const char *bb_applet_name = "sysctl";
Eric Andersenb9050282003-12-24 06:02:11 +0000345#endif