diff options
-rw-r--r-- | toys/pending/sysctl.c | 249 |
1 files changed, 94 insertions, 155 deletions
diff --git a/toys/pending/sysctl.c b/toys/pending/sysctl.c index 7e8736d7..741b8aef 100644 --- a/toys/pending/sysctl.c +++ b/toys/pending/sysctl.c @@ -11,38 +11,29 @@ config SYSCTL bool "sysctl" default n help - usage: sysctl [OPTIONS] [KEY[=VALUE]]... + usage: sysctl [-aAeNnqw] [-p [FILE] | KEY[=VALUE]...] - Configure kernel parameters at runtime. + Read/write system control data (under /proc/sys). - -a, A Show all values - -e Don't warn about unknown keys - -N Show only key names - -n Show only key values - -p FILE Set values from FILE (default /etc/sysctl.conf) - -q Set values silently - -w Set values + -a,A Show all values + -e Don't warn about unknown keys + -N Don't print key values + -n Don't print key names + -p [FILE] Read values from FILE (default /etc/sysctl.conf) + -q Don't show value after write + -w Only write values (object to reading) */ #define FOR_sysctl #include "toys.h" -#define PROC_SYS_DIR "/proc/sys" -#define MAX_BYTES_LINE 1024 - -static void parse_key_name_value(char *param, char **key_name, char **key_value) +// Null terminate at =, return value +static char *split_key(char *key) { - char *name, *value; - - if (!(name = strchr(param, '='))) goto show_error_msg; - value = name; - value++; - if (!(*value)) goto show_error_msg; - *name = '\0'; - *key_name = param; - *key_value = value; - return; -show_error_msg: - error_msg("error: '%s' must be of the form name=value", param); + char *value = strchr(key, '='); + + if (value) *(value++)=0; + + return value; } static void replace_char(char *str, char old, char new) @@ -50,159 +41,107 @@ static void replace_char(char *str, char old, char new) for (; *str; str++) if (*str == old) *str = new; } -static void handle_file_error(char *key_name) +static void key_error(char *key) { - replace_char(key_name, '/', '.'); - if (errno == ENOENT) { - if (!(toys.optflags & FLAG_e)) - error_msg("error: '%s' is an unknown key", key_name); - else toys.exitval = 1; - } else perror_msg("error: %s key '%s'", (toys.optflags & FLAG_w) ? - "setting" : "reading", key_name); + if (!(errno == ENOENT && (toys.optflags & FLAG_e))) + perror_msg("key '%s'", key); } -static void write_to_file(char *fpath, char *key_name, char *key_value) +static int write_key(char *path, char *key, char *value) { - int fd; + int fd = open(path, O_WRONLY);; - replace_char(key_name, '.', '/'); - sprintf(toybuf, "%s/%s", fpath, key_name); - if ((fd = open(toybuf, O_WRONLY)) < 0) { - handle_file_error(key_name); - return; + if (fd < 0) { + key_error(key); + + return 0; } - xwrite(fd, key_value, strlen(key_value)); + xwrite(fd, value, strlen(value)); xclose(fd); - if (!(toys.optflags & FLAG_q)) { - replace_char(key_name, '/', '.'); - if (toys.optflags & FLAG_N) xprintf("%s\n", key_name); - else if (toys.optflags & FLAG_n) xprintf("%s\n", key_value); - else xprintf("%s = %s\n", key_name, key_value); - } -} -static char *get_key_value(char *buff, int *offset) -{ - char *line, *tmp = buff + *offset; - int index = 0, multiplier = 1; - - if (!*tmp) return 0; - line = xmalloc(MAX_BYTES_LINE); - for (; *tmp != '\n'; tmp++) { - line[index++] = *tmp; - if (MAX_BYTES_LINE == index) { // buffer overflow - multiplier++; - line = (char *) xrealloc(line, multiplier * MAX_BYTES_LINE); - } - } - line[index++] = '\0'; - *offset += index; - return line; + return 1; } -static void trim_spaces(char **param) +// Display all keys under a path +static int do_show_keys(struct dirtree *dt) { - int len = 0; - char *str = *param, *p_start = str, *p_end; - - if (p_start) { // start pointer to string - p_end = str + strlen(str) - 1; // end pointer to string - while (*p_start == ' ') p_start++; - str = p_start; - while (*p_end == ' ') p_end--; - p_end++; - *p_end = '\0'; - len = (int) (p_end - str) + 1; - memmove(*param, str, len); - } -} + char *path, *data, *key; -// Read config file and write values to corresponding key name files -static void read_config_file(char *fname) -{ - char *line, *name = NULL, *value = NULL; - int fd = xopen(fname, O_RDONLY); - - for (; (line = get_line(fd)); free(line), name = NULL, value = NULL) { - char *ptr = line; - - while (*ptr == ' ' || *ptr == '\t') ptr++; - if (*ptr != '#' && *ptr != ';' && *ptr !='\n' && *ptr) { - parse_key_name_value(ptr, &name, &value); - trim_spaces(&name); - trim_spaces(&value); - if (name && value) write_to_file(PROC_SYS_DIR, name, value); - } + if (!dirtree_notdotdot(dt)) return 0; // Skip . and .. + if (S_ISDIR(dt->st.st_mode)) return DIRTREE_RECURSE; + + path = dirtree_path(dt, 0); + data = readfile(path, 0, 0); + replace_char(key = path + 10, '/', '.'); // skip "/proc/sys/" + if (!data) key_error(key); + else { + // Print the parts that aren't switched off by flags. + if (!(toys.optflags & FLAG_n)) xprintf("%s", key); + if (!(toys.optflags & (FLAG_N|FLAG_n))) xprintf(" = "); + for (key = data+strlen(data); key > data && isspace(*--key); *key = 0); + if (!(toys.optflags & FLAG_N)) xprintf("%s", data); + if ((toys.optflags & (FLAG_N|FLAG_n)) != (FLAG_N|FLAG_n)) xputc('\n'); } - xclose(fd); -} -// Open file for each and every key name and read file contents -void read_key_values(char *fpath) -{ - char *key_value, *fdata, *key_name, *tmp = xstrdup(fpath); - int offset = 0; - - key_name = (tmp + strlen(PROC_SYS_DIR) + 1); - replace_char(key_name, '/', '.'); - if (!(fdata = readfile(fpath, NULL, 0))) { - handle_file_error(key_name); - free(tmp); - return; - } - if (toys.optflags & FLAG_N) { - xprintf("%s\n", key_name); - free(tmp); - free(fdata); - return; - } - for (; (key_value = get_key_value(fdata, &offset)); free(key_value)) { - if (!(toys.optflags & FLAG_q)) { - if (!(toys.optflags & FLAG_n)) xprintf("%s = ", key_name); - xprintf("%s\n", key_value); - } - } - free(tmp); - free(fdata); + free(data); + free(path); + + return 0; } -static int do_flag_a(struct dirtree *dt) +// Read/write entries under a key +static void process_key(char *key, char *value) { - char *fpath; + char *path, *pattern = "%s/%s/%s"; - if (!dirtree_notdotdot(dt)) return 0; // Skip . and .. - if (S_ISDIR(dt->st.st_mode)) return DIRTREE_RECURSE; - if ((fpath = dirtree_path(dt, 0))) { - read_key_values(fpath); - free(fpath); + if ((toys.optflags & FLAG_w) && !value && !strchr(key, '=')) { + error_msg("'%s' not key=value"); + + return; } - return 0; + path = xmprintf(pattern + 3*!value, "/proc/sys", key, value); + value = split_key(path); + replace_char(path, '.', '/'); + // Note: failure to assign to a non-leaf node suppresses the display. + if (!(value && (write_key(path, key, value) || (toys.optflags & FLAG_q)))) + dirtree_read(path, do_show_keys); + free(path); } void sysctl_main() { - char *name = 0, *value = 0, **args = 0; - - if (toys.optflags & FLAG_a) { - dirtree_read(PROC_SYS_DIR, do_flag_a); - return; - } - if (toys.optflags & FLAG_p) { - if (*toys.optargs) read_config_file(*toys.optargs); - else read_config_file("/etc/sysctl.conf"); - return; - } - if (toys.optflags & FLAG_w) { - for (args = toys.optargs; *args; args++, name = NULL, value = NULL) { - parse_key_name_value(*args, &name, &value); - if (name && value) write_to_file(PROC_SYS_DIR, name, value); + char **args = 0; + + // Display all keys + if (toys.optflags & FLAG_a) dirtree_read("/proc/sys", do_show_keys); + + // read file + else if (toys.optflags & FLAG_p) { + FILE *fp = xfopen(*toys.optargs ? *toys.optargs : "/etc/sysctl.conf", "r"); + char *line = 0; + size_t len; + + for (;-1 != (len = getline(&line, &len, fp)); free(line), line = 0) { + char *key = line, *val; + + while (isspace(*key)) key++; + if (*key == '#' || *key == ';' || !*key) continue; + if (!(val = split_key(line))) { + error_msg("'%s' not key=value"); + continue; + } + + // Trim whitespace off key and value + while (len && isspace(line[len-1])) line[--len] = 0; + len = (val-line)-1; + while (len && isspace(line[len-1])) line[--len] = 0; + while (isspace(*val)) val++;; + + process_key(key, val); } - return; - } - for (args = toys.optargs; *args; args++) { - replace_char(*args, '.', '/'); - sprintf(toybuf, "%s/%s", PROC_SYS_DIR, *args); - read_key_values(toybuf); - } + fclose(fp); + + // Loop through arguments, displaying or assigning as appropriate + } else for (args = toys.optargs; *args; args++) process_key(*args, 0); } |