8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering/***
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering This file is part of systemd.
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering Copyright 2014 Lennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering systemd is free software; you can redistribute it and/or modify it
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering under the terms of the GNU Lesser General Public License as published by
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering (at your option) any later version.
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering systemd is distributed in the hope that it will be useful, but
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering Lesser General Public License for more details.
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering You should have received a copy of the GNU Lesser General Public License
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering***/
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "fd-util.h"
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#include "io-util.h"
d7b8eec7dc7fe307d3a08b32cf1a9ad4276ce6d5Lennart Poettering#include "selinux-util.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "util.h"
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
4aa4d2ae9717d0f8656528a3197bbc0c256380b1Zbigniew Jędrzejewski-Szmek#define MESSAGE \
4aa4d2ae9717d0f8656528a3197bbc0c256380b1Zbigniew Jędrzejewski-Szmek "This file was created by systemd-update-done. Its only \n" \
4aa4d2ae9717d0f8656528a3197bbc0c256380b1Zbigniew Jędrzejewski-Szmek "purpose is to hold a timestamp of the time this directory\n" \
4aa4d2ae9717d0f8656528a3197bbc0c256380b1Zbigniew Jędrzejewski-Szmek "was updated. See systemd-update-done.service(8).\n"
4aa4d2ae9717d0f8656528a3197bbc0c256380b1Zbigniew Jędrzejewski-Szmek
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poetteringstatic int apply_timestamp(const char *path, struct timespec *ts) {
0a2f9085e29c855ec1aaa996ded00fc36b06210cLennart Poettering struct timespec twice[2] = {
0a2f9085e29c855ec1aaa996ded00fc36b06210cLennart Poettering *ts,
0a2f9085e29c855ec1aaa996ded00fc36b06210cLennart Poettering *ts
0a2f9085e29c855ec1aaa996ded00fc36b06210cLennart Poettering };
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering struct stat st;
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering assert(path);
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering assert(ts);
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering if (stat(path, &st) >= 0) {
329c542585cd92cb905990e3bf59eda16fd88cfbLennart Poettering /* Is the timestamp file already newer than the OS? If
329c542585cd92cb905990e3bf59eda16fd88cfbLennart Poettering * so, there's nothing to do. We ignore the nanosecond
329c542585cd92cb905990e3bf59eda16fd88cfbLennart Poettering * component of the timestamp, since some file systems
329c542585cd92cb905990e3bf59eda16fd88cfbLennart Poettering * do not support any better accuracy than 1s and we
329c542585cd92cb905990e3bf59eda16fd88cfbLennart Poettering * have no way to identify the accuracy
329c542585cd92cb905990e3bf59eda16fd88cfbLennart Poettering * available. Most notably ext4 on small disks (where
329c542585cd92cb905990e3bf59eda16fd88cfbLennart Poettering * 128 byte inodes are used) does not support better
329c542585cd92cb905990e3bf59eda16fd88cfbLennart Poettering * accuracy than 1s. */
329c542585cd92cb905990e3bf59eda16fd88cfbLennart Poettering if (st.st_mtim.tv_sec > ts->tv_sec)
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering return 0;
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering /* It is older? Then let's update it */
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering if (utimensat(AT_FDCWD, path, twice, AT_SYMLINK_NOFOLLOW) < 0) {
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering if (errno == EROFS)
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering return log_debug("Can't update timestamp file %s, file system is read-only.", path);
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering }
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering } else if (errno == ENOENT) {
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering _cleanup_close_ int fd = -1;
7dbb1d08f66cd44b1296be3ee8e3629b989e19a8Zbigniew Jędrzejewski-Szmek int r;
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering /* The timestamp file doesn't exist yet? Then let's create it. */
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
ecabcf8b6edcc856ec2fd5bd43fc675a8fe04731Lennart Poettering r = mac_selinux_create_file_prepare(path, S_IFREG);
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering if (r < 0)
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering return log_error_errno(r, "Failed to set SELinux context for %s: %m", path);
7dbb1d08f66cd44b1296be3ee8e3629b989e19a8Zbigniew Jędrzejewski-Szmek
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering fd = open(path, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
ecabcf8b6edcc856ec2fd5bd43fc675a8fe04731Lennart Poettering mac_selinux_create_file_clear();
7dbb1d08f66cd44b1296be3ee8e3629b989e19a8Zbigniew Jędrzejewski-Szmek
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering if (fd < 0) {
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering if (errno == EROFS)
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering return log_debug("Can't create timestamp file %s, file system is read-only.", path);
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering return log_error_errno(errno, "Failed to create timestamp file %s: %m", path);
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering }
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
4aa4d2ae9717d0f8656528a3197bbc0c256380b1Zbigniew Jędrzejewski-Szmek (void) loop_write(fd, MESSAGE, strlen(MESSAGE), false);
4aa4d2ae9717d0f8656528a3197bbc0c256380b1Zbigniew Jędrzejewski-Szmek
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering if (futimens(fd, twice) < 0)
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering } else
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering log_error_errno(errno, "Failed to stat() timestamp file %s: %m", path);
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering return 0;
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering}
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poetteringint main(int argc, char *argv[]) {
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering struct stat st;
7dbb1d08f66cd44b1296be3ee8e3629b989e19a8Zbigniew Jędrzejewski-Szmek int r, q = 0;
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering log_set_target(LOG_TARGET_AUTO);
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering log_parse_environment();
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering log_open();
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering if (stat("/usr", &st) < 0) {
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poettering log_error_errno(errno, "Failed to stat /usr: %m");
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering return EXIT_FAILURE;
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering }
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
cc56fafeebf814ef035e549115cf1850e6473fa5WaLyong Cho r = mac_selinux_init(NULL);
7dbb1d08f66cd44b1296be3ee8e3629b989e19a8Zbigniew Jędrzejewski-Szmek if (r < 0) {
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "SELinux setup failed: %m");
7dbb1d08f66cd44b1296be3ee8e3629b989e19a8Zbigniew Jędrzejewski-Szmek goto finish;
7dbb1d08f66cd44b1296be3ee8e3629b989e19a8Zbigniew Jędrzejewski-Szmek }
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
7dbb1d08f66cd44b1296be3ee8e3629b989e19a8Zbigniew Jędrzejewski-Szmek r = apply_timestamp("/etc/.updated", &st.st_mtim);
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering q = apply_timestamp("/var/.updated", &st.st_mtim);
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering
7dbb1d08f66cd44b1296be3ee8e3629b989e19a8Zbigniew Jędrzejewski-Szmekfinish:
7dbb1d08f66cd44b1296be3ee8e3629b989e19a8Zbigniew Jędrzejewski-Szmek return r < 0 || q < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
8ea48dfcd33e8db0c01bf8c57c3bbcfdc3c86d4bLennart Poettering}