]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/sysctl/sysctl.c
udev: path_id - skip PCI-only-parents for block devices
[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
22#include <stdlib.h>
23#include <stdbool.h>
24#include <errno.h>
25#include <string.h>
8e1bd70d
LP
26#include <stdio.h>
27#include <limits.h>
7a2a0b90 28#include <getopt.h>
8e1bd70d
LP
29
30#include "log.h"
db1413d7 31#include "strv.h"
8e1bd70d 32#include "util.h"
f68c5a70 33#include "strv.h"
8e1bd70d
LP
34
35#define PROC_SYS_PREFIX "/proc/sys/"
36
f68c5a70 37static char **arg_prefixes = NULL;
7a2a0b90 38
c1b664d0 39static int apply_sysctl(const char *property, const char *value) {
8e1bd70d 40 char *p, *n;
c1b664d0 41 int r = 0, k;
8e1bd70d
LP
42
43 log_debug("Setting '%s' to '%s'", property, value);
44
7a2a0b90
LP
45 p = new(char, sizeof(PROC_SYS_PREFIX) + strlen(property));
46 if (!p) {
8e1bd70d 47 log_error("Out of memory");
c1b664d0 48 return -ENOMEM;
8e1bd70d
LP
49 }
50
51 n = stpcpy(p, PROC_SYS_PREFIX);
52 strcpy(n, property);
53
54 for (; *n; n++)
55 if (*n == '.')
56 *n = '/';
57
f68c5a70
LP
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 }
7a2a0b90
LP
73 }
74
75 k = write_one_line_file(p, value);
76 if (k < 0) {
5707631e 77
c1b664d0
LP
78 log_full(k == -ENOENT ? LOG_DEBUG : LOG_WARNING,
79 "Failed to write '%s' to '%s': %s", value, p, strerror(-k));
24a35973 80
c1b664d0
LP
81 if (k != -ENOENT && r == 0)
82 r = k;
8e1bd70d
LP
83 }
84
85 free(p);
c1b664d0
LP
86
87 return r;
8e1bd70d
LP
88}
89
c1b664d0 90static int apply_file(const char *path, bool ignore_enoent) {
8e1bd70d 91 FILE *f;
c1b664d0 92 int r = 0;
8e1bd70d
LP
93
94 assert(path);
95
96 if (!(f = fopen(path, "re"))) {
c1b664d0
LP
97 if (ignore_enoent && errno == ENOENT)
98 return 0;
99
8e1bd70d 100 log_error("Failed to open file '%s', ignoring: %m", path);
c1b664d0 101 return -errno;
8e1bd70d
LP
102 }
103
db1413d7 104 log_debug("apply: %s\n", path);
8e1bd70d
LP
105 while (!feof(f)) {
106 char l[LINE_MAX], *p, *value;
c1b664d0 107 int k;
8e1bd70d
LP
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);
c1b664d0 114 r = -errno;
8e1bd70d
LP
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);
c1b664d0
LP
128
129 if (r == 0)
130 r = -EINVAL;
8e1bd70d
LP
131 continue;
132 }
133
134 *value = 0;
135 value++;
136
c1b664d0
LP
137 if ((k = apply_sysctl(strstrip(p), strstrip(value))) < 0 && r == 0)
138 r = k;
8e1bd70d
LP
139 }
140
141finish:
142 fclose(f);
c1b664d0
LP
143
144 return r;
8e1bd70d
LP
145}
146
7a2a0b90
LP
147static 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
158static 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;
f68c5a70 185 char **l;
7a2a0b90
LP
186
187 for (p = optarg; *p; p++)
188 if (*p == '.')
189 *p = '/';
190
f68c5a70
LP
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;
7a2a0b90
LP
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
8e1bd70d 215int main(int argc, char *argv[]) {
c1b664d0 216 int r = 0;
8e1bd70d 217
7a2a0b90
LP
218 r = parse_argv(argc, argv);
219 if (r <= 0)
220 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
221
8e1bd70d
LP
222 log_set_target(LOG_TARGET_AUTO);
223 log_parse_environment();
224 log_open();
225
4c12626c
LP
226 umask(0022);
227
de19ece7
LP
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 {
db1413d7 239 char **files, **f;
de19ece7 240 int k;
c1b664d0 241
44143309 242 r = conf_files_list(&files, ".conf",
44143309 243 "/etc/sysctl.d",
fc1a2e06 244 "/run/sysctl.d",
40013ebc 245 "/usr/local/lib/sysctl.d",
44143309 246 "/usr/lib/sysctl.d",
de19ece7 247#ifdef HAVE_SPLIT_USR
223a3558 248 "/lib/sysctl.d",
de19ece7 249#endif
44143309
KS
250 NULL);
251 if (r < 0) {
252 log_error("Failed to enumerate sysctl.d files: %s", strerror(-r));
253 goto finish;
254 }
db1413d7
KS
255
256 STRV_FOREACH(f, files) {
db1413d7
KS
257 k = apply_file(*f, true);
258 if (k < 0 && r == 0)
259 r = k;
260 }
261
de19ece7
LP
262 k = apply_file("/etc/sysctl.conf", true);
263 if (k < 0 && r == 0)
264 r = k;
cb804011 265
db1413d7 266 strv_free(files);
8e1bd70d 267 }
44143309 268finish:
f68c5a70
LP
269 strv_free(arg_prefixes);
270
c1b664d0 271 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
8e1bd70d 272}