]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/sysctl/sysctl.c
util: don't accept an empty peer label as valid
[thirdparty/systemd.git] / src / sysctl / sysctl.c
CommitLineData
8e1bd70d
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
8e1bd70d
LP
11 (at your option) any later version.
12
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
5430f7f2 16 Lesser General Public License for more details.
8e1bd70d 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
8e1bd70d
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <stdlib.h>
23#include <stdbool.h>
24#include <errno.h>
25#include <string.h>
8e1bd70d
LP
26#include <stdio.h>
27#include <limits.h>
7a2a0b90 28#include <getopt.h>
8e1bd70d
LP
29
30#include "log.h"
db1413d7 31#include "strv.h"
8e1bd70d 32#include "util.h"
86fc77c4 33#include "hashmap.h"
9eb977db 34#include "path-util.h"
2c21044f 35#include "conf-files.h"
a5c32cff 36#include "fileio.h"
eb9da376 37#include "build.h"
8e1bd70d 38
fabe5c0e 39static char **arg_prefixes = NULL;
8e1bd70d 40
fabe5c0e
LP
41static const char conf_file_dirs[] =
42 "/etc/sysctl.d\0"
43 "/run/sysctl.d\0"
44 "/usr/local/lib/sysctl.d\0"
45 "/usr/lib/sysctl.d\0"
46#ifdef HAVE_SPLIT_USR
47 "/lib/sysctl.d\0"
48#endif
49 ;
50
51static char *normalize_sysctl(char *s) {
52 char *n;
53
54 for (n = s; *n; n++)
55 if (*n == '.')
56 *n = '/';
57
58 return s;
59}
7a2a0b90 60
c1b664d0 61static int apply_sysctl(const char *property, const char *value) {
fabe5c0e
LP
62 _cleanup_free_ char *p = NULL;
63 char *n;
c1b664d0 64 int r = 0, k;
8e1bd70d
LP
65
66 log_debug("Setting '%s' to '%s'", property, value);
67
fabe5c0e 68 p = new(char, sizeof("/proc/sys/") + strlen(property));
0d0f0c50
SL
69 if (!p)
70 return log_oom();
8e1bd70d 71
fabe5c0e 72 n = stpcpy(p, "/proc/sys/");
8e1bd70d
LP
73 strcpy(n, property);
74
f68c5a70
LP
75 if (!strv_isempty(arg_prefixes)) {
76 char **i;
77 bool good = false;
78
79 STRV_FOREACH(i, arg_prefixes)
80 if (path_startswith(p, *i)) {
81 good = true;
82 break;
83 }
84
85 if (!good) {
86 log_debug("Skipping %s", p);
f68c5a70
LP
87 return 0;
88 }
7a2a0b90
LP
89 }
90
574d5f2d 91 k = write_string_file(p, value);
7a2a0b90 92 if (k < 0) {
c1b664d0
LP
93 log_full(k == -ENOENT ? LOG_DEBUG : LOG_WARNING,
94 "Failed to write '%s' to '%s': %s", value, p, strerror(-k));
24a35973 95
c1b664d0
LP
96 if (k != -ENOENT && r == 0)
97 r = k;
8e1bd70d
LP
98 }
99
c1b664d0 100 return r;
8e1bd70d
LP
101}
102
fabe5c0e 103static int apply_all(Hashmap *sysctl_options) {
86fc77c4
MS
104 int r = 0;
105 char *property, *value;
106 Iterator i;
107
fabe5c0e
LP
108 assert(sysctl_options);
109
86fc77c4
MS
110 HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) {
111 int k;
112
113 k = apply_sysctl(property, value);
114 if (k < 0 && r == 0)
115 r = k;
116 }
117 return r;
118}
119
fabe5c0e
LP
120static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_enoent) {
121 _cleanup_fclose_ FILE *f = NULL;
122 int r;
8e1bd70d
LP
123
124 assert(path);
125
fabe5c0e
LP
126 r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f);
127 if (r < 0) {
6f6fad96 128 if (ignore_enoent && r == -ENOENT)
c1b664d0
LP
129 return 0;
130
fabe5c0e
LP
131 log_error("Failed to open file '%s', ignoring: %s", path, strerror(-r));
132 return r;
8e1bd70d
LP
133 }
134
86fc77c4 135 log_debug("parse: %s\n", path);
8e1bd70d 136 while (!feof(f)) {
fabe5c0e 137 char l[LINE_MAX], *p, *value, *new_value, *property, *existing;
04bf3c1a 138 void *v;
fabe5c0e 139 int k;
8e1bd70d
LP
140
141 if (!fgets(l, sizeof(l), f)) {
142 if (feof(f))
143 break;
144
145 log_error("Failed to read file '%s', ignoring: %m", path);
fabe5c0e 146 return -errno;
8e1bd70d
LP
147 }
148
149 p = strstrip(l);
8e1bd70d
LP
150 if (!*p)
151 continue;
152
d3b6d0c2 153 if (strchr(COMMENTS "\n", *p))
8e1bd70d
LP
154 continue;
155
86fc77c4
MS
156 value = strchr(p, '=');
157 if (!value) {
8e1bd70d 158 log_error("Line is not an assignment in file '%s': %s", path, value);
c1b664d0
LP
159
160 if (r == 0)
161 r = -EINVAL;
8e1bd70d
LP
162 continue;
163 }
164
165 *value = 0;
166 value++;
167
fabe5c0e
LP
168 p = normalize_sysctl(strstrip(p));
169 value = strstrip(value);
170
04bf3c1a 171 existing = hashmap_get2(sysctl_options, p, &v);
fabe5c0e 172 if (existing) {
04bf3c1a
KS
173 if (streq(value, existing))
174 continue;
fabe5c0e 175
04bf3c1a
KS
176 log_info("Overwriting earlier assignment of %s in file '%s'.", p, path);
177 free(hashmap_remove(sysctl_options, p));
178 free(v);
86fc77c4
MS
179 }
180
fabe5c0e
LP
181 property = strdup(p);
182 if (!property)
183 return log_oom();
184
185 new_value = strdup(value);
86fc77c4
MS
186 if (!new_value) {
187 free(property);
fabe5c0e 188 return log_oom();
86fc77c4
MS
189 }
190
fabe5c0e
LP
191 k = hashmap_put(sysctl_options, property, new_value);
192 if (k < 0) {
04bf3c1a 193 log_error("Failed to add sysctl variable %s to hashmap: %s", property, strerror(-k));
86fc77c4
MS
194 free(property);
195 free(new_value);
fabe5c0e 196 return k;
86fc77c4 197 }
8e1bd70d
LP
198 }
199
c1b664d0 200 return r;
8e1bd70d
LP
201}
202
7a2a0b90
LP
203static int help(void) {
204
205 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
206 "Applies kernel sysctl settings.\n\n"
207 " -h --help Show this help\n"
eb9da376 208 " --version Show package version\n"
7a2a0b90
LP
209 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n",
210 program_invocation_short_name);
211
212 return 0;
213}
214
215static int parse_argv(int argc, char *argv[]) {
216
217 enum {
eb9da376 218 ARG_VERSION = 0x100,
7a2a0b90
LP
219 ARG_PREFIX
220 };
221
222 static const struct option options[] = {
223 { "help", no_argument, NULL, 'h' },
eb9da376 224 { "version", no_argument, NULL, ARG_VERSION },
7a2a0b90 225 { "prefix", required_argument, NULL, ARG_PREFIX },
eb9da376 226 {}
7a2a0b90
LP
227 };
228
229 int c;
230
231 assert(argc >= 0);
232 assert(argv);
233
234 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
235
236 switch (c) {
237
238 case 'h':
eb9da376
LP
239 return help();
240
241 case ARG_VERSION:
242 puts(PACKAGE_STRING);
243 puts(SYSTEMD_FEATURES);
7a2a0b90
LP
244 return 0;
245
246 case ARG_PREFIX: {
247 char *p;
f68c5a70 248 char **l;
7a2a0b90
LP
249
250 for (p = optarg; *p; p++)
251 if (*p == '.')
252 *p = '/';
253
f68c5a70 254 l = strv_append(arg_prefixes, optarg);
0d0f0c50
SL
255 if (!l)
256 return log_oom();
f68c5a70
LP
257
258 strv_free(arg_prefixes);
259 arg_prefixes = l;
7a2a0b90
LP
260
261 break;
262 }
263
264 case '?':
265 return -EINVAL;
266
267 default:
eb9da376 268 assert_not_reached("Unhandled option");
7a2a0b90
LP
269 }
270 }
271
272 return 1;
273}
274
8e1bd70d 275int main(int argc, char *argv[]) {
0187f62b 276 int r = 0, k;
fabe5c0e 277 Hashmap *sysctl_options;
8e1bd70d 278
7a2a0b90
LP
279 r = parse_argv(argc, argv);
280 if (r <= 0)
281 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
282
8e1bd70d
LP
283 log_set_target(LOG_TARGET_AUTO);
284 log_parse_environment();
285 log_open();
286
4c12626c
LP
287 umask(0022);
288
86fc77c4
MS
289 sysctl_options = hashmap_new(string_hash_func, string_compare_func);
290 if (!sysctl_options) {
291 r = log_oom();
292 goto finish;
293 }
294
0187f62b
LP
295 r = 0;
296
de19ece7
LP
297 if (argc > optind) {
298 int i;
299
300 for (i = optind; i < argc; i++) {
fabe5c0e
LP
301 k = parse_file(sysctl_options, argv[i], false);
302 if (k < 0 && r == 0)
de19ece7
LP
303 r = k;
304 }
305 } else {
fabe5c0e
LP
306 _cleanup_strv_free_ char **files = NULL;
307 char **f;
c1b664d0 308
fabe5c0e 309 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
44143309
KS
310 if (r < 0) {
311 log_error("Failed to enumerate sysctl.d files: %s", strerror(-r));
312 goto finish;
313 }
db1413d7 314
fabe5c0e
LP
315 STRV_FOREACH(f, files) {
316 k = parse_file(sysctl_options, *f, true);
317 if (k < 0 && r == 0)
db1413d7
KS
318 r = k;
319 }
8e1bd70d 320 }
86fc77c4 321
fabe5c0e
LP
322 k = apply_all(sysctl_options);
323 if (k < 0 && r == 0)
0187f62b
LP
324 r = k;
325
44143309 326finish:
fabe5c0e 327 hashmap_free_free_free(sysctl_options);
f68c5a70
LP
328 strv_free(arg_prefixes);
329
c1b664d0 330 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
8e1bd70d 331}