git: 06a6d0259fe5 - stable/14 - Revert "tzsetup: symlink /etc/localtime instead of copying"
Date: Sat, 21 Sep 2024 11:10:34 UTC
The branch stable/14 has been updated by emaste: URL: https://cgit.FreeBSD.org/src/commit/?id=06a6d0259fe5721bfb3b745b231ecf7cf3a5e28e commit 06a6d0259fe5721bfb3b745b231ecf7cf3a5e28e Author: Ed Maste <emaste@FreeBSD.org> AuthorDate: 2024-09-21 11:06:02 +0000 Commit: Ed Maste <emaste@FreeBSD.org> CommitDate: 2024-09-21 11:06:39 +0000 Revert "tzsetup: symlink /etc/localtime instead of copying" This failed when used with tzsetup's -C option (for example, when using etcupdate -D to update a jail from the host). Revert the stable/14 MFC for now; will be reapplied after being fixed in main.. This reverts commit fc43a1b6842afa806dfd7ba48de5bece63d04456. This reverts commit 87f7f0389f8b7bf30ef12df5c0d337cb2789883e. --- usr.sbin/etcupdate/tests/tzsetup_test.sh | 5 +- usr.sbin/tzsetup/tzsetup.8 | 2 +- usr.sbin/tzsetup/tzsetup.c | 119 ++++++++++++++++++++++++------- 3 files changed, 96 insertions(+), 30 deletions(-) diff --git a/usr.sbin/etcupdate/tests/tzsetup_test.sh b/usr.sbin/etcupdate/tests/tzsetup_test.sh index 155830bddae7..dd76884e13eb 100644 --- a/usr.sbin/etcupdate/tests/tzsetup_test.sh +++ b/usr.sbin/etcupdate/tests/tzsetup_test.sh @@ -232,8 +232,7 @@ echo "Differences for real update:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \ || FAILED=yes -# XXX tzsetup installs a symlink as of 5e16809c953f -#file /etc/localtime "foo" -#file /var/db/zoneinfo "foo" +file /etc/localtime "foo" +file /var/db/zoneinfo "foo" [ "${FAILED}" = no ] diff --git a/usr.sbin/tzsetup/tzsetup.8 b/usr.sbin/tzsetup/tzsetup.8 index 499d25765541..bfa625a1af3a 100644 --- a/usr.sbin/tzsetup/tzsetup.8 +++ b/usr.sbin/tzsetup/tzsetup.8 @@ -52,7 +52,7 @@ The following options are available: Open all files and directories relative to .Ar chroot_directory . .It Fl n -Do not create or symlink files. +Do not create or copy files. .It Fl r Reinstall the zoneinfo file installed last time. The name is obtained from diff --git a/usr.sbin/tzsetup/tzsetup.c b/usr.sbin/tzsetup/tzsetup.c index 617de4efb765..6cd2e16b607c 100644 --- a/usr.sbin/tzsetup/tzsetup.c +++ b/usr.sbin/tzsetup/tzsetup.c @@ -744,42 +744,109 @@ static void message_zoneinfo_file(const char *title, char *prompt) static int install_zoneinfo_file(const char *zoneinfo_file) { + char buf[1024]; char prompt[SILLY_BUFFER_SIZE]; + struct stat sb; + ssize_t len; + int fd1, fd2, copymode; + + if (lstat(path_localtime, &sb) < 0) { + /* Nothing there yet... */ + copymode = 1; + } else if (S_ISLNK(sb.st_mode)) + copymode = 0; + else + copymode = 1; #ifdef VERBOSE - snprintf(prompt, sizeof(prompt), "Creating symbolic link %s to %s", - path_localtime, zoneinfo_file); + if (copymode) + snprintf(prompt, sizeof(prompt), + "Copying %s to %s", zoneinfo_file, path_localtime); + else + snprintf(prompt, sizeof(prompt), + "Creating symbolic link %s to %s", + path_localtime, zoneinfo_file); message_zoneinfo_file("Info", prompt); #endif if (reallydoit) { - if (access(zoneinfo_file, R_OK) != 0) { - snprintf(prompt, sizeof(prompt), - "Cannot access %s: %s", zoneinfo_file, - strerror(errno)); - message_zoneinfo_file("Error", prompt); - return (DITEM_FAILURE | DITEM_RECREATE); - } - if (unlink(path_localtime) < 0 && errno != ENOENT) { - snprintf(prompt, sizeof(prompt), - "Could not delete %s: %s", - path_localtime, strerror(errno)); - message_zoneinfo_file("Error", prompt); - return (DITEM_FAILURE | DITEM_RECREATE); - } - if (symlink(zoneinfo_file, path_localtime) < 0) { - snprintf(prompt, sizeof(prompt), - "Cannot create symbolic link %s to %s: %s", - path_localtime, zoneinfo_file, - strerror(errno)); - message_zoneinfo_file("Error", prompt); - return (DITEM_FAILURE | DITEM_RECREATE); + if (copymode) { + fd1 = open(zoneinfo_file, O_RDONLY, 0); + if (fd1 < 0) { + snprintf(prompt, sizeof(prompt), + "Could not open %s: %s", zoneinfo_file, + strerror(errno)); + message_zoneinfo_file("Error", prompt); + return (DITEM_FAILURE | DITEM_RECREATE); + } + + if (unlink(path_localtime) < 0 && errno != ENOENT) { + snprintf(prompt, sizeof(prompt), + "Could not delete %s: %s", + path_localtime, strerror(errno)); + message_zoneinfo_file("Error", prompt); + return (DITEM_FAILURE | DITEM_RECREATE); + } + + fd2 = open(path_localtime, O_CREAT | O_EXCL | O_WRONLY, + S_IRUSR | S_IRGRP | S_IROTH); + if (fd2 < 0) { + snprintf(prompt, sizeof(prompt), + "Could not open %s: %s", + path_localtime, strerror(errno)); + message_zoneinfo_file("Error", prompt); + return (DITEM_FAILURE | DITEM_RECREATE); + } + + while ((len = read(fd1, buf, sizeof(buf))) > 0) + if ((len = write(fd2, buf, len)) < 0) + break; + + if (len == -1) { + snprintf(prompt, sizeof(prompt), + "Error copying %s to %s %s", zoneinfo_file, + path_localtime, strerror(errno)); + message_zoneinfo_file("Error", prompt); + /* Better to leave none than a corrupt one. */ + unlink(path_localtime); + return (DITEM_FAILURE | DITEM_RECREATE); + } + close(fd1); + close(fd2); + } else { + if (access(zoneinfo_file, R_OK) != 0) { + snprintf(prompt, sizeof(prompt), + "Cannot access %s: %s", zoneinfo_file, + strerror(errno)); + message_zoneinfo_file("Error", prompt); + return (DITEM_FAILURE | DITEM_RECREATE); + } + if (unlink(path_localtime) < 0 && errno != ENOENT) { + snprintf(prompt, sizeof(prompt), + "Could not delete %s: %s", + path_localtime, strerror(errno)); + message_zoneinfo_file("Error", prompt); + return (DITEM_FAILURE | DITEM_RECREATE); + } + if (symlink(zoneinfo_file, path_localtime) < 0) { + snprintf(prompt, sizeof(prompt), + "Cannot create symbolic link %s to %s: %s", + path_localtime, zoneinfo_file, + strerror(errno)); + message_zoneinfo_file("Error", prompt); + return (DITEM_FAILURE | DITEM_RECREATE); + } } #ifdef VERBOSE - snprintf(prompt, sizeof(prompt), - "Created symbolic link from %s to %s", zoneinfo_file, - path_localtime); + if (copymode) + snprintf(prompt, sizeof(prompt), + "Copied timezone file from %s to %s", + zoneinfo_file, path_localtime); + else + snprintf(prompt, sizeof(prompt), + "Created symbolic link from %s to %s", + zoneinfo_file, path_localtime); message_zoneinfo_file("Done", prompt); #endif } /* reallydoit */