sysctl.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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 ATTRIBUTE_UNUSED, 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. #define PRELOAD_BUF 256
  79. static int sysctl_preload_file_and_exit(const char *filename)
  80. {
  81. int lineno;
  82. char oneline[PRELOAD_BUF];
  83. char buffer[PRELOAD_BUF];
  84. char *name, *value;
  85. FILE *fp;
  86. fp = xfopen(filename, "r");
  87. lineno = 0;
  88. while (fgets(oneline, sizeof(oneline) - 1, fp)) {
  89. lineno++;
  90. trim(oneline);
  91. if (oneline[0] == '#' || oneline[0] == ';')
  92. continue;
  93. if (!oneline[0] || !oneline[1])
  94. continue;
  95. name = strtok(oneline, "=");
  96. if (!name) {
  97. bb_error_msg(WARN_BAD_LINE, filename, lineno);
  98. continue;
  99. }
  100. trim(name);
  101. if (!*name) {
  102. bb_error_msg(WARN_BAD_LINE, filename, lineno);
  103. continue;
  104. }
  105. value = strtok(NULL, "\n\r");
  106. if (!value) {
  107. bb_error_msg(WARN_BAD_LINE, filename, lineno);
  108. continue;
  109. }
  110. while (*value == ' ' || *value == '\t')
  111. value++;
  112. if (!*value) {
  113. bb_error_msg(WARN_BAD_LINE, filename, lineno);
  114. continue;
  115. }
  116. /* safe because sizeof(oneline) == sizeof(buffer) */
  117. sprintf(buffer, "%s=%s", name, value);
  118. sysctl_write_setting(buffer);
  119. }
  120. if (ENABLE_FEATURE_CLEAN_UP)
  121. fclose(fp);
  122. return 0;
  123. } /* end sysctl_preload_file_and_exit() */
  124. /*
  125. * Write a single sysctl setting
  126. */
  127. static int sysctl_write_setting(const char *setting)
  128. {
  129. int retval;
  130. const char *name;
  131. const char *value;
  132. const char *equals;
  133. char *tmpname, *outname, *cptr;
  134. int fd;
  135. name = setting;
  136. equals = strchr(setting, '=');
  137. if (!equals) {
  138. bb_error_msg(ERR_NO_EQUALS, setting);
  139. return EXIT_FAILURE;
  140. }
  141. value = equals + 1; /* point to the value in name=value */
  142. if (name == equals || !*value) {
  143. bb_error_msg(ERR_MALFORMED_SETTING, setting);
  144. return EXIT_FAILURE;
  145. }
  146. tmpname = xasprintf("%s%.*s", PROC_SYS, (int)(equals - name), name);
  147. outname = xstrdup(tmpname + strlen_PROC_SYS);
  148. while ((cptr = strchr(tmpname, '.')) != NULL)
  149. *cptr = '/';
  150. while ((cptr = strchr(outname, '/')) != NULL)
  151. *cptr = '.';
  152. fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
  153. if (fd < 0) {
  154. switch (errno) {
  155. case ENOENT:
  156. if (option_mask32 & FLAG_SHOW_KEY_ERRORS)
  157. bb_error_msg(ERR_INVALID_KEY, outname);
  158. break;
  159. case EACCES:
  160. bb_perror_msg(ERR_PERMISSION_DENIED, outname);
  161. break;
  162. default:
  163. bb_perror_msg(ERR_UNKNOWN_WRITING, outname);
  164. break;
  165. }
  166. retval = EXIT_FAILURE;
  167. } else {
  168. dwrite_str(fd, value);
  169. close(fd);
  170. if (option_mask32 & FLAG_SHOW_KEYS) {
  171. printf("%s = ", outname);
  172. }
  173. puts(value);
  174. retval = EXIT_SUCCESS;
  175. }
  176. free(tmpname);
  177. free(outname);
  178. return retval;
  179. } /* end sysctl_write_setting() */
  180. /*
  181. * Read a sysctl setting
  182. */
  183. static int sysctl_read_setting(const char *name)
  184. {
  185. int retval;
  186. char *tmpname, *outname, *cptr;
  187. char inbuf[1025];
  188. FILE *fp;
  189. if (!*name) {
  190. if (option_mask32 & FLAG_SHOW_KEY_ERRORS)
  191. bb_error_msg(ERR_INVALID_KEY, name);
  192. return -1;
  193. }
  194. tmpname = concat_path_file(PROC_SYS, name);
  195. outname = xstrdup(tmpname + strlen_PROC_SYS);
  196. while ((cptr = strchr(tmpname, '.')) != NULL)
  197. *cptr = '/';
  198. while ((cptr = strchr(outname, '/')) != NULL)
  199. *cptr = '.';
  200. fp = fopen(tmpname, "r");
  201. if (fp == NULL) {
  202. switch (errno) {
  203. case ENOENT:
  204. if (option_mask32 & FLAG_SHOW_KEY_ERRORS)
  205. bb_error_msg(ERR_INVALID_KEY, outname);
  206. break;
  207. case EACCES:
  208. bb_error_msg(ERR_PERMISSION_DENIED, outname);
  209. break;
  210. default:
  211. bb_perror_msg(ERR_UNKNOWN_READING, outname);
  212. break;
  213. }
  214. retval = EXIT_FAILURE;
  215. } else {
  216. while (fgets(inbuf, sizeof(inbuf) - 1, fp)) {
  217. if (option_mask32 & FLAG_SHOW_KEYS) {
  218. printf("%s = ", outname);
  219. }
  220. fputs(inbuf, stdout);
  221. }
  222. fclose(fp);
  223. retval = EXIT_SUCCESS;
  224. }
  225. free(tmpname);
  226. free(outname);
  227. return retval;
  228. } /* end sysctl_read_setting() */
  229. /*
  230. * Display all the sysctl settings
  231. */
  232. static int sysctl_display_all(const char *path)
  233. {
  234. int retval = 0;
  235. DIR *dp;
  236. struct dirent *de;
  237. char *tmpdir;
  238. struct stat ts;
  239. dp = opendir(path);
  240. if (!dp) {
  241. return EXIT_FAILURE;
  242. }
  243. while ((de = readdir(dp)) != NULL) {
  244. tmpdir = concat_subpath_file(path, de->d_name);
  245. if (tmpdir == NULL)
  246. continue; /* . or .. */
  247. if (stat(tmpdir, &ts) != 0) {
  248. bb_perror_msg(tmpdir);
  249. } else if (S_ISDIR(ts.st_mode)) {
  250. retval |= sysctl_display_all(tmpdir);
  251. } else {
  252. retval |= sysctl_read_setting(tmpdir + strlen_PROC_SYS);
  253. }
  254. free(tmpdir);
  255. } /* end while */
  256. closedir(dp);
  257. return retval;
  258. } /* end sysctl_display_all() */