blob: b5a01894fbd08f13ff1fdb86f987ba924a8422cc [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
205 if ((fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
206 switch (errno) {
207 case ENOENT:
208 bb_error_msg(ERR_INVALID_KEY, outname);
209 break;
210 case EACCES:
211 bb_perror_msg(ERR_PERMISSION_DENIED, outname);
212 break;
213 default:
214 bb_error_msg(ERR_UNKNOWN_WRITING, errno, outname);
215 break;
216 }
217 retval = -1;
218 } else {
Glenn L McGrathab821542003-12-26 02:19:34 +0000219 dwrite_str(fd, value);
Eric Andersenb9050282003-12-24 06:02:11 +0000220 close(fd);
221 if (output) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000222 dwrite_str(STDOUT_FILENO, outname);
223 dwrite_str(STDOUT_FILENO, " = ");
Eric Andersenb9050282003-12-24 06:02:11 +0000224 }
Glenn L McGrathab821542003-12-26 02:19:34 +0000225 dwrite_str(STDOUT_FILENO, value);
226 dwrite_str(STDOUT_FILENO, "\n");
Eric Andersenb9050282003-12-24 06:02:11 +0000227 }
228
229 /* cleanup */
230 free(tmpname);
231 free(outname);
232 return retval;
233} /* end sysctl_write_setting() */
234
235
236/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000237 * Read a sysctl setting
Eric Andersenb9050282003-12-24 06:02:11 +0000238 *
239 */
240int sysctl_read_setting(const char *setting, int output)
241{
242 int retval = 0;
243 char *tmpname, *outname, *cptr;
244 char inbuf[1025];
245 const char *name = setting;
246 FILE *fp;
247
248 if (!setting || !*setting)
249 bb_error_msg(ERR_INVALID_KEY, setting);
250
Glenn L McGrathab821542003-12-26 02:19:34 +0000251 tmpname = concat_path_file(PROC_PATH, name);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000252 outname = xstrdup(tmpname + strlen(PROC_PATH));
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
259 if ((fp = fopen(tmpname, "r")) == NULL) {
260 switch (errno) {
261 case ENOENT:
262 bb_error_msg(ERR_INVALID_KEY, outname);
263 break;
264 case EACCES:
265 bb_error_msg(ERR_PERMISSION_DENIED, outname);
266 break;
267 default:
268 bb_error_msg(ERR_UNKNOWN_READING, errno, outname);
269 break;
270 }
271 retval = -1;
272 } else {
273 while (fgets(inbuf, sizeof(inbuf) - 1, fp)) {
274 if (output) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000275 dwrite_str(STDOUT_FILENO, outname);
276 dwrite_str(STDOUT_FILENO, " = ");
Eric Andersenb9050282003-12-24 06:02:11 +0000277 }
Glenn L McGrathab821542003-12-26 02:19:34 +0000278 dwrite_str(STDOUT_FILENO, inbuf);
Eric Andersenb9050282003-12-24 06:02:11 +0000279 }
280 fclose(fp);
281 }
282
283 free(tmpname);
284 free(outname);
285 return retval;
286} /* end sysctl_read_setting() */
287
288
289
290/*
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000291 * Display all the sysctl settings
Eric Andersenb9050282003-12-24 06:02:11 +0000292 *
293 */
294int sysctl_display_all(const char *path, int output, int show_table)
295{
296 int retval = 0;
297 int retval2;
298 DIR *dp;
299 struct dirent *de;
300 char *tmpdir;
301 struct stat ts;
302
Rob Landleyd921b2e2006-08-03 15:41:12 +0000303 if (!(dp = opendir(path))) {
Eric Andersenb9050282003-12-24 06:02:11 +0000304 retval = -1;
305 } else {
Eric Andersenb9050282003-12-24 06:02:11 +0000306 while ((de = readdir(dp)) != NULL) {
Glenn L McGrathab821542003-12-26 02:19:34 +0000307 tmpdir = concat_subpath_file(path, de->d_name);
308 if(tmpdir == NULL)
309 continue;
Eric Andersenb9050282003-12-24 06:02:11 +0000310 if ((retval2 = stat(tmpdir, &ts)) != 0)
311 bb_perror_msg(tmpdir);
312 else {
313 if (S_ISDIR(ts.st_mode)) {
Eric Andersenb9050282003-12-24 06:02:11 +0000314 sysctl_display_all(tmpdir, output, show_table);
315 } else
316 retval |=
Rob Landleya3896512006-05-07 20:20:34 +0000317 sysctl_read_setting(tmpdir + strlen(PROC_PATH),
Eric Andersenb9050282003-12-24 06:02:11 +0000318 output);
319
320 }
321 free(tmpdir);
322 } /* end while */
323 closedir(dp);
324 }
325
326 return retval;
327} /* end sysctl_display_all() */