]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/update-done/update-done.c
util-lib: split out fd-related operations into fd-util.[ch]
[thirdparty/systemd.git] / src / update-done / update-done.c
CommitLineData
8ea48dfc
LP
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
3ffd4af2 22#include "fd-util.h"
d7b8eec7 23#include "selinux-util.h"
3ffd4af2 24#include "util.h"
8ea48dfc 25
4aa4d2ae
ZJS
26#define MESSAGE \
27 "This file was created by systemd-update-done. Its only \n" \
28 "purpose is to hold a timestamp of the time this directory\n" \
29 "was updated. See systemd-update-done.service(8).\n"
30
8ea48dfc 31static int apply_timestamp(const char *path, struct timespec *ts) {
0a2f9085
LP
32 struct timespec twice[2] = {
33 *ts,
34 *ts
35 };
8ea48dfc
LP
36 struct stat st;
37
38 assert(path);
39 assert(ts);
40
41 if (stat(path, &st) >= 0) {
329c5425
LP
42 /* Is the timestamp file already newer than the OS? If
43 * so, there's nothing to do. We ignore the nanosecond
44 * component of the timestamp, since some file systems
45 * do not support any better accuracy than 1s and we
46 * have no way to identify the accuracy
47 * available. Most notably ext4 on small disks (where
48 * 128 byte inodes are used) does not support better
49 * accuracy than 1s. */
50 if (st.st_mtim.tv_sec > ts->tv_sec)
8ea48dfc
LP
51 return 0;
52
53 /* It is older? Then let's update it */
8ea48dfc
LP
54 if (utimensat(AT_FDCWD, path, twice, AT_SYMLINK_NOFOLLOW) < 0) {
55
755bde37
LP
56 if (errno == EROFS)
57 return log_debug("Can't update timestamp file %s, file system is read-only.", path);
8ea48dfc 58
755bde37 59 return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
8ea48dfc
LP
60 }
61
62 } else if (errno == ENOENT) {
63 _cleanup_close_ int fd = -1;
7dbb1d08 64 int r;
8ea48dfc
LP
65
66 /* The timestamp file doesn't exist yet? Then let's create it. */
67
ecabcf8b 68 r = mac_selinux_create_file_prepare(path, S_IFREG);
755bde37
LP
69 if (r < 0)
70 return log_error_errno(r, "Failed to set SELinux context for %s: %m", path);
7dbb1d08 71
8ea48dfc 72 fd = open(path, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
ecabcf8b 73 mac_selinux_create_file_clear();
7dbb1d08 74
8ea48dfc 75 if (fd < 0) {
755bde37
LP
76 if (errno == EROFS)
77 return log_debug("Can't create timestamp file %s, file system is read-only.", path);
8ea48dfc 78
755bde37 79 return log_error_errno(errno, "Failed to create timestamp file %s: %m", path);
8ea48dfc
LP
80 }
81
4aa4d2ae
ZJS
82 (void) loop_write(fd, MESSAGE, strlen(MESSAGE), false);
83
755bde37
LP
84 if (futimens(fd, twice) < 0)
85 return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
86 } else
87 log_error_errno(errno, "Failed to stat() timestamp file %s: %m", path);
8ea48dfc
LP
88
89 return 0;
90}
91
92int main(int argc, char *argv[]) {
93 struct stat st;
7dbb1d08 94 int r, q = 0;
8ea48dfc
LP
95
96 log_set_target(LOG_TARGET_AUTO);
97 log_parse_environment();
98 log_open();
99
100 if (stat("/usr", &st) < 0) {
755bde37 101 log_error_errno(errno, "Failed to stat /usr: %m");
8ea48dfc
LP
102 return EXIT_FAILURE;
103 }
104
cc56fafe 105 r = mac_selinux_init(NULL);
7dbb1d08 106 if (r < 0) {
da927ba9 107 log_error_errno(r, "SELinux setup failed: %m");
7dbb1d08
ZJS
108 goto finish;
109 }
8ea48dfc 110
7dbb1d08 111 r = apply_timestamp("/etc/.updated", &st.st_mtim);
8ea48dfc 112 q = apply_timestamp("/var/.updated", &st.st_mtim);
8ea48dfc 113
7dbb1d08
ZJS
114finish:
115 return r < 0 || q < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
8ea48dfc 116}