chiark / gitweb /
journalctl: clean up how we log errors
[elogind.git] / src / shared / generator.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 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 <unistd.h>
23
24 #include "util.h"
25 #include "special.h"
26 #include "mkdir.h"
27 #include "unit-name.h"
28 #include "generator.h"
29 #include "path-util.h"
30 #include "fstab-util.h"
31 #include "fileio.h"
32 #include "dropin.h"
33
34 static int write_fsck_sysroot_service(const char *dir, const char *what) {
35         const char *unit;
36         _cleanup_free_ char *device = NULL;
37         _cleanup_fclose_ FILE *f = NULL;
38         int r;
39
40         unit = strjoina(dir, "/systemd-fsck-root.service");
41         log_debug("Creating %s", unit);
42
43         r = unit_name_from_path(what, ".device", &device);
44         if (r < 0)
45                 return log_error_errno(r, "Failed to convert device \"%s\" to unit name: %m", what);
46
47         f = fopen(unit, "wxe");
48         if (!f)
49                 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
50
51         fprintf(f,
52                 "# Automatically generated by %1$s\n\n"
53                 "[Unit]\n"
54                 "Documentation=man:systemd-fsck-root.service(8)\n"
55                 "Description=File System Check on %2$s\n"
56                 "DefaultDependencies=no\n"
57                 "BindsTo=%3$s\n"
58                 "After=%3$s\n"
59                 "Before=shutdown.target\n"
60                 "\n"
61                 "[Service]\n"
62                 "Type=oneshot\n"
63                 "RemainAfterExit=yes\n"
64                 "ExecStart=/usr/lib/systemd/systemd-fsck %2$s\n"
65                 "TimeoutSec=0\n",
66                 program_invocation_short_name,
67                 what,
68                 device);
69
70         r = fflush_and_check(f);
71         if (r < 0)
72                 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
73
74         return 0;
75 }
76
77 int generator_write_fsck_deps(
78                 FILE *f,
79                 const char *dir,
80                 const char *what,
81                 const char *where,
82                 const char *fstype) {
83
84         int r;
85
86         assert(f);
87         assert(dir);
88         assert(what);
89         assert(where);
90
91         if (!is_device_path(what)) {
92                 log_warning("Checking was requested for \"%s\", but it is not a device.", what);
93                 return 0;
94         }
95
96         if (!isempty(fstype) && !streq(fstype, "auto")) {
97                 r = fsck_exists(fstype);
98                 if (r == -ENOENT) {
99                         /* treat missing check as essentially OK */
100                         log_debug_errno(r, "Checking was requested for %s, but fsck.%s does not exist: %m", what, fstype);
101                         return 0;
102                 } else if (r < 0)
103                         return log_warning_errno(r, "Checking was requested for %s, but fsck.%s cannot be used: %m", what, fstype);
104         }
105
106         if (path_equal(where, "/")) {
107                 char *lnk;
108
109                 lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");
110
111                 mkdir_parents(lnk, 0755);
112                 if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-fsck-root.service", lnk) < 0)
113                         return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
114
115         } else {
116                 _cleanup_free_ char *_fsck = NULL;
117                 const char *fsck;
118
119                 if (in_initrd() && path_equal(where, "/sysroot")) {
120                         r = write_fsck_sysroot_service(dir, what);
121                         if (r < 0)
122                                 return r;
123
124                         fsck = "systemd-fsck-root.service";
125                 } else {
126                         r = unit_name_from_path_instance("systemd-fsck", what, ".service", &_fsck);
127                         if (r < 0)
128                                 return log_error_errno(r, "Failed to create fsck service name: %m");
129
130                         fsck = _fsck;
131                 }
132
133                 fprintf(f,
134                         "RequiresOverridable=%1$s\n"
135                         "After=%1$s\n",
136                         fsck);
137         }
138
139         return 0;
140 }
141
142 int generator_write_timeouts(
143                 const char *dir,
144                 const char *what,
145                 const char *where,
146                 const char *opts,
147                 char **filtered) {
148
149         /* Allow configuration how long we wait for a device that
150          * backs a mount point to show up. This is useful to support
151          * endless device timeouts for devices that show up only after
152          * user input, like crypto devices. */
153
154         _cleanup_free_ char *node = NULL, *unit = NULL, *timeout = NULL;
155         usec_t u;
156         int r;
157
158         r = fstab_filter_options(opts, "comment=systemd.device-timeout\0" "x-systemd.device-timeout\0",
159                                  NULL, &timeout, filtered);
160         if (r <= 0)
161                 return r;
162
163         r = parse_sec(timeout, &u);
164         if (r < 0) {
165                 log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
166                 return 0;
167         }
168
169         node = fstab_node_to_udev_node(what);
170         if (!node)
171                 return log_oom();
172
173         r = unit_name_from_path(node, ".device", &unit);
174         if (r < 0)
175                 return log_error_errno(r, "Failed to make unit name from path: %m");
176
177         return write_drop_in_format(dir, unit, 50, "device-timeout",
178                                     "# Automatically generated by %s\n\n"
179                                     "[Unit]\nJobTimeoutSec=" USEC_FMT,
180                                     program_invocation_short_name,
181                                     u / USEC_PER_SEC);
182 }