suppress warnings about easch <applet>_main() having
[oweals/busybox.git] / procps / sysctl.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Sysctl 1.01 - A utility to read and manipulate the sysctl parameters
4  *
5  * Copyright 1999 George Staikos
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8  *
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>
14  *
15  */
16
17 #include "busybox.h"
18
19 /*
20  *    Function Prototypes
21  */
22 static int sysctl_read_setting(const char *setting, int output);
23 static int sysctl_write_setting(const char *setting, int output);
24 static int sysctl_preload_file(const char *filename, int output);
25 static int sysctl_display_all(const char *path, int output, int show_table);
26
27 /*
28  *    Globals...
29  */
30 static const char PROC_PATH[] = "/proc/sys/";
31 static const char DEFAULT_PRELOAD[] = "/etc/sysctl.conf";
32
33 /* error messages */
34 static const char ERR_UNKNOWN_PARAMETER[] = "error: Unknown parameter '%s'\n";
35 static const char ERR_MALFORMED_SETTING[] = "error: Malformed setting '%s'\n";
36 static const char ERR_NO_EQUALS[] =
37         "error: '%s' must be of the form name=value\n";
38 static const char ERR_INVALID_KEY[] = "error: '%s' is an unknown key\n";
39 static const char ERR_UNKNOWN_WRITING[] =
40         "error: unknown error %d setting key '%s'\n";
41 static const char ERR_UNKNOWN_READING[] =
42         "error: unknown error %d reading key '%s'\n";
43 static const char ERR_PERMISSION_DENIED[] =
44         "error: permission denied on key '%s'\n";
45 static const char ERR_PRELOAD_FILE[] =
46         "error: cannot open preload file '%s'\n";
47 static const char WARN_BAD_LINE[] =
48         "warning: %s(%d): invalid syntax, continuing...\n";
49
50
51 static void dwrite_str(int fd, const char *buf)
52 {
53         write(fd, buf, strlen(buf));
54 }
55
56 /*
57  *    sysctl_main()...
58  */
59 int sysctl_main(int argc, char **argv);
60 int 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)
68                 bb_show_usage();
69
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 '?':
95                                 bb_show_usage();
96                         default:
97                                 bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv);
98                                 bb_show_usage();
99                         }
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
111
112
113 /*
114  *     sysctl_preload_file
115  *      preload the sysctl's from a conf file
116  *           - we parse the file and then reform it (strip out whitespace)
117  */
118 #define PRELOAD_BUF 256
119
120 int sysctl_preload_file(const char *filename, int output)
121 {
122         int lineno = 0;
123         char oneline[PRELOAD_BUF];
124         char buffer[PRELOAD_BUF];
125         char *name, *value, *ptr;
126         FILE *fp = NULL;
127
128         if (!filename || ((fp = fopen(filename, "r")) == NULL)) {
129                 bb_error_msg_and_die(ERR_PRELOAD_FILE, filename);
130         }
131
132         while (fgets(oneline, sizeof(oneline) - 1, fp)) {
133                 oneline[sizeof(oneline) - 1] = '\0';
134                 lineno++;
135                 trim(oneline);
136                 ptr = (char *) oneline;
137
138                 if (*ptr == '#' || *ptr == ';')
139                         continue;
140
141                 if (strlen(ptr) < 2)
142                         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++;
160                 /* safe because sizeof(oneline) == sizeof(buffer) */
161                 sprintf(buffer, "%s=%s", name, value);
162                 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  */
172 int 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
184         if (!(equals = strchr(setting, '='))) {
185                 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
196         tmpname = xasprintf("%s%.*s", PROC_PATH, (int)(equals - name), name);
197         outname = xstrdup(tmpname + strlen(PROC_PATH));
198
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 {
219                 dwrite_str(fd, value);
220                 close(fd);
221                 if (output) {
222                         dwrite_str(STDOUT_FILENO, outname);
223                         dwrite_str(STDOUT_FILENO, " = ");
224                 }
225                 dwrite_str(STDOUT_FILENO, value);
226                 dwrite_str(STDOUT_FILENO, "\n");
227         }
228
229         /* cleanup */
230         free(tmpname);
231         free(outname);
232         return retval;
233 }                                               /* end sysctl_write_setting() */
234
235
236 /*
237  *     Read a sysctl setting
238  *
239  */
240 int 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
251         tmpname = concat_path_file(PROC_PATH, name);
252         outname = xstrdup(tmpname + strlen(PROC_PATH));
253
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) {
275                                 dwrite_str(STDOUT_FILENO, outname);
276                                 dwrite_str(STDOUT_FILENO, " = ");
277                         }
278                         dwrite_str(STDOUT_FILENO, inbuf);
279                 }
280                 fclose(fp);
281         }
282
283         free(tmpname);
284         free(outname);
285         return retval;
286 }                                               /* end sysctl_read_setting() */
287
288
289
290 /*
291  *     Display all the sysctl settings
292  *
293  */
294 int 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
303         if (!(dp = opendir(path))) {
304                 retval = -1;
305         } else {
306                 while ((de = readdir(dp)) != NULL) {
307                         tmpdir = concat_subpath_file(path, de->d_name);
308                         if(tmpdir == NULL)
309                                 continue;
310                         if ((retval2 = stat(tmpdir, &ts)) != 0)
311                                 bb_perror_msg(tmpdir);
312                         else {
313                                 if (S_ISDIR(ts.st_mode)) {
314                                         sysctl_display_all(tmpdir, output, show_table);
315                                 } else
316                                         retval |=
317                                                 sysctl_read_setting(tmpdir + strlen(PROC_PATH),
318                                                                                         output);
319
320                         }
321                         free(tmpdir);
322                 }                               /* end while */
323                 closedir(dp);
324         }
325
326         return retval;
327 }                                               /* end sysctl_display_all() */