xref: /aosp_15_r20/external/toybox/toys/other/sysctl.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1 /* sysctl.c - A utility to read and manipulate the sysctl parameters.
2  *
3  * Copyright 2014 Bilal Qureshi <[email protected]>
4  * Copyright 2014 Kyungwan Han <[email protected]>
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 [-aeNnqw] [-p [FILE] | KEY[=VALUE]...]
15 
16     Read/write system control data (under /proc/sys).
17 
18     -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
split_key(char * key)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 
replace_char(char * str,char old,char new)39 static void replace_char(char *str, char old, char new)
40 {
41   for (; *str; str++) if (*str == old) *str = new;
42 }
43 
key_error(char * key)44 static void key_error(char *key)
45 {
46   if (errno != ENOENT) perror_msg("key '%s'", key);
47   else if (!FLAG(e)) error_msg("unknown key '%s'", key);
48 }
49 
write_key(char * path,char * key,char * value)50 static int write_key(char *path, char *key, char *value)
51 {
52   int fd = open(path, O_WRONLY);
53 
54   if (fd < 0) {
55     key_error(key);
56 
57     return 0;
58   }
59   xwrite(fd, value, strlen(value));
60   xclose(fd);
61 
62   return 1;
63 }
64 
65 // Display all keys under a path
do_show_keys(struct dirtree * dt)66 static int do_show_keys(struct dirtree *dt)
67 {
68   char *path, *data, *key;
69 
70   if (!dirtree_notdotdot(dt)) return 0; // Skip . and ..
71   if (S_ISDIR(dt->st.st_mode)) return DIRTREE_RECURSE;
72 
73   path = dirtree_path(dt, 0);
74   data = readfile(path, 0, 0);
75   replace_char(key = path + 10, '/', '.'); // skip "/proc/sys/"
76   if (!data) key_error(key);
77   else {
78     // Print the parts that aren't switched off by flags.
79     if (!FLAG(n)) xprintf("%s", key);
80     if (!FLAG(N) && !FLAG(n)) xprintf(" = ");
81     for (key = data+strlen(data); key > data && isspace(*--key); *key = 0);
82     if (!FLAG(N)) xprintf("%s", data);
83     if (!FLAG(N) || !FLAG(n)) xputc('\n');
84   }
85 
86   free(data);
87   free(path);
88 
89   return 0;
90 }
91 
92 // Read/write entries under a key. Accepts "key=value" in key if !value
process_key(char * key,char * value)93 static void process_key(char *key, char *value)
94 {
95   char *path;
96 
97   if (!value) value = split_key(key);
98   if (FLAG(w) && !value) return error_msg("'%s' not key=value", key);
99   path = xmprintf("/proc/sys/%s", key);
100   replace_char(path, '.', '/');
101   // Note: failure to assign to a non-leaf node suppresses the display.
102   if (!(value && (!write_key(path, key, value) || FLAG(q)))) {
103     if (!access(path, R_OK)) dirtree_read(path, do_show_keys);
104     else key_error(key);
105   }
106   free(path);
107 }
108 
sysctl_main()109 void sysctl_main()
110 {
111   char **args = 0;
112 
113   // Display all keys
114   if (FLAG(a)) dirtree_read("/proc/sys", do_show_keys);
115 
116   // read file
117   else if (FLAG(p)) {
118     FILE *fp = xfopen(*toys.optargs ? *toys.optargs : "/etc/sysctl.conf", "r");
119     size_t len;
120 
121     for (;;) {
122       char *line = 0, *key, *val;
123 
124       if (-1 == (len = getline(&line, &len, fp))) break;
125       key = line;
126       while (isspace(*key)) key++;
127       if (*key == '#' || *key == ';' || !*key) continue;
128       while (len && isspace(line[len-1])) line[--len] = 0;
129       if (!(val = split_key(line))) {
130         error_msg("'%s' not key=value", line);
131         continue;
132       }
133 
134       // Trim whitespace around =
135       len = (val-line)-1;
136       while (len && isspace(line[len-1])) line[--len] = 0;
137       while (isspace(*val)) val++;;
138 
139       process_key(key, val);
140       free(line);
141     }
142     fclose(fp);
143 
144   // Loop through arguments, displaying or assigning as appropriate
145   } else {
146     if (!*toys.optargs) help_exit("Needs 1 arg");
147     for (args = toys.optargs; *args; args++) process_key(*args, 0);
148   }
149 }
150