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