]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/sysctl.c
umask: change default umask to 0022 just to be sure, and set it explicitly in all...
[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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
17
18 You should have received a copy of the GNU 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 if (argc-optind > 1) {
223 log_error("This program expects one or no arguments.");
224 return EXIT_FAILURE;
225 }
226
227 log_set_target(LOG_TARGET_AUTO);
228 log_parse_environment();
229 log_open();
230
231 umask(0022);
232
233 if (argc > optind)
234 r = apply_file(argv[optind], false);
235 else {
236 char **files, **f;
237
238 r = conf_files_list(&files, ".conf",
239 "/run/sysctl.d",
240 "/etc/sysctl.d",
241 "/usr/local/lib/sysctl.d",
242 "/usr/lib/sysctl.d",
243 "/lib/sysctl.d",
244 NULL);
245 if (r < 0) {
246 log_error("Failed to enumerate sysctl.d files: %s", strerror(-r));
247 goto finish;
248 }
249
250 STRV_FOREACH(f, files) {
251 int k;
252
253 k = apply_file(*f, true);
254 if (k < 0 && r == 0)
255 r = k;
256 }
257
258 apply_file("/etc/sysctl.conf", true);
259
260 strv_free(files);
261 }
262 finish:
263 strv_free(arg_prefixes);
264
265 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
266 }