svn commit: r198350 - head/usr.sbin/tzsetup

Edwin Groothuis edwin at FreeBSD.org
Wed Oct 21 20:55:04 UTC 2009


Author: edwin
Date: Wed Oct 21 20:55:04 2009
New Revision: 198350
URL: http://svn.freebsd.org/changeset/base/198350

Log:
  - Add support for chrooted installs.
  - Add examples to the man-page.
  
  MFC after:	1 week

Modified:
  head/usr.sbin/tzsetup/tzsetup.8
  head/usr.sbin/tzsetup/tzsetup.c

Modified: head/usr.sbin/tzsetup/tzsetup.8
==============================================================================
--- head/usr.sbin/tzsetup/tzsetup.8	Wed Oct 21 20:33:50 2009	(r198349)
+++ head/usr.sbin/tzsetup/tzsetup.8	Wed Oct 21 20:55:04 2009	(r198350)
@@ -32,7 +32,8 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl nrs
-.Op Ar zoneinfo file
+.Op Fl C Ar chroot directory
+.Op Ar zoneinfo file | zoneinfo name
 .Sh DESCRIPTION
 The
 .Nm
@@ -49,6 +50,9 @@ 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
@@ -62,8 +66,10 @@ Skip the initial question about adjustin
 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.
+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 .
@@ -97,21 +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: head/usr.sbin/tzsetup/tzsetup.c
==============================================================================
--- head/usr.sbin/tzsetup/tzsetup.c	Wed Oct 21 20:33:50 2009	(r198349)
+++ head/usr.sbin/tzsetup/tzsetup.c	Wed Oct 21 20:55:04 2009	(r198350)
@@ -56,8 +56,14 @@ __FBSDID("$FreeBSD$");
 #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 *);
@@ -196,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, 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;
@@ -212,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");
@@ -251,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)
@@ -282,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)
@@ -336,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, 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);
+			errx(1, "%s:%d: invalid country code `%s'",
+			    path_zonetab, lineno, tlc);
 		coord = strsep(&line, "\t");
 		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;
@@ -498,16 +503,15 @@ set_zone_menu(dialogMenuItem *dmi)
 }
 
 static int
-install_zone_file(const char *filename, int usedialog)
+install_zoneinfo_file(const char *zoneinfo_file)
 {
 	char		buf[1024];
 	char		title[64], prompt[64];
 	struct stat	sb;
 	ssize_t		len;
 	int		fd1, fd2, copymode;
-	FILE		*f;
 
-	if (lstat(_PATH_LOCALTIME, &sb) < 0) {
+	if (lstat(path_localtime, &sb) < 0) {
 		/* Nothing there yet... */
 		copymode = 1;
 	} else if (S_ISLNK(sb.st_mode))
@@ -518,11 +522,11 @@ 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);
+		    "Creating symbolic link %s to %s",
+		    path_localtime, zoneinfo_file);
 	if (usedialog)
 		dialog_notify(prompt);
 	else
@@ -531,11 +535,11 @@ install_zone_file(const char *filename, 
 
 	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));
 				if (usedialog)
 					dialog_mesgbox(title, prompt, 8, 72);
@@ -544,14 +548,14 @@ install_zone_file(const char *filename, 
 				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));
+				    "Could not open %s: %s",
+				    path_localtime, strerror(errno));
 				if (usedialog)
 					dialog_mesgbox(title, prompt, 8, 72);
 				else
@@ -565,23 +569,23 @@ install_zone_file(const char *filename, 
 			if (len == -1) {
 				snprintf(title, sizeof(title), "Error");
 				snprintf(prompt, sizeof(prompt),
-				    "Error copying %s to " _PATH_LOCALTIME
-				    ": %s", filename, strerror(errno));
+				    "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));
 				if (usedialog)
 					dialog_mesgbox(title, prompt, 8, 72);
@@ -589,12 +593,12 @@ install_zone_file(const char *filename, 
 					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));
 				if (usedialog)
 					dialog_mesgbox(title, prompt, 8, 72);
@@ -609,24 +613,38 @@ 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 "
-		    _PATH_LOCALTIME " to %s", filename);
+		snprintf(prompt, sizeof(prompt),
+		    "Created symbolic link from %s to %s", zoneinfo_file,
+		    path_localtime);
 	if (usedialog)
 		dialog_mesgbox(title, prompt, 8, 72);
 	else
 		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", filename + strlen(_PATH_ZONEINFO) + 1);
+	if ((f = fopen(path_db, "w")) != NULL) {
+		fprintf(f, "%s\n", zoneinfo);
 		fclose(f);
 	}
 
-	return (DITEM_LEAVE_MENU);
+	return (rv);
 }
 
 static int
@@ -652,15 +670,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, 1);
-	free(fn);
+	rv = install_zoneinfo(zp->filename);
 	return (rv);
 }
 
@@ -668,15 +683,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, 1);
-	free(fn);
+	rv = install_zoneinfo(cp->filename);
 	return (rv);
 }
 
@@ -701,13 +713,17 @@ main(int argc, char **argv)
 	int		c, fd, rv, skiputc;
 
 	skiputc = 0;
-	while ((c = getopt(argc, argv, "nrs")) != -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;
@@ -720,6 +736,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);
 
@@ -731,25 +765,49 @@ main(int argc, char **argv)
 	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);
 
-		sprintf(zonefile, "%s/", _PATH_ZONEINFO);
-		if ((f = fopen(_PATH_DB, "r")) != NULL) {
-			if (fgets(zonefile + strlen(zonefile),
-			    sizeof(zonefile) - strlen(zonefile), f) != NULL) {
+		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_zone_file(zonefile, 0);
+					rv = install_zoneinfo(zonefile);
 					exit(rv & ~DITEM_LEAVE_MENU);
 				}
-				errx(1, "Error reading %s.\n", _PATH_DB);
+				errx(1, "Error reading %s.\n", path_db);
 			}
 			fclose(f);
 			errx(1,
 			    "Unable to determine earlier installed zoneinfo "
-			    "file. Check %s", _PATH_DB);
+			    "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);
 		}
-		errx(1, "Cannot open %s for reading. Does it exist?", _PATH_DB);
+		/* FALLTHROUGH */
 	}
 
 	init_dialog();
@@ -783,7 +841,7 @@ main(int argc, char **argv)
 		snprintf(prompt, sizeof(prompt),
 		    "\nUse the default `%s' zone?", argv[optind]);
 		if (!dialog_yesno(title, prompt, 7, 72)) {
-			rv = install_zone_file(argv[optind], 1);
+			rv = install_zoneinfo_file(argv[optind]);
 			dialog_clear();
 			end_dialog();
 			exit(rv & ~DITEM_LEAVE_MENU);


More information about the svn-src-all mailing list