]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/sysctl/sysctl.c
util-lib: split our string related calls from util.[ch] into its own file string...
[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
8e1bd70d 22#include <errno.h>
7a2a0b90 23#include <getopt.h>
3f6fd1ba
LP
24#include <limits.h>
25#include <stdbool.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
8e1bd70d 29
2c21044f 30#include "conf-files.h"
a5c32cff 31#include "fileio.h"
3f6fd1ba
LP
32#include "hashmap.h"
33#include "log.h"
34#include "path-util.h"
07630cea 35#include "string-util.h"
3f6fd1ba 36#include "strv.h"
88a60da0 37#include "sysctl-util.h"
3f6fd1ba 38#include "util.h"
8e1bd70d 39
fabe5c0e 40static char **arg_prefixes = NULL;
8e1bd70d 41
7f0a55d4 42static const char conf_file_dirs[] = CONF_DIRS_NULSTR("sysctl");
fabe5c0e 43
fabe5c0e 44static int apply_all(Hashmap *sysctl_options) {
86fc77c4
MS
45 char *property, *value;
46 Iterator i;
e50b33be 47 int r = 0;
fabe5c0e 48
86fc77c4
MS
49 HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) {
50 int k;
51
88a60da0
KS
52 k = sysctl_write(property, value);
53 if (k < 0) {
9bcfdd74 54 log_full_errno(k == -ENOENT ? LOG_INFO : LOG_WARNING, k,
384c5b44 55 "Couldn't write '%s' to '%s', ignoring: %m", value, property);
88a60da0 56
e50b33be 57 if (r == 0 && k != -ENOENT)
88a60da0
KS
58 r = k;
59 }
86fc77c4 60 }
e50b33be 61
86fc77c4
MS
62 return r;
63}
64
fabe5c0e
LP
65static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_enoent) {
66 _cleanup_fclose_ FILE *f = NULL;
67 int r;
8e1bd70d
LP
68
69 assert(path);
70
4cf7ea55 71 r = search_and_fopen_nulstr(path, "re", NULL, conf_file_dirs, &f);
fabe5c0e 72 if (r < 0) {
6f6fad96 73 if (ignore_enoent && r == -ENOENT)
c1b664d0
LP
74 return 0;
75
8d3d7072 76 return log_error_errno(r, "Failed to open file '%s', ignoring: %m", path);
8e1bd70d
LP
77 }
78
924bc14f 79 log_debug("Parsing %s", path);
8e1bd70d 80 while (!feof(f)) {
fabe5c0e 81 char l[LINE_MAX], *p, *value, *new_value, *property, *existing;
04bf3c1a 82 void *v;
fabe5c0e 83 int k;
8e1bd70d
LP
84
85 if (!fgets(l, sizeof(l), f)) {
86 if (feof(f))
87 break;
88
56f64d95 89 log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
fabe5c0e 90 return -errno;
8e1bd70d
LP
91 }
92
93 p = strstrip(l);
8e1bd70d
LP
94 if (!*p)
95 continue;
96
d3b6d0c2 97 if (strchr(COMMENTS "\n", *p))
8e1bd70d
LP
98 continue;
99
86fc77c4
MS
100 value = strchr(p, '=');
101 if (!value) {
8e1bd70d 102 log_error("Line is not an assignment in file '%s': %s", path, value);
c1b664d0
LP
103
104 if (r == 0)
105 r = -EINVAL;
8e1bd70d
LP
106 continue;
107 }
108
109 *value = 0;
110 value++;
111
88a60da0 112 p = sysctl_normalize(strstrip(p));
fabe5c0e
LP
113 value = strstrip(value);
114
b99802f7
UTL
115 if (!strv_isempty(arg_prefixes)) {
116 char **i, *t;
117 STRV_FOREACH(i, arg_prefixes) {
118 t = path_startswith(*i, "/proc/sys/");
119 if (t == NULL)
120 t = *i;
121 if (path_startswith(p, t))
122 goto found;
123 }
124 /* not found */
125 continue;
126 }
127
128found:
04bf3c1a 129 existing = hashmap_get2(sysctl_options, p, &v);
fabe5c0e 130 if (existing) {
04bf3c1a
KS
131 if (streq(value, existing))
132 continue;
fabe5c0e 133
7933e426 134 log_debug("Overwriting earlier assignment of %s in file '%s'.", p, path);
04bf3c1a
KS
135 free(hashmap_remove(sysctl_options, p));
136 free(v);
86fc77c4
MS
137 }
138
fabe5c0e
LP
139 property = strdup(p);
140 if (!property)
141 return log_oom();
142
143 new_value = strdup(value);
86fc77c4
MS
144 if (!new_value) {
145 free(property);
fabe5c0e 146 return log_oom();
86fc77c4
MS
147 }
148
fabe5c0e
LP
149 k = hashmap_put(sysctl_options, property, new_value);
150 if (k < 0) {
da927ba9 151 log_error_errno(k, "Failed to add sysctl variable %s to hashmap: %m", property);
86fc77c4
MS
152 free(property);
153 free(new_value);
fabe5c0e 154 return k;
86fc77c4 155 }
8e1bd70d
LP
156 }
157
c1b664d0 158 return r;
8e1bd70d
LP
159}
160
601185b4 161static void help(void) {
7a2a0b90
LP
162 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
163 "Applies kernel sysctl settings.\n\n"
164 " -h --help Show this help\n"
eb9da376 165 " --version Show package version\n"
0e1f5792 166 " --prefix=PATH Only apply rules with the specified prefix\n"
601185b4 167 , program_invocation_short_name);
7a2a0b90
LP
168}
169
170static int parse_argv(int argc, char *argv[]) {
171
172 enum {
eb9da376 173 ARG_VERSION = 0x100,
7a2a0b90
LP
174 ARG_PREFIX
175 };
176
177 static const struct option options[] = {
178 { "help", no_argument, NULL, 'h' },
eb9da376 179 { "version", no_argument, NULL, ARG_VERSION },
7a2a0b90 180 { "prefix", required_argument, NULL, ARG_PREFIX },
eb9da376 181 {}
7a2a0b90
LP
182 };
183
184 int c;
185
186 assert(argc >= 0);
187 assert(argv);
188
601185b4 189 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
7a2a0b90
LP
190
191 switch (c) {
192
193 case 'h':
601185b4
ZJS
194 help();
195 return 0;
eb9da376
LP
196
197 case ARG_VERSION:
3f6fd1ba 198 return version();
7a2a0b90
LP
199
200 case ARG_PREFIX: {
201 char *p;
202
0e1f5792
DH
203 /* We used to require people to specify absolute paths
204 * in /proc/sys in the past. This is kinda useless, but
205 * we need to keep compatibility. We now support any
206 * sysctl name available. */
88a60da0 207 sysctl_normalize(optarg);
e50b33be 208
0e1f5792
DH
209 if (startswith(optarg, "/proc/sys"))
210 p = strdup(optarg);
211 else
212 p = strappend("/proc/sys/", optarg);
0e1f5792
DH
213 if (!p)
214 return log_oom();
e50b33be 215
0e1f5792 216 if (strv_consume(&arg_prefixes, p) < 0)
0d0f0c50 217 return log_oom();
f68c5a70 218
7a2a0b90
LP
219 break;
220 }
221
222 case '?':
223 return -EINVAL;
224
225 default:
eb9da376 226 assert_not_reached("Unhandled option");
7a2a0b90 227 }
7a2a0b90
LP
228
229 return 1;
230}
231
8e1bd70d 232int main(int argc, char *argv[]) {
0187f62b 233 int r = 0, k;
fabe5c0e 234 Hashmap *sysctl_options;
8e1bd70d 235
7a2a0b90
LP
236 r = parse_argv(argc, argv);
237 if (r <= 0)
238 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
239
8e1bd70d
LP
240 log_set_target(LOG_TARGET_AUTO);
241 log_parse_environment();
242 log_open();
243
4c12626c
LP
244 umask(0022);
245
d5099efc 246 sysctl_options = hashmap_new(&string_hash_ops);
86fc77c4
MS
247 if (!sysctl_options) {
248 r = log_oom();
249 goto finish;
250 }
251
0187f62b
LP
252 r = 0;
253
de19ece7
LP
254 if (argc > optind) {
255 int i;
256
257 for (i = optind; i < argc; i++) {
fabe5c0e
LP
258 k = parse_file(sysctl_options, argv[i], false);
259 if (k < 0 && r == 0)
de19ece7
LP
260 r = k;
261 }
262 } else {
fabe5c0e
LP
263 _cleanup_strv_free_ char **files = NULL;
264 char **f;
c1b664d0 265
fabe5c0e 266 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
44143309 267 if (r < 0) {
da927ba9 268 log_error_errno(r, "Failed to enumerate sysctl.d files: %m");
44143309
KS
269 goto finish;
270 }
db1413d7 271
fabe5c0e
LP
272 STRV_FOREACH(f, files) {
273 k = parse_file(sysctl_options, *f, true);
274 if (k < 0 && r == 0)
db1413d7
KS
275 r = k;
276 }
8e1bd70d 277 }
86fc77c4 278
fabe5c0e
LP
279 k = apply_all(sysctl_options);
280 if (k < 0 && r == 0)
0187f62b
LP
281 r = k;
282
44143309 283finish:
fabe5c0e 284 hashmap_free_free_free(sysctl_options);
f68c5a70
LP
285 strv_free(arg_prefixes);
286
c1b664d0 287 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
8e1bd70d 288}