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