toybox/toys/other/sysctl.c
<<
>>
Prefs
   1/* sysctl.c - A utility to read and manipulate the sysctl parameters.
   2 *
   3 * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
   4 * Copyright 2014 Kyungwan Han <asura321@gmail.com>
   5 *
   6 * No Standard
   7 
   8USE_SYSCTL(NEWTOY(sysctl, "^neNqwpaA[!ap][!aq][!aw][+aA]", TOYFLAG_SBIN))
   9
  10config SYSCTL
  11  bool "sysctl"
  12  default y
  13  help
  14    usage: sysctl [-aAeNnqw] [-p [FILE] | KEY[=VALUE]...]
  15
  16    Read/write system control data (under /proc/sys).
  17
  18    -a,A        Show all values
  19    -e  Don't warn about unknown keys
  20    -N  Don't print key values
  21    -n  Don't print key names
  22    -p  Read values from FILE (default /etc/sysctl.conf)
  23    -q  Don't show value after write
  24    -w  Only write values (object to reading)
  25*/
  26#define FOR_sysctl
  27#include "toys.h"
  28
  29// Null terminate at =, return value
  30static char *split_key(char *key)
  31{
  32  char *value = strchr(key, '=');
  33
  34  if (value) *(value++)=0;
  35
  36  return value;
  37}
  38
  39static void replace_char(char *str, char old, char new)
  40{
  41  for (; *str; str++) if (*str == old) *str = new;
  42}
  43
  44static void key_error(char *key)
  45{
  46  if (errno == ENOENT) {
  47    if (!(toys.optflags & FLAG_e)) error_msg("unknown key '%s'", key);
  48  } else perror_msg("key '%s'", key);
  49}
  50
  51static int write_key(char *path, char *key, char *value)
  52{
  53  int fd = open(path, O_WRONLY);
  54
  55  if (fd < 0) {
  56    key_error(key);
  57
  58    return 0;
  59  }
  60  xwrite(fd, value, strlen(value));
  61  xclose(fd);
  62
  63  return 1;
  64}
  65
  66// Display all keys under a path
  67static int do_show_keys(struct dirtree *dt)
  68{
  69  char *path, *data, *key;
  70
  71  if (!dirtree_notdotdot(dt)) return 0; // Skip . and ..
  72  if (S_ISDIR(dt->st.st_mode)) return DIRTREE_RECURSE;
  73
  74  path = dirtree_path(dt, 0);
  75  data = readfile(path, 0, 0);
  76  replace_char(key = path + 10, '/', '.'); // skip "/proc/sys/"
  77  if (!data) key_error(key);
  78  else {
  79    // Print the parts that aren't switched off by flags.
  80    if (!(toys.optflags & FLAG_n)) xprintf("%s", key);
  81    if (!(toys.optflags & (FLAG_N|FLAG_n))) xprintf(" = ");
  82    for (key = data+strlen(data); key > data && isspace(*--key); *key = 0);
  83    if (!(toys.optflags & FLAG_N)) xprintf("%s", data);
  84    if ((toys.optflags & (FLAG_N|FLAG_n)) != (FLAG_N|FLAG_n)) xputc('\n');
  85  }
  86
  87  free(data);
  88  free(path);
  89
  90  return 0;
  91}
  92
  93// Read/write entries under a key. Accepts "key=value" in key if !value
  94static void process_key(char *key, char *value)
  95{
  96  char *path;
  97
  98  if (!value) value = split_key(key);
  99  if ((toys.optflags & FLAG_w) && !value) {
 100    error_msg("'%s' not key=value", key);
 101
 102    return;
 103  }
 104
 105  path = xmprintf("/proc/sys/%s", key);
 106  replace_char(path, '.', '/');
 107  // Note: failure to assign to a non-leaf node suppresses the display.
 108  if (!(value && (!write_key(path, key, value) || (toys.optflags & FLAG_q)))) {
 109    if (!access(path, R_OK)) dirtree_read(path, do_show_keys);
 110    else key_error(key);
 111  }
 112  free(path);
 113}
 114
 115void sysctl_main()
 116{
 117  char **args = 0;
 118
 119  // Display all keys
 120  if (toys.optflags & FLAG_a) dirtree_read("/proc/sys", do_show_keys);
 121
 122  // read file
 123  else if (toys.optflags & FLAG_p) {
 124    FILE *fp = xfopen(*toys.optargs ? *toys.optargs : "/etc/sysctl.conf", "r");
 125    size_t len;
 126
 127    for (;;) {
 128      char *line = 0, *key, *val;
 129
 130      if (-1 == (len = getline(&line, &len, fp))) break;
 131      key = line;
 132      while (isspace(*key)) key++;
 133      if (*key == '#' || *key == ';' || !*key) continue;
 134      while (len && isspace(line[len-1])) line[--len] = 0;
 135      if (!(val = split_key(line))) {
 136        error_msg("'%s' not key=value", line);
 137        continue;
 138      }
 139
 140      // Trim whitespace around =
 141      len = (val-line)-1;
 142      while (len && isspace(line[len-1])) line[--len] = 0;
 143      while (isspace(*val)) val++;;
 144
 145      process_key(key, val);
 146      free(line);
 147    }
 148    fclose(fp);
 149
 150  // Loop through arguments, displaying or assigning as appropriate
 151  } else {
 152    if (!*toys.optargs) help_exit("Needs 1 arg");
 153    for (args = toys.optargs; *args; args++) process_key(*args, 0);
 154  }
 155}
 156