sysctl.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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. #include "libbb.h"
  17. static int sysctl_read_setting(const char *setting);
  18. static int sysctl_write_setting(const char *setting);
  19. static int sysctl_display_all(const char *path);
  20. static int sysctl_preload_file_and_exit(const char *filename);
  21. static const char ETC_SYSCTL_CONF[] ALIGN1 = "/etc/sysctl.conf";
  22. static const char PROC_SYS[] ALIGN1 = "/proc/sys/";
  23. enum { strlen_PROC_SYS = sizeof(PROC_SYS) - 1 };
  24. /* error messages */
  25. static const char ERR_MALFORMED_SETTING[] ALIGN1 =
  26. "error: malformed setting '%s'";
  27. static const char ERR_NO_EQUALS[] ALIGN1 =
  28. "error: '%s' must be of the form name=value";
  29. static const char ERR_INVALID_KEY[] ALIGN1 =
  30. "error: '%s' is an unknown key";
  31. static const char ERR_UNKNOWN_WRITING[] ALIGN1 =
  32. "error setting key '%s'";
  33. static const char ERR_UNKNOWN_READING[] ALIGN1 =
  34. "error reading key '%s'";
  35. static const char ERR_PERMISSION_DENIED[] ALIGN1 =
  36. "error: permission denied on key '%s'";
  37. static const char WARN_BAD_LINE[] ALIGN1 =
  38. "warning: %s(%d): invalid syntax, continuing";
  39. static void dwrite_str(int fd, const char *buf)
  40. {
  41. write(fd, buf, strlen(buf));
  42. }
  43. enum {
  44. FLAG_SHOW_KEYS = 1 << 0,
  45. FLAG_SHOW_KEY_ERRORS = 1 << 1,
  46. FLAG_TABLE_FORMAT = 1 << 2, /* not implemented */
  47. FLAG_SHOW_ALL = 1 << 3,
  48. FLAG_PRELOAD_FILE = 1 << 4,
  49. FLAG_WRITE = 1 << 5,
  50. };
  51. int sysctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  52. int sysctl_main(int argc UNUSED_PARAM, char **argv)
  53. {
  54. int retval;
  55. int opt;
  56. opt = getopt32(argv, "+neAapw"); /* '+' - stop on first non-option */
  57. argv += optind;
  58. opt ^= (FLAG_SHOW_KEYS | FLAG_SHOW_KEY_ERRORS);
  59. option_mask32 ^= (FLAG_SHOW_KEYS | FLAG_SHOW_KEY_ERRORS);
  60. if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL))
  61. return sysctl_display_all(PROC_SYS);
  62. if (opt & FLAG_PRELOAD_FILE)
  63. return sysctl_preload_file_and_exit(*argv ? *argv : ETC_SYSCTL_CONF);
  64. retval = 0;
  65. while (*argv) {
  66. if (opt & FLAG_WRITE)
  67. retval |= sysctl_write_setting(*argv);
  68. else
  69. retval |= sysctl_read_setting(*argv);
  70. argv++;
  71. }
  72. return retval;
  73. } /* end sysctl_main() */
  74. /*
  75. * preload the sysctl's from a conf file
  76. * - we parse the file and then reform it (strip out whitespace)
  77. */
  78. static int sysctl_preload_file_and_exit(const char *filename)
  79. {
  80. char *token[2];
  81. parser_t *parser;
  82. parser = config_open(filename);
  83. while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) { // TODO: ';' is comment char too
  84. // if (!token[1]) {
  85. // bb_error_msg(WARN_BAD_LINE, filename, parser->lineno);
  86. // } else {
  87. {
  88. #if 0
  89. char *s = xasprintf("%s=%s", token[0], token[1]);
  90. sysctl_write_setting(s);
  91. free(s);
  92. #else // PLAY_WITH_FIRE for -4 bytes?
  93. sprintf(parser->line, "%s=%s", token[0], token[1]); // must have room by definition
  94. sysctl_write_setting(parser->line);
  95. #endif
  96. }
  97. }
  98. if (ENABLE_FEATURE_CLEAN_UP)
  99. config_close(parser);
  100. return 0;
  101. } /* end sysctl_preload_file_and_exit() */
  102. /*
  103. * Write a single sysctl setting
  104. */
  105. static int sysctl_write_setting(const char *setting)
  106. {
  107. int retval;
  108. const char *name;
  109. const char *value;
  110. const char *equals;
  111. char *tmpname, *outname, *cptr;
  112. int fd;
  113. name = setting;
  114. equals = strchr(setting, '=');
  115. if (!equals) {
  116. bb_error_msg(ERR_NO_EQUALS, setting);
  117. return EXIT_FAILURE;
  118. }
  119. value = equals + 1; /* point to the value in name=value */
  120. if (name == equals || !*value) {
  121. bb_error_msg(ERR_MALFORMED_SETTING, setting);
  122. return EXIT_FAILURE;
  123. }
  124. tmpname = xasprintf("%s%.*s", PROC_SYS, (int)(equals - name), name);
  125. outname = xstrdup(tmpname + strlen_PROC_SYS);
  126. while ((cptr = strchr(tmpname, '.')) != NULL)
  127. *cptr = '/';
  128. while ((cptr = strchr(outname, '/')) != NULL)
  129. *cptr = '.';
  130. fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
  131. if (fd < 0) {
  132. switch (errno) {
  133. case ENOENT:
  134. if (option_mask32 & FLAG_SHOW_KEY_ERRORS)
  135. bb_error_msg(ERR_INVALID_KEY, outname);
  136. break;
  137. case EACCES:
  138. bb_perror_msg(ERR_PERMISSION_DENIED, outname);
  139. break;
  140. default:
  141. bb_perror_msg(ERR_UNKNOWN_WRITING, outname);
  142. break;
  143. }
  144. retval = EXIT_FAILURE;
  145. } else {
  146. dwrite_str(fd, value);
  147. close(fd);
  148. if (option_mask32 & FLAG_SHOW_KEYS) {
  149. printf("%s = ", outname);
  150. }
  151. puts(value);
  152. retval = EXIT_SUCCESS;
  153. }
  154. free(tmpname);
  155. free(outname);
  156. return retval;
  157. } /* end sysctl_write_setting() */
  158. /*
  159. * Read a sysctl setting
  160. */
  161. static int sysctl_read_setting(const char *name)
  162. {
  163. int retval;
  164. char *tmpname, *outname, *cptr;
  165. char inbuf[1025];
  166. FILE *fp;
  167. if (!*name) {
  168. if (option_mask32 & FLAG_SHOW_KEY_ERRORS)
  169. bb_error_msg(ERR_INVALID_KEY, name);
  170. return -1;
  171. }
  172. tmpname = concat_path_file(PROC_SYS, name);
  173. outname = xstrdup(tmpname + strlen_PROC_SYS);
  174. while ((cptr = strchr(tmpname, '.')) != NULL)
  175. *cptr = '/';
  176. while ((cptr = strchr(outname, '/')) != NULL)
  177. *cptr = '.';
  178. fp = fopen_for_read(tmpname);
  179. if (fp == NULL) {
  180. switch (errno) {
  181. case ENOENT:
  182. if (option_mask32 & FLAG_SHOW_KEY_ERRORS)
  183. bb_error_msg(ERR_INVALID_KEY, outname);
  184. break;
  185. case EACCES:
  186. bb_error_msg(ERR_PERMISSION_DENIED, outname);
  187. break;
  188. default:
  189. bb_perror_msg(ERR_UNKNOWN_READING, outname);
  190. break;
  191. }
  192. retval = EXIT_FAILURE;
  193. } else {
  194. while (fgets(inbuf, sizeof(inbuf) - 1, fp)) {
  195. if (option_mask32 & FLAG_SHOW_KEYS) {
  196. printf("%s = ", outname);
  197. }
  198. fputs(inbuf, stdout);
  199. }
  200. fclose(fp);
  201. retval = EXIT_SUCCESS;
  202. }
  203. free(tmpname);
  204. free(outname);
  205. return retval;
  206. } /* end sysctl_read_setting() */
  207. /*
  208. * Display all the sysctl settings
  209. */
  210. static int sysctl_display_all(const char *path)
  211. {
  212. int retval = 0;
  213. DIR *dp;
  214. struct dirent *de;
  215. char *tmpdir;
  216. struct stat ts;
  217. dp = opendir(path);
  218. if (!dp) {
  219. return EXIT_FAILURE;
  220. }
  221. while ((de = readdir(dp)) != NULL) {
  222. tmpdir = concat_subpath_file(path, de->d_name);
  223. if (tmpdir == NULL)
  224. continue; /* . or .. */
  225. if (stat(tmpdir, &ts) != 0) {
  226. bb_perror_msg(tmpdir);
  227. } else if (S_ISDIR(ts.st_mode)) {
  228. retval |= sysctl_display_all(tmpdir);
  229. } else {
  230. retval |= sysctl_read_setting(tmpdir + strlen_PROC_SYS);
  231. }
  232. free(tmpdir);
  233. } /* end while */
  234. closedir(dp);
  235. return retval;
  236. } /* end sysctl_display_all() */