1281
|
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
|
|
8 USE_SYSCTL(NEWTOY(sysctl, "^neNqwpaA[!ap][!aq][!aw][+aA]", TOYFLAG_USR|TOYFLAG_BIN))
|
|
9
|
|
10 config SYSCTL
|
|
11 bool "sysctl"
|
|
12 default n
|
|
13 help
|
|
14 usage: sysctl [OPTIONS] [KEY[=VALUE]]...
|
|
15
|
|
16 -a, A Show all values
|
|
17 -e Don't warn about unknown keys
|
|
18 -N Show only key names
|
|
19 -n Show only key values
|
|
20 -p FILE Set values from FILE (default /etc/sysctl.conf)
|
|
21 -q Set values silently
|
|
22 -w Set values
|
|
23 */
|
|
24 #define FOR_sysctl
|
|
25 #include "toys.h"
|
|
26
|
|
27 #define PROC_SYS_DIR "/proc/sys"
|
|
28 #define MAX_BYTES_LINE 1024
|
|
29
|
|
30 static void parse_key_name_value(char *param, char **key_name, char **key_value)
|
|
31 {
|
|
32 char *name, *value;
|
|
33
|
|
34 if (!(name = strchr(param, '='))) goto show_error_msg;
|
|
35 value = name;
|
|
36 value++;
|
|
37 if (!(*value)) goto show_error_msg;
|
|
38 *name = '\0';
|
|
39 *key_name = param;
|
|
40 *key_value = value;
|
|
41 return;
|
|
42 show_error_msg:
|
|
43 error_msg("error: '%s' must be of the form name=value", param);
|
|
44 }
|
|
45
|
|
46 static void replace_char(char *str, char old, char new)
|
|
47 {
|
|
48 char *tmp = str;
|
|
49
|
|
50 for (; *tmp; tmp++)
|
|
51 if (*tmp == old) *tmp = new;
|
|
52 }
|
|
53
|
|
54 static void handle_file_error(char *key_name)
|
|
55 {
|
|
56 replace_char(key_name, '/', '.');
|
|
57 if (errno == ENOENT) {
|
|
58 if (!(toys.optflags & FLAG_e))
|
|
59 error_msg("error: '%s' is an unknown key", key_name);
|
|
60 else toys.exitval = 1;
|
|
61 } else perror_msg("error: %s key '%s'", (toys.optflags & FLAG_w) ?
|
|
62 "setting" : "reading", key_name);
|
|
63 }
|
|
64
|
|
65 static void write_to_file(char *fpath, char *key_name, char *key_value)
|
|
66 {
|
|
67 int fd;
|
|
68
|
|
69 replace_char(key_name, '.', '/');
|
|
70 sprintf(toybuf, "%s/%s", fpath, key_name);
|
|
71 if ((fd = open(toybuf, O_WRONLY)) < 0) {
|
|
72 handle_file_error(key_name);
|
|
73 return;
|
|
74 }
|
|
75 xwrite(fd, key_value, strlen(key_value));
|
|
76 xclose(fd);
|
|
77 if (!(toys.optflags & FLAG_q)) {
|
|
78 replace_char(key_name, '/', '.');
|
|
79 if (toys.optflags & FLAG_N) xprintf("%s\n", key_name);
|
|
80 else if (toys.optflags & FLAG_n) xprintf("%s\n", key_value);
|
|
81 else xprintf("%s = %s\n", key_name, key_value);
|
|
82 }
|
|
83 }
|
|
84
|
|
85 static char *get_key_value(char *buff, int *offset)
|
|
86 {
|
|
87 char *line, *tmp = (char *) (buff + *offset);
|
|
88 int index = 0, multiplier = 1;
|
|
89
|
|
90 if (!(*tmp)) return NULL;
|
|
91 line = (char *) xmalloc(sizeof(char) * MAX_BYTES_LINE);
|
|
92 for (; *tmp != '\n'; tmp++) {
|
|
93 line[index++] = *tmp;
|
|
94 if (MAX_BYTES_LINE == index) { // buffer overflow
|
|
95 multiplier++;
|
|
96 line = (char *) xrealloc(line, multiplier * MAX_BYTES_LINE);
|
|
97 }
|
|
98 }
|
|
99 line[index++] = '\0';
|
|
100 *offset += index;
|
|
101 return line;
|
|
102 }
|
|
103
|
|
104 // Open file for each and every key name and read file contents
|
|
105 void read_key_values(char *fpath)
|
|
106 {
|
|
107 char *key_value, *fdata, *key_name, *tmp = xstrdup(fpath);
|
|
108 int offset = 0;
|
|
109
|
|
110 key_name = (tmp + strlen(PROC_SYS_DIR) + 1);
|
|
111 replace_char(key_name, '/', '.');
|
|
112 if (!(fdata = readfile(fpath, NULL, 0))) {
|
|
113 handle_file_error(key_name);
|
|
114 free(tmp);
|
|
115 return;
|
|
116 }
|
|
117 if (toys.optflags & FLAG_N) {
|
|
118 xprintf("%s\n", key_name);
|
|
119 free(tmp);
|
|
120 free(fdata);
|
|
121 return;
|
|
122 }
|
|
123 for (; (key_value = get_key_value(fdata, &offset)); free(key_value)) {
|
|
124 if (!(toys.optflags & FLAG_q)) {
|
|
125 if (!(toys.optflags & FLAG_n)) xprintf("%s = ", key_name);
|
|
126 xprintf("%s\n", key_value);
|
|
127 }
|
|
128 }
|
|
129 free(tmp);
|
|
130 free(fdata);
|
|
131 }
|
|
132
|
|
133 static void trim_spaces(char **param)
|
|
134 {
|
|
135 int len = 0;
|
|
136 char *str = *param, *p_start = str, *p_end;
|
|
137
|
|
138 if (p_start) { // start pointer to string
|
|
139 p_end = str + strlen(str) - 1; // end pointer to string
|
|
140 while (*p_start == ' ') p_start++;
|
|
141 str = p_start;
|
|
142 while (*p_end == ' ') p_end--;
|
|
143 p_end++;
|
|
144 *p_end = '\0';
|
|
145 len = (int) (p_end - str) + 1;
|
|
146 memmove(*param, str, len);
|
|
147 }
|
|
148 }
|
|
149
|
|
150 // Read config file and write values to there corresponding key name files
|
|
151 static void read_config_file(char *fname)
|
|
152 {
|
|
153 char *line, *name = NULL, *value = NULL;
|
|
154 int fd = xopen(fname, O_RDONLY);
|
|
155
|
|
156 for (; (line = get_line(fd)); free(line), name = NULL, value = NULL) {
|
|
157 char *ptr = line;
|
|
158
|
|
159 while (*ptr == ' ' || *ptr == '\t') ptr++;
|
|
160 if (*ptr != '#' && *ptr != ';' && *ptr !='\n' && *ptr) {
|
|
161 parse_key_name_value(ptr, &name, &value);
|
|
162 trim_spaces(&name);
|
|
163 trim_spaces(&value);
|
|
164 if (name && value) write_to_file(PROC_SYS_DIR, name, value);
|
|
165 }
|
|
166 }
|
|
167 xclose(fd);
|
|
168 }
|
|
169
|
|
170 static int do_process(struct dirtree *dt)
|
|
171 {
|
|
172 char *fpath;
|
|
173
|
|
174 if (!dirtree_notdotdot(dt)) return 0; // Skip . and ..
|
|
175 if (S_ISDIR(dt->st.st_mode)) return DIRTREE_RECURSE;
|
|
176 if ((fpath = dirtree_path(dt, 0))) {
|
|
177 read_key_values(fpath);
|
|
178 free(fpath);
|
|
179 }
|
|
180 return 0;
|
|
181 }
|
|
182
|
|
183 void sysctl_main()
|
|
184 {
|
|
185 char *name = NULL, *value = NULL, **args = NULL;
|
|
186
|
|
187 if (toys.optflags & FLAG_a) {
|
|
188 dirtree_read(PROC_SYS_DIR, do_process);
|
|
189 return;
|
|
190 }
|
|
191 if (toys.optflags & FLAG_p) {
|
|
192 if (*toys.optargs) read_config_file(*toys.optargs);
|
|
193 else read_config_file("/etc/sysctl.conf");
|
|
194 return;
|
|
195 }
|
|
196 if (toys.optflags & FLAG_w) {
|
|
197 for (args = toys.optargs; *args; args++, name = NULL, value = NULL) {
|
|
198 parse_key_name_value(*args, &name, &value);
|
|
199 if (name && value) write_to_file(PROC_SYS_DIR, name, value);
|
|
200 }
|
|
201 return;
|
|
202 }
|
|
203 for (args = toys.optargs; *args; args++) {
|
|
204 replace_char(*args, '.', '/');
|
|
205 sprintf(toybuf, "%s/%s", PROC_SYS_DIR, *args);
|
|
206 read_key_values(toybuf);
|
|
207 }
|
|
208 }
|