]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/sysctl/sysctl.c
util: split-out conf-file.[ch]
[thirdparty/systemd.git] / src / sysctl / sysctl.c
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
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.
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
16 Lesser General Public License for more details.
17
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/>.
20 ***/
21
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <limits.h>
28 #include <getopt.h>
29
30 #include "log.h"
31 #include "strv.h"
32 #include "util.h"
33 #include "strv.h"
34 #include "conf-files.h"
35
36 #define PROC_SYS_PREFIX "/proc/sys/"
37
38 static char **arg_prefixes = NULL;
39
40 static int apply_sysctl(const char *property, const char *value) {
41 char *p, *n;
42 int r = 0, k;
43
44 log_debug("Setting '%s' to '%s'", property, value);
45
46 p = new(char, sizeof(PROC_SYS_PREFIX) + strlen(property));
47 if (!p) {
48 log_error("Out of memory");
49 return -ENOMEM;
50 }
51
52 n = stpcpy(p, PROC_SYS_PREFIX);
53 strcpy(n, property);
54
55 for (; *n; n++)
56 if (*n == '.')
57 *n = '/';
58
59 if (!strv_isempty(arg_prefixes)) {
60 char **i;
61 bool good = false;
62
63 STRV_FOREACH(i, arg_prefixes)
64 if (path_startswith(p, *i)) {
65 good = true;
66 break;
67 }
68
69 if (!good) {
70 log_debug("Skipping %s", p);
71 free(p);
72 return 0;
73 }
74 }
75
76 k = write_one_line_file(p, value);
77 if (k < 0) {
78
79 log_full(k == -ENOENT ? LOG_DEBUG : LOG_WARNING,
80 "Failed to write '%s' to '%s': %s", value, p, strerror(-k));
81
82 if (k != -ENOENT && r == 0)
83 r = k;
84 }
85
86 free(p);
87
88 return r;
89 }
90
91 static int apply_file(const char *path, bool ignore_enoent) {
92 FILE *f;
93 int r = 0;
94
95 assert(path);
96
97 if (!(f = fopen(path, "re"))) {
98 if (ignore_enoent && errno == ENOENT)
99 return 0;
100
101 log_error("Failed to open file '%s', ignoring: %m", path);
102 return -errno;
103 }
104
105 log_debug("apply: %s\n", path);
106 while (!feof(f)) {
107 char l[LINE_MAX], *p, *value;
108 int k;
109
110 if (!fgets(l, sizeof(l), f)) {
111 if (feof(f))
112 break;
113
114 log_error("Failed to read file '%s', ignoring: %m", path);
115 r = -errno;
116 goto finish;
117 }
118
119 p = strstrip(l);
120
121 if (!*p)
122 continue;
123
124 if (strchr(COMMENTS, *p))
125 continue;
126
127 if (!(value = strchr(p, '='))) {
128 log_error("Line is not an assignment in file '%s': %s", path, value);
129
130 if (r == 0)
131 r = -EINVAL;
132 continue;
133 }
134
135 *value = 0;
136 value++;
137
138 if ((k = apply_sysctl(strstrip(p), strstrip(value))) < 0 && r == 0)
139 r = k;
140 }
141
142 finish:
143 fclose(f);
144
145 return r;
146 }
147
148 static int help(void) {
149
150 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
151 "Applies kernel sysctl settings.\n\n"
152 " -h --help Show this help\n"
153 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n",
154 program_invocation_short_name);
155
156 return 0;
157 }
158
159 static int parse_argv(int argc, char *argv[]) {
160
161 enum {
162 ARG_PREFIX
163 };
164
165 static const struct option options[] = {
166 { "help", no_argument, NULL, 'h' },
167 { "prefix", required_argument, NULL, ARG_PREFIX },
168 { NULL, 0, NULL, 0 }
169 };
170
171 int c;
172
173 assert(argc >= 0);
174 assert(argv);
175
176 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
177
178 switch (c) {
179
180 case 'h':
181 help();
182 return 0;
183
184 case ARG_PREFIX: {
185 char *p;
186 char **l;
187
188 for (p = optarg; *p; p++)
189 if (*p == '.')
190 *p = '/';
191
192 l = strv_append(arg_prefixes, optarg);
193 if (!l) {
194 log_error("Out of memory");
195 return -ENOMEM;
196 }
197
198 strv_free(arg_prefixes);
199 arg_prefixes = l;
200
201 break;
202 }
203
204 case '?':
205 return -EINVAL;
206
207 default:
208 log_error("Unknown option code %c", c);
209 return -EINVAL;
210 }
211 }
212
213 return 1;
214 }
215
216 int main(int argc, char *argv[]) {
217 int r = 0;
218
219 r = parse_argv(argc, argv);
220 if (r <= 0)
221 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
222
223 log_set_target(LOG_TARGET_AUTO);
224 log_parse_environment();
225 log_open();
226
227 umask(0022);
228
229 if (argc > optind) {
230 int i;
231
232 for (i = optind; i < argc; i++) {
233 int k;
234
235 k = apply_file(argv[i], false);
236 if (k < 0 && r == 0)
237 r = k;
238 }
239 } else {
240 char **files, **f;
241 int k;
242
243 r = conf_files_list(&files, ".conf",
244 "/etc/sysctl.d",
245 "/run/sysctl.d",
246 "/usr/local/lib/sysctl.d",
247 "/usr/lib/sysctl.d",
248 #ifdef HAVE_SPLIT_USR
249 "/lib/sysctl.d",
250 #endif
251 NULL);
252 if (r < 0) {
253 log_error("Failed to enumerate sysctl.d files: %s", strerror(-r));
254 goto finish;
255 }
256
257 STRV_FOREACH(f, files) {
258 k = apply_file(*f, true);
259 if (k < 0 && r == 0)
260 r = k;
261 }
262
263 k = apply_file("/etc/sysctl.conf", true);
264 if (k < 0 && r == 0)
265 r = k;
266
267 strv_free(files);
268 }
269 finish:
270 strv_free(arg_prefixes);
271
272 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
273 }