update-done.c revision 0a2f9085e29c855ec1aaa996ded00fc36b06210c
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder/***
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder This file is part of systemd.
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder Copyright 2014 Lennart Poettering
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder systemd is free software; you can redistribute it and/or modify it
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder under the terms of the GNU Lesser General Public License as published by
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder the Free Software Foundation; either version 2.1 of the License, or
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder (at your option) any later version.
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder systemd is distributed in the hope that it will be useful, but
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder WITHOUT ANY WARRANTY; without even the implied warranty of
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder Lesser General Public License for more details.
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder You should have received a copy of the GNU Lesser General Public License
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder along with systemd; If not, see <http://www.gnu.org/licenses/>.
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder***/
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder#include "util.h"
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder#include "selinux-util.h"
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder#define MESSAGE \
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder "This file was created by systemd-update-done. Its only \n" \
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder "purpose is to hold a timestamp of the time this directory\n" \
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder "was updated. See systemd-update-done.service(8).\n"
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederstatic int apply_timestamp(const char *path, struct timespec *ts) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder struct timespec twice[2] = {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder *ts,
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder *ts
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder };
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder struct stat st;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder assert(path);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder assert(ts);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder if (stat(path, &st) >= 0) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder /* Is the timestamp file already newer than the OS? If so, there's nothing to do. */
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder if (st.st_mtim.tv_sec > ts->tv_sec ||
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder (st.st_mtim.tv_sec == ts->tv_sec && st.st_mtim.tv_nsec >= ts->tv_nsec))
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder return 0;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder /* It is older? Then let's update it */
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder if (utimensat(AT_FDCWD, path, twice, AT_SYMLINK_NOFOLLOW) < 0) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder if (errno == EROFS)
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder return log_debug("Can't update timestamp file %s, file system is read-only.", path);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder }
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder } else if (errno == ENOENT) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder _cleanup_close_ int fd = -1;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder int r;
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder /* The timestamp file doesn't exist yet? Then let's create it. */
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = mac_selinux_create_file_prepare(path, S_IFREG);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder if (r < 0)
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder return log_error_errno(r, "Failed to set SELinux context for %s: %m", path);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder fd = open(path, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder mac_selinux_create_file_clear();
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder if (fd < 0) {
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder if (errno == EROFS)
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder return log_debug("Can't create timestamp file %s, file system is read-only.", path);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder return log_error_errno(errno, "Failed to create timestamp file %s: %m", path);
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder }
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder (void) loop_write(fd, MESSAGE, strlen(MESSAGE), false);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder if (futimens(fd, twice) < 0)
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder } else
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder log_error_errno(errno, "Failed to stat() timestamp file %s: %m", path);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder return 0;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder}
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederint main(int argc, char *argv[]) {
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder struct stat st;
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder int r, q = 0;
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder log_set_target(LOG_TARGET_AUTO);
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder log_parse_environment();
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder log_open();
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder if (stat("/usr", &st) < 0) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder log_error_errno(errno, "Failed to stat /usr: %m");
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder return EXIT_FAILURE;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder }
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder r = mac_selinux_init(NULL);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder if (r < 0) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder log_error_errno(r, "SELinux setup failed: %m");
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder goto finish;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder }
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = apply_timestamp("/etc/.updated", &st.st_mtim);
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder q = apply_timestamp("/var/.updated", &st.st_mtim);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederfinish:
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder return r < 0 || q < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
db9680b2bbd9d091b198eaa4e324762921965fb3Christian Maeder}
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder