blob: 850cbae676e9d4e81a293e0620e0b36773a066ce [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 *
Rob Landley8b1f11d2006-04-17 21:49:34 +00005 * Copyright 1999 George Staikos
Bernhard Reutner-Fischercb448162006-04-12 07:35:12 +00006 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Eric Andersenb9050282003-12-24 06:02:11 +00008 *
9 * Changelog:
10 * v1.01:
11 * - added -p <preload> to preload values from a file
12 * v1.01.1
13 * - busybox applet aware by <solar@gentoo.org>
Eric Andersenc7bda1c2004-03-15 08:29:22 +000014 *
Eric Andersenb9050282003-12-24 06:02:11 +000015 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <sys/stat.h>
21#include <sys/types.h>
22#include <dirent.h>
23#include <string.h>
24#include <errno.h>
25#include <fcntl.h>
26#include "busybox.h"
27
28/*
29 * Function Prototypes
30 */
Eric Andersenb9050282003-12-24 06:02:11 +000031static int sysctl_read_setting(const char *setting, int output);
32static int sysctl_write_setting(const char *setting, int output);
33static int sysctl_preload_file(const char *filename, int output);
34static int sysctl_display_all(const char *path, int output, int show_table);
35
36/*
37 * Globals...
38 */
Glenn L McGrathab821542003-12-26 02:19:34 +000039static const char PROC_PATH[] = "/proc/sys/";
40static const char DEFAULT_PRELOAD[] = "/etc/sysctl.conf";
Eric Andersenb9050282003-12-24 06:02:11 +000041
42/* error messages */
Glenn L McGrathab821542003-12-26 02:19:34 +000043static const char ERR_UNKNOWN_PARAMETER[] = "error: Unknown parameter '%s'\n";
44static const char ERR_MALFORMED_SETTING[] = "error: Malformed setting '%s'\n";
45static const char ERR_NO_EQUALS[] =
Eric Andersenb9050282003-12-24 06:02:11 +000046 "error: '%s' must be of the form name=value\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000047static const char ERR_INVALID_KEY[] = "error: '%s' is an unknown key\n";
48static const char ERR_UNKNOWN_WRITING[] =
Eric Andersenb9050282003-12-24 06:02:11 +000049 "error: unknown error %d setting key '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000050static const char ERR_UNKNOWN_READING[] =
Eric Andersenb9050282003-12-24 06:02:11 +000051 "error: unknown error %d reading key '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000052static const char ERR_PERMISSION_DENIED[] =
Eric Andersenb9050282003-12-24 06:02:11 +000053 "error: permission denied on key '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000054static const char ERR_PRELOAD_FILE[] =
Eric Andersenb9050282003-12-24 06:02:11 +000055 "error: unable to open preload file '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000056static const char WARN_BAD_LINE[] =
Eric Andersenb9050282003-12-24 06:02:11 +000057 "warning: %s(%d): invalid syntax, continuing...\n";
58
59
Glenn L McGrathab821542003-12-26 02:19:34 +000060static void dwrite_str(int fd, const char *buf)
61{
62 write(fd, buf, strlen(buf));
63}
64
Eric Andersenb9050282003-12-24 06:02:11 +000065/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +000066 * sysctl_main()...
Eric Andersenb9050282003-12-24 06:02:11 +000067 */
68int sysctl_main(int argc, char **argv)
69{
70 int retval = 0;
71 int output = 1;
72 int write_mode = 0;
73 int switches_allowed = 1;
74
75 if (argc < 2)
Glenn L McGrathab821542003-12-26 02:19:34 +000076 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +000077
78 argv++;
79
80 for (; argv && *argv && **argv; argv++) {
81 if (switches_allowed && **argv == '-') { /* we have a switch */
82 switch ((*argv)[1]) {
83 case 'n':
84 output = 0;
85 break;
86 case 'w':
87 write_mode = 1;
88 switches_allowed = 0;
89 break;
90 case 'p':
91 argv++;
92 return
93 sysctl_preload_file(((argv && *argv
94 && **argv) ? *argv :
95 DEFAULT_PRELOAD), output);
96 case 'a':
97 case 'A':
98 switches_allowed = 0;
99 return sysctl_display_all(PROC_PATH, output,
100 ((*argv)[1] == 'a') ? 0 : 1);
101 case 'h':
102 case '?':
Glenn L McGrathab821542003-12-26 02:19:34 +0000103 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +0000104 default:
105 bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv);
Glenn L McGrathab821542003-12-26 02:19:34 +0000106 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +0000107 }
108 } else {
109 switches_allowed = 0;
110 if (write_mode)
111 retval = sysctl_write_setting(*argv, output);
112 else
113 sysctl_read_setting(*argv, output);
114 }
115 }
116 return retval;
117} /* end sysctl_main() */
118
Eric Andersenb9050282003-12-24 06:02:11 +0000119
120
121/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000122 * sysctl_preload_file
Eric Andersenb9050282003-12-24 06:02:11 +0000123 * preload the sysctl's from a conf file
124 * - we parse the file and then reform it (strip out whitespace)
125 */
Glenn L McGrathab821542003-12-26 02:19:34 +0000126#define PRELOAD_BUF 256
127
Eric Andersenb9050282003-12-24 06:02:11 +0000128int sysctl_preload_file(const char *filename, int output)
129{
130 int lineno = 0;
Glenn L McGrathab821542003-12-26 02:19:34 +0000131 char oneline[PRELOAD_BUF];
132 char buffer[PRELOAD_BUF];
Eric Andersenb9050282003-12-24 06:02:11 +0000133 char *name, *value, *ptr;
134 FILE *fp = NULL;
135
136 if (!filename || ((fp = fopen(filename, "r")) == NULL)) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000137 bb_error_msg_and_die(ERR_PRELOAD_FILE, filename);
Eric Andersenb9050282003-12-24 06:02:11 +0000138 }
139
140 while (fgets(oneline, sizeof(oneline) - 1, fp)) {
141 oneline[sizeof(oneline) - 1] = 0;
142 lineno++;
143 trim(oneline);
144 ptr = (char *) oneline;
145
146 if (*ptr == '#' || *ptr == ';')
147 continue;
148
149 if (bb_strlen(ptr) < 2)
150 continue;
151
152 name = strtok(ptr, "=");
153 if (!name || !*name) {
154 bb_error_msg(WARN_BAD_LINE, filename, lineno);
155 continue;
156 }
157
158 trim(name);
159
160 value = strtok(NULL, "\n\r");
161 if (!value || !*value) {
162 bb_error_msg(WARN_BAD_LINE, filename, lineno);
163 continue;
164 }
165
166 while ((*value == ' ' || *value == '\t') && *value != 0)
167 value++;
Glenn L McGrathab821542003-12-26 02:19:34 +0000168 strcpy(buffer, name);
169 strcat(buffer, "=");
170 strcat(buffer, value);
Eric Andersenb9050282003-12-24 06:02:11 +0000171 sysctl_write_setting(buffer, output);
172 }
173 fclose(fp);
174 return 0;
175} /* end sysctl_preload_file() */
176
177
178/*
179 * Write a single sysctl setting
180 */
181int sysctl_write_setting(const char *setting, int output)
182{
183 int retval = 0;
184 const char *name = setting;
185 const char *value;
186 const char *equals;
187 char *tmpname, *outname, *cptr;
188 int fd = -1;
189
190 if (!name) /* probably dont' want to display this err */
191 return 0;
192
Glenn L McGrathab821542003-12-26 02:19:34 +0000193 if (!(equals = strchr(setting, '='))) {
Eric Andersenb9050282003-12-24 06:02:11 +0000194 bb_error_msg(ERR_NO_EQUALS, setting);
195 return -1;
196 }
197
198 value = equals + sizeof(char); /* point to the value in name=value */
199
200 if (!*name || !*value || name == equals) {
201 bb_error_msg(ERR_MALFORMED_SETTING, setting);
202 return -2;
203 }
204
Eric Andersena68ea1c2006-01-30 22:48:39 +0000205 tmpname = bb_xasprintf("%s%.*s", PROC_PATH, (int)(equals - name), name);
Glenn L McGrathab821542003-12-26 02:19:34 +0000206 outname = bb_xstrdup(tmpname + strlen(PROC_PATH));
Eric Andersenb9050282003-12-24 06:02:11 +0000207
208 while ((cptr = strchr(tmpname, '.')) != NULL)
209 *cptr = '/';
210
211 while ((cptr = strchr(outname, '/')) != NULL)
212 *cptr = '.';
213
214 if ((fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
215 switch (errno) {
216 case ENOENT:
217 bb_error_msg(ERR_INVALID_KEY, outname);
218 break;
219 case EACCES:
220 bb_perror_msg(ERR_PERMISSION_DENIED, outname);
221 break;
222 default:
223 bb_error_msg(ERR_UNKNOWN_WRITING, errno, outname);
224 break;
225 }
226 retval = -1;
227 } else {
Glenn L McGrathab821542003-12-26 02:19:34 +0000228 dwrite_str(fd, value);
Eric Andersenb9050282003-12-24 06:02:11 +0000229 close(fd);
230 if (output) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000231 dwrite_str(STDOUT_FILENO, outname);
232 dwrite_str(STDOUT_FILENO, " = ");
Eric Andersenb9050282003-12-24 06:02:11 +0000233 }
Glenn L McGrathab821542003-12-26 02:19:34 +0000234 dwrite_str(STDOUT_FILENO, value);
235 dwrite_str(STDOUT_FILENO, "\n");
Eric Andersenb9050282003-12-24 06:02:11 +0000236 }
237
238 /* cleanup */
239 free(tmpname);
240 free(outname);
241 return retval;
242} /* end sysctl_write_setting() */
243
244
245/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000246 * Read a sysctl setting
Eric Andersenb9050282003-12-24 06:02:11 +0000247 *
248 */
249int sysctl_read_setting(const char *setting, int output)
250{
251 int retval = 0;
252 char *tmpname, *outname, *cptr;
253 char inbuf[1025];
254 const char *name = setting;
255 FILE *fp;
256
257 if (!setting || !*setting)
258 bb_error_msg(ERR_INVALID_KEY, setting);
259
Glenn L McGrathab821542003-12-26 02:19:34 +0000260 tmpname = concat_path_file(PROC_PATH, name);
261 outname = bb_xstrdup(tmpname + strlen(PROC_PATH));
Eric Andersenb9050282003-12-24 06:02:11 +0000262
263 while ((cptr = strchr(tmpname, '.')) != NULL)
264 *cptr = '/';
265 while ((cptr = strchr(outname, '/')) != NULL)
266 *cptr = '.';
267
268 if ((fp = fopen(tmpname, "r")) == NULL) {
269 switch (errno) {
270 case ENOENT:
271 bb_error_msg(ERR_INVALID_KEY, outname);
272 break;
273 case EACCES:
274 bb_error_msg(ERR_PERMISSION_DENIED, outname);
275 break;
276 default:
277 bb_error_msg(ERR_UNKNOWN_READING, errno, outname);
278 break;
279 }
280 retval = -1;
281 } else {
282 while (fgets(inbuf, sizeof(inbuf) - 1, fp)) {
283 if (output) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000284 dwrite_str(STDOUT_FILENO, outname);
285 dwrite_str(STDOUT_FILENO, " = ");
Eric Andersenb9050282003-12-24 06:02:11 +0000286 }
Glenn L McGrathab821542003-12-26 02:19:34 +0000287 dwrite_str(STDOUT_FILENO, inbuf);
Eric Andersenb9050282003-12-24 06:02:11 +0000288 }
289 fclose(fp);
290 }
291
292 free(tmpname);
293 free(outname);
294 return retval;
295} /* end sysctl_read_setting() */
296
297
298
299/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000300 * Display all the sysctl settings
Eric Andersenb9050282003-12-24 06:02:11 +0000301 *
302 */
303int sysctl_display_all(const char *path, int output, int show_table)
304{
305 int retval = 0;
306 int retval2;
307 DIR *dp;
308 struct dirent *de;
309 char *tmpdir;
310 struct stat ts;
311
Bernhard Reutner-Fischercb448162006-04-12 07:35:12 +0000312 if (!(dp = bb_opendir(path))) {
Eric Andersenb9050282003-12-24 06:02:11 +0000313 retval = -1;
314 } else {
Eric Andersenb9050282003-12-24 06:02:11 +0000315 while ((de = readdir(dp)) != NULL) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000316 tmpdir = concat_subpath_file(path, de->d_name);
317 if(tmpdir == NULL)
318 continue;
Eric Andersenb9050282003-12-24 06:02:11 +0000319 if ((retval2 = stat(tmpdir, &ts)) != 0)
320 bb_perror_msg(tmpdir);
321 else {
322 if (S_ISDIR(ts.st_mode)) {
Eric Andersenb9050282003-12-24 06:02:11 +0000323 sysctl_display_all(tmpdir, output, show_table);
324 } else
325 retval |=
326 sysctl_read_setting(tmpdir + bb_strlen(PROC_PATH),
327 output);
328
329 }
330 free(tmpdir);
331 } /* end while */
332 closedir(dp);
333 }
334
335 return retval;
336} /* end sysctl_display_all() */