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/>.
30 #include "conf-files.h"
36 #include "path-util.h"
37 #include "string-util.h"
39 #include "sysctl-util.h"
42 static char **arg_prefixes
= NULL
;
44 static const char conf_file_dirs
[] = CONF_PATHS_NULSTR("sysctl.d");
46 static int apply_all(Hashmap
*sysctl_options
) {
47 char *property
, *value
;
51 HASHMAP_FOREACH_KEY(value
, property
, sysctl_options
, i
) {
54 k
= sysctl_write(property
, value
);
56 log_full_errno(k
== -ENOENT
? LOG_INFO
: LOG_WARNING
, k
,
57 "Couldn't write '%s' to '%s', ignoring: %m", value
, property
);
59 if (r
== 0 && k
!= -ENOENT
)
67 static int parse_file(Hashmap
*sysctl_options
, const char *path
, bool ignore_enoent
) {
68 _cleanup_fclose_
FILE *f
= NULL
;
73 r
= search_and_fopen_nulstr(path
, "re", NULL
, conf_file_dirs
, &f
);
75 if (ignore_enoent
&& r
== -ENOENT
)
78 return log_error_errno(r
, "Failed to open file '%s', ignoring: %m", path
);
81 log_debug("Parsing %s", path
);
83 char l
[LINE_MAX
], *p
, *value
, *new_value
, *property
, *existing
;
87 if (!fgets(l
, sizeof(l
), f
)) {
91 return log_error_errno(errno
, "Failed to read file '%s', ignoring: %m", path
);
98 if (strchr(COMMENTS
"\n", *p
))
101 value
= strchr(p
, '=');
103 log_error("Line is not an assignment in file '%s': %s", path
, value
);
113 p
= sysctl_normalize(strstrip(p
));
114 value
= strstrip(value
);
116 if (!strv_isempty(arg_prefixes
)) {
118 STRV_FOREACH(i
, arg_prefixes
) {
119 t
= path_startswith(*i
, "/proc/sys/");
122 if (path_startswith(p
, t
))
130 existing
= hashmap_get2(sysctl_options
, p
, &v
);
132 if (streq(value
, existing
))
135 log_debug("Overwriting earlier assignment of %s in file '%s'.", p
, path
);
136 free(hashmap_remove(sysctl_options
, p
));
140 property
= strdup(p
);
144 new_value
= strdup(value
);
150 k
= hashmap_put(sysctl_options
, property
, new_value
);
152 log_error_errno(k
, "Failed to add sysctl variable %s to hashmap: %m", property
);
162 static void help(void) {
163 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
164 "Applies kernel sysctl settings.\n\n"
165 " -h --help Show this help\n"
166 " --version Show package version\n"
167 " --prefix=PATH Only apply rules with the specified prefix\n"
168 , program_invocation_short_name
);
171 static int parse_argv(int argc
, char *argv
[]) {
178 static const struct option options
[] = {
179 { "help", no_argument
, NULL
, 'h' },
180 { "version", no_argument
, NULL
, ARG_VERSION
},
181 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
190 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
204 /* We used to require people to specify absolute paths
205 * in /proc/sys in the past. This is kinda useless, but
206 * we need to keep compatibility. We now support any
207 * sysctl name available. */
208 sysctl_normalize(optarg
);
210 if (startswith(optarg
, "/proc/sys"))
213 p
= strappend("/proc/sys/", optarg
);
217 if (strv_consume(&arg_prefixes
, p
) < 0)
227 assert_not_reached("Unhandled option");
233 int main(int argc
, char *argv
[]) {
235 Hashmap
*sysctl_options
;
237 r
= parse_argv(argc
, argv
);
239 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;
241 log_set_target(LOG_TARGET_AUTO
);
242 log_parse_environment();
247 sysctl_options
= hashmap_new(&string_hash_ops
);
248 if (!sysctl_options
) {
258 for (i
= optind
; i
< argc
; i
++) {
259 k
= parse_file(sysctl_options
, argv
[i
], false);
264 _cleanup_strv_free_
char **files
= NULL
;
267 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, conf_file_dirs
);
269 log_error_errno(r
, "Failed to enumerate sysctl.d files: %m");
273 STRV_FOREACH(f
, files
) {
274 k
= parse_file(sysctl_options
, *f
, true);
280 k
= apply_all(sysctl_options
);
285 hashmap_free_free_free(sysctl_options
);
286 strv_free(arg_prefixes
);
288 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;