www.usr.com/support/gpl/USR9107_release.1.4.tar.gz
[bcm963xx.git] / userapps / opensource / busybox / procps / sysctl.c
1
2 /*
3  * Sysctl 1.01 - A utility to read and manipulate the sysctl parameters
4  *
5  *
6  * "Copyright 1999 George Staikos
7  * This file may be used subject to the terms and conditions of the
8  * GNU General Public License Version 2, or any later version
9  * at your option, as published by the Free Software Foundation.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details."
14  *
15  * Changelog:
16  *      v1.01:
17  *              - added -p <preload> to preload values from a file
18  *      v1.01.1
19  *              - busybox applet aware by <solar@gentoo.org>
20  *
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <dirent.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include "busybox.h"
33
34 /*
35  *    Function Prototypes
36  */
37 static int sysctl_read_setting(const char *setting, int output);
38 static int sysctl_write_setting(const char *setting, int output);
39 static int sysctl_preload_file(const char *filename, int output);
40 static int sysctl_display_all(const char *path, int output, int show_table);
41
42 /*
43  *    Globals...
44  */
45 static const char PROC_PATH[] = "/proc/sys/";
46 static const char DEFAULT_PRELOAD[] = "/etc/sysctl.conf";
47
48 /* error messages */
49 static const char ERR_UNKNOWN_PARAMETER[] = "error: Unknown parameter '%s'\n";
50 static const char ERR_MALFORMED_SETTING[] = "error: Malformed setting '%s'\n";
51 static const char ERR_NO_EQUALS[] =
52         "error: '%s' must be of the form name=value\n";
53 static const char ERR_INVALID_KEY[] = "error: '%s' is an unknown key\n";
54 static const char ERR_UNKNOWN_WRITING[] =
55         "error: unknown error %d setting key '%s'\n";
56 static const char ERR_UNKNOWN_READING[] =
57         "error: unknown error %d reading key '%s'\n";
58 static const char ERR_PERMISSION_DENIED[] =
59         "error: permission denied on key '%s'\n";
60 static const char ERR_OPENING_DIR[] = "error: unable to open directory '%s'\n";
61 static const char ERR_PRELOAD_FILE[] =
62         "error: unable to open preload file '%s'\n";
63 static const char WARN_BAD_LINE[] =
64         "warning: %s(%d): invalid syntax, continuing...\n";
65
66
67 static void dwrite_str(int fd, const char *buf)
68 {
69         write(fd, buf, strlen(buf));
70 }
71
72 /*
73  *    sysctl_main()...
74  */
75 int sysctl_main(int argc, char **argv)
76 {
77         int retval = 0;
78         int output = 1;
79         int write_mode = 0;
80         int switches_allowed = 1;
81
82         if (argc < 2)
83                 bb_show_usage();
84
85         argv++;
86
87         for (; argv && *argv && **argv; argv++) {
88                 if (switches_allowed && **argv == '-') {        /* we have a switch */
89                         switch ((*argv)[1]) {
90                         case 'n':
91                                 output = 0;
92                                 break;
93                         case 'w':
94                                 write_mode = 1;
95                                 switches_allowed = 0;
96                                 break;
97                         case 'p':
98                                 argv++;
99                                 return
100                                         sysctl_preload_file(((argv && *argv
101                                                                                   && **argv) ? *argv :
102                                                                                  DEFAULT_PRELOAD), output);
103                         case 'a':
104                         case 'A':
105                                 switches_allowed = 0;
106                                 return sysctl_display_all(PROC_PATH, output,
107                                                                                   ((*argv)[1] == 'a') ? 0 : 1);
108                         case 'h':
109                         case '?':
110                                 bb_show_usage();
111                         default:
112                                 bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv);
113                                 bb_show_usage();
114                         }
115                 } else {
116                         switches_allowed = 0;
117                         if (write_mode)
118                                 retval = sysctl_write_setting(*argv, output);
119                         else
120                                 sysctl_read_setting(*argv, output);
121                 }
122         }
123         return retval;
124 }                                               /* end sysctl_main() */
125
126
127
128 /*
129  *     sysctl_preload_file
130  *      preload the sysctl's from a conf file
131  *           - we parse the file and then reform it (strip out whitespace)
132  */
133 #define PRELOAD_BUF 256
134
135 int sysctl_preload_file(const char *filename, int output)
136 {
137         int lineno = 0;
138         char oneline[PRELOAD_BUF];
139         char buffer[PRELOAD_BUF];
140         char *name, *value, *ptr;
141         FILE *fp = NULL;
142
143         if (!filename || ((fp = fopen(filename, "r")) == NULL)) {
144                 bb_error_msg_and_die(ERR_PRELOAD_FILE, filename);
145         }
146
147         while (fgets(oneline, sizeof(oneline) - 1, fp)) {
148                 oneline[sizeof(oneline) - 1] = 0;
149                 lineno++;
150                 trim(oneline);
151                 ptr = (char *) oneline;
152
153                 if (*ptr == '#' || *ptr == ';')
154                         continue;
155
156                 if (bb_strlen(ptr) < 2)
157                         continue;
158
159                 name = strtok(ptr, "=");
160                 if (!name || !*name) {
161                         bb_error_msg(WARN_BAD_LINE, filename, lineno);
162                         continue;
163                 }
164
165                 trim(name);
166
167                 value = strtok(NULL, "\n\r");
168                 if (!value || !*value) {
169                         bb_error_msg(WARN_BAD_LINE, filename, lineno);
170                         continue;
171                 }
172
173                 while ((*value == ' ' || *value == '\t') && *value != 0)
174                         value++;
175                 strcpy(buffer, name);
176                 strcat(buffer, "=");
177                 strcat(buffer, value);
178                 sysctl_write_setting(buffer, output);
179         }
180         fclose(fp);
181         return 0;
182 }                                               /* end sysctl_preload_file() */
183
184
185 /*
186  *     Write a single sysctl setting
187  */
188 int sysctl_write_setting(const char *setting, int output)
189 {
190         int retval = 0;
191         const char *name = setting;
192         const char *value;
193         const char *equals;
194         char *tmpname, *outname, *cptr;
195         int fd = -1;
196
197         if (!name)                      /* probably dont' want to display this  err */
198                 return 0;
199
200         if (!(equals = strchr(setting, '='))) {
201                 bb_error_msg(ERR_NO_EQUALS, setting);
202                 return -1;
203         }
204
205         value = equals + sizeof(char);  /* point to the value in name=value */
206
207         if (!*name || !*value || name == equals) {
208                 bb_error_msg(ERR_MALFORMED_SETTING, setting);
209                 return -2;
210         }
211
212         bb_xasprintf(&tmpname, "%s%.*s", PROC_PATH, (equals - name), name);
213         outname = bb_xstrdup(tmpname + strlen(PROC_PATH));
214
215         while ((cptr = strchr(tmpname, '.')) != NULL)
216                 *cptr = '/';
217
218         while ((cptr = strchr(outname, '/')) != NULL)
219                 *cptr = '.';
220
221         if ((fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
222                 switch (errno) {
223                 case ENOENT:
224                         bb_error_msg(ERR_INVALID_KEY, outname);
225                         break;
226                 case EACCES:
227                         bb_perror_msg(ERR_PERMISSION_DENIED, outname);
228                         break;
229                 default:
230                         bb_error_msg(ERR_UNKNOWN_WRITING, errno, outname);
231                         break;
232                 }
233                 retval = -1;
234         } else {
235                 dwrite_str(fd, value);
236                 close(fd);
237                 if (output) {
238                         dwrite_str(STDOUT_FILENO, outname);
239                         dwrite_str(STDOUT_FILENO, " = ");
240                 }
241                 dwrite_str(STDOUT_FILENO, value);
242                 dwrite_str(STDOUT_FILENO, "\n");
243         }
244
245         /* cleanup */
246         free(tmpname);
247         free(outname);
248         return retval;
249 }                                               /* end sysctl_write_setting() */
250
251
252 /*
253  *     Read a sysctl setting
254  *
255  */
256 int sysctl_read_setting(const char *setting, int output)
257 {
258         int retval = 0;
259         char *tmpname, *outname, *cptr;
260         char inbuf[1025];
261         const char *name = setting;
262         FILE *fp;
263
264         if (!setting || !*setting)
265                 bb_error_msg(ERR_INVALID_KEY, setting);
266
267         tmpname = concat_path_file(PROC_PATH, name);
268         outname = bb_xstrdup(tmpname + strlen(PROC_PATH));
269
270         while ((cptr = strchr(tmpname, '.')) != NULL)
271                 *cptr = '/';
272         while ((cptr = strchr(outname, '/')) != NULL)
273                 *cptr = '.';
274
275         if ((fp = fopen(tmpname, "r")) == NULL) {
276                 switch (errno) {
277                 case ENOENT:
278                         bb_error_msg(ERR_INVALID_KEY, outname);
279                         break;
280                 case EACCES:
281                         bb_error_msg(ERR_PERMISSION_DENIED, outname);
282                         break;
283                 default:
284                         bb_error_msg(ERR_UNKNOWN_READING, errno, outname);
285                         break;
286                 }
287                 retval = -1;
288         } else {
289                 while (fgets(inbuf, sizeof(inbuf) - 1, fp)) {
290                         if (output) {
291                                 dwrite_str(STDOUT_FILENO, outname);
292                                 dwrite_str(STDOUT_FILENO, " = ");
293                         }
294                         dwrite_str(STDOUT_FILENO, inbuf);
295                 }
296                 fclose(fp);
297         }
298
299         free(tmpname);
300         free(outname);
301         return retval;
302 }                                               /* end sysctl_read_setting() */
303
304
305
306 /*
307  *     Display all the sysctl settings
308  *
309  */
310 int sysctl_display_all(const char *path, int output, int show_table)
311 {
312         int retval = 0;
313         int retval2;
314         DIR *dp;
315         struct dirent *de;
316         char *tmpdir;
317         struct stat ts;
318
319         if (!(dp = opendir(path))) {
320                 bb_perror_msg(ERR_OPENING_DIR, path);
321                 retval = -1;
322         } else {
323                 while ((de = readdir(dp)) != NULL) {
324                         tmpdir = concat_subpath_file(path, de->d_name);
325                         if(tmpdir == NULL)
326                                 continue;
327                         if ((retval2 = stat(tmpdir, &ts)) != 0)
328                                 bb_perror_msg(tmpdir);
329                         else {
330                                 if (S_ISDIR(ts.st_mode)) {
331                                         sysctl_display_all(tmpdir, output, show_table);
332                                 } else
333                                         retval |=
334                                                 sysctl_read_setting(tmpdir + bb_strlen(PROC_PATH),
335                                                                                         output);
336
337                         }
338                         free(tmpdir);
339                 }                               /* end while */
340                 closedir(dp);
341         }
342
343         return retval;
344 }                                               /* end sysctl_display_all() */
345
346 #ifdef STANDALONE_SYSCTL
347 int main(int argc, char **argv)
348 {
349         return sysctl_main(argc, argv);
350 }
351 const char *bb_applet_name = "sysctl";
352 #endif