tzsetup: symlink /etc/localtime instead of copying

Using a symlink means that new timezone data (installed by an errata
update, say) will be usable without having to be copied again.

Reviewed by:	bapt, kevans, philip
Sponsored by:	The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D37005
This commit is contained in:
Ed Maste 2022-10-14 12:44:35 -04:00
parent c4dacfa7f4
commit 5e16809c95
2 changed files with 27 additions and 94 deletions

View file

@ -52,7 +52,7 @@ The following options are available:
Open all files and directories relative to Open all files and directories relative to
.Ar chroot_directory . .Ar chroot_directory .
.It Fl n .It Fl n
Do not create or copy files. Do not create or symlink files.
.It Fl r .It Fl r
Reinstall the zoneinfo file installed last time. Reinstall the zoneinfo file installed last time.
The name is obtained from The name is obtained from

View file

@ -744,109 +744,42 @@ static void message_zoneinfo_file(const char *title, char *prompt)
static int static int
install_zoneinfo_file(const char *zoneinfo_file) install_zoneinfo_file(const char *zoneinfo_file)
{ {
char buf[1024];
char prompt[SILLY_BUFFER_SIZE]; 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 #ifdef VERBOSE
if (copymode) snprintf(prompt, sizeof(prompt), "Creating symbolic link %s to %s",
snprintf(prompt, sizeof(prompt), path_localtime, zoneinfo_file);
"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); message_zoneinfo_file("Info", prompt);
#endif #endif
if (reallydoit) { if (reallydoit) {
if (copymode) { if (access(zoneinfo_file, R_OK) != 0) {
fd1 = open(zoneinfo_file, O_RDONLY, 0); snprintf(prompt, sizeof(prompt),
if (fd1 < 0) { "Cannot access %s: %s", zoneinfo_file,
snprintf(prompt, sizeof(prompt), strerror(errno));
"Could not open %s: %s", zoneinfo_file, message_zoneinfo_file("Error", prompt);
strerror(errno)); return (DITEM_FAILURE | DITEM_RECREATE);
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",
if (unlink(path_localtime) < 0 && errno != ENOENT) { path_localtime, strerror(errno));
snprintf(prompt, sizeof(prompt), message_zoneinfo_file("Error", prompt);
"Could not delete %s: %s", return (DITEM_FAILURE | DITEM_RECREATE);
path_localtime, strerror(errno)); }
message_zoneinfo_file("Error", prompt); if (symlink(zoneinfo_file, path_localtime) < 0) {
return (DITEM_FAILURE | DITEM_RECREATE); snprintf(prompt, sizeof(prompt),
} "Cannot create symbolic link %s to %s: %s",
path_localtime, zoneinfo_file,
fd2 = open(path_localtime, O_CREAT | O_EXCL | O_WRONLY, strerror(errno));
S_IRUSR | S_IRGRP | S_IROTH); message_zoneinfo_file("Error", prompt);
if (fd2 < 0) { return (DITEM_FAILURE | DITEM_RECREATE);
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 #ifdef VERBOSE
if (copymode) snprintf(prompt, sizeof(prompt),
snprintf(prompt, sizeof(prompt), "Created symbolic link from %s to %s", zoneinfo_file,
"Copied timezone file from %s to %s", path_localtime);
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); message_zoneinfo_file("Done", prompt);
#endif #endif
} /* reallydoit */ } /* reallydoit */