- int retval = 0;
- int output = 1;
- int write_mode = 0;
- int switches_allowed = 1;
-
- if (argc < 2)
- bb_show_usage();
-
- argv++;
-
- for (; argv && *argv && **argv; argv++) {
- if (switches_allowed && **argv == '-') { /* we have a switch */
- switch ((*argv)[1]) {
- case 'n':
- output = 0;
- break;
- case 'w':
- write_mode = 1;
- switches_allowed = 0;
- break;
- case 'p':
- argv++;
- return
- sysctl_preload_file(((argv && *argv
- && **argv) ? *argv :
- DEFAULT_PRELOAD), output);
- case 'a':
- case 'A':
- switches_allowed = 0;
- return sysctl_display_all(PROC_PATH, output,
- ((*argv)[1] == 'a') ? 0 : 1);
- case 'h':
- case '?':
- bb_show_usage();
- default:
- bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv);
- bb_show_usage();
+ char *cptr, *last_good, *end, *slash;
+ char end_ch;
+
+ end = strchrnul(name, '=');
+
+ slash = strchrnul(name, '/');
+ if (slash < end
+ && strchrnul(name, '.') < slash
+ ) {
+ /* There are both dots and slashes, and 1st dot is
+ * before 1st slash.
+ * (IOW: not raw, unmangled a/b/c.d format)
+ *
+ * procps supports this syntax for names with dots:
+ * net.ipv4.conf.eth0/100.mc_forwarding
+ * (dots and slashes are simply swapped)
+ */
+ while (end != name) {
+ end--;
+ if (*end == '.') *end = '/';
+ else if (*end == '/') *end = '.';
+ }
+ return;
+ }
+ /* else: use our old behavior: */
+
+ /* Convert minimum number of '.' to '/' so that
+ * we end up with existing file's name.
+ *
+ * Example from bug 3894:
+ * net.ipv4.conf.eth0.100.mc_forwarding ->
+ * net/ipv4/conf/eth0.100/mc_forwarding
+ * NB: net/ipv4/conf/eth0/mc_forwarding *also exists*,
+ * therefore we must start from the end, and if
+ * we replaced even one . -> /, start over again,
+ * but never replace dots before the position
+ * where last replacement occurred.
+ *
+ * Another bug we later had is that
+ * net.ipv4.conf.eth0.100
+ * (without .mc_forwarding) was mishandled.
+ *
+ * To set up testing: modprobe 8021q; vconfig add eth0 100
+ */
+ end_ch = *end;
+ *end = '.'; /* trick the loop into trying full name too */
+
+ last_good = name - 1;
+ again:
+ cptr = end;
+ while (cptr > last_good) {
+ if (*cptr == '.') {
+ *cptr = '\0';
+ //bb_error_msg("trying:'%s'", name);
+ if (access(name, F_OK) == 0) {
+ *cptr = '/';
+ //bb_error_msg("replaced:'%s'", name);
+ last_good = cptr;
+ goto again;