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 "libbb.h" 18 19/* 20 * Function Prototypes 21 */ 22static 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 */ 30static const char PROC_PATH[] ALIGN1 = "/proc/sys/"; 31static const char DEFAULT_PRELOAD[] ALIGN1 = "/etc/sysctl.conf"; 32 33/* error messages */ 34static 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 = 39 "error: '%s' must be of the form name=value\n"; 40static const char ERR_INVALID_KEY[] ALIGN1 = 41 "error: '%s' is an unknown key\n"; 42static const char ERR_UNKNOWN_WRITING[] ALIGN1 = 43 "error: unknown error %d setting key '%s'\n"; 44static const char ERR_UNKNOWN_READING[] ALIGN1 = 45 "error: unknown error %d reading key '%s'\n"; 46static const char ERR_PERMISSION_DENIED[] ALIGN1 = 47 "error: permission denied on key '%s'\n"; 48static const char ERR_PRELOAD_FILE[] ALIGN1 = 49 "error: cannot open preload file '%s'\n"; 50static const char WARN_BAD_LINE[] ALIGN1 = 51 "warning: %s(%d): invalid syntax, continuing...\n"; 52 53 54static void dwrite_str(int fd, const char *buf) 55{ 56 write(fd, buf, strlen(buf)); 57} 58 59/* 60 * sysctl_main()... 61 */ 62int sysctl_main(int argc, char **argv); 63int 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) 71 bb_show_usage(); 72 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 '?': 98 bb_show_usage(); 99 default: 100 bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv); 101 bb_show_usage(); 102 } 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 114 115 116/* 117 * sysctl_preload_file 118 * preload the sysctl's from a conf file 119 * - we parse the file and then reform it (strip out whitespace) 120 */ 121#define PRELOAD_BUF 256 122 123int sysctl_preload_file(const char *filename, int output) 124{ 125 int lineno = 0; 126 char oneline[PRELOAD_BUF]; 127 char buffer[PRELOAD_BUF]; 128 char *name, *value, *ptr; 129 FILE *fp = NULL; 130 131 if (!filename || ((fp = fopen(filename, "r")) == NULL)) { 132 bb_error_msg_and_die(ERR_PRELOAD_FILE, filename); 133 } 134 135 while (fgets(oneline, sizeof(oneline) - 1, fp)) { 136 oneline[sizeof(oneline) - 1] = '\0'; 137 lineno++; 138 trim(oneline); 139 ptr = (char *) oneline; 140 141 if (*ptr == '#' || *ptr == ';') 142 continue; 143 144 if (strlen(ptr) < 2) 145 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++; 163 /* safe because sizeof(oneline) == sizeof(buffer) */ 164 sprintf(buffer, "%s=%s", name, value); 165 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 187 if (!(equals = strchr(setting, '='))) { 188 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 199 tmpname = xasprintf("%s%.*s", PROC_PATH, (int)(equals - name), name); 200 outname = xstrdup(tmpname + strlen(PROC_PATH)); 201 202 while ((cptr = strchr(tmpname, '.')) != NULL) 203 *cptr = '/'; 204 205 while ((cptr = strchr(outname, '/')) != NULL) 206 *cptr = '.'; 207 208 fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666); 209 if (fd < 0) { 210 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 { 223 dwrite_str(fd, value); 224 close(fd); 225 if (output) { 226 dwrite_str(STDOUT_FILENO, outname); 227 dwrite_str(STDOUT_FILENO, " = "); 228 } 229 dwrite_str(STDOUT_FILENO, value); 230 dwrite_str(STDOUT_FILENO, "\n"); 231 } 232 233 /* cleanup */ 234 free(tmpname); 235 free(outname); 236 return retval; 237} /* end sysctl_write_setting() */ 238 239 240/* 241 * Read a sysctl setting 242 * 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 255 tmpname = concat_path_file(PROC_PATH, name); 256 outname = xstrdup(tmpname + strlen(PROC_PATH)); 257 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) { 279 dwrite_str(STDOUT_FILENO, outname); 280 dwrite_str(STDOUT_FILENO, " = "); 281 } 282 dwrite_str(STDOUT_FILENO, inbuf); 283 } 284 fclose(fp); 285 } 286 287 free(tmpname); 288 free(outname); 289 return retval; 290} /* end sysctl_read_setting() */ 291 292 293 294/* 295 * Display all the sysctl settings 296 * 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 307 dp = opendir(path); 308 if (!dp) { 309 retval = -1; 310 } else { 311 while ((de = readdir(dp)) != NULL) { 312 tmpdir = concat_subpath_file(path, de->d_name); 313 if (tmpdir == NULL) 314 continue; 315 retval2 = stat(tmpdir, &ts); 316 if (retval2 != 0) 317 bb_perror_msg(tmpdir); 318 else { 319 if (S_ISDIR(ts.st_mode)) { 320 sysctl_display_all(tmpdir, output, show_table); 321 } else 322 retval |= 323 sysctl_read_setting(tmpdir + strlen(PROC_PATH), 324 output); 325 326 } 327 free(tmpdir); 328 } /* end while */ 329 closedir(dp); 330 } 331 332 return retval; 333} /* end sysctl_display_all() */ 334