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