sysctl.c 7.9 KB

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