*: tweak error messages sysctl: shrink; support recursing if name is a directory: "sysctl net.ipv4.conf". Patch by xmaks AT email.cz
No binary (build failed)
—
(log yok)
| @@ -12632,7 +12632,7 @@ static void check_mount(e2fsck_t ctx) | |
| retval = ext2fs_check_if_mounted(ctx->filesystem_name, | |
| &ctx->mount_flags); | |
| if (retval) { | |
| - | bb_error_msg(_("while determining whether %s is mounted."), |
| + | bb_error_msg(_("while determining whether %s is mounted"), |
| ctx->filesystem_name); | |
| return; | |
| } | |
| @@ -12653,7 +12653,7 @@ static void check_mount(e2fsck_t ctx) | |
| printf(_("%s is mounted. "), ctx->filesystem_name); | |
| if (!ctx->interactive) | |
| - | bb_error_msg_and_die(_("Cannot continue, aborting.")); |
| + | bb_error_msg_and_die(_("cannot continue, aborting")); |
| printf(_("\n\n\007\007\007\007WARNING!!! " | |
| "Running e2fsck on a mounted filesystem may cause\n" | |
| "SEVERE filesystem damage.\007\007\007\n\n")); | |
| @@ -13060,7 +13060,7 @@ static errcode_t PRS(int argc, char **argv, e2fsck_t *ret_ctx) | |
| case 'a': | |
| if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) { | |
| conflict_opt: | |
| - | bb_error_msg_and_die(_("Only one the options -p/-a, -n or -y may be specified.")); |
| + | bb_error_msg_and_die(_("only one the options -p/-a, -n or -y may be specified")); |
| } | |
| ctx->options |= E2F_OPT_PREEN; | |
| break; | |
| @@ -13405,7 +13405,7 @@ restart: | |
| #ifdef ENABLE_COMPRESSION | |
| /* FIXME - do we support this at all? */ | |
| if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION) | |
| - | bb_error_msg(_("Warning: compression support is experimental.")); |
| + | bb_error_msg(_("warning: compression support is experimental")); |
| #endif | |
| #ifndef ENABLE_HTREE | |
| if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) { | |
| @@ -193,7 +193,7 @@ error: | |
| if (ENABLE_FEATURE_CLEAN_UP) | |
| RELEASE_CONFIG_BUFFER(modname); | |
| if (rc > 0 && !(option_mask32 & INSMOD_OPT_SILENT)) | |
| - | bb_error_msg("Failed to %sload module %s: %s.", |
| + | bb_error_msg("failed to %sload module %s: %s", |
| (option_mask32 & MODPROBE_OPT_REMOVE) ? "un" : "", | |
| module, moderror(rc)); | |
| return rc; | |
| @@ -270,7 +270,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) | |
| check_blacklist(conf, conf->probename)) { | |
| rc = do_modprobe(conf, conf->probename); | |
| if (rc < 0 && !(opt & INSMOD_OPT_SILENT)) | |
| - | bb_error_msg("Module %s not found.", arg); |
| + | bb_error_msg("module %s not found", arg); |
| } | |
| } else { | |
| /* Probe all aliases */ | |
| @@ -16,19 +16,11 @@ | |
| #include "libbb.h" | |
| - | static int sysctl_read_setting(const char *setting); |
| - | static int sysctl_write_setting(const char *setting); |
| + | static int sysctl_act_on_setting(char *setting); |
| static int sysctl_display_all(const char *path); | |
| - | static int sysctl_preload_file_and_exit(const char *filename); |
| + | static int sysctl_handle_preload_file(const char *filename); |
| static void sysctl_dots_to_slashes(char *name); | |
| - | static const char ETC_SYSCTL_CONF[] ALIGN1 = "/etc/sysctl.conf"; |
| - | static const char PROC_SYS[] ALIGN1 = "/proc/sys/"; |
| - | enum { strlen_PROC_SYS = sizeof(PROC_SYS) - 1 }; |
| - | |
| - | static const char msg_unknown_key[] ALIGN1 = |
| - | "error: '%s' is an unknown key"; |
| - | |
| static void dwrite_str(int fd, const char *buf) | |
| { | |
| write(fd, buf, strlen(buf)); | |
| @@ -52,212 +44,209 @@ int sysctl_main(int argc UNUSED_PARAM, char **argv) | |
| opt = getopt32(argv, "+neAapw"); /* '+' - stop on first non-option */ | |
| argv += optind; | |
| opt ^= (FLAG_SHOW_KEYS | FLAG_SHOW_KEY_ERRORS); | |
| - | option_mask32 ^= (FLAG_SHOW_KEYS | FLAG_SHOW_KEY_ERRORS); |
| + | option_mask32 = opt; |
| - | if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) |
| - | return sysctl_display_all(PROC_SYS); |
| - | if (opt & FLAG_PRELOAD_FILE) |
| - | return sysctl_preload_file_and_exit(*argv ? *argv : ETC_SYSCTL_CONF); |
| + | if (opt & FLAG_PRELOAD_FILE) { |
| + | option_mask32 |= FLAG_WRITE; |
| + | /* xchdir("/proc/sys") is inside */ |
| + | return sysctl_handle_preload_file(*argv ? *argv : "/etc/sysctl.conf"); |
| + | } |
| + | xchdir("/proc/sys"); |
| + | /* xchroot(".") - if you are paranoid */ |
| + | if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) { |
| + | return sysctl_display_all("."); |
| + | } |
| retval = 0; | |
| while (*argv) { | |
| - | if (opt & FLAG_WRITE) |
| - | retval |= sysctl_write_setting(*argv); |
| - | else |
| - | retval |= sysctl_read_setting(*argv); |
| + | sysctl_dots_to_slashes(*argv); |
| + | retval |= sysctl_display_all(*argv); |
| argv++; | |
| } | |
| return retval; | |
| - | } /* end sysctl_main() */ |
| + | } |
| /* Set sysctl's from a conf file. Format example: | |
| * # Controls IP packet forwarding | |
| * net.ipv4.ip_forward = 0 | |
| */ | |
| - | static int sysctl_preload_file_and_exit(const char *filename) |
| + | static int sysctl_handle_preload_file(const char *filename) |
| { | |
| char *token[2]; | |
| parser_t *parser; | |
| parser = config_open(filename); | |
| + | /* Must do it _after_ config_open(): */ |
| + | xchdir("/proc/sys"); |
| + | /* xchroot(".") - if you are paranoid */ |
| + | |
| // TODO: ';' is comment char too | |
| while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) { | |
| - | #if 0 |
| - | char *s = xasprintf("%s=%s", token[0], token[1]); |
| - | sysctl_write_setting(s); |
| - | free(s); |
| - | #else /* Save ~4 bytes by using parser internals */ |
| - | sprintf(parser->line, "%s=%s", token[0], token[1]); // must have room by definition |
| - | sysctl_write_setting(parser->line); |
| - | #endif |
| + | /* Save ~4 bytes by using parser internals */ |
| + | /* parser->line is big enough for sprintf */ |
| + | sprintf(parser->line, "%s=%s", token[0], token[1]); |
| + | sysctl_dots_to_slashes(parser->line); |
| + | sysctl_display_all(parser->line); |
| } | |
| if (ENABLE_FEATURE_CLEAN_UP) | |
| config_close(parser); | |
| return 0; | |
| - | } /* end sysctl_preload_file_and_exit() */ |
| + | } |
| - | static int sysctl_write_setting(const char *setting) |
| + | static int sysctl_act_on_setting(char *setting) |
| { | |
| - | int retval; |
| - | const char *name; |
| - | const char *value; |
| - | const char *equals; |
| - | char *tmpname, *outname, *cptr; |
| - | int fd; |
| + | int fd, retval = EXIT_SUCCESS; |
| + | char *cptr, *outname, *value; |
| - | name = setting; |
| - | equals = strchr(setting, '='); |
| - | if (!equals) { |
| - | bb_error_msg("error: '%s' must be of the form name=value", setting); |
| - | return EXIT_FAILURE; |
| - | } |
| + | outname = xstrdup(setting); |
| - | value = equals + 1; /* point to the value in name=value */ |
| - | if (name == equals || !*value) { |
| - | bb_error_msg("error: malformed setting '%s'", setting); |
| - | return EXIT_FAILURE; |
| + | cptr = outname; |
| + | while (*cptr) { |
| + | if (*cptr == '/') |
| + | *cptr = '.'; |
| + | cptr++; |
| } | |
| - | tmpname = xasprintf("%s%.*s", PROC_SYS, (int)(equals - name), name); |
| - | outname = xstrdup(tmpname + strlen_PROC_SYS); |
| - | |
| - | sysctl_dots_to_slashes(tmpname); |
| - | |
| - | while ((cptr = strchr(outname, '/')) != NULL) |
| - | *cptr = '.'; |
| + | if (option_mask32 & FLAG_WRITE) { |
| + | cptr = strchr(setting, '='); |
| + | if (cptr == NULL) { |
| + | bb_error_msg("error: '%s' must be of the form name=value", |
| + | outname); |
| + | retval = EXIT_FAILURE; |
| + | goto end; |
| + | } |
| + | value = cptr + 1; /* point to the value in name=value */ |
| + | if (setting == cptr || !*value) { |
| + | bb_error_msg("error: malformed setting '%s'", outname); |
| + | retval = EXIT_FAILURE; |
| + | goto end; |
| + | } |
| + | *cptr = '\0'; |
| + | fd = open(setting, O_WRONLY|O_CREAT|O_TRUNC, 0666); |
| + | } else { |
| + | fd = open(setting, O_RDONLY); |
| + | } |
| - | fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666); |
| if (fd < 0) { | |
| switch (errno) { | |
| case ENOENT: | |
| if (option_mask32 & FLAG_SHOW_KEY_ERRORS) | |
| - | bb_error_msg(msg_unknown_key, outname); |
| + | bb_error_msg("error: '%s' is an unknown key", outname); |
| break; | |
| default: | |
| - | bb_perror_msg("error setting key '%s'", outname); |
| + | bb_perror_msg("error %sing key '%s'", |
| + | option_mask32 & FLAG_WRITE ? |
| + | "sett" : "read", |
| + | outname); |
| break; | |
| } | |
| retval = EXIT_FAILURE; | |
| - | } else { |
| + | goto end; |
| + | } |
| + | |
| + | if (option_mask32 & FLAG_WRITE) { |
| dwrite_str(fd, value); | |
| close(fd); | |
| - | if (option_mask32 & FLAG_SHOW_KEYS) { |
| + | if (option_mask32 & FLAG_SHOW_KEYS) |
| printf("%s = ", outname); | |
| - | } |
| puts(value); | |
| - | retval = EXIT_SUCCESS; |
| - | } |
| - | |
| - | free(tmpname); |
| - | free(outname); |
| - | return retval; |
| - | } /* end sysctl_write_setting() */ |
| - | |
| - | static int sysctl_read_setting(const char *name) |
| - | { |
| - | int retval; |
| - | char *tmpname, *outname, *cptr; |
| - | char inbuf[1025]; |
| - | FILE *fp; |
| - | |
| - | if (!*name) { |
| - | if (option_mask32 & FLAG_SHOW_KEY_ERRORS) |
| - | bb_error_msg(msg_unknown_key, name); |
| - | return -1; |
| - | } |
| - | |
| - | tmpname = concat_path_file(PROC_SYS, name); |
| - | outname = xstrdup(tmpname + strlen_PROC_SYS); |
| - | |
| - | sysctl_dots_to_slashes(tmpname); |
| - | |
| - | while ((cptr = strchr(outname, '/')) != NULL) |
| - | *cptr = '.'; |
| + | } else { |
| + | char c; |
| - | fp = fopen_for_read(tmpname); |
| - | if (fp == NULL) { |
| - | switch (errno) { |
| - | case ENOENT: |
| - | if (option_mask32 & FLAG_SHOW_KEY_ERRORS) |
| - | bb_error_msg(msg_unknown_key, outname); |
| - | break; |
| - | default: |
| + | value = cptr = xmalloc_read(fd, NULL); |
| + | close(fd); |
| + | if (value == NULL) { |
| bb_perror_msg("error reading key '%s'", outname); | |
| - | break; |
| + | goto end; |
| } | |
| - | retval = EXIT_FAILURE; |
| - | } else { |
| - | while (fgets(inbuf, sizeof(inbuf) - 1, fp)) { |
| - | if (option_mask32 & FLAG_SHOW_KEYS) { |
| + | |
| + | /* dev.cdrom.info and sunrpc.transports, for example, |
| + | * are multi-line. Try "sysctl sunrpc.transports" |
| + | */ |
| + | while ((c = *cptr) != '\0') { |
| + | if (option_mask32 & FLAG_SHOW_KEYS) |
| printf("%s = ", outname); | |
| + | while (1) { |
| + | fputc(c, stdout); |
| + | cptr++; |
| + | if (c == '\n') |
| + | break; |
| + | c = *cptr; |
| + | if (c == '\0') |
| + | break; |
| } | |
| - | fputs(inbuf, stdout); |
| } | |
| - | fclose(fp); |
| - | retval = EXIT_SUCCESS; |
| + | free(value); |
| } | |
| - | |
| - | free(tmpname); |
| + | end: |
| free(outname); | |
| return retval; | |
| - | } /* end sysctl_read_setting() */ |
| + | } |
| static int sysctl_display_all(const char *path) | |
| { | |
| - | int retval = EXIT_SUCCESS; |
| - | DIR *dp; |
| - | struct dirent *de; |
| - | char *tmpdir; |
| - | struct stat ts; |
| - | |
| - | dp = opendir(path); |
| - | if (!dp) { |
| - | return EXIT_FAILURE; |
| - | } |
| - | while ((de = readdir(dp)) != NULL) { |
| - | tmpdir = concat_subpath_file(path, de->d_name); |
| - | if (tmpdir == NULL) |
| - | continue; /* . or .. */ |
| - | if (stat(tmpdir, &ts) != 0) { |
| - | bb_perror_msg(tmpdir); |
| - | } else if (S_ISDIR(ts.st_mode)) { |
| - | retval |= sysctl_display_all(tmpdir); |
| - | } else { |
| - | retval |= sysctl_read_setting(tmpdir + strlen_PROC_SYS); |
| + | DIR *dirp; |
| + | struct stat buf; |
| + | struct dirent *entry; |
| + | char *next; |
| + | int retval = 0; |
| + | |
| + | stat(path, &buf); |
| + | if (S_ISDIR(buf.st_mode) && !(option_mask32 & FLAG_WRITE)) { |
| + | dirp = opendir(path); |
| + | if (dirp == NULL) |
| + | return -1; |
| + | while ((entry = readdir(dirp)) != NULL) { |
| + | next = concat_subpath_file( |
| + | path, entry->d_name); |
| + | if (next == NULL) |
| + | continue; /* d_name is "." or ".." */ |
| + | /* if path was ".", drop "./" prefix: */ |
| + | retval |= sysctl_display_all((next[0] == '.' && next[1] == '/') ? |
| + | next + 2 : next); |
| + | free(next); |
| } | |
| - | free(tmpdir); |
| - | } /* end while */ |
| - | closedir(dp); |
| + | closedir(dirp); |
| + | } else { |
| + | char *name = xstrdup(path); |
| + | retval |= sysctl_act_on_setting(name); |
| + | free(name); |
| + | } |
| return retval; | |
| - | } /* end sysctl_display_all() */ |
| + | } |
| static void sysctl_dots_to_slashes(char *name) | |
| { | |
| char *cptr, *last_good, *end; | |
| - | /* It can be good as-is! */ |
| - | if (access(name, F_OK) == 0) |
| - | return; |
| - | |
| - | /* Example from bug 3894: |
| + | /* 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*, |
| + | * 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 replacement occurred. */ |
| - | end = name + strlen(name) - 1; |
| + | * where last replacement occurred. |
| + | */ |
| + | end = name + strlen(name); |
| last_good = name - 1; | |
| + | *end = '.'; /* trick the loop in trying full name too */ |
| + | |
| again: | |
| cptr = end; | |
| while (cptr > last_good) { | |
| if (*cptr == '.') { | |
| *cptr = '\0'; | |
| + | //bb_error_msg("trying:'%s'", name); |
| if (access(name, F_OK) == 0) { | |
| *cptr = '/'; | |
| + | *end = '\0'; /* prevent trailing '/' */ |
| + | //bb_error_msg("replaced:'%s'", name); |
| last_good = cptr; | |
| goto again; | |
| } | |
| @@ -265,4 +254,5 @@ static void sysctl_dots_to_slashes(char *name) | |
| } | |
| cptr--; | |
| } | |
| - | } /* end sysctl_dots_to_slashes() */ |
| + | *end = '\0'; |
| + | } |