blob: a1294801798eb6f3aebc2d42dea78bab5e3b6cf9 [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 Vlasenko5a28a252007-10-29 19:22:13 +000030static const char ETC_SYSCTL_CONF[] ALIGN1 = "/etc/sysctl.conf";
31static const char PROC_SYS[] ALIGN1 = "/proc/sys/";
32enum { strlen_PROC_SYS = sizeof(PROC_SYS) - 1 };
Eric Andersenb9050282003-12-24 06:02:11 +000033
34/* error messages */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000035static const char ERR_UNKNOWN_PARAMETER[] ALIGN1 =
Denis Vlasenko5a28a252007-10-29 19:22:13 +000036 "error: unknown parameter '%s'";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000037static const char ERR_MALFORMED_SETTING[] ALIGN1 =
Denis Vlasenko5a28a252007-10-29 19:22:13 +000038 "error: malformed setting '%s'";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000039static const char ERR_NO_EQUALS[] ALIGN1 =
Denis Vlasenko5a28a252007-10-29 19:22:13 +000040 "error: '%s' must be of the form name=value";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000041static const char ERR_INVALID_KEY[] ALIGN1 =
Denis Vlasenko5a28a252007-10-29 19:22:13 +000042 "error: '%s' is an unknown key";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000043static const char ERR_UNKNOWN_WRITING[] ALIGN1 =
Denis Vlasenko5a28a252007-10-29 19:22:13 +000044 "error setting key '%s'";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000045static const char ERR_UNKNOWN_READING[] ALIGN1 =
Denis Vlasenko5a28a252007-10-29 19:22:13 +000046 "error reading key '%s'";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000047static const char ERR_PERMISSION_DENIED[] ALIGN1 =
Denis Vlasenko5a28a252007-10-29 19:22:13 +000048 "error: permission denied on key '%s'";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000049static const char ERR_PRELOAD_FILE[] ALIGN1 =
Denis Vlasenko5a28a252007-10-29 19:22:13 +000050 "error: cannot open preload file '%s'";
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000051static const char WARN_BAD_LINE[] ALIGN1 =
Denis Vlasenko5a28a252007-10-29 19:22:13 +000052 "warning: %s(%d): invalid syntax, continuing";
Eric Andersenb9050282003-12-24 06:02:11 +000053
54
Glenn L McGrathab821542003-12-26 02:19:34 +000055static void dwrite_str(int fd, const char *buf)
56{
57 write(fd, buf, strlen(buf));
58}
59
Eric Andersenb9050282003-12-24 06:02:11 +000060/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +000061 * sysctl_main()...
Eric Andersenb9050282003-12-24 06:02:11 +000062 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000063int sysctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Eric Andersenb9050282003-12-24 06:02:11 +000064int sysctl_main(int argc, char **argv)
65{
66 int retval = 0;
67 int output = 1;
68 int write_mode = 0;
69 int switches_allowed = 1;
70
71 if (argc < 2)
Glenn L McGrathab821542003-12-26 02:19:34 +000072 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +000073
74 argv++;
75
Denis Vlasenko5a28a252007-10-29 19:22:13 +000076 for (; *argv /*&& **argv*/; argv++) {
Eric Andersenb9050282003-12-24 06:02:11 +000077 if (switches_allowed && **argv == '-') { /* we have a switch */
78 switch ((*argv)[1]) {
79 case 'n':
80 output = 0;
81 break;
82 case 'w':
83 write_mode = 1;
84 switches_allowed = 0;
85 break;
86 case 'p':
87 argv++;
Denis Vlasenko5a28a252007-10-29 19:22:13 +000088 return sysctl_preload_file(((*argv /*&& **argv*/) ? *argv : ETC_SYSCTL_CONF),
89 output);
Eric Andersenb9050282003-12-24 06:02:11 +000090 case 'a':
91 case 'A':
Denis Vlasenko5a28a252007-10-29 19:22:13 +000092 return sysctl_display_all(PROC_SYS, output,
93 ((*argv)[1] == 'A'));
Eric Andersenb9050282003-12-24 06:02:11 +000094 default:
95 bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv);
Denis Vlasenko5a28a252007-10-29 19:22:13 +000096 /* fall through */
97 //case 'h':
98 //case '?':
Glenn L McGrathab821542003-12-26 02:19:34 +000099 bb_show_usage();
Eric Andersenb9050282003-12-24 06:02:11 +0000100 }
101 } else {
102 switches_allowed = 0;
103 if (write_mode)
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000104 retval |= sysctl_write_setting(*argv, output);
Eric Andersenb9050282003-12-24 06:02:11 +0000105 else
106 sysctl_read_setting(*argv, output);
107 }
108 }
109 return retval;
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000110} /* end sysctl_main() */
Eric Andersenb9050282003-12-24 06:02:11 +0000111
112/*
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000113 * sysctl_preload_file
114 * preload the sysctl's from a conf file
115 * - we parse the file and then reform it (strip out whitespace)
Eric Andersenb9050282003-12-24 06:02:11 +0000116 */
Glenn L McGrathab821542003-12-26 02:19:34 +0000117#define PRELOAD_BUF 256
118
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000119static int sysctl_preload_file(const char *filename, int output)
Eric Andersenb9050282003-12-24 06:02:11 +0000120{
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000121 int lineno;
Glenn L McGrathab821542003-12-26 02:19:34 +0000122 char oneline[PRELOAD_BUF];
123 char buffer[PRELOAD_BUF];
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000124 char *name, *value;
125 FILE *fp;
Eric Andersenb9050282003-12-24 06:02:11 +0000126
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000127 fp = fopen(filename, "r");
128 if (fp == 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
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000132 lineno = 0;
Eric Andersenb9050282003-12-24 06:02:11 +0000133 while (fgets(oneline, sizeof(oneline) - 1, fp)) {
Eric Andersenb9050282003-12-24 06:02:11 +0000134 lineno++;
135 trim(oneline);
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000136 if (oneline[0] == '#' || oneline[0] == ';')
137 continue;
138 if (!oneline[0] || !oneline[1])
Eric Andersenb9050282003-12-24 06:02:11 +0000139 continue;
140
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000141 name = strtok(oneline, "=");
142 if (!name) {
Eric Andersenb9050282003-12-24 06:02:11 +0000143 bb_error_msg(WARN_BAD_LINE, filename, lineno);
144 continue;
145 }
Eric Andersenb9050282003-12-24 06:02:11 +0000146 trim(name);
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000147 if (!*name) {
148 bb_error_msg(WARN_BAD_LINE, filename, lineno);
149 continue;
150 }
Eric Andersenb9050282003-12-24 06:02:11 +0000151
152 value = strtok(NULL, "\n\r");
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000153 if (!value) {
154 bb_error_msg(WARN_BAD_LINE, filename, lineno);
155 continue;
156 }
157 while (*value == ' ' || *value == '\t')
158 value++;
159 if (!*value) {
Eric Andersenb9050282003-12-24 06:02:11 +0000160 bb_error_msg(WARN_BAD_LINE, filename, lineno);
161 continue;
162 }
163
Denis Vlasenko9cac5212006-09-09 12:24:19 +0000164 /* safe because sizeof(oneline) == sizeof(buffer) */
165 sprintf(buffer, "%s=%s", name, value);
Eric Andersenb9050282003-12-24 06:02:11 +0000166 sysctl_write_setting(buffer, output);
167 }
168 fclose(fp);
169 return 0;
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000170} /* end sysctl_preload_file() */
Eric Andersenb9050282003-12-24 06:02:11 +0000171
172/*
173 * Write a single sysctl setting
174 */
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000175static int sysctl_write_setting(const char *setting, int output)
Eric Andersenb9050282003-12-24 06:02:11 +0000176{
177 int retval = 0;
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000178 const char *name;
Eric Andersenb9050282003-12-24 06:02:11 +0000179 const char *value;
180 const char *equals;
181 char *tmpname, *outname, *cptr;
182 int fd = -1;
183
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000184 name = setting;
185 equals = strchr(setting, '=');
186 if (!equals) {
Eric Andersenb9050282003-12-24 06:02:11 +0000187 bb_error_msg(ERR_NO_EQUALS, setting);
188 return -1;
189 }
190
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000191 value = equals + 1; /* point to the value in name=value */
192 if (name == equals || !*value) {
Eric Andersenb9050282003-12-24 06:02:11 +0000193 bb_error_msg(ERR_MALFORMED_SETTING, setting);
194 return -2;
195 }
196
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000197 tmpname = xasprintf("%s%.*s", PROC_SYS, (int)(equals - name), name);
198 outname = xstrdup(tmpname + strlen_PROC_SYS);
Eric Andersenb9050282003-12-24 06:02:11 +0000199
200 while ((cptr = strchr(tmpname, '.')) != NULL)
201 *cptr = '/';
202
203 while ((cptr = strchr(outname, '/')) != NULL)
204 *cptr = '.';
205
Denis Vlasenko50f7f442007-04-11 23:20:53 +0000206 fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
207 if (fd < 0) {
Eric Andersenb9050282003-12-24 06:02:11 +0000208 switch (errno) {
209 case ENOENT:
210 bb_error_msg(ERR_INVALID_KEY, outname);
211 break;
212 case EACCES:
213 bb_perror_msg(ERR_PERMISSION_DENIED, outname);
214 break;
215 default:
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000216 bb_perror_msg(ERR_UNKNOWN_WRITING, outname);
Eric Andersenb9050282003-12-24 06:02:11 +0000217 break;
218 }
219 retval = -1;
220 } else {
Glenn L McGrathab821542003-12-26 02:19:34 +0000221 dwrite_str(fd, value);
Eric Andersenb9050282003-12-24 06:02:11 +0000222 close(fd);
223 if (output) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000224 dwrite_str(STDOUT_FILENO, outname);
225 dwrite_str(STDOUT_FILENO, " = ");
Eric Andersenb9050282003-12-24 06:02:11 +0000226 }
Glenn L McGrathab821542003-12-26 02:19:34 +0000227 dwrite_str(STDOUT_FILENO, value);
228 dwrite_str(STDOUT_FILENO, "\n");
Eric Andersenb9050282003-12-24 06:02:11 +0000229 }
230
Eric Andersenb9050282003-12-24 06:02:11 +0000231 free(tmpname);
232 free(outname);
233 return retval;
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000234} /* end sysctl_write_setting() */
Eric Andersenb9050282003-12-24 06:02:11 +0000235
236/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000237 * Read a sysctl setting
Eric Andersenb9050282003-12-24 06:02:11 +0000238 */
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000239static int sysctl_read_setting(const char *setting, int output)
Eric Andersenb9050282003-12-24 06:02:11 +0000240{
241 int retval = 0;
242 char *tmpname, *outname, *cptr;
243 char inbuf[1025];
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000244 const char *name;
Eric Andersenb9050282003-12-24 06:02:11 +0000245 FILE *fp;
246
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000247 if (!*setting)
Eric Andersenb9050282003-12-24 06:02:11 +0000248 bb_error_msg(ERR_INVALID_KEY, setting);
249
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000250 name = setting;
251 tmpname = concat_path_file(PROC_SYS, name);
252 outname = xstrdup(tmpname + strlen_PROC_SYS);
Eric Andersenb9050282003-12-24 06:02:11 +0000253
254 while ((cptr = strchr(tmpname, '.')) != NULL)
255 *cptr = '/';
256 while ((cptr = strchr(outname, '/')) != NULL)
257 *cptr = '.';
258
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000259 fp = fopen(tmpname, "r");
260 if (fp == NULL) {
Eric Andersenb9050282003-12-24 06:02:11 +0000261 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:
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000269 bb_perror_msg(ERR_UNKNOWN_READING, outname);
Eric Andersenb9050282003-12-24 06:02:11 +0000270 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;
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000287} /* end sysctl_read_setting() */
Eric Andersenb9050282003-12-24 06:02:11 +0000288
289/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000290 * Display all the sysctl settings
Eric Andersenb9050282003-12-24 06:02:11 +0000291 */
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000292static int sysctl_display_all(const char *path, int output, int show_table)
Eric Andersenb9050282003-12-24 06:02:11 +0000293{
294 int retval = 0;
Eric Andersenb9050282003-12-24 06:02:11 +0000295 DIR *dp;
296 struct dirent *de;
297 char *tmpdir;
298 struct stat ts;
299
Denis Vlasenko51742f42007-04-12 00:32:05 +0000300 dp = opendir(path);
301 if (!dp) {
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000302 return -1;
Eric Andersenb9050282003-12-24 06:02:11 +0000303 }
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000304 while ((de = readdir(dp)) != NULL) {
305 tmpdir = concat_subpath_file(path, de->d_name);
306 if (tmpdir == NULL)
307 continue;
308 if (stat(tmpdir, &ts) != 0) {
309 bb_perror_msg(tmpdir);
310 } else if (S_ISDIR(ts.st_mode)) {
311 sysctl_display_all(tmpdir, output, show_table);
312 } else {
313 retval |= sysctl_read_setting(tmpdir + strlen_PROC_SYS, output);
314 }
315 free(tmpdir);
316 } /* end while */
317 closedir(dp);
Eric Andersenb9050282003-12-24 06:02:11 +0000318
319 return retval;
Denis Vlasenko5a28a252007-10-29 19:22:13 +0000320} /* end sysctl_display_all() */