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