1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
35 #include "path-util.h"
36 #include "conf-files.h"
39 static char **arg_prefixes = NULL;
41 static const char conf_file_dirs[] =
44 "/usr/local/lib/sysctl.d\0"
51 static char *normalize_sysctl(char *s) {
61 static int apply_sysctl(const char *property, const char *value) {
62 _cleanup_free_ char *p = NULL;
66 log_debug("Setting '%s' to '%s'", property, value);
68 p = new(char, sizeof("/proc/sys/") + strlen(property));
72 n = stpcpy(p, "/proc/sys/");
75 if (!strv_isempty(arg_prefixes)) {
79 STRV_FOREACH(i, arg_prefixes)
80 if (path_startswith(p, *i)) {
86 log_debug("Skipping %s", p);
91 k = write_string_file(p, value);
93 log_full(k == -ENOENT ? LOG_DEBUG : LOG_WARNING,
94 "Failed to write '%s' to '%s': %s", value, p, strerror(-k));
96 if (k != -ENOENT && r == 0)
103 static int apply_all(Hashmap *sysctl_options) {
105 char *property, *value;
108 assert(sysctl_options);
110 HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) {
113 k = apply_sysctl(property, value);
120 static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_enoent) {
121 _cleanup_fclose_ FILE *f = NULL;
126 r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f);
128 if (ignore_enoent && r == -ENOENT)
131 log_error("Failed to open file '%s', ignoring: %s", path, strerror(-r));
135 log_debug("parse: %s\n", path);
137 char l[LINE_MAX], *p, *value, *new_value, *property, *existing;
141 if (!fgets(l, sizeof(l), f)) {
145 log_error("Failed to read file '%s', ignoring: %m", path);
153 if (strchr(COMMENTS "\n", *p))
156 value = strchr(p, '=');
158 log_error("Line is not an assignment in file '%s': %s", path, value);
168 p = normalize_sysctl(strstrip(p));
169 value = strstrip(value);
171 existing = hashmap_get2(sysctl_options, p, &v);
173 if (streq(value, existing))
176 log_info("Overwriting earlier assignment of %s in file '%s'.", p, path);
177 free(hashmap_remove(sysctl_options, p));
181 property = strdup(p);
185 new_value = strdup(value);
191 k = hashmap_put(sysctl_options, property, new_value);
193 log_error("Failed to add sysctl variable %s to hashmap: %s", property, strerror(-k));
203 static int help(void) {
205 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
206 "Applies kernel sysctl settings.\n\n"
207 " -h --help Show this help\n"
208 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n",
209 program_invocation_short_name);
214 static int parse_argv(int argc, char *argv[]) {
220 static const struct option options[] = {
221 { "help", no_argument, NULL, 'h' },
222 { "prefix", required_argument, NULL, ARG_PREFIX },
231 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
243 for (p = optarg; *p; p++)
247 l = strv_append(arg_prefixes, optarg);
251 strv_free(arg_prefixes);
261 log_error("Unknown option code %c", c);
269 int main(int argc, char *argv[]) {
271 Hashmap *sysctl_options;
273 r = parse_argv(argc, argv);
275 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
277 log_set_target(LOG_TARGET_AUTO);
278 log_parse_environment();
283 sysctl_options = hashmap_new(string_hash_func, string_compare_func);
284 if (!sysctl_options) {
294 for (i = optind; i < argc; i++) {
295 k = parse_file(sysctl_options, argv[i], false);
300 _cleanup_strv_free_ char **files = NULL;
303 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
305 log_error("Failed to enumerate sysctl.d files: %s", strerror(-r));
309 STRV_FOREACH(f, files) {
310 k = parse_file(sysctl_options, *f, true);
316 k = apply_all(sysctl_options);
321 hashmap_free_free_free(sysctl_options);
322 strv_free(arg_prefixes);
324 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;