changeset 1281:6b78ac1d7d58 draft

Add sysctl by Bilal Qureshi.
author Rob Landley <rob@landley.net>
date Mon, 12 May 2014 06:22:10 -0500
parents 4947ec3aa896
children c99912c6bc09
files toys/pending/sysctl.c
diffstat 1 files changed, 208 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toys/pending/sysctl.c	Mon May 12 06:22:10 2014 -0500
@@ -0,0 +1,208 @@
+/* sysctl.c - A utility to read and manipulate the sysctl parameters.
+ *
+ * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
+ * Copyright 2014 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard
+ 
+USE_SYSCTL(NEWTOY(sysctl, "^neNqwpaA[!ap][!aq][!aw][+aA]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config SYSCTL
+  bool "sysctl"
+  default n
+  help
+    usage: sysctl [OPTIONS] [KEY[=VALUE]]...
+
+    -a, A      Show all values
+    -e         Don't warn about unknown keys
+    -N         Show only key names
+    -n         Show only key values
+    -p FILE    Set values from FILE (default /etc/sysctl.conf)
+    -q         Set values silently
+    -w         Set values
+*/
+#define FOR_sysctl
+#include "toys.h"
+
+#define PROC_SYS_DIR	"/proc/sys"
+#define MAX_BYTES_LINE	1024
+
+static void parse_key_name_value(char *param, char **key_name, char **key_value)
+{
+  char *name, *value;
+
+  if (!(name = strchr(param, '='))) goto show_error_msg;
+  value = name;
+  value++;
+  if (!(*value)) goto show_error_msg;
+  *name = '\0';
+  *key_name = param;
+  *key_value = value;
+  return;
+show_error_msg:
+  error_msg("error: '%s' must be of the form name=value", param);
+}
+
+static void replace_char(char *str, char old, char new)
+{
+  char *tmp = str;
+
+  for (; *tmp; tmp++) 
+    if (*tmp == old) *tmp = new;
+}
+
+static void handle_file_error(char *key_name)
+{
+  replace_char(key_name, '/', '.');
+  if (errno == ENOENT) { 
+    if (!(toys.optflags & FLAG_e)) 
+      error_msg("error: '%s' is an unknown key", key_name);
+    else toys.exitval = 1;
+  } else perror_msg("error: %s key '%s'", (toys.optflags & FLAG_w) ?
+      "setting" : "reading", key_name);
+}
+
+static void write_to_file(char *fpath, char *key_name, char *key_value)
+{
+  int fd;
+
+  replace_char(key_name, '.', '/');
+  sprintf(toybuf, "%s/%s", fpath, key_name);
+  if ((fd = open(toybuf, O_WRONLY)) < 0) { 
+    handle_file_error(key_name);
+    return;
+  }
+  xwrite(fd, key_value, strlen(key_value));
+  xclose(fd);
+  if (!(toys.optflags & FLAG_q)) {
+    replace_char(key_name, '/', '.');
+    if (toys.optflags & FLAG_N) xprintf("%s\n", key_name);
+    else if (toys.optflags & FLAG_n) xprintf("%s\n", key_value);
+    else xprintf("%s = %s\n", key_name, key_value);
+  }
+}
+
+static char *get_key_value(char *buff, int *offset)
+{
+  char *line, *tmp = (char *) (buff + *offset);
+  int index = 0, multiplier = 1;
+
+  if (!(*tmp)) return NULL;
+  line = (char *) xmalloc(sizeof(char) * MAX_BYTES_LINE);
+  for (; *tmp != '\n'; tmp++) {
+    line[index++] = *tmp;
+    if (MAX_BYTES_LINE == index) { // buffer overflow
+      multiplier++;
+      line = (char *) xrealloc(line, multiplier * MAX_BYTES_LINE);
+    }
+  }
+  line[index++] = '\0';
+  *offset += index;
+  return line;
+}
+
+// Open file for each and every key name and read file contents
+void read_key_values(char *fpath)
+{
+  char *key_value, *fdata, *key_name, *tmp = xstrdup(fpath);
+  int offset = 0;
+
+  key_name = (tmp + strlen(PROC_SYS_DIR) + 1);
+  replace_char(key_name, '/', '.');
+  if (!(fdata = readfile(fpath, NULL, 0))) {
+    handle_file_error(key_name);
+    free(tmp);
+    return;
+  }
+  if (toys.optflags & FLAG_N) {
+    xprintf("%s\n", key_name);
+    free(tmp);
+    free(fdata);
+    return;
+  }
+  for (; (key_value = get_key_value(fdata, &offset)); free(key_value)) {
+    if (!(toys.optflags & FLAG_q)) {
+      if (!(toys.optflags & FLAG_n)) xprintf("%s = ", key_name);
+      xprintf("%s\n", key_value);
+    }
+  }
+  free(tmp);
+  free(fdata);
+}
+
+static void trim_spaces(char **param)
+{
+  int len = 0;
+  char *str = *param, *p_start = str, *p_end;
+
+  if (p_start) {   // start pointer to string 
+    p_end = str + strlen(str) - 1; // end pointer to string
+    while (*p_start == ' ') p_start++;
+    str = p_start;
+    while (*p_end == ' ') p_end--;
+    p_end++;
+    *p_end = '\0';
+    len = (int) (p_end - str) + 1;
+    memmove(*param, str, len);
+  }
+}
+
+// Read config file and write values to there corresponding key name files
+static void read_config_file(char *fname)
+{
+  char *line, *name = NULL, *value = NULL;
+  int fd = xopen(fname, O_RDONLY);
+
+  for (; (line = get_line(fd)); free(line), name = NULL, value = NULL) {
+    char *ptr = line;
+
+    while (*ptr == ' ' || *ptr == '\t') ptr++;
+    if (*ptr != '#' && *ptr != ';' && *ptr !='\n' && *ptr) {
+      parse_key_name_value(ptr, &name, &value);
+      trim_spaces(&name);
+      trim_spaces(&value);
+      if (name && value) write_to_file(PROC_SYS_DIR, name, value);
+    }
+  }
+  xclose(fd);
+}
+
+static int do_process(struct dirtree *dt)
+{
+  char *fpath;
+
+  if (!dirtree_notdotdot(dt)) return 0; // Skip . and ..
+  if (S_ISDIR(dt->st.st_mode)) return DIRTREE_RECURSE; 
+  if ((fpath = dirtree_path(dt, 0))) {
+    read_key_values(fpath);
+    free(fpath);
+  }
+  return 0;
+}
+
+void sysctl_main()
+{
+  char *name = NULL, *value = NULL, **args = NULL;
+
+  if (toys.optflags & FLAG_a) {
+    dirtree_read(PROC_SYS_DIR, do_process);
+    return;
+  }
+  if (toys.optflags & FLAG_p) {
+    if (*toys.optargs) read_config_file(*toys.optargs);
+    else read_config_file("/etc/sysctl.conf");
+    return;
+  }
+  if (toys.optflags & FLAG_w) {
+    for (args = toys.optargs; *args; args++, name = NULL, value = NULL) {
+      parse_key_name_value(*args, &name, &value);
+      if (name && value) write_to_file(PROC_SYS_DIR, name, value);
+    }
+    return;
+  }
+  for (args = toys.optargs; *args; args++) {
+    replace_char(*args, '.', '/');
+    sprintf(toybuf, "%s/%s", PROC_SYS_DIR, *args);
+    read_key_values(toybuf);
+  }
+}