xref: /third_party/toybox/toys/other/sysctl.c (revision 0f66f451)
10f66f451Sopenharmony_ci/* sysctl.c - A utility to read and manipulate the sysctl parameters.
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
40f66f451Sopenharmony_ci * Copyright 2014 Kyungwan Han <asura321@gmail.com>
50f66f451Sopenharmony_ci *
60f66f451Sopenharmony_ci * No Standard
70f66f451Sopenharmony_ci
80f66f451Sopenharmony_ciUSE_SYSCTL(NEWTOY(sysctl, "^neNqwpaA[!ap][!aq][!aw][+aA]", TOYFLAG_SBIN))
90f66f451Sopenharmony_ci
100f66f451Sopenharmony_ciconfig SYSCTL
110f66f451Sopenharmony_ci  bool "sysctl"
120f66f451Sopenharmony_ci  default y
130f66f451Sopenharmony_ci  help
140f66f451Sopenharmony_ci    usage: sysctl [-aAeNnqw] [-p [FILE] | KEY[=VALUE]...]
150f66f451Sopenharmony_ci
160f66f451Sopenharmony_ci    Read/write system control data (under /proc/sys).
170f66f451Sopenharmony_ci
180f66f451Sopenharmony_ci    -a,A	Show all values
190f66f451Sopenharmony_ci    -e	Don't warn about unknown keys
200f66f451Sopenharmony_ci    -N	Don't print key values
210f66f451Sopenharmony_ci    -n	Don't print key names
220f66f451Sopenharmony_ci    -p	Read values from FILE (default /etc/sysctl.conf)
230f66f451Sopenharmony_ci    -q	Don't show value after write
240f66f451Sopenharmony_ci    -w	Only write values (object to reading)
250f66f451Sopenharmony_ci*/
260f66f451Sopenharmony_ci#define FOR_sysctl
270f66f451Sopenharmony_ci#include "toys.h"
280f66f451Sopenharmony_ci
290f66f451Sopenharmony_ci// Null terminate at =, return value
300f66f451Sopenharmony_cistatic char *split_key(char *key)
310f66f451Sopenharmony_ci{
320f66f451Sopenharmony_ci  char *value = strchr(key, '=');
330f66f451Sopenharmony_ci
340f66f451Sopenharmony_ci  if (value) *(value++)=0;
350f66f451Sopenharmony_ci
360f66f451Sopenharmony_ci  return value;
370f66f451Sopenharmony_ci}
380f66f451Sopenharmony_ci
390f66f451Sopenharmony_cistatic void replace_char(char *str, char old, char new)
400f66f451Sopenharmony_ci{
410f66f451Sopenharmony_ci  for (; *str; str++) if (*str == old) *str = new;
420f66f451Sopenharmony_ci}
430f66f451Sopenharmony_ci
440f66f451Sopenharmony_cistatic void key_error(char *key)
450f66f451Sopenharmony_ci{
460f66f451Sopenharmony_ci  if (errno == ENOENT) {
470f66f451Sopenharmony_ci    if (!(toys.optflags & FLAG_e)) error_msg("unknown key '%s'", key);
480f66f451Sopenharmony_ci  } else perror_msg("key '%s'", key);
490f66f451Sopenharmony_ci}
500f66f451Sopenharmony_ci
510f66f451Sopenharmony_cistatic int write_key(char *path, char *key, char *value)
520f66f451Sopenharmony_ci{
530f66f451Sopenharmony_ci  int fd = open(path, O_WRONLY);
540f66f451Sopenharmony_ci
550f66f451Sopenharmony_ci  if (fd < 0) {
560f66f451Sopenharmony_ci    key_error(key);
570f66f451Sopenharmony_ci
580f66f451Sopenharmony_ci    return 0;
590f66f451Sopenharmony_ci  }
600f66f451Sopenharmony_ci  xwrite(fd, value, strlen(value));
610f66f451Sopenharmony_ci  xclose(fd);
620f66f451Sopenharmony_ci
630f66f451Sopenharmony_ci  return 1;
640f66f451Sopenharmony_ci}
650f66f451Sopenharmony_ci
660f66f451Sopenharmony_ci// Display all keys under a path
670f66f451Sopenharmony_cistatic int do_show_keys(struct dirtree *dt)
680f66f451Sopenharmony_ci{
690f66f451Sopenharmony_ci  char *path, *data, *key;
700f66f451Sopenharmony_ci
710f66f451Sopenharmony_ci  if (!dirtree_notdotdot(dt)) return 0; // Skip . and ..
720f66f451Sopenharmony_ci  if (S_ISDIR(dt->st.st_mode)) return DIRTREE_RECURSE;
730f66f451Sopenharmony_ci
740f66f451Sopenharmony_ci  path = dirtree_path(dt, 0);
750f66f451Sopenharmony_ci  data = readfile(path, 0, 0);
760f66f451Sopenharmony_ci  replace_char(key = path + 10, '/', '.'); // skip "/proc/sys/"
770f66f451Sopenharmony_ci  if (!data) key_error(key);
780f66f451Sopenharmony_ci  else {
790f66f451Sopenharmony_ci    // Print the parts that aren't switched off by flags.
800f66f451Sopenharmony_ci    if (!(toys.optflags & FLAG_n)) xprintf("%s", key);
810f66f451Sopenharmony_ci    if (!(toys.optflags & (FLAG_N|FLAG_n))) xprintf(" = ");
820f66f451Sopenharmony_ci    for (key = data+strlen(data); key > data && isspace(*--key); *key = 0);
830f66f451Sopenharmony_ci    if (!(toys.optflags & FLAG_N)) xprintf("%s", data);
840f66f451Sopenharmony_ci    if ((toys.optflags & (FLAG_N|FLAG_n)) != (FLAG_N|FLAG_n)) xputc('\n');
850f66f451Sopenharmony_ci  }
860f66f451Sopenharmony_ci
870f66f451Sopenharmony_ci  free(data);
880f66f451Sopenharmony_ci  free(path);
890f66f451Sopenharmony_ci
900f66f451Sopenharmony_ci  return 0;
910f66f451Sopenharmony_ci}
920f66f451Sopenharmony_ci
930f66f451Sopenharmony_ci// Read/write entries under a key. Accepts "key=value" in key if !value
940f66f451Sopenharmony_cistatic void process_key(char *key, char *value)
950f66f451Sopenharmony_ci{
960f66f451Sopenharmony_ci  char *path;
970f66f451Sopenharmony_ci
980f66f451Sopenharmony_ci  if (!value) value = split_key(key);
990f66f451Sopenharmony_ci  if ((toys.optflags & FLAG_w) && !value) {
1000f66f451Sopenharmony_ci    error_msg("'%s' not key=value", key);
1010f66f451Sopenharmony_ci
1020f66f451Sopenharmony_ci    return;
1030f66f451Sopenharmony_ci  }
1040f66f451Sopenharmony_ci
1050f66f451Sopenharmony_ci  path = xmprintf("/proc/sys/%s", key);
1060f66f451Sopenharmony_ci  replace_char(path, '.', '/');
1070f66f451Sopenharmony_ci  // Note: failure to assign to a non-leaf node suppresses the display.
1080f66f451Sopenharmony_ci  if (!(value && (!write_key(path, key, value) || (toys.optflags & FLAG_q)))) {
1090f66f451Sopenharmony_ci    if (!access(path, R_OK)) dirtree_read(path, do_show_keys);
1100f66f451Sopenharmony_ci    else key_error(key);
1110f66f451Sopenharmony_ci  }
1120f66f451Sopenharmony_ci  free(path);
1130f66f451Sopenharmony_ci}
1140f66f451Sopenharmony_ci
1150f66f451Sopenharmony_civoid sysctl_main()
1160f66f451Sopenharmony_ci{
1170f66f451Sopenharmony_ci  char **args = 0;
1180f66f451Sopenharmony_ci
1190f66f451Sopenharmony_ci  // Display all keys
1200f66f451Sopenharmony_ci  if (toys.optflags & FLAG_a) dirtree_read("/proc/sys", do_show_keys);
1210f66f451Sopenharmony_ci
1220f66f451Sopenharmony_ci  // read file
1230f66f451Sopenharmony_ci  else if (toys.optflags & FLAG_p) {
1240f66f451Sopenharmony_ci    FILE *fp = xfopen(*toys.optargs ? *toys.optargs : "/etc/sysctl.conf", "r");
1250f66f451Sopenharmony_ci    size_t len;
1260f66f451Sopenharmony_ci
1270f66f451Sopenharmony_ci    for (;;) {
1280f66f451Sopenharmony_ci      char *line = 0, *key, *val;
1290f66f451Sopenharmony_ci
1300f66f451Sopenharmony_ci      if (-1 == (len = getline(&line, &len, fp))) break;
1310f66f451Sopenharmony_ci      key = line;
1320f66f451Sopenharmony_ci      while (isspace(*key)) key++;
1330f66f451Sopenharmony_ci      if (*key == '#' || *key == ';' || !*key) continue;
1340f66f451Sopenharmony_ci      while (len && isspace(line[len-1])) line[--len] = 0;
1350f66f451Sopenharmony_ci      if (!(val = split_key(line))) {
1360f66f451Sopenharmony_ci        error_msg("'%s' not key=value", line);
1370f66f451Sopenharmony_ci        continue;
1380f66f451Sopenharmony_ci      }
1390f66f451Sopenharmony_ci
1400f66f451Sopenharmony_ci      // Trim whitespace around =
1410f66f451Sopenharmony_ci      len = (val-line)-1;
1420f66f451Sopenharmony_ci      while (len && isspace(line[len-1])) line[--len] = 0;
1430f66f451Sopenharmony_ci      while (isspace(*val)) val++;;
1440f66f451Sopenharmony_ci
1450f66f451Sopenharmony_ci      process_key(key, val);
1460f66f451Sopenharmony_ci      free(line);
1470f66f451Sopenharmony_ci    }
1480f66f451Sopenharmony_ci    fclose(fp);
1490f66f451Sopenharmony_ci
1500f66f451Sopenharmony_ci  // Loop through arguments, displaying or assigning as appropriate
1510f66f451Sopenharmony_ci  } else {
1520f66f451Sopenharmony_ci    if (!*toys.optargs) help_exit("Needs 1 arg");
1530f66f451Sopenharmony_ci    for (args = toys.optargs; *args; args++) process_key(*args, 0);
1540f66f451Sopenharmony_ci  }
1550f66f451Sopenharmony_ci}
156