blob: 5100f57e7d8da807a5b80909eec7a6bf0d88dcc6 [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
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000017#include "libbb.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 */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000030static const char PROC_PATH[] ALIGN1 = "/proc/sys/";
31static const char DEFAULT_PRELOAD[] ALIGN1 = "/etc/sysctl.conf";
Eric Andersenb9050282003-12-24 06:02:11 +000032
33/* error messages */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000034static const char ERR_UNKNOWN_PARAMETER[] ALIGN1 =
35 "error: Unknown parameter '%s'\n";
36static const char ERR_MALFORMED_SETTING[] ALIGN1 =
37 "error: Malformed setting '%s'\n";
38static const char ERR_NO_EQUALS[] ALIGN1 =
Eric Andersenb9050282003-12-24 06:02:11 +000039 "error: '%s' must be of the form name=value\n";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000040static const char ERR_INVALID_KEY[] ALIGN1 =
41 "error: '%s' is an unknown key\n";
42static const char ERR_UNKNOWN_WRITING[] ALIGN1 =
Eric Andersenb9050282003-12-24 06:02:11 +000043 "error: unknown error %d setting key '%s'\n";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000044static const char ERR_UNKNOWN_READING[] ALIGN1 =
Eric Andersenb9050282003-12-24 06:02:11 +000045 "error: unknown error %d reading key '%s'\n";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000046static const char ERR_PERMISSION_DENIED[] ALIGN1 =
Eric Andersenb9050282003-12-24 06:02:11 +000047 "error: permission denied on key '%s'\n";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000048static const char ERR_PRELOAD_FILE[] ALIGN1 =
Denis Vlasenko89f0b342006-11-18 22:04:09 +000049 "error: cannot open preload file '%s'\n";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000050static const char WARN_BAD_LINE[] ALIGN1 =
Eric Andersenb9050282003-12-24 06:02:11 +000051 "warning: %s(%d): invalid syntax, continuing...\n";
52
53
Glenn L McGrathab821542003-12-26 02:19:34 +000054static void dwrite_str(int fd, const char *buf)
55{
56 write(fd, buf, strlen(buf));
57}
58
Eric Andersenb9050282003-12-24 06:02:11 +000059/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +000060 * sysctl_main()...
Eric Andersenb9050282003-12-24 06:02:11 +000061 */
Denis Vlasenko06af2162007-02-03 17:28:39 +000062int sysctl_main(int argc, char **argv);
Eric Andersenb9050282003-12-24 06:02:11 +000063int sysctl_main(int argc, char **argv)
64{
65 int retval = 0;
66 int output = 1;
67 int write_mode = 0;
68 int switches_allowed = 1;
69
70 if (argc < 2)
Glenn L McGrathab821542003-12-26 02:19:34 +000071 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +000072
73 argv++;
74
75 for (; argv && *argv && **argv; argv++) {
76 if (switches_allowed && **argv == '-') { /* we have a switch */
77 switch ((*argv)[1]) {
78 case 'n':
79 output = 0;
80 break;
81 case 'w':
82 write_mode = 1;
83 switches_allowed = 0;
84 break;
85 case 'p':
86 argv++;
87 return
88 sysctl_preload_file(((argv && *argv
89 && **argv) ? *argv :
90 DEFAULT_PRELOAD), output);
91 case 'a':
92 case 'A':
93 switches_allowed = 0;
94 return sysctl_display_all(PROC_PATH, output,
95 ((*argv)[1] == 'a') ? 0 : 1);
96 case 'h':
97 case '?':
Glenn L McGrathab821542003-12-26 02:19:34 +000098 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +000099 default:
100 bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv);
Glenn L McGrathab821542003-12-26 02:19:34 +0000101 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +0000102 }
103 } else {
104 switches_allowed = 0;
105 if (write_mode)
106 retval = sysctl_write_setting(*argv, output);
107 else
108 sysctl_read_setting(*argv, output);
109 }
110 }
111 return retval;
112} /* end sysctl_main() */
113
Eric Andersenb9050282003-12-24 06:02:11 +0000114
115
116/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000117 * sysctl_preload_file
Eric Andersenb9050282003-12-24 06:02:11 +0000118 * preload the sysctl's from a conf file
119 * - we parse the file and then reform it (strip out whitespace)
120 */
Glenn L McGrathab821542003-12-26 02:19:34 +0000121#define PRELOAD_BUF 256
122
Eric Andersenb9050282003-12-24 06:02:11 +0000123int sysctl_preload_file(const char *filename, int output)
124{
125 int lineno = 0;
Glenn L McGrathab821542003-12-26 02:19:34 +0000126 char oneline[PRELOAD_BUF];
127 char buffer[PRELOAD_BUF];
Eric Andersenb9050282003-12-24 06:02:11 +0000128 char *name, *value, *ptr;
129 FILE *fp = NULL;
130
131 if (!filename || ((fp = fopen(filename, "r")) == NULL)) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000132 bb_error_msg_and_die(ERR_PRELOAD_FILE, filename);
Eric Andersenb9050282003-12-24 06:02:11 +0000133 }
134
135 while (fgets(oneline, sizeof(oneline) - 1, fp)) {
Denis Vlasenko9cac5212006-09-09 12:24:19 +0000136 oneline[sizeof(oneline) - 1] = '\0';
Eric Andersenb9050282003-12-24 06:02:11 +0000137 lineno++;
138 trim(oneline);
139 ptr = (char *) oneline;
140
141 if (*ptr == '#' || *ptr == ';')
142 continue;
143
Rob Landleya3896512006-05-07 20:20:34 +0000144 if (strlen(ptr) < 2)
Eric Andersenb9050282003-12-24 06:02:11 +0000145 continue;
146
147 name = strtok(ptr, "=");
148 if (!name || !*name) {
149 bb_error_msg(WARN_BAD_LINE, filename, lineno);
150 continue;
151 }
152
153 trim(name);
154
155 value = strtok(NULL, "\n\r");
156 if (!value || !*value) {
157 bb_error_msg(WARN_BAD_LINE, filename, lineno);
158 continue;
159 }
160
161 while ((*value == ' ' || *value == '\t') && *value != 0)
162 value++;
Denis Vlasenko9cac5212006-09-09 12:24:19 +0000163 /* safe because sizeof(oneline) == sizeof(buffer) */
164 sprintf(buffer, "%s=%s", name, value);
Eric Andersenb9050282003-12-24 06:02:11 +0000165 sysctl_write_setting(buffer, output);
166 }
167 fclose(fp);
168 return 0;
169} /* end sysctl_preload_file() */
170
171
172/*
173 * Write a single sysctl setting
174 */
175int sysctl_write_setting(const char *setting, int output)
176{
177 int retval = 0;
178 const char *name = setting;
179 const char *value;
180 const char *equals;
181 char *tmpname, *outname, *cptr;
182 int fd = -1;
183
184 if (!name) /* probably dont' want to display this err */
185 return 0;
186
Glenn L McGrathab821542003-12-26 02:19:34 +0000187 if (!(equals = strchr(setting, '='))) {
Eric Andersenb9050282003-12-24 06:02:11 +0000188 bb_error_msg(ERR_NO_EQUALS, setting);
189 return -1;
190 }
191
192 value = equals + sizeof(char); /* point to the value in name=value */
193
194 if (!*name || !*value || name == equals) {
195 bb_error_msg(ERR_MALFORMED_SETTING, setting);
196 return -2;
197 }
198
Rob Landleyd921b2e2006-08-03 15:41:12 +0000199 tmpname = xasprintf("%s%.*s", PROC_PATH, (int)(equals - name), name);
200 outname = xstrdup(tmpname + strlen(PROC_PATH));
Eric Andersenb9050282003-12-24 06:02:11 +0000201
202 while ((cptr = strchr(tmpname, '.')) != NULL)
203 *cptr = '/';
204
205 while ((cptr = strchr(outname, '/')) != NULL)
206 *cptr = '.';
207
Denis Vlasenko50f7f442007-04-11 23:20:53 +0000208 fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
209 if (fd < 0) {
Eric Andersenb9050282003-12-24 06:02:11 +0000210 switch (errno) {
211 case ENOENT:
212 bb_error_msg(ERR_INVALID_KEY, outname);
213 break;
214 case EACCES:
215 bb_perror_msg(ERR_PERMISSION_DENIED, outname);
216 break;
217 default:
218 bb_error_msg(ERR_UNKNOWN_WRITING, errno, outname);
219 break;
220 }
221 retval = -1;
222 } else {
Glenn L McGrathab821542003-12-26 02:19:34 +0000223 dwrite_str(fd, value);
Eric Andersenb9050282003-12-24 06:02:11 +0000224 close(fd);
225 if (output) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000226 dwrite_str(STDOUT_FILENO, outname);
227 dwrite_str(STDOUT_FILENO, " = ");
Eric Andersenb9050282003-12-24 06:02:11 +0000228 }
Glenn L McGrathab821542003-12-26 02:19:34 +0000229 dwrite_str(STDOUT_FILENO, value);
230 dwrite_str(STDOUT_FILENO, "\n");
Eric Andersenb9050282003-12-24 06:02:11 +0000231 }
232
233 /* cleanup */
234 free(tmpname);
235 free(outname);
236 return retval;
237} /* end sysctl_write_setting() */
238
239
240/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000241 * Read a sysctl setting
Eric Andersenb9050282003-12-24 06:02:11 +0000242 *
243 */
244int sysctl_read_setting(const char *setting, int output)
245{
246 int retval = 0;
247 char *tmpname, *outname, *cptr;
248 char inbuf[1025];
249 const char *name = setting;
250 FILE *fp;
251
252 if (!setting || !*setting)
253 bb_error_msg(ERR_INVALID_KEY, setting);
254
Glenn L McGrathab821542003-12-26 02:19:34 +0000255 tmpname = concat_path_file(PROC_PATH, name);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000256 outname = xstrdup(tmpname + strlen(PROC_PATH));
Eric Andersenb9050282003-12-24 06:02:11 +0000257
258 while ((cptr = strchr(tmpname, '.')) != NULL)
259 *cptr = '/';
260 while ((cptr = strchr(outname, '/')) != NULL)
261 *cptr = '.';
262
263 if ((fp = fopen(tmpname, "r")) == NULL) {
264 switch (errno) {
265 case ENOENT:
266 bb_error_msg(ERR_INVALID_KEY, outname);
267 break;
268 case EACCES:
269 bb_error_msg(ERR_PERMISSION_DENIED, outname);
270 break;
271 default:
272 bb_error_msg(ERR_UNKNOWN_READING, errno, outname);
273 break;
274 }
275 retval = -1;
276 } else {
277 while (fgets(inbuf, sizeof(inbuf) - 1, fp)) {
278 if (output) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000279 dwrite_str(STDOUT_FILENO, outname);
280 dwrite_str(STDOUT_FILENO, " = ");
Eric Andersenb9050282003-12-24 06:02:11 +0000281 }
Glenn L McGrathab821542003-12-26 02:19:34 +0000282 dwrite_str(STDOUT_FILENO, inbuf);
Eric Andersenb9050282003-12-24 06:02:11 +0000283 }
284 fclose(fp);
285 }
286
287 free(tmpname);
288 free(outname);
289 return retval;
290} /* end sysctl_read_setting() */
291
292
293
294/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000295 * Display all the sysctl settings
Eric Andersenb9050282003-12-24 06:02:11 +0000296 *
297 */
298int sysctl_display_all(const char *path, int output, int show_table)
299{
300 int retval = 0;
301 int retval2;
302 DIR *dp;
303 struct dirent *de;
304 char *tmpdir;
305 struct stat ts;
306
Denis Vlasenko51742f42007-04-12 00:32:05 +0000307 dp = opendir(path);
308 if (!dp) {
Eric Andersenb9050282003-12-24 06:02:11 +0000309 retval = -1;
310 } else {
Eric Andersenb9050282003-12-24 06:02:11 +0000311 while ((de = readdir(dp)) != NULL) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000312 tmpdir = concat_subpath_file(path, de->d_name);
Denis Vlasenko51742f42007-04-12 00:32:05 +0000313 if (tmpdir == NULL)
Glenn L McGrathab821542003-12-26 02:19:34 +0000314 continue;
Denis Vlasenko51742f42007-04-12 00:32:05 +0000315 retval2 = stat(tmpdir, &ts);
316 if (retval2 != 0)
Eric Andersenb9050282003-12-24 06:02:11 +0000317 bb_perror_msg(tmpdir);
318 else {
319 if (S_ISDIR(ts.st_mode)) {
Eric Andersenb9050282003-12-24 06:02:11 +0000320 sysctl_display_all(tmpdir, output, show_table);
321 } else
322 retval |=
Rob Landleya3896512006-05-07 20:20:34 +0000323 sysctl_read_setting(tmpdir + strlen(PROC_PATH),
Eric Andersenb9050282003-12-24 06:02:11 +0000324 output);
325
326 }
327 free(tmpdir);
328 } /* end while */
329 closedir(dp);
330 }
331
332 return retval;
333} /* end sysctl_display_all() */