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/>.
34 #include "path-util.h"
35 #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) {
55 /* If the first separator is a slash, the path is
56 * assumed to be normalized and slashes remain slashes
57 * and dots remains dots. */
61 /* Otherwise, dots become slashes and slashes become
69 n = strpbrk(n + 1, "/.");
75 static int apply_sysctl(const char *property, const char *value) {
76 _cleanup_free_ char *p = NULL;
80 log_debug("Setting '%s' to '%s'", property, value);
82 p = new(char, strlen("/proc/sys/") + strlen(property) + 1);
86 n = stpcpy(p, "/proc/sys/");
89 if (!strv_isempty(arg_prefixes)) {
93 STRV_FOREACH(i, arg_prefixes)
94 if (path_startswith(p, *i)) {
100 log_debug("Skipping %s", p);
105 k = write_string_file(p, value);
107 log_full(k == -ENOENT ? LOG_DEBUG : LOG_WARNING,
108 "Failed to write '%s' to '%s': %s", value, p, strerror(-k));
110 if (k != -ENOENT && r == 0)
117 static int apply_all(Hashmap *sysctl_options) {
119 char *property, *value;
122 assert(sysctl_options);
124 HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) {
127 k = apply_sysctl(property, value);
134 static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_enoent) {
135 _cleanup_fclose_ FILE *f = NULL;
140 r = search_and_fopen_nulstr(path, "re", NULL, conf_file_dirs, &f);
142 if (ignore_enoent && r == -ENOENT)
145 log_error("Failed to open file '%s', ignoring: %s", path, strerror(-r));
149 log_debug("parse: %s", path);
151 char l[LINE_MAX], *p, *value, *new_value, *property, *existing;
155 if (!fgets(l, sizeof(l), f)) {
159 log_error("Failed to read file '%s', ignoring: %m", path);
167 if (strchr(COMMENTS "\n", *p))
170 value = strchr(p, '=');
172 log_error("Line is not an assignment in file '%s': %s", path, value);
182 p = normalize_sysctl(strstrip(p));
183 value = strstrip(value);
185 existing = hashmap_get2(sysctl_options, p, &v);
187 if (streq(value, existing))
190 log_info("Overwriting earlier assignment of %s in file '%s'.", p, path);
191 free(hashmap_remove(sysctl_options, p));
195 property = strdup(p);
199 new_value = strdup(value);
205 k = hashmap_put(sysctl_options, property, new_value);
207 log_error("Failed to add sysctl variable %s to hashmap: %s", property, strerror(-k));
217 static int help(void) {
219 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
220 "Applies kernel sysctl settings.\n\n"
221 " -h --help Show this help\n"
222 " --version Show package version\n"
223 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n",
224 program_invocation_short_name);
229 static int parse_argv(int argc, char *argv[]) {
236 static const struct option options[] = {
237 { "help", no_argument, NULL, 'h' },
238 { "version", no_argument, NULL, ARG_VERSION },
239 { "prefix", required_argument, NULL, ARG_PREFIX },
248 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
256 puts(PACKAGE_STRING);
257 puts(SYSTEMD_FEATURES);
263 for (p = optarg; *p; p++)
267 if (strv_extend(&arg_prefixes, optarg) < 0)
277 assert_not_reached("Unhandled option");
284 int main(int argc, char *argv[]) {
286 Hashmap *sysctl_options;
288 r = parse_argv(argc, argv);
290 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
292 log_set_target(LOG_TARGET_AUTO);
293 log_parse_environment();
298 sysctl_options = hashmap_new(string_hash_func, string_compare_func);
299 if (!sysctl_options) {
309 for (i = optind; i < argc; i++) {
310 k = parse_file(sysctl_options, argv[i], false);
315 _cleanup_strv_free_ char **files = NULL;
318 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
320 log_error("Failed to enumerate sysctl.d files: %s", strerror(-r));
324 STRV_FOREACH(f, files) {
325 k = parse_file(sysctl_options, *f, true);
331 k = apply_all(sysctl_options);
336 hashmap_free_free_free(sysctl_options);
337 strv_free(arg_prefixes);
339 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;