Home | History | Annotate | Download | only in other
      1 /* sysctl.c - A utility to read and manipulate the sysctl parameters.
      2  *
      3  * Copyright 2014 Bilal Qureshi <bilal.jmi (at) gmail.com>
      4  * Copyright 2014 Kyungwan Han <asura321 (at) gmail.com>
      5  *
      6  * No Standard
      7 
      8 USE_SYSCTL(NEWTOY(sysctl, "^neNqwpaA[!ap][!aq][!aw][+aA]", TOYFLAG_SBIN))
      9 
     10 config 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
     30 static char *split_key(char *key)
     31 {
     32   char *value = strchr(key, '=');
     33 
     34   if (value) *(value++)=0;
     35 
     36   return value;
     37 }
     38 
     39 static void replace_char(char *str, char old, char new)
     40 {
     41   for (; *str; str++) if (*str == old) *str = new;
     42 }
     43 
     44 static 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 
     51 static 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
     67 static 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
     94 static 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 
    115 void 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(0);
    153     for (args = toys.optargs; *args; args++) process_key(*args, 0);
    154   }
    155 }
    156