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_one_line_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 && errno == -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;
140 if (!fgets(l, sizeof(l), f)) {
144 log_error("Failed to read file '%s', ignoring: %m", path);
152 if (strchr(COMMENTS, *p))
155 value = strchr(p, '=');
157 log_error("Line is not an assignment in file '%s': %s", path, value);
167 p = normalize_sysctl(strstrip(p));
168 value = strstrip(value);
170 existing = hashmap_get(sysctl_options, p);
172 if (!streq(value, existing))
173 log_warning("Duplicate assignment of %s in file '%s', ignoring.",
179 property = strdup(p);
183 new_value = strdup(value);
189 k = hashmap_put(sysctl_options, property, new_value);
191 log_error("Failed to add sysctl variable %s to hashmap: %s", property, strerror(-r));
201 static int help(void) {
203 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
204 "Applies kernel sysctl settings.\n\n"
205 " -h --help Show this help\n"
206 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n",
207 program_invocation_short_name);
212 static int parse_argv(int argc, char *argv[]) {
218 static const struct option options[] = {
219 { "help", no_argument, NULL, 'h' },
220 { "prefix", required_argument, NULL, ARG_PREFIX },
229 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
241 for (p = optarg; *p; p++)
245 l = strv_append(arg_prefixes, optarg);
249 strv_free(arg_prefixes);
259 log_error("Unknown option code %c", c);
267 int main(int argc, char *argv[]) {
269 Hashmap *sysctl_options;
271 r = parse_argv(argc, argv);
273 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
275 log_set_target(LOG_TARGET_AUTO);
276 log_parse_environment();
281 sysctl_options = hashmap_new(string_hash_func, string_compare_func);
282 if (!sysctl_options) {
292 for (i = optind; i < argc; i++) {
293 k = parse_file(sysctl_options, argv[i], false);
298 _cleanup_strv_free_ char **files = NULL;
301 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
303 log_error("Failed to enumerate sysctl.d files: %s", strerror(-r));
307 r = parse_file(sysctl_options, "/etc/sysctl.conf", true);
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;