chiark / gitweb /
use "Out of memory." consistantly (or with "\n")
[elogind.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 }