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