]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/generator.c
Merge pull request #6231 from keszybz/man-nss-resolved
[thirdparty/systemd.git] / src / shared / generator.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2014 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <unistd.h>
22
23 #include "alloc-util.h"
24 #include "dropin.h"
25 #include "escape.h"
26 #include "fd-util.h"
27 #include "fileio.h"
28 #include "fstab-util.h"
29 #include "generator.h"
30 #include "log.h"
31 #include "macro.h"
32 #include "mkdir.h"
33 #include "path-util.h"
34 #include "special.h"
35 #include "string-util.h"
36 #include "time-util.h"
37 #include "unit-name.h"
38 #include "util.h"
39
40 static int write_fsck_sysroot_service(const char *dir, const char *what) {
41 _cleanup_free_ char *device = NULL, *escaped = NULL;
42 _cleanup_fclose_ FILE *f = NULL;
43 const char *unit;
44 int r;
45
46 escaped = cescape(what);
47 if (!escaped)
48 return log_oom();
49
50 unit = strjoina(dir, "/systemd-fsck-root.service");
51 log_debug("Creating %s", unit);
52
53 r = unit_name_from_path(what, ".device", &device);
54 if (r < 0)
55 return log_error_errno(r, "Failed to convert device \"%s\" to unit name: %m", what);
56
57 f = fopen(unit, "wxe");
58 if (!f)
59 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
60
61 fprintf(f,
62 "# Automatically generated by %1$s\n\n"
63 "[Unit]\n"
64 "Documentation=man:systemd-fsck-root.service(8)\n"
65 "Description=File System Check on %2$s\n"
66 "DefaultDependencies=no\n"
67 "BindsTo=%3$s\n"
68 "After=initrd-root-device.target local-fs-pre.target %3$s\n"
69 "Before=shutdown.target\n"
70 "\n"
71 "[Service]\n"
72 "Type=oneshot\n"
73 "RemainAfterExit=yes\n"
74 "ExecStart=" SYSTEMD_FSCK_PATH " %4$s\n"
75 "TimeoutSec=0\n",
76 program_invocation_short_name,
77 what,
78 device,
79 escaped);
80
81 r = fflush_and_check(f);
82 if (r < 0)
83 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
84
85 return 0;
86 }
87
88 int generator_write_fsck_deps(
89 FILE *f,
90 const char *dir,
91 const char *what,
92 const char *where,
93 const char *fstype) {
94
95 int r;
96
97 assert(f);
98 assert(dir);
99 assert(what);
100 assert(where);
101
102 if (!is_device_path(what)) {
103 log_warning("Checking was requested for \"%s\", but it is not a device.", what);
104 return 0;
105 }
106
107 if (!isempty(fstype) && !streq(fstype, "auto")) {
108 r = fsck_exists(fstype);
109 if (r < 0)
110 log_warning_errno(r, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what, fstype);
111 else if (r == 0) {
112 /* treat missing check as essentially OK */
113 log_debug("Checking was requested for %s, but fsck.%s does not exist.", what, fstype);
114 return 0;
115 }
116 }
117
118 if (path_equal(where, "/")) {
119 const char *lnk;
120
121 lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");
122
123 mkdir_parents(lnk, 0755);
124 if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-fsck-root.service", lnk) < 0)
125 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
126
127 } else {
128 _cleanup_free_ char *_fsck = NULL;
129 const char *fsck;
130
131 if (in_initrd() && path_equal(where, "/sysroot")) {
132 r = write_fsck_sysroot_service(dir, what);
133 if (r < 0)
134 return r;
135
136 fsck = "systemd-fsck-root.service";
137 } else {
138 r = unit_name_from_path_instance("systemd-fsck", what, ".service", &_fsck);
139 if (r < 0)
140 return log_error_errno(r, "Failed to create fsck service name: %m");
141
142 fsck = _fsck;
143 }
144
145 fprintf(f,
146 "Requires=%1$s\n"
147 "After=%1$s\n",
148 fsck);
149 }
150
151 return 0;
152 }
153
154 int generator_write_timeouts(
155 const char *dir,
156 const char *what,
157 const char *where,
158 const char *opts,
159 char **filtered) {
160
161 /* Allow configuration how long we wait for a device that
162 * backs a mount point to show up. This is useful to support
163 * endless device timeouts for devices that show up only after
164 * user input, like crypto devices. */
165
166 _cleanup_free_ char *node = NULL, *unit = NULL, *timeout = NULL;
167 usec_t u;
168 int r;
169
170 r = fstab_filter_options(opts, "comment=systemd.device-timeout\0"
171 "x-systemd.device-timeout\0",
172 NULL, &timeout, filtered);
173 if (r <= 0)
174 return r;
175
176 r = parse_sec_fix_0(timeout, &u);
177 if (r < 0) {
178 log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
179 return 0;
180 }
181
182 node = fstab_node_to_udev_node(what);
183 if (!node)
184 return log_oom();
185
186 r = unit_name_from_path(node, ".device", &unit);
187 if (r < 0)
188 return log_error_errno(r, "Failed to make unit name from path: %m");
189
190 return write_drop_in_format(dir, unit, 50, "device-timeout",
191 "# Automatically generated by %s\n\n"
192 "[Unit]\nJobRunningTimeoutSec=%s",
193 program_invocation_short_name, timeout);
194 }
195
196 int generator_write_device_deps(
197 const char *dir,
198 const char *what,
199 const char *where,
200 const char *opts) {
201
202 /* fstab records that specify _netdev option should apply the network
203 * ordering on the actual device depending on network connection. If we
204 * are not mounting real device (NFS, CIFS), we rely on _netdev effect
205 * on the mount unit itself. */
206
207 _cleanup_free_ char *node = NULL, *unit = NULL;
208 int r;
209
210 if (!fstab_test_option(opts, "_netdev\0"))
211 return 0;
212
213 node = fstab_node_to_udev_node(what);
214 if (!node)
215 return log_oom();
216
217 /* Nothing to apply dependencies to. */
218 if (!is_device_path(node))
219 return 0;
220
221 r = unit_name_from_path(node, ".device", &unit);
222 if (r < 0)
223 return log_error_errno(r, "Failed to make unit name from path: %m");
224
225 /* See mount_add_default_dependencies for explanation why we create such
226 * dependencies. */
227 return write_drop_in_format(dir, unit, 50, "netdev-dependencies",
228 "# Automatically generated by %s\n\n"
229 "[Unit]\n"
230 "After=" SPECIAL_NETWORK_ONLINE_TARGET " " SPECIAL_NETWORK_TARGET "\n"
231 "Wants=" SPECIAL_NETWORK_ONLINE_TARGET "\n",
232 program_invocation_short_name);
233 }
234
235 int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
236 _cleanup_free_ char *unit = NULL;
237 int r;
238
239 r = unit_name_from_path(what, ".device", &unit);
240 if (r < 0)
241 return log_error_errno(r, "Failed to make unit name from path: %m");
242
243 return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device",
244 "# Automatically generated by %s\n\n"
245 "[Unit]\nRequires=%s\nAfter=%s",
246 program_invocation_short_name, unit, unit);
247 }