From owner-svn-src-stable@FreeBSD.ORG Thu Mar 31 06:29:16 2011 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 290B3106566C; Thu, 31 Mar 2011 06:29:16 +0000 (UTC) (envelope-from edwin@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 15ADA8FC0C; Thu, 31 Mar 2011 06:29:16 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id p2V6TG5T093914; Thu, 31 Mar 2011 06:29:16 GMT (envelope-from edwin@svn.freebsd.org) Received: (from edwin@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p2V6TG6n093911; Thu, 31 Mar 2011 06:29:16 GMT (envelope-from edwin@svn.freebsd.org) Message-Id: <201103310629.p2V6TG6n093911@svn.freebsd.org> From: Edwin Groothuis Date: Thu, 31 Mar 2011 06:29:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r220183 - stable/8/usr.sbin/tzsetup X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 31 Mar 2011 06:29:16 -0000 Author: edwin Date: Thu Mar 31 06:29:15 2011 New Revision: 220183 URL: http://svn.freebsd.org/changeset/base/220183 Log: MFC of 198254, 198255, 198350, 198267, 209190, 208831, 208830, 210243 198254: When tzsetup is run as non-root and the "CMOS clock question on UTC" is answered as No, it would abort without properly ending the dialog session. 198255: Make the usage of the default zoneinfo file to install clearer. 198350: - Add support for chrooted installs. - Add examples to the man-page. 198267: Instead of having to know which timezone was picked last time, you now can run "tzsetup -r" which will reinstall the last choice. This data is recorded in /var/db/zoneinfo. 209190: Use literal format strings. Found by clang. 208831: Add comment that this value is unused. It is obvious that it isn't used, but both clang and Coverity talk about it. 208830: When there is a problem with writing, also bail out. Found with the clang checker. 210243: Fix support for chrooted installs. Modified: stable/8/usr.sbin/tzsetup/tzsetup.8 stable/8/usr.sbin/tzsetup/tzsetup.c Directory Properties: stable/8/usr.sbin/tzsetup/ (props changed) Modified: stable/8/usr.sbin/tzsetup/tzsetup.8 ============================================================================== --- stable/8/usr.sbin/tzsetup/tzsetup.8 Thu Mar 31 06:11:49 2011 (r220182) +++ stable/8/usr.sbin/tzsetup/tzsetup.8 Thu Mar 31 06:29:15 2011 (r220183) @@ -31,8 +31,9 @@ .Nd set local timezone .Sh SYNOPSIS .Nm -.Op Fl ns -.Op Ar default +.Op Fl nrs +.Op Fl C Ar chroot directory +.Op Ar zoneinfo file | zoneinfo name .Sh DESCRIPTION The .Nm @@ -49,17 +50,26 @@ the hardware clock does not keep .Pp The following option is available: .Bl -tag -offset indent -width Fl +.It Fl C Ar chroot directory +Open all files and directories relative to +.Ar chroot directory . .It Fl n Do not create or copy files. +.It Fl r +Reinstall the zoneinfo file installed last time. The name is obtained from +.Pa /var/db/zoneinfo . .It Fl s Skip the initial question about adjusting the clock if not set to .Tn UTC . .El .Pp -It is possible to short-circuit the menu system by specifying a -.Ar default -on the command line; this is intended mainly for pre-configured -installation scripts. +It is possible to short-circuit the menu system by specifying the +location of a +.Ar zoneinfo file +or the name of the +.Ar zoneinfo name +on the command line; this is intended mainly for pre-configured installation +scripts or people who know which zoneinfo they want to install. .Sh TIMEZONE DATABASE The contents of the timezone database are indexed by .Pa /usr/share/zoneinfo/zone.tab . @@ -93,19 +103,36 @@ historically minded. .Sh FILES .Bl -tag -width /usr/share/zoneinfo/zone.tab -compact .It Pa /etc/localtime -current time zone file +current time zone file. .It Pa /etc/wall_cmos_clock see .Xr adjkerntz 8 . .It Pa /usr/share/misc/iso3166 mapping of .Tn ISO -3166 territory codes to names +3166 territory codes to names. .It Pa /usr/share/zoneinfo -directory for zoneinfo files +directory for zoneinfo files. .It Pa /usr/share/zoneinfo/zone.tab -mapping of timezone file to country and location +mapping of timezone file to country and location. +.It Pa /var/db/zoneinfo +saved name of the timezone file installed last. .El +.Sh EXAMPLES +Normal usage, to select the right zoneinfo file via the dialog-based +user interface: +.Dl # tzsetup +Install the file +.Pa /usr/share/zoneinfo/Australia/Sydney : +.Dl # tzsetup /usr/share/zoneinfo/Australia/Sydney +Install the zoneinfo file for Australia/Sydney, assumed to be located +in +.Pa /usr/share/zoneinfo : +.Dl # tzsetup Australia/Sydney +After a reinstall of the zoneinfo files, you can reinstall the +latest installed zoneinfo file: (as specified in +.Pa /var/db/zoneinfo ) +.Dl # tzsetup -r .Sh SEE ALSO .Xr date 1 , .Xr adjtime 2 , Modified: stable/8/usr.sbin/tzsetup/tzsetup.c ============================================================================== --- stable/8/usr.sbin/tzsetup/tzsetup.c Thu Mar 31 06:11:49 2011 (r220182) +++ stable/8/usr.sbin/tzsetup/tzsetup.c Thu Mar 31 06:29:15 2011 (r220183) @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -52,9 +53,17 @@ __FBSDID("$FreeBSD$"); #define _PATH_ISO3166 "/usr/share/misc/iso3166" #define _PATH_ZONEINFO "/usr/share/zoneinfo" #define _PATH_LOCALTIME "/etc/localtime" +#define _PATH_DB "/var/db/zoneinfo" #define _PATH_WALL_CMOS_CLOCK "/etc/wall_cmos_clock" +static char path_zonetab[MAXPATHLEN], path_iso3166[MAXPATHLEN], + path_zoneinfo[MAXPATHLEN], path_localtime[MAXPATHLEN], + path_db[MAXPATHLEN], path_wall_cmos_clock[MAXPATHLEN]; + static int reallydoit = 1; +static int reinstall = 0; +static int usedialog = 1; +static char *chrootenv = NULL; static void usage(void); static int continent_country_menu(dialogMenuItem *); @@ -193,15 +202,15 @@ read_iso3166_table(void) char *s, *t, *name; int lineno; - fp = fopen(_PATH_ISO3166, "r"); + fp = fopen(path_iso3166, "r"); if (!fp) - err(1, _PATH_ISO3166); + err(1, "%s", path_iso3166); lineno = 0; while ((s = fgetln(fp, &len)) != 0) { lineno++; if (s[len - 1] != '\n') - errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); + errx(1, "%s:%d: invalid format", path_iso3166, lineno); s[len - 1] = '\0'; if (s[0] == '#' || strspn(s, " \t") == len - 1) continue; @@ -209,26 +218,25 @@ read_iso3166_table(void) /* Isolate the two-letter code. */ t = strsep(&s, "\t"); if (t == 0 || strlen(t) != 2) - errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); + errx(1, "%s:%d: invalid format", path_iso3166, lineno); if (t[0] < 'A' || t[0] > 'Z' || t[1] < 'A' || t[1] > 'Z') - errx(1, _PATH_ISO3166 ":%d: invalid code `%s'", + errx(1, "%s:%d: invalid code `%s'", path_iso3166, lineno, t); /* Now skip past the three-letter and numeric codes. */ name = strsep(&s, "\t"); /* 3-let */ if (name == 0 || strlen(name) != 3) - errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); + errx(1, "%s:%d: invalid format", path_iso3166, lineno); name = strsep(&s, "\t"); /* numeric */ if (name == 0 || strlen(name) != 3) - errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); + errx(1, "%s:%d: invalid format", path_iso3166, lineno); name = s; cp = &countries[CODE2INT(t)]; if (cp->name) - errx(1, _PATH_ISO3166 - ":%d: country code `%s' multiply defined: %s", - lineno, t, cp->name); + errx(1, "%s:%d: country code `%s' multiply defined: %s", + path_iso3166, lineno, t, cp->name); cp->name = strdup(name); if (cp->name == NULL) errx(1, "malloc failed"); @@ -248,18 +256,18 @@ add_zone_to_country(int lineno, const ch struct country *cp; if (tlc[0] < 'A' || tlc[0] > 'Z' || tlc[1] < 'A' || tlc[1] > 'Z') - errx(1, _PATH_ZONETAB ":%d: country code `%s' invalid", + errx(1, "%s:%d: country code `%s' invalid", path_zonetab, lineno, tlc); cp = &countries[CODE2INT(tlc)]; if (cp->name == 0) - errx(1, _PATH_ZONETAB ":%d: country code `%s' unknown", + errx(1, "%s:%d: country code `%s' unknown", path_zonetab, lineno, tlc); if (descr) { if (cp->nzones < 0) - errx(1, _PATH_ZONETAB - ":%d: conflicting zone definition", lineno); + errx(1, "%s:%d: conflicting zone definition", + path_zonetab, lineno); zp = malloc(sizeof(*zp)); if (zp == 0) @@ -279,11 +287,11 @@ add_zone_to_country(int lineno, const ch cp->nzones++; } else { if (cp->nzones > 0) - errx(1, _PATH_ZONETAB - ":%d: zone must have description", lineno); + errx(1, "%s:%d: zone must have description", + path_zonetab, lineno); if (cp->nzones < 0) - errx(1, _PATH_ZONETAB - ":%d: zone multiply defined", lineno); + errx(1, "%s:%d: zone multiply defined", + path_zonetab, lineno); cp->nzones = -1; cp->filename = strdup(file); if (cp->filename == NULL) @@ -333,34 +341,34 @@ read_zones(void) char *line, *tlc, *coord, *file, *descr, *p; int lineno; - fp = fopen(_PATH_ZONETAB, "r"); + fp = fopen(path_zonetab, "r"); if (!fp) - err(1, _PATH_ZONETAB); + err(1, "%s", path_zonetab); lineno = 0; while ((line = fgetln(fp, &len)) != 0) { lineno++; if (line[len - 1] != '\n') - errx(1, _PATH_ZONETAB ":%d: invalid format", lineno); + errx(1, "%s:%d: invalid format", path_zonetab, lineno); line[len - 1] = '\0'; if (line[0] == '#') continue; tlc = strsep(&line, "\t"); if (strlen(tlc) != 2) - errx(1, _PATH_ZONETAB ":%d: invalid country code `%s'", - lineno, tlc); - coord = strsep(&line, "\t"); + errx(1, "%s:%d: invalid country code `%s'", + path_zonetab, lineno, tlc); + coord = strsep(&line, "\t"); /* Unused */ file = strsep(&line, "\t"); p = strchr(file, '/'); if (p == 0) - errx(1, _PATH_ZONETAB ":%d: invalid zone name `%s'", + errx(1, "%s:%d: invalid zone name `%s'", path_zonetab, lineno, file); contbuf[0] = '\0'; strncat(contbuf, file, p - file); cont = find_continent(contbuf); if (!cont) - errx(1, _PATH_ZONETAB ":%d: invalid region `%s'", + errx(1, "%s:%d: invalid region `%s'", path_zonetab, lineno, contbuf); descr = (line != NULL && *line != '\0') ? line : NULL; @@ -495,7 +503,7 @@ set_zone_menu(dialogMenuItem *dmi) } static int -install_zone_file(const char *filename) +install_zoneinfo_file(const char *zoneinfo_file) { char buf[1024]; char title[64], prompt[64]; @@ -503,7 +511,7 @@ install_zone_file(const char *filename) ssize_t len; int fd1, fd2, copymode; - if (lstat(_PATH_LOCALTIME, &sb) < 0) { + if (lstat(path_localtime, &sb) < 0) { /* Nothing there yet... */ copymode = 1; } else if (S_ISLNK(sb.st_mode)) @@ -514,70 +522,89 @@ install_zone_file(const char *filename) #ifdef VERBOSE if (copymode) snprintf(prompt, sizeof(prompt), - "Copying %s to " _PATH_LOCALTIME, filename); + "Copying %s to %s", zoneinfo_file, path_localtime); else snprintf(prompt, sizeof(prompt), - "Creating symbolic link " _PATH_LOCALTIME " to %s", - filename); - dialog_notify(prompt); + "Creating symbolic link %s to %s", + path_localtime, zoneinfo_file); + if (usedialog) + dialog_notify(prompt); + else + fprintf(stderr, "%s\n", prompt); #endif if (reallydoit) { if (copymode) { - fd1 = open(filename, O_RDONLY, 0); + fd1 = open(zoneinfo_file, O_RDONLY, 0); if (fd1 < 0) { snprintf(title, sizeof(title), "Error"); snprintf(prompt, sizeof(prompt), - "Could not open %s: %s", filename, + "Could not open %s: %s", zoneinfo_file, strerror(errno)); - dialog_mesgbox(title, prompt, 8, 72); + if (usedialog) + dialog_mesgbox(title, prompt, 8, 72); + else + fprintf(stderr, "%s\n", prompt); return (DITEM_FAILURE | DITEM_RECREATE); } - unlink(_PATH_LOCALTIME); - fd2 = open(_PATH_LOCALTIME, O_CREAT | O_EXCL | O_WRONLY, + unlink(path_localtime); + fd2 = open(path_localtime, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IRGRP | S_IROTH); if (fd2 < 0) { snprintf(title, sizeof(title), "Error"); snprintf(prompt, sizeof(prompt), - "Could not open " _PATH_LOCALTIME ": %s", - strerror(errno)); - dialog_mesgbox(title, prompt, 8, 72); + "Could not open %s: %s", + path_localtime, strerror(errno)); + if (usedialog) + dialog_mesgbox(title, prompt, 8, 72); + else + fprintf(stderr, "%s\n", prompt); return (DITEM_FAILURE | DITEM_RECREATE); } while ((len = read(fd1, buf, sizeof(buf))) > 0) - len = write(fd2, buf, len); + if ((len = write(fd2, buf, len)) < 0) + break; if (len == -1) { snprintf(title, sizeof(title), "Error"); snprintf(prompt, sizeof(prompt), - "Error copying %s to " _PATH_LOCALTIME - ": %s", filename, strerror(errno)); - dialog_mesgbox(title, prompt, 8, 72); + "Error copying %s to %s %s", zoneinfo_file, + path_localtime, strerror(errno)); + if (usedialog) + dialog_mesgbox(title, prompt, 8, 72); + else + fprintf(stderr, "%s\n", prompt); /* Better to leave none than a corrupt one. */ - unlink(_PATH_LOCALTIME); + unlink(path_localtime); return (DITEM_FAILURE | DITEM_RECREATE); } close(fd1); close(fd2); } else { - if (access(filename, R_OK) != 0) { + if (access(zoneinfo_file, R_OK) != 0) { snprintf(title, sizeof(title), "Error"); snprintf(prompt, sizeof(prompt), - "Cannot access %s: %s", filename, + "Cannot access %s: %s", zoneinfo_file, strerror(errno)); - dialog_mesgbox(title, prompt, 8, 72); + if (usedialog) + dialog_mesgbox(title, prompt, 8, 72); + else + fprintf(stderr, "%s\n", prompt); return (DITEM_FAILURE | DITEM_RECREATE); } - unlink(_PATH_LOCALTIME); - if (symlink(filename, _PATH_LOCALTIME) < 0) { + unlink(path_localtime); + if (symlink(zoneinfo_file, path_localtime) < 0) { snprintf(title, sizeof(title), "Error"); snprintf(prompt, sizeof(prompt), - "Cannot create symbolic link " - _PATH_LOCALTIME " to %s: %s", filename, + "Cannot create symbolic link %s to %s: %s", + path_localtime, zoneinfo_file, strerror(errno)); - dialog_mesgbox(title, prompt, 8, 72); + if (usedialog) + dialog_mesgbox(title, prompt, 8, 72); + else + fprintf(stderr, "%s\n", prompt); return (DITEM_FAILURE | DITEM_RECREATE); } } @@ -587,17 +614,41 @@ install_zone_file(const char *filename) snprintf(title, sizeof(title), "Done"); if (copymode) snprintf(prompt, sizeof(prompt), - "Copied timezone file from %s to " _PATH_LOCALTIME, - filename); + "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); + if (usedialog) + dialog_mesgbox(title, prompt, 8, 72); else - snprintf(prompt, sizeof(prompt), "Created symbolic link from " - _PATH_LOCALTIME " to %s", filename); - dialog_mesgbox(title, prompt, 8, 72); + fprintf(stderr, "%s\n", prompt); #endif + return (DITEM_LEAVE_MENU); } static int +install_zoneinfo(const char *zoneinfo) +{ + int rv; + FILE *f; + char path_zoneinfo_file[MAXPATHLEN]; + + sprintf(path_zoneinfo_file, "%s/%s", path_zoneinfo, zoneinfo); + rv = install_zoneinfo_file(path_zoneinfo_file); + + /* Save knowledge for later */ + if ((f = fopen(path_db, "w")) != NULL) { + fprintf(f, "%s\n", zoneinfo); + fclose(f); + } + + return (rv); +} + +static int confirm_zone(const char *filename) { char title[64], prompt[64]; @@ -620,15 +671,12 @@ static int set_zone_multi(dialogMenuItem *dmi) { struct zone *zp = dmi->data; - char *fn; int rv; if (!confirm_zone(zp->filename)) return (DITEM_FAILURE | DITEM_RECREATE); - asprintf(&fn, "%s/%s", _PATH_ZONEINFO, zp->filename); - rv = install_zone_file(fn); - free(fn); + rv = install_zoneinfo(zp->filename); return (rv); } @@ -636,15 +684,12 @@ static int set_zone_whole_country(dialogMenuItem *dmi) { struct country *cp = dmi->data; - char *fn; int rv; if (!confirm_zone(cp->filename)) return (DITEM_FAILURE | DITEM_RECREATE); - asprintf(&fn, "%s/%s", _PATH_ZONEINFO, cp->filename); - rv = install_zone_file(fn); - free(fn); + rv = install_zoneinfo(cp->filename); return (rv); } @@ -652,7 +697,7 @@ static void usage(void) { - fprintf(stderr, "usage: tzsetup [-ns]\n"); + fprintf(stderr, "usage: tzsetup [-nrs] [zoneinfo file]\n"); exit(1); } @@ -666,14 +711,21 @@ int main(int argc, char **argv) { char title[64], prompt[128]; - int c, fd, skiputc; + int c, fd, rv, skiputc; skiputc = 0; - while ((c = getopt(argc, argv, "ns")) != -1) { + while ((c = getopt(argc, argv, "C:nrs")) != -1) { switch(c) { + case 'C': + chrootenv = optarg; + break; case 'n': reallydoit = 0; break; + case 'r': + reinstall = 1; + usedialog = 0; + break; case 's': skiputc = 1; break; @@ -685,6 +737,24 @@ main(int argc, char **argv) if (argc - optind > 1) usage(); + if (chrootenv == NULL) { + strcpy(path_zonetab, _PATH_ZONETAB); + strcpy(path_iso3166, _PATH_ISO3166); + strcpy(path_zoneinfo, _PATH_ZONEINFO); + strcpy(path_localtime, _PATH_LOCALTIME); + strcpy(path_db, _PATH_DB); + strcpy(path_wall_cmos_clock, _PATH_WALL_CMOS_CLOCK); + } else { + sprintf(path_zonetab, "%s/%s", chrootenv, _PATH_ZONETAB); + sprintf(path_iso3166, "%s/%s", chrootenv, _PATH_ISO3166); + sprintf(path_zoneinfo, "%s/%s", chrootenv, _PATH_ZONEINFO); + sprintf(path_localtime, "%s/%s", chrootenv, _PATH_LOCALTIME); + sprintf(path_db, "%s/%s", chrootenv, _PATH_DB); + sprintf(path_wall_cmos_clock, "%s/%s", chrootenv, + _PATH_WALL_CMOS_CLOCK); + } + + /* Override the user-supplied umask. */ (void)umask(S_IWGRP | S_IWOTH); @@ -693,6 +763,54 @@ main(int argc, char **argv) sort_countries(); make_menus(); + if (reinstall == 1) { + FILE *f; + char zonefile[MAXPATHLEN]; + char path_db[MAXPATHLEN]; + + zonefile[0] = '\0'; + path_db[0] = '\0'; + if (chrootenv != NULL) { + sprintf(zonefile, "%s/", chrootenv); + sprintf(path_db, "%s/", chrootenv); + } + strcat(zonefile, _PATH_ZONEINFO); + strcat(zonefile, "/"); + strcat(path_db, _PATH_DB); + + if ((f = fopen(path_db, "r")) != NULL) { + if (fgets(zonefile, sizeof(zonefile), f) != NULL) { + zonefile[sizeof(zonefile) - 1] = 0; + if (strlen(zonefile) > 0) { + zonefile[strlen(zonefile) - 1] = 0; + rv = install_zoneinfo(zonefile); + exit(rv & ~DITEM_LEAVE_MENU); + } + errx(1, "Error reading %s.\n", path_db); + } + fclose(f); + errx(1, + "Unable to determine earlier installed zoneinfo " + "file. Check %s", path_db); + } + errx(1, "Cannot open %s for reading. Does it exist?", path_db); + } + + /* + * If the arguments on the command-line do not specify a file, + * then interpret it as a zoneinfo name + */ + if (optind == argc - 1) { + struct stat sb; + + if (stat(argv[optind], &sb) != 0) { + usedialog = 0; + rv = install_zoneinfo(argv[optind]); + exit(rv & ~DITEM_LEAVE_MENU); + } + /* FALLTHROUGH */ + } + init_dialog(); if (skiputc == 0) { snprintf(title, sizeof(title), @@ -703,15 +821,17 @@ main(int argc, char **argv) "or you don't know, please choose NO here!"); if (!DIALOG_UTC(title, prompt, 7, 72)) { if (reallydoit) - unlink(_PATH_WALL_CMOS_CLOCK); + unlink(path_wall_cmos_clock); } else { if (reallydoit) { - fd = open(_PATH_WALL_CMOS_CLOCK, + fd = open(path_wall_cmos_clock, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IRGRP | S_IROTH); - if (fd < 0) + if (fd < 0) { + end_dialog(); err(1, "create %s", - _PATH_WALL_CMOS_CLOCK); + path_wall_cmos_clock); + } close(fd); } } @@ -722,10 +842,10 @@ main(int argc, char **argv) snprintf(prompt, sizeof(prompt), "\nUse the default `%s' zone?", argv[optind]); if (!dialog_yesno(title, prompt, 7, 72)) { - install_zone_file(argv[optind]); + rv = install_zoneinfo_file(argv[optind]); dialog_clear(); end_dialog(); - return (0); + exit(rv & ~DITEM_LEAVE_MENU); } dialog_clear_norefresh(); }