blob: 2c3fda5fed1753b6baa3a19d96dce3bc451d4518 [file] [log] [blame]
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +00001/* vi: set sw=4 ts=4: */
Eric Andersenb9050282003-12-24 06:02:11 +00002/*
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
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000017#include "busybox.h"
Eric Andersenb9050282003-12-24 06:02:11 +000018
19/*
20 * Function Prototypes
21 */
Eric Andersenb9050282003-12-24 06:02:11 +000022static int sysctl_read_setting(const char *setting, int output);
23static int sysctl_write_setting(const char *setting, int output);
24static int sysctl_preload_file(const char *filename, int output);
25static int sysctl_display_all(const char *path, int output, int show_table);
26
27/*
28 * Globals...
29 */
Glenn L McGrathab821542003-12-26 02:19:34 +000030static const char PROC_PATH[] = "/proc/sys/";
31static const char DEFAULT_PRELOAD[] = "/etc/sysctl.conf";
Eric Andersenb9050282003-12-24 06:02:11 +000032
33/* error messages */
Glenn L McGrathab821542003-12-26 02:19:34 +000034static const char ERR_UNKNOWN_PARAMETER[] = "error: Unknown parameter '%s'\n";
35static const char ERR_MALFORMED_SETTING[] = "error: Malformed setting '%s'\n";
36static const char ERR_NO_EQUALS[] =
Eric Andersenb9050282003-12-24 06:02:11 +000037 "error: '%s' must be of the form name=value\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000038static const char ERR_INVALID_KEY[] = "error: '%s' is an unknown key\n";
39static const char ERR_UNKNOWN_WRITING[] =
Eric Andersenb9050282003-12-24 06:02:11 +000040 "error: unknown error %d setting key '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000041static const char ERR_UNKNOWN_READING[] =
Eric Andersenb9050282003-12-24 06:02:11 +000042 "error: unknown error %d reading key '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000043static const char ERR_PERMISSION_DENIED[] =
Eric Andersenb9050282003-12-24 06:02:11 +000044 "error: permission denied on key '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000045static const char ERR_PRELOAD_FILE[] =
Denis Vlasenko89f0b342006-11-18 22:04:09 +000046 "error: cannot open preload file '%s'\n";
Glenn L McGrathab821542003-12-26 02:19:34 +000047static const char WARN_BAD_LINE[] =
Eric Andersenb9050282003-12-24 06:02:11 +000048 "warning: %s(%d): invalid syntax, continuing...\n";
49
50
Glenn L McGrathab821542003-12-26 02:19:34 +000051static void dwrite_str(int fd, const char *buf)
52{
53 write(fd, buf, strlen(buf));
54}
55
Eric Andersenb9050282003-12-24 06:02:11 +000056/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +000057 * sysctl_main()...
Eric Andersenb9050282003-12-24 06:02:11 +000058 */
Denis Vlasenko06af2162007-02-03 17:28:39 +000059int sysctl_main(int argc, char **argv);
Eric Andersenb9050282003-12-24 06:02:11 +000060int sysctl_main(int argc, char **argv)
61{
62 int retval = 0;
63 int output = 1;
64 int write_mode = 0;
65 int switches_allowed = 1;
66
67 if (argc < 2)
Glenn L McGrathab821542003-12-26 02:19:34 +000068 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +000069
70 argv++;
71
72 for (; argv && *argv && **argv; argv++) {
73 if (switches_allowed && **argv == '-') { /* we have a switch */
74 switch ((*argv)[1]) {
75 case 'n':
76 output = 0;
77 break;
78 case 'w':
79 write_mode = 1;
80 switches_allowed = 0;
81 break;
82 case 'p':
83 argv++;
84 return
85 sysctl_preload_file(((argv && *argv
86 && **argv) ? *argv :
87 DEFAULT_PRELOAD), output);
88 case 'a':
89 case 'A':
90 switches_allowed = 0;
91 return sysctl_display_all(PROC_PATH, output,
92 ((*argv)[1] == 'a') ? 0 : 1);
93 case 'h':
94 case '?':
Glenn L McGrathab821542003-12-26 02:19:34 +000095 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +000096 default:
97 bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv);
Glenn L McGrathab821542003-12-26 02:19:34 +000098 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +000099 }
100 } else {
101 switches_allowed = 0;
102 if (write_mode)
103 retval = sysctl_write_setting(*argv, output);
104 else
105 sysctl_read_setting(*argv, output);
106 }
107 }
108 return retval;
109} /* end sysctl_main() */
110
Eric Andersenb9050282003-12-24 06:02:11 +0000111
112
113/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000114 * sysctl_preload_file
Eric Andersenb9050282003-12-24 06:02:11 +0000115 * preload the sysctl's from a conf file
116 * - we parse the file and then reform it (strip out whitespace)
117 */
Glenn L McGrathab821542003-12-26 02:19:34 +0000118#define PRELOAD_BUF 256
119
Eric Andersenb9050282003-12-24 06:02:11 +0000120int sysctl_preload_file(const char *filename, int output)
121{
122 int lineno = 0;
Glenn L McGrathab821542003-12-26 02:19:34 +0000123 char oneline[PRELOAD_BUF];
124 char buffer[PRELOAD_BUF];
Eric Andersenb9050282003-12-24 06:02:11 +0000125 char *name, *value, *ptr;
126 FILE *fp = NULL;
127
128 if (!filename || ((fp = fopen(filename, "r")) == NULL)) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000129 bb_error_msg_and_die(ERR_PRELOAD_FILE, filename);
Eric Andersenb9050282003-12-24 06:02:11 +0000130 }
131
132 while (fgets(oneline, sizeof(oneline) - 1, fp)) {
Denis Vlasenko9cac5212006-09-09 12:24:19 +0000133 oneline[sizeof(oneline) - 1] = '\0';
Eric Andersenb9050282003-12-24 06:02:11 +0000134 lineno++;
135 trim(oneline);
136 ptr = (char *) oneline;
137
138 if (*ptr == '#' || *ptr == ';')
139 continue;
140
Rob Landleya3896512006-05-07 20:20:34 +0000141 if (strlen(ptr) < 2)
Eric Andersenb9050282003-12-24 06:02:11 +0000142 continue;
143
144 name = strtok(ptr, "=");
145 if (!name || !*name) {
146 bb_error_msg(WARN_BAD_LINE, filename, lineno);
147 continue;
148 }
149
150 trim(name);
151
152 value = strtok(NULL, "\n\r");
153 if (!value || !*value) {
154 bb_error_msg(WARN_BAD_LINE, filename, lineno);
155 continue;
156 }
157
158 while ((*value == ' ' || *value == '\t') && *value != 0)
159 value++;
Denis Vlasenko9cac5212006-09-09 12:24:19 +0000160 /* safe because sizeof(oneline) == sizeof(buffer) */
161 sprintf(buffer, "%s=%s", name, value);
Eric Andersenb9050282003-12-24 06:02:11 +0000162 sysctl_write_setting(buffer, output);
163 }
164 fclose(fp);
165 return 0;
166} /* end sysctl_preload_file() */
167
168
169/*
170 * Write a single sysctl setting
171 */
172int sysctl_write_setting(const char *setting, int output)
173{
174 int retval = 0;
175 const char *name = setting;
176 const char *value;
177 const char *equals;
178 char *tmpname, *outname, *cptr;
179 int fd = -1;
180
181 if (!name) /* probably dont' want to display this err */
182 return 0;
183
Glenn L McGrathab821542003-12-26 02:19:34 +0000184 if (!(equals = strchr(setting, '='))) {
Eric Andersenb9050282003-12-24 06:02:11 +0000185 bb_error_msg(ERR_NO_EQUALS, setting);
186 return -1;
187 }
188
189 value = equals + sizeof(char); /* point to the value in name=value */
190
191 if (!*name || !*value || name == equals) {
192 bb_error_msg(ERR_MALFORMED_SETTING, setting);
193 return -2;
194 }
195
Rob Landleyd921b2e2006-08-03 15:41:12 +0000196 tmpname = xasprintf("%s%.*s", PROC_PATH, (int)(equals - name), name);
197 outname = xstrdup(tmpname + strlen(PROC_PATH));
Eric Andersenb9050282003-12-24 06:02:11 +0000198
199 while ((cptr = strchr(tmpname, '.')) != NULL)
200 *cptr = '/';
201
202 while ((cptr = strchr(outname, '/')) != NULL)
203 *cptr = '.';
204
Denis Vlasenko50f7f442007-04-11 23:20:53 +0000205 fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
206 if (fd < 0) {
Eric Andersenb9050282003-12-24 06:02:11 +0000207 switch (errno) {
208 case ENOENT:
209 bb_error_msg(ERR_INVALID_KEY, outname);
210 break;
211 case EACCES:
212 bb_perror_msg(ERR_PERMISSION_DENIED, outname);
213 break;
214 default:
215 bb_error_msg(ERR_UNKNOWN_WRITING, errno, outname);
216 break;
217 }
218 retval = -1;
219 } else {
Glenn L McGrathab821542003-12-26 02:19:34 +0000220 dwrite_str(fd, value);
Eric Andersenb9050282003-12-24 06:02:11 +0000221 close(fd);
222 if (output) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000223 dwrite_str(STDOUT_FILENO, outname);
224 dwrite_str(STDOUT_FILENO, " = ");
Eric Andersenb9050282003-12-24 06:02:11 +0000225 }
Glenn L McGrathab821542003-12-26 02:19:34 +0000226 dwrite_str(STDOUT_FILENO, value);
227 dwrite_str(STDOUT_FILENO, "\n");
Eric Andersenb9050282003-12-24 06:02:11 +0000228 }
229
230 /* cleanup */
231 free(tmpname);
232 free(outname);
233 return retval;
234} /* end sysctl_write_setting() */
235
236
237/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000238 * Read a sysctl setting
Eric Andersenb9050282003-12-24 06:02:11 +0000239 *
240 */
241int sysctl_read_setting(const char *setting, int output)
242{
243 int retval = 0;
244 char *tmpname, *outname, *cptr;
245 char inbuf[1025];
246 const char *name = setting;
247 FILE *fp;
248
249 if (!setting || !*setting)
250 bb_error_msg(ERR_INVALID_KEY, setting);
251
Glenn L McGrathab821542003-12-26 02:19:34 +0000252 tmpname = concat_path_file(PROC_PATH, name);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000253 outname = xstrdup(tmpname + strlen(PROC_PATH));
Eric Andersenb9050282003-12-24 06:02:11 +0000254
255 while ((cptr = strchr(tmpname, '.')) != NULL)
256 *cptr = '/';
257 while ((cptr = strchr(outname, '/')) != NULL)
258 *cptr = '.';
259
260 if ((fp = fopen(tmpname, "r")) == NULL) {
261 switch (errno) {
262 case ENOENT:
263 bb_error_msg(ERR_INVALID_KEY, outname);
264 break;
265 case EACCES:
266 bb_error_msg(ERR_PERMISSION_DENIED, outname);
267 break;
268 default:
269 bb_error_msg(ERR_UNKNOWN_READING, errno, outname);
270 break;
271 }
272 retval = -1;
273 } else {
274 while (fgets(inbuf, sizeof(inbuf) - 1, fp)) {
275 if (output) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000276 dwrite_str(STDOUT_FILENO, outname);
277 dwrite_str(STDOUT_FILENO, " = ");
Eric Andersenb9050282003-12-24 06:02:11 +0000278 }
Glenn L McGrathab821542003-12-26 02:19:34 +0000279 dwrite_str(STDOUT_FILENO, inbuf);
Eric Andersenb9050282003-12-24 06:02:11 +0000280 }
281 fclose(fp);
282 }
283
284 free(tmpname);
285 free(outname);
286 return retval;
287} /* end sysctl_read_setting() */
288
289
290
291/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000292 * Display all the sysctl settings
Eric Andersenb9050282003-12-24 06:02:11 +0000293 *
294 */
295int sysctl_display_all(const char *path, int output, int show_table)
296{
297 int retval = 0;
298 int retval2;
299 DIR *dp;
300 struct dirent *de;
301 char *tmpdir;
302 struct stat ts;
303
Denis Vlasenko51742f42007-04-12 00:32:05 +0000304 dp = opendir(path);
305 if (!dp) {
Eric Andersenb9050282003-12-24 06:02:11 +0000306 retval = -1;
307 } else {
Eric Andersenb9050282003-12-24 06:02:11 +0000308 while ((de = readdir(dp)) != NULL) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000309 tmpdir = concat_subpath_file(path, de->d_name);
Denis Vlasenko51742f42007-04-12 00:32:05 +0000310 if (tmpdir == NULL)
Glenn L McGrathab821542003-12-26 02:19:34 +0000311 continue;
Denis Vlasenko51742f42007-04-12 00:32:05 +0000312 retval2 = stat(tmpdir, &ts);
313 if (retval2 != 0)
Eric Andersenb9050282003-12-24 06:02:11 +0000314 bb_perror_msg(tmpdir);
315 else {
316 if (S_ISDIR(ts.st_mode)) {
Eric Andersenb9050282003-12-24 06:02:11 +0000317 sysctl_display_all(tmpdir, output, show_table);
318 } else
319 retval |=
Rob Landleya3896512006-05-07 20:20:34 +0000320 sysctl_read_setting(tmpdir + strlen(PROC_PATH),
Eric Andersenb9050282003-12-24 06:02:11 +0000321 output);
322
323 }
324 free(tmpdir);
325 } /* end while */
326 closedir(dp);
327 }
328
329 return retval;
330} /* end sysctl_display_all() */