17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27*2385a442SJohn Levon /*
28*2385a442SJohn Levon  * Copyright (c) 2018, Joyent, Inc.
29*2385a442SJohn Levon  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <stdio.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <unistd.h>
357c478bd9Sstevel@tonic-gate #include <sys/param.h>
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
377c478bd9Sstevel@tonic-gate #include <sys/stat.h>
387c478bd9Sstevel@tonic-gate #include <tzfile.h>
397c478bd9Sstevel@tonic-gate #include <fcntl.h>
407c478bd9Sstevel@tonic-gate #include <regex.h>
417c478bd9Sstevel@tonic-gate #include <errno.h>
427c478bd9Sstevel@tonic-gate #include <libintl.h>
437c478bd9Sstevel@tonic-gate #include <libzoneinfo.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #define	DEFINIT		"/etc/default/init"
467c478bd9Sstevel@tonic-gate #define	ZONEINFOTABDIR	"/usr/share/lib/zoneinfo/tab/"
477c478bd9Sstevel@tonic-gate #define	CONTINENT_TAB	ZONEINFOTABDIR "continent.tab"
487c478bd9Sstevel@tonic-gate #define	COUNTRY_TAB	ZONEINFOTABDIR "country.tab"
497c478bd9Sstevel@tonic-gate #define	ZONE_SUN_TAB	ZONEINFOTABDIR "zone_sun.tab"
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate #define	NEWLINE		"\n"
527c478bd9Sstevel@tonic-gate #define	SLASH		"/"
537c478bd9Sstevel@tonic-gate #define	WHITESPACE	"\t "
547c478bd9Sstevel@tonic-gate #define	WHITESPACE_NL	"\t \n"
557c478bd9Sstevel@tonic-gate #define	DIGITS		"0123456789"
567c478bd9Sstevel@tonic-gate #define	BUFFLEN		1024
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #define	CCLEN		2		/* country code length */
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #define	GMT_MAX		(12*60*60)	/* The maximum GMT offset */
617c478bd9Sstevel@tonic-gate #define	GMT_MIN		(-13*60*60)	/* The minimum GMT offset */
627c478bd9Sstevel@tonic-gate #define	GMT_FMT_Q	"<GMT%c%d>%c%d"
637c478bd9Sstevel@tonic-gate #define	GMT_FMT_Q_LEN	(11)		/* "<GMT+dd>+dd" - maximum 11 chars */
647c478bd9Sstevel@tonic-gate #define	GMT0_FMT	"GMT0"		/* backwards compatibility name */
657c478bd9Sstevel@tonic-gate #define	GMT_FMT_ZONE	":Etc/GMT%c%d"	/* ":Etc/GMT+dd" */
667c478bd9Sstevel@tonic-gate #define	GMT_FMT_ZONE_LEN	(11)	/* ":Etc/GMT+dd" - maximum 11 chars */
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #define	TZ_FMT		"TZ=%s\n"	/* format TZ entry init file */
697c478bd9Sstevel@tonic-gate #define	TZ_FMT_Q	"TZ=\"%s\"\n"	/* format quoted TZ entry init file */
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate #define	COORD_FMTLEN1	(sizeof ("+DDMM+DDDMM") - 1)
727c478bd9Sstevel@tonic-gate #define	COORD_FMTLEN2	(sizeof ("+DDMMSS+DDDMMSS") - 1)
737c478bd9Sstevel@tonic-gate #define	COORD_FMT1		(1)	/* flag for format 1 */
747c478bd9Sstevel@tonic-gate #define	COORD_FMT2		(2)	/* flag for format 2 */
757c478bd9Sstevel@tonic-gate #define	COORD_DLEN_LAT		(2)	/* length of DD for latitude */
767c478bd9Sstevel@tonic-gate #define	COORD_DLEN_LONG		(3)	/* length of DDD for longtitude */
777c478bd9Sstevel@tonic-gate #define	COORD_MLEN		(2)	/* length of MM */
787c478bd9Sstevel@tonic-gate #define	COORD_SLEN		(2)	/* length of SS */
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate #define	TRAILER		"/XXXXXX"
817c478bd9Sstevel@tonic-gate #define	TR_LEN		(sizeof (TRAILER) -1)
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /* Internal Declarations */
847c478bd9Sstevel@tonic-gate static char *skipwhite(char *);
857c478bd9Sstevel@tonic-gate static int skipline(char *);
867c478bd9Sstevel@tonic-gate static int trav_link(char **);
877c478bd9Sstevel@tonic-gate static void remove_component(char *);
887c478bd9Sstevel@tonic-gate static void strip_quotes(char *, char *);
897c478bd9Sstevel@tonic-gate static int compar(struct tz_country *, struct tz_country *);
907c478bd9Sstevel@tonic-gate static int get_coord(struct tz_timezone *, char *, size_t);
917c478bd9Sstevel@tonic-gate static int _tz_match(const char *, const char *);
927c478bd9Sstevel@tonic-gate static char *_conv_gmt_zoneinfo(int);
937c478bd9Sstevel@tonic-gate static char *_conv_gmt_posix(int);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * get_tz_continents() reads the continent.tab file, and
977c478bd9Sstevel@tonic-gate  * returns a list of continents.
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate int
get_tz_continents(struct tz_continent ** cont)1007c478bd9Sstevel@tonic-gate get_tz_continents(struct tz_continent **cont)
1017c478bd9Sstevel@tonic-gate {
1027c478bd9Sstevel@tonic-gate 	FILE *fp;
1037c478bd9Sstevel@tonic-gate 	char buff[BUFFLEN];
1047c478bd9Sstevel@tonic-gate 	char *lp;		/* line pointer */
1057c478bd9Sstevel@tonic-gate 	char *lptr, *ptr;	/* temp pointer */
1067c478bd9Sstevel@tonic-gate 	struct tz_continent *head = NULL, *lcp, *prev = NULL;
1077c478bd9Sstevel@tonic-gate 	int sav_errno = 0, ncount, status;
1087c478bd9Sstevel@tonic-gate 	size_t len;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	/* open continents file */
1117c478bd9Sstevel@tonic-gate 	if ((fp = fopen(CONTINENT_TAB, "r")) == NULL) {
1127c478bd9Sstevel@tonic-gate 		/* fopen() sets errno */
1137c478bd9Sstevel@tonic-gate 		return (-1);
1147c478bd9Sstevel@tonic-gate 	}
1157c478bd9Sstevel@tonic-gate 	/* read and count continents */
1167c478bd9Sstevel@tonic-gate 	ncount = 0;
1177c478bd9Sstevel@tonic-gate 	/*CONSTANTCONDITION*/
1187c478bd9Sstevel@tonic-gate 	while (1) {
1197c478bd9Sstevel@tonic-gate 		if (fgets(buff, sizeof (buff), fp) == NULL) {
1207c478bd9Sstevel@tonic-gate 			if (feof(fp) == 0) {
1217c478bd9Sstevel@tonic-gate 				/* fgets() sets errno */
1227c478bd9Sstevel@tonic-gate 				sav_errno = errno;
1237c478bd9Sstevel@tonic-gate 				ncount = -1;
1247c478bd9Sstevel@tonic-gate 			}
1257c478bd9Sstevel@tonic-gate 			break;
1267c478bd9Sstevel@tonic-gate 		}
1277c478bd9Sstevel@tonic-gate 		/* Skip comments or blank/whitespace lines */
1287c478bd9Sstevel@tonic-gate 		if ((status = skipline(buff)) != 0) {
1297c478bd9Sstevel@tonic-gate 			if (status == 1)
1307c478bd9Sstevel@tonic-gate 				continue;
1317c478bd9Sstevel@tonic-gate 			else {
1327c478bd9Sstevel@tonic-gate 				sav_errno = EINVAL;
1337c478bd9Sstevel@tonic-gate 				ncount = -1;
1347c478bd9Sstevel@tonic-gate 				break;
1357c478bd9Sstevel@tonic-gate 			}
1367c478bd9Sstevel@tonic-gate 		}
1377c478bd9Sstevel@tonic-gate 		/* Get continent name */
1387c478bd9Sstevel@tonic-gate 		lp = skipwhite(&buff[0]);
1397c478bd9Sstevel@tonic-gate 		if ((len = strcspn(lp, WHITESPACE)) > _TZBUFLEN -1) {
1407c478bd9Sstevel@tonic-gate 			sav_errno = ENAMETOOLONG;
1417c478bd9Sstevel@tonic-gate 			ncount = -1;
1427c478bd9Sstevel@tonic-gate 			break;
1437c478bd9Sstevel@tonic-gate 		}
1447c478bd9Sstevel@tonic-gate 		/* create continent struct */
1457c478bd9Sstevel@tonic-gate 		if ((lcp = (struct tz_continent *)
1467c478bd9Sstevel@tonic-gate 			calloc(1, sizeof (struct tz_continent))) == NULL) {
1477c478bd9Sstevel@tonic-gate 			sav_errno = ENOMEM;
1487c478bd9Sstevel@tonic-gate 			ncount = -1;
1497c478bd9Sstevel@tonic-gate 			break;
1507c478bd9Sstevel@tonic-gate 		}
1517c478bd9Sstevel@tonic-gate 		(void) strncpy(lcp->ctnt_name, lp, len);
1527c478bd9Sstevel@tonic-gate 		lcp->ctnt_name[len] = '\0';
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 		/* Get continent description */
1557c478bd9Sstevel@tonic-gate 		lp = skipwhite(lp + len);
1567c478bd9Sstevel@tonic-gate 		len = strcspn(lp, NEWLINE);
1577c478bd9Sstevel@tonic-gate 		if ((ptr = malloc(len + 1)) == NULL) {
1587c478bd9Sstevel@tonic-gate 			(void) free_tz_continents(lcp);
1597c478bd9Sstevel@tonic-gate 			sav_errno = ENOMEM;
1607c478bd9Sstevel@tonic-gate 			ncount = -1;
1617c478bd9Sstevel@tonic-gate 			break;
1627c478bd9Sstevel@tonic-gate 		}
1637c478bd9Sstevel@tonic-gate 		(void) strncpy(ptr, lp, len);
1647c478bd9Sstevel@tonic-gate 		*(ptr + len) = '\0';
1657c478bd9Sstevel@tonic-gate 		lcp->ctnt_id_desc = ptr;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 		/* Get localized continent description */
1687c478bd9Sstevel@tonic-gate 		lptr = dgettext(TEXT_DOMAIN, lcp->ctnt_id_desc);
1697c478bd9Sstevel@tonic-gate 		if ((ptr = strdup(lptr)) == NULL) {
1707c478bd9Sstevel@tonic-gate 			(void) free_tz_continents(lcp);
1717c478bd9Sstevel@tonic-gate 			sav_errno = ENOMEM;
1727c478bd9Sstevel@tonic-gate 			ncount = -1;
1737c478bd9Sstevel@tonic-gate 			break;
1747c478bd9Sstevel@tonic-gate 		}
1757c478bd9Sstevel@tonic-gate 		lcp->ctnt_display_desc = ptr;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 		if (head == NULL) {
1787c478bd9Sstevel@tonic-gate 			head = lcp;
1797c478bd9Sstevel@tonic-gate 		} else {
1807c478bd9Sstevel@tonic-gate 			prev->ctnt_next = lcp;
1817c478bd9Sstevel@tonic-gate 		}
1827c478bd9Sstevel@tonic-gate 		prev = lcp;
1837c478bd9Sstevel@tonic-gate 		ncount++;
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
1867c478bd9Sstevel@tonic-gate 	if (ncount == -1) {
1877c478bd9Sstevel@tonic-gate 		if (head != NULL) {
1887c478bd9Sstevel@tonic-gate 			(void) free_tz_continents(head);
1897c478bd9Sstevel@tonic-gate 		}
1907c478bd9Sstevel@tonic-gate 		if (sav_errno)
1917c478bd9Sstevel@tonic-gate 			errno = sav_errno;
1927c478bd9Sstevel@tonic-gate 	} else {
1937c478bd9Sstevel@tonic-gate 		*cont = head;
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate 	return (ncount);
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate /*
1997c478bd9Sstevel@tonic-gate  * get_tz_countries() finds the list of countries from the zone_sun.tab
2007c478bd9Sstevel@tonic-gate  * file, for the input continent, and retrieves the country
2017c478bd9Sstevel@tonic-gate  * names from the country.tab file.  It also retrieves the localized
2027c478bd9Sstevel@tonic-gate  * country names.  The returned list of countries is sorted by the
2037c478bd9Sstevel@tonic-gate  * countries' localized name fields.
2047c478bd9Sstevel@tonic-gate  */
2057c478bd9Sstevel@tonic-gate int
get_tz_countries(struct tz_country ** country,struct tz_continent * cont)2067c478bd9Sstevel@tonic-gate get_tz_countries(struct tz_country **country, struct tz_continent *cont)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	FILE *fp_zone, *fp_cc;
2097c478bd9Sstevel@tonic-gate 	char buff[BUFFLEN], ccbuf[_CCBUFLEN], *ptr;
2107c478bd9Sstevel@tonic-gate 	char *lp, *lptr, *lp_coord, *lp_cc, *lp_tz;	/* line pointer */
2117c478bd9Sstevel@tonic-gate 	struct tz_country *head = NULL, *prev = NULL, *next, *cp, *cp2;
2127c478bd9Sstevel@tonic-gate 	int sav_errno = 0, ncount, i;
2137c478bd9Sstevel@tonic-gate 	int cmp, status;
2147c478bd9Sstevel@tonic-gate 	size_t len, len_coord, len_ctnt;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	len_ctnt = strlen(cont->ctnt_name);
2177c478bd9Sstevel@tonic-gate 	ccbuf[0] = '\0';
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/* open zone_sun.tab and country.tab files */
2207c478bd9Sstevel@tonic-gate 	if ((fp_zone = fopen(ZONE_SUN_TAB, "r")) == NULL) {
2217c478bd9Sstevel@tonic-gate 		/* fopen() sets errno */
2227c478bd9Sstevel@tonic-gate 		return (-1);
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 	if ((fp_cc = fopen(COUNTRY_TAB, "r")) == NULL) {
2257c478bd9Sstevel@tonic-gate 		/* fopen() sets errno */
2267c478bd9Sstevel@tonic-gate 		(void) fclose(fp_zone);
2277c478bd9Sstevel@tonic-gate 		return (-1);
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	/* read timezones to match continents, and get countries */
2317c478bd9Sstevel@tonic-gate 	ncount = 0;
2327c478bd9Sstevel@tonic-gate 	/*CONSTANTCONDITION*/
2337c478bd9Sstevel@tonic-gate 	while (1) {
2347c478bd9Sstevel@tonic-gate 		if (fgets(buff, sizeof (buff), fp_zone) == NULL) {
2357c478bd9Sstevel@tonic-gate 			if (feof(fp_zone) == 0) {
2367c478bd9Sstevel@tonic-gate 				/* fgets() error - errno set */
2377c478bd9Sstevel@tonic-gate 				sav_errno = errno;
2387c478bd9Sstevel@tonic-gate 				ncount = -1;
2397c478bd9Sstevel@tonic-gate 			}
2407c478bd9Sstevel@tonic-gate 			break;
2417c478bd9Sstevel@tonic-gate 		}
2427c478bd9Sstevel@tonic-gate 		/* Skip comments or blank/whitespace lines */
2437c478bd9Sstevel@tonic-gate 		if ((status = skipline(buff)) != 0) {
2447c478bd9Sstevel@tonic-gate 			if (status == 1)
2457c478bd9Sstevel@tonic-gate 				continue;
2467c478bd9Sstevel@tonic-gate 			else {
2477c478bd9Sstevel@tonic-gate 				sav_errno = EINVAL;
2487c478bd9Sstevel@tonic-gate 				ncount = -1;
2497c478bd9Sstevel@tonic-gate 				break;
2507c478bd9Sstevel@tonic-gate 			}
2517c478bd9Sstevel@tonic-gate 		}
2527c478bd9Sstevel@tonic-gate 		/*
2537c478bd9Sstevel@tonic-gate 		 * If country matches previously *matched* country, skip
2547c478bd9Sstevel@tonic-gate 		 * entry, since zone.tab is alphabetized by country code
2557c478bd9Sstevel@tonic-gate 		 * (It should be a *matched* country, because the same country
2567c478bd9Sstevel@tonic-gate 		 * can be in different continents.)
2577c478bd9Sstevel@tonic-gate 		 */
2587c478bd9Sstevel@tonic-gate 		/* Get country code */
2597c478bd9Sstevel@tonic-gate 		lp_cc = skipwhite(&buff[0]);
2607c478bd9Sstevel@tonic-gate 		if (strcspn(lp_cc, WHITESPACE) != CCLEN) {
2617c478bd9Sstevel@tonic-gate 			ncount = -1;
2627c478bd9Sstevel@tonic-gate 			sav_errno = EINVAL;
2637c478bd9Sstevel@tonic-gate 			break;
2647c478bd9Sstevel@tonic-gate 		}
2657c478bd9Sstevel@tonic-gate 		/* Check country code cache; skip if already found */
2667c478bd9Sstevel@tonic-gate 		if (strncmp(ccbuf, lp_cc, CCLEN) == 0) {
2677c478bd9Sstevel@tonic-gate 			continue;
2687c478bd9Sstevel@tonic-gate 		}
2697c478bd9Sstevel@tonic-gate 		/* Get coordinates */
2707c478bd9Sstevel@tonic-gate 		lp_coord = skipwhite(lp_cc + CCLEN);
2717c478bd9Sstevel@tonic-gate 		if (((len_coord = strcspn(lp_coord, WHITESPACE)) !=
2727c478bd9Sstevel@tonic-gate 				COORD_FMTLEN1) &&
2737c478bd9Sstevel@tonic-gate 				(len_coord != COORD_FMTLEN2)) {
2747c478bd9Sstevel@tonic-gate 			ncount = -1;
2757c478bd9Sstevel@tonic-gate 			sav_errno = EINVAL;
2767c478bd9Sstevel@tonic-gate 			break;
2777c478bd9Sstevel@tonic-gate 		}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 		/* Get timezone name (Skip timezone description) */
2807c478bd9Sstevel@tonic-gate 		lp_tz = skipwhite(lp_coord + len_coord);
2817c478bd9Sstevel@tonic-gate 		if ((len = strcspn(lp_tz, SLASH)) == 0) {
2827c478bd9Sstevel@tonic-gate 			ncount = -1;
2837c478bd9Sstevel@tonic-gate 			sav_errno = EINVAL;
2847c478bd9Sstevel@tonic-gate 			break;
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 		/* If continents match, allocate a country struct */
2877c478bd9Sstevel@tonic-gate 		if ((len == len_ctnt) &&
2887c478bd9Sstevel@tonic-gate 				(strncmp(cont->ctnt_name, lp_tz, len) == 0)) {
2897c478bd9Sstevel@tonic-gate 			if ((cp = (struct tz_country *)
2907c478bd9Sstevel@tonic-gate 			    calloc(1, sizeof (struct tz_country))) == NULL) {
2917c478bd9Sstevel@tonic-gate 				sav_errno = ENOMEM;
2927c478bd9Sstevel@tonic-gate 				ncount = -1;
2937c478bd9Sstevel@tonic-gate 				break;
2947c478bd9Sstevel@tonic-gate 			}
2957c478bd9Sstevel@tonic-gate 			/* Copy and save country code (len already checked) */
2967c478bd9Sstevel@tonic-gate 			(void) strncpy(cp->ctry_code, lp_cc, CCLEN);
2977c478bd9Sstevel@tonic-gate 			cp->ctry_code[CCLEN] = '\0';
2987c478bd9Sstevel@tonic-gate 			(void) strncpy(ccbuf, lp_cc, CCLEN);
2997c478bd9Sstevel@tonic-gate 			ccbuf[CCLEN] = '\0';
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 			/* Create linked list */
3027c478bd9Sstevel@tonic-gate 			if (head == NULL) {
3037c478bd9Sstevel@tonic-gate 				head = cp;
3047c478bd9Sstevel@tonic-gate 			} else {
3057c478bd9Sstevel@tonic-gate 				prev->ctry_next = cp;
3067c478bd9Sstevel@tonic-gate 			};
3077c478bd9Sstevel@tonic-gate 			prev = cp;
3087c478bd9Sstevel@tonic-gate 			ncount++;
3097c478bd9Sstevel@tonic-gate 		}
3107c478bd9Sstevel@tonic-gate 	}	/* while */
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	if (ncount == -1)
3137c478bd9Sstevel@tonic-gate 		goto error;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/* Get country name from country.tab; get localized country name */
3167c478bd9Sstevel@tonic-gate 	/* Read country list, match country codes to process entry */
3177c478bd9Sstevel@tonic-gate 	cp = head;
3187c478bd9Sstevel@tonic-gate 	/*CONSTANTCONDITION*/
3197c478bd9Sstevel@tonic-gate 	while (1) {
3207c478bd9Sstevel@tonic-gate 		if (fgets(buff, sizeof (buff), fp_cc) == NULL) {
3217c478bd9Sstevel@tonic-gate 			if (feof(fp_cc) == 0) {
3227c478bd9Sstevel@tonic-gate 				/* fgets() sets errno */
3237c478bd9Sstevel@tonic-gate 				ncount = -1;
3247c478bd9Sstevel@tonic-gate 				sav_errno = errno;
3257c478bd9Sstevel@tonic-gate 			}
3267c478bd9Sstevel@tonic-gate 			break;
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 		/* Skip comments or blank/whitespace lines */
3297c478bd9Sstevel@tonic-gate 		if ((status = skipline(buff)) != 0) {
3307c478bd9Sstevel@tonic-gate 			if (status == 1)
3317c478bd9Sstevel@tonic-gate 				continue;
3327c478bd9Sstevel@tonic-gate 			else {
3337c478bd9Sstevel@tonic-gate 				sav_errno = EINVAL;
3347c478bd9Sstevel@tonic-gate 				ncount = -1;
3357c478bd9Sstevel@tonic-gate 				break;
3367c478bd9Sstevel@tonic-gate 			}
3377c478bd9Sstevel@tonic-gate 		}
3387c478bd9Sstevel@tonic-gate 		/* Match country codes */
3397c478bd9Sstevel@tonic-gate 		if ((len = strcspn(buff, WHITESPACE)) != CCLEN) {
3407c478bd9Sstevel@tonic-gate 			sav_errno = EINVAL;
3417c478bd9Sstevel@tonic-gate 			ncount = -1;
3427c478bd9Sstevel@tonic-gate 			break;
3437c478bd9Sstevel@tonic-gate 		}
3447c478bd9Sstevel@tonic-gate 		if ((cmp = strncmp(cp->ctry_code, buff, CCLEN)) == 0) {
3457c478bd9Sstevel@tonic-gate 			/* Get country description, and localized desc. */
3467c478bd9Sstevel@tonic-gate 			/* Skip to country description */
3477c478bd9Sstevel@tonic-gate 			lp = &buff[CCLEN];
3487c478bd9Sstevel@tonic-gate 			if ((len = strspn(lp, WHITESPACE)) == 0) {
3497c478bd9Sstevel@tonic-gate 				sav_errno = EINVAL;
3507c478bd9Sstevel@tonic-gate 				ncount = -1;
3517c478bd9Sstevel@tonic-gate 				break;
3527c478bd9Sstevel@tonic-gate 			}
3537c478bd9Sstevel@tonic-gate 			lp += len;		/* lp points to country desc. */
3547c478bd9Sstevel@tonic-gate 			len = strcspn(lp, NEWLINE);
3557c478bd9Sstevel@tonic-gate 			if ((ptr = calloc(len + 1, 1)) == NULL) {
3567c478bd9Sstevel@tonic-gate 				ncount = -1;
3577c478bd9Sstevel@tonic-gate 				errno = ENOMEM;
3587c478bd9Sstevel@tonic-gate 				break;
3597c478bd9Sstevel@tonic-gate 			}
3607c478bd9Sstevel@tonic-gate 			(void) strncpy(ptr, lp, len);
3617c478bd9Sstevel@tonic-gate 			*(ptr + len) = '\0';
3627c478bd9Sstevel@tonic-gate 			cp->ctry_id_desc = ptr;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 			/* Get localized country description */
3657c478bd9Sstevel@tonic-gate 			lptr = dgettext(TEXT_DOMAIN, ptr);
3667c478bd9Sstevel@tonic-gate 			if ((ptr = strdup(lptr)) == NULL) {
3677c478bd9Sstevel@tonic-gate 				ncount = -1;
3687c478bd9Sstevel@tonic-gate 				errno = ENOMEM;
3697c478bd9Sstevel@tonic-gate 				break;
3707c478bd9Sstevel@tonic-gate 			}
3717c478bd9Sstevel@tonic-gate 			cp->ctry_display_desc = ptr;
3727c478bd9Sstevel@tonic-gate 		} else if (cmp > 0) {
3737c478bd9Sstevel@tonic-gate 			/* Keep searching country.tab */
3747c478bd9Sstevel@tonic-gate 			continue;
3757c478bd9Sstevel@tonic-gate 		} else {
3767c478bd9Sstevel@tonic-gate 			/* Not found - should not happen */
3777c478bd9Sstevel@tonic-gate 			ncount = -1;
3787c478bd9Sstevel@tonic-gate 			errno = EILSEQ;
3797c478bd9Sstevel@tonic-gate 			break;
3807c478bd9Sstevel@tonic-gate 		}
3817c478bd9Sstevel@tonic-gate 		if (cp->ctry_next == NULL) {
3827c478bd9Sstevel@tonic-gate 			/* done with countries list */
3837c478bd9Sstevel@tonic-gate 			break;
3847c478bd9Sstevel@tonic-gate 		} else {
3857c478bd9Sstevel@tonic-gate 			cp = cp->ctry_next;
3867c478bd9Sstevel@tonic-gate 		}
3877c478bd9Sstevel@tonic-gate 	}		/* while */
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	/* Now sort the list by ctry_display_desc field */
3907c478bd9Sstevel@tonic-gate 	if ((ncount != -1) &&
3917c478bd9Sstevel@tonic-gate 		((cp2 = calloc(ncount, sizeof (struct tz_country))) != NULL)) {
3927c478bd9Sstevel@tonic-gate 		/*
3937c478bd9Sstevel@tonic-gate 		 * First copy list to a static array for qsort() to use.
3947c478bd9Sstevel@tonic-gate 		 * Use the cnt_next field to point back to original structure.
3957c478bd9Sstevel@tonic-gate 		 */
3967c478bd9Sstevel@tonic-gate 		cp = head;
3977c478bd9Sstevel@tonic-gate 		for (i = 0; i < ncount; i++) {
3987c478bd9Sstevel@tonic-gate 			next = cp->ctry_next;
3997c478bd9Sstevel@tonic-gate 			cp->ctry_next = cp;
4007c478bd9Sstevel@tonic-gate 			(void) memcpy(&cp2[i], cp, sizeof (struct tz_country));
4017c478bd9Sstevel@tonic-gate 			cp = next;
4027c478bd9Sstevel@tonic-gate 		}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 		/* Next, call qsort() using strcoll() to order */
4057c478bd9Sstevel@tonic-gate 		qsort(cp2, ncount, sizeof (struct tz_country),
4067c478bd9Sstevel@tonic-gate 			(int (*)(const void *, const void *))compar);
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 		/* Rearrange the country list according to qsort order */
4097c478bd9Sstevel@tonic-gate 		head = cp2->ctry_next; /* ctry_next is pointer to orig struct */
4107c478bd9Sstevel@tonic-gate 		cp = head;
4117c478bd9Sstevel@tonic-gate 		for (i = 0; i < ncount; i++) {
4127c478bd9Sstevel@tonic-gate 			prev = cp;
4137c478bd9Sstevel@tonic-gate 			cp = cp2[i].ctry_next;
4147c478bd9Sstevel@tonic-gate 			prev->ctry_next = cp;
4157c478bd9Sstevel@tonic-gate 		}
4167c478bd9Sstevel@tonic-gate 		cp->ctry_next = NULL;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 		/* Last, free the static buffer */
4197c478bd9Sstevel@tonic-gate 		free(cp2);
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	} else {
4227c478bd9Sstevel@tonic-gate 		if (ncount != -1)
4237c478bd9Sstevel@tonic-gate 			ncount = -1;
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate error:
4277c478bd9Sstevel@tonic-gate 	(void) fclose(fp_zone);
4287c478bd9Sstevel@tonic-gate 	(void) fclose(fp_cc);
4297c478bd9Sstevel@tonic-gate 	if (ncount == -1) {
4307c478bd9Sstevel@tonic-gate 		/* free the linked list */
4317c478bd9Sstevel@tonic-gate 		if (head != NULL)
4327c478bd9Sstevel@tonic-gate 			(void) free_tz_countries(head);
4337c478bd9Sstevel@tonic-gate 		if (sav_errno)
4347c478bd9Sstevel@tonic-gate 			errno = sav_errno;
4357c478bd9Sstevel@tonic-gate 	} else {
4367c478bd9Sstevel@tonic-gate 		*country = head;
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 	return (ncount);
4397c478bd9Sstevel@tonic-gate }
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate /*
4427c478bd9Sstevel@tonic-gate  * get_timezones_by_country() finds the list of timezones from the
4437c478bd9Sstevel@tonic-gate  * zone_sun.tab file, for the input country.
4447c478bd9Sstevel@tonic-gate  */
4457c478bd9Sstevel@tonic-gate int
get_timezones_by_country(struct tz_timezone ** tmzone,struct tz_country * country)4467c478bd9Sstevel@tonic-gate get_timezones_by_country(struct tz_timezone **tmzone,
4477c478bd9Sstevel@tonic-gate 	struct tz_country *country)
4487c478bd9Sstevel@tonic-gate {
4497c478bd9Sstevel@tonic-gate 	FILE *fp_zone;		/* zone.tab */
4507c478bd9Sstevel@tonic-gate 	int match = 0, ncount = 0, sav_errno = 0, status;
4517c478bd9Sstevel@tonic-gate 	char buff[1024];
4527c478bd9Sstevel@tonic-gate 	char *lp_cc, *lp_tz, *lp_otz, *lp_coord, *lp_tzdesc, *ptr, *lptr;
4537c478bd9Sstevel@tonic-gate 	size_t len_tz, len_otz, len_coord, len_tzdesc;
4547c478bd9Sstevel@tonic-gate 	struct tz_timezone *head = NULL, *prev = NULL, *tp;
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	/* open zone.tab file */
4577c478bd9Sstevel@tonic-gate 	if ((fp_zone = fopen(ZONE_SUN_TAB, "r")) == NULL)
4587c478bd9Sstevel@tonic-gate 		return (-1);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	/* Read through zone.tab until countries match */
4617c478bd9Sstevel@tonic-gate 	/*CONSTANTCONDITION*/
4627c478bd9Sstevel@tonic-gate 	while (1) {
4637c478bd9Sstevel@tonic-gate 		if (fgets(buff, sizeof (buff), fp_zone) == NULL) {
4647c478bd9Sstevel@tonic-gate 			if (feof(fp_zone)) {
4657c478bd9Sstevel@tonic-gate 				break;
4667c478bd9Sstevel@tonic-gate 			} else {
4677c478bd9Sstevel@tonic-gate 				/* fgets() sets errno */
4687c478bd9Sstevel@tonic-gate 				ncount = -1;
4697c478bd9Sstevel@tonic-gate 				sav_errno = errno;
4707c478bd9Sstevel@tonic-gate 				break;
4717c478bd9Sstevel@tonic-gate 			}
4727c478bd9Sstevel@tonic-gate 		}
4737c478bd9Sstevel@tonic-gate 		/* Skip comments or blank/whitespace lines */
4747c478bd9Sstevel@tonic-gate 		if ((status = skipline(buff)) != 0) {
4757c478bd9Sstevel@tonic-gate 			if (status == 1)
4767c478bd9Sstevel@tonic-gate 				continue;
4777c478bd9Sstevel@tonic-gate 			else {
4787c478bd9Sstevel@tonic-gate 				sav_errno = EINVAL;
4797c478bd9Sstevel@tonic-gate 				ncount = -1;
4807c478bd9Sstevel@tonic-gate 				break;
4817c478bd9Sstevel@tonic-gate 			}
4827c478bd9Sstevel@tonic-gate 		}
4837c478bd9Sstevel@tonic-gate 		/*
4847c478bd9Sstevel@tonic-gate 		 * Find country entries, or detect if no country matches.
4857c478bd9Sstevel@tonic-gate 		 */
4867c478bd9Sstevel@tonic-gate 		lp_cc = skipwhite(&buff[0]);
4877c478bd9Sstevel@tonic-gate 		if (strcspn(lp_cc, WHITESPACE) != CCLEN) {
4887c478bd9Sstevel@tonic-gate 			sav_errno = EINVAL;
4897c478bd9Sstevel@tonic-gate 			ncount = -1;
4907c478bd9Sstevel@tonic-gate 			break;
4917c478bd9Sstevel@tonic-gate 		}
4927c478bd9Sstevel@tonic-gate 		if (strncmp(country->ctry_code, lp_cc, CCLEN) == 0) {
4937c478bd9Sstevel@tonic-gate 			match = 1;
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 			/* Get coordinates */
4967c478bd9Sstevel@tonic-gate 			lp_coord = skipwhite(lp_cc + CCLEN);
4977c478bd9Sstevel@tonic-gate 			if (((len_coord = strcspn(lp_coord, WHITESPACE)) !=
4987c478bd9Sstevel@tonic-gate 					COORD_FMTLEN1) &&
4997c478bd9Sstevel@tonic-gate 					(len_coord != COORD_FMTLEN2)) {
5007c478bd9Sstevel@tonic-gate 				ncount = -1;
5017c478bd9Sstevel@tonic-gate 				sav_errno = EINVAL;
5027c478bd9Sstevel@tonic-gate 				break;
5037c478bd9Sstevel@tonic-gate 			}
5047c478bd9Sstevel@tonic-gate 			/* Get Olson timezone name */
5057c478bd9Sstevel@tonic-gate 			lp_otz = skipwhite(lp_coord + len_coord);
5067c478bd9Sstevel@tonic-gate 			len_otz = strcspn(lp_otz, WHITESPACE);
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 			/* Get Solaris compatible timezone name */
5097c478bd9Sstevel@tonic-gate 			lp_tz = skipwhite(lp_otz + len_otz);
5107c478bd9Sstevel@tonic-gate 			len_tz = strcspn(lp_tz, WHITESPACE_NL);
5117c478bd9Sstevel@tonic-gate 			if (*(lp_tz + len_tz - 1) == '\n') {
5127c478bd9Sstevel@tonic-gate 				/* No timezone description */
5137c478bd9Sstevel@tonic-gate 				len_tz--;
5147c478bd9Sstevel@tonic-gate 				lp_tzdesc = NULL;
5157c478bd9Sstevel@tonic-gate 				len_tzdesc = 0;
5167c478bd9Sstevel@tonic-gate 			} else {
5177c478bd9Sstevel@tonic-gate 				/* Get timezone description */
5187c478bd9Sstevel@tonic-gate 				lp_tzdesc = skipwhite(lp_tz +
5197c478bd9Sstevel@tonic-gate 					len_tz);
5207c478bd9Sstevel@tonic-gate 				len_tzdesc = strcspn(lp_tzdesc,
5217c478bd9Sstevel@tonic-gate 					NEWLINE);
5227c478bd9Sstevel@tonic-gate 			}
5237c478bd9Sstevel@tonic-gate 			/*
5247c478bd9Sstevel@tonic-gate 			 * Check tz name lengths.  This check assumes the
5257c478bd9Sstevel@tonic-gate 			 * tz_oname and tz_name fields are the same size.
5267c478bd9Sstevel@tonic-gate 			 * (since tz_name may be written with lp_otz, if
5277c478bd9Sstevel@tonic-gate 			 * lp_tz is "-".)
5287c478bd9Sstevel@tonic-gate 			 */
5297c478bd9Sstevel@tonic-gate 			if ((len_otz > _TZBUFLEN - 1) ||
5307c478bd9Sstevel@tonic-gate 				(len_tz > _TZBUFLEN - 1)) {
5317c478bd9Sstevel@tonic-gate 				sav_errno = ENAMETOOLONG;
5327c478bd9Sstevel@tonic-gate 				ncount = -1;
5337c478bd9Sstevel@tonic-gate 				break;
5347c478bd9Sstevel@tonic-gate 			}
5357c478bd9Sstevel@tonic-gate 			/* Create timezone struct */
5367c478bd9Sstevel@tonic-gate 			if ((tp =  (struct tz_timezone *)
5377c478bd9Sstevel@tonic-gate 				calloc(1, sizeof (struct tz_timezone))) ==
5387c478bd9Sstevel@tonic-gate 					NULL) {
5397c478bd9Sstevel@tonic-gate 				sav_errno = ENOMEM;
5407c478bd9Sstevel@tonic-gate 				ncount = -1;
5417c478bd9Sstevel@tonic-gate 				break;
5427c478bd9Sstevel@tonic-gate 			}
5437c478bd9Sstevel@tonic-gate 			/*
5447c478bd9Sstevel@tonic-gate 			 * Copy the timezone names - use the Solaris
5457c478bd9Sstevel@tonic-gate 			 * compatible timezone name if one exists,
5467c478bd9Sstevel@tonic-gate 			 * otherwise use the current Olson timezone
5477c478bd9Sstevel@tonic-gate 			 * name.
5487c478bd9Sstevel@tonic-gate 			 */
5497c478bd9Sstevel@tonic-gate 			(void) strncpy(tp->tz_oname, lp_otz, len_otz);
5507c478bd9Sstevel@tonic-gate 			tp->tz_oname[len_otz] = '\0';
5517c478bd9Sstevel@tonic-gate 			if (strncmp("-", lp_tz, len_tz) == 0) {
5527c478bd9Sstevel@tonic-gate 				lp_tz = lp_otz;
5537c478bd9Sstevel@tonic-gate 				len_tz = len_otz;
5547c478bd9Sstevel@tonic-gate 			}
5557c478bd9Sstevel@tonic-gate 			/* If name has numeric digits, prefix ':' */
5567c478bd9Sstevel@tonic-gate 			if (strcspn(lp_tz, DIGITS) < len_tz) {
5577c478bd9Sstevel@tonic-gate 				if (len_tz > _TZBUFLEN - 2) {
5587c478bd9Sstevel@tonic-gate 					free(tp);
5597c478bd9Sstevel@tonic-gate 					sav_errno = ENAMETOOLONG;
5607c478bd9Sstevel@tonic-gate 					ncount = -1;
5617c478bd9Sstevel@tonic-gate 					break;
5627c478bd9Sstevel@tonic-gate 				}
5637c478bd9Sstevel@tonic-gate 				tp->tz_name[0] = ':';
5647c478bd9Sstevel@tonic-gate 				(void) strncpy(tp->tz_name + 1, lp_tz, len_tz);
5657c478bd9Sstevel@tonic-gate 				tp->tz_name[len_tz + 1] = '\0';
5667c478bd9Sstevel@tonic-gate 			} else {
5677c478bd9Sstevel@tonic-gate 				(void) strncpy(tp->tz_name, lp_tz, len_tz);
5687c478bd9Sstevel@tonic-gate 				tp->tz_name[len_tz] = '\0';
5697c478bd9Sstevel@tonic-gate 			}
5707c478bd9Sstevel@tonic-gate 			/* Process timezone description, if one exists */
5717c478bd9Sstevel@tonic-gate 			if ((lp_tzdesc != NULL) && (*lp_tzdesc != '\n')) {
5727c478bd9Sstevel@tonic-gate 				if ((ptr = calloc(1, len_tzdesc + 1))
5737c478bd9Sstevel@tonic-gate 						== NULL) {
5747c478bd9Sstevel@tonic-gate 					sav_errno = ENOMEM;
5757c478bd9Sstevel@tonic-gate 					ncount = -1;
5767c478bd9Sstevel@tonic-gate 					(void) free_timezones(tp);
5777c478bd9Sstevel@tonic-gate 					break;
5787c478bd9Sstevel@tonic-gate 				}
5797c478bd9Sstevel@tonic-gate 				(void) strncpy(ptr, lp_tzdesc, len_tzdesc);
5807c478bd9Sstevel@tonic-gate 				*(ptr + len_tzdesc) = '\0';
5817c478bd9Sstevel@tonic-gate 				tp->tz_id_desc = ptr;
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 				/* Get localized country description */
5847c478bd9Sstevel@tonic-gate 				lptr = dgettext(TEXT_DOMAIN, ptr);
5857c478bd9Sstevel@tonic-gate 				if ((ptr = strdup(lptr)) == NULL) {
5867c478bd9Sstevel@tonic-gate 					sav_errno = ENOMEM;
5877c478bd9Sstevel@tonic-gate 					ncount = -1;
5887c478bd9Sstevel@tonic-gate 					(void) free_timezones(tp);
5897c478bd9Sstevel@tonic-gate 					break;
5907c478bd9Sstevel@tonic-gate 				}
5917c478bd9Sstevel@tonic-gate 				tp->tz_display_desc = ptr;
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 			} else {
5947c478bd9Sstevel@tonic-gate 				tp->tz_id_desc = NULL;
5957c478bd9Sstevel@tonic-gate 				tp->tz_display_desc = NULL;
5967c478bd9Sstevel@tonic-gate 			}
5977c478bd9Sstevel@tonic-gate 			/* Get coordinate information */
5987c478bd9Sstevel@tonic-gate 			if (get_coord(tp, lp_coord, len_coord) == -1) {
5997c478bd9Sstevel@tonic-gate 				sav_errno = EILSEQ;
6007c478bd9Sstevel@tonic-gate 				ncount = -1;
6017c478bd9Sstevel@tonic-gate 				(void) free_timezones(tp);
6027c478bd9Sstevel@tonic-gate 				break;
6037c478bd9Sstevel@tonic-gate 			}
6047c478bd9Sstevel@tonic-gate 			/* Store timezone struct in a linked list */
6057c478bd9Sstevel@tonic-gate 			if (head == NULL) {
6067c478bd9Sstevel@tonic-gate 				head = tp;
6077c478bd9Sstevel@tonic-gate 			} else {
6087c478bd9Sstevel@tonic-gate 				prev->tz_next = tp;
6097c478bd9Sstevel@tonic-gate 			}
6107c478bd9Sstevel@tonic-gate 			prev = tp;
6117c478bd9Sstevel@tonic-gate 			ncount++;
6127c478bd9Sstevel@tonic-gate 		} else {
6137c478bd9Sstevel@tonic-gate 			if (match == 1) {
6147c478bd9Sstevel@tonic-gate 				/*
6157c478bd9Sstevel@tonic-gate 				 * At this point, since zone_sun.tab is ordered,
6167c478bd9Sstevel@tonic-gate 				 * if we've already found timezone entries for
6177c478bd9Sstevel@tonic-gate 				 * the input country, then we've found all of
6187c478bd9Sstevel@tonic-gate 				 * the desired timezone entries (since we will
6197c478bd9Sstevel@tonic-gate 				 * be past that country's section in
6207c478bd9Sstevel@tonic-gate 				 * zone_sun.tab), and we are done.
6217c478bd9Sstevel@tonic-gate 				 */
6227c478bd9Sstevel@tonic-gate 				break;
6237c478bd9Sstevel@tonic-gate 			}
6247c478bd9Sstevel@tonic-gate 		}
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	/* Finish up */
6287c478bd9Sstevel@tonic-gate 	(void) fclose(fp_zone);
6297c478bd9Sstevel@tonic-gate 	if (ncount == -1) {
6307c478bd9Sstevel@tonic-gate 		if (head != NULL)
6317c478bd9Sstevel@tonic-gate 			(void) free_timezones(head);
6327c478bd9Sstevel@tonic-gate 		if (sav_errno)
6337c478bd9Sstevel@tonic-gate 			errno = sav_errno;
6347c478bd9Sstevel@tonic-gate 	} else {
6357c478bd9Sstevel@tonic-gate 		*tmzone = head;
6367c478bd9Sstevel@tonic-gate 	}
6377c478bd9Sstevel@tonic-gate 	return (ncount);
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate int
free_tz_continents(struct tz_continent * cont)6417c478bd9Sstevel@tonic-gate free_tz_continents(struct tz_continent *cont)
6427c478bd9Sstevel@tonic-gate {
6437c478bd9Sstevel@tonic-gate 	struct tz_continent *cptr, *cprev;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	cptr = cont;
6467c478bd9Sstevel@tonic-gate 	while (cptr != NULL) {
6477c478bd9Sstevel@tonic-gate 		if (cptr->ctnt_id_desc != NULL)
6487c478bd9Sstevel@tonic-gate 			free(cptr->ctnt_id_desc);
6497c478bd9Sstevel@tonic-gate 		if (cptr->ctnt_display_desc != NULL)
6507c478bd9Sstevel@tonic-gate 			free(cptr->ctnt_display_desc);
6517c478bd9Sstevel@tonic-gate 		cprev = cptr;
6527c478bd9Sstevel@tonic-gate 		cptr = cptr->ctnt_next;
6537c478bd9Sstevel@tonic-gate 		free(cprev);
6547c478bd9Sstevel@tonic-gate 	}
6557c478bd9Sstevel@tonic-gate 	return (0);
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate int
free_tz_countries(struct tz_country * country)6597c478bd9Sstevel@tonic-gate free_tz_countries(struct tz_country *country)
6607c478bd9Sstevel@tonic-gate {
6617c478bd9Sstevel@tonic-gate 	struct tz_country *cptr, *cprev;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	cptr = country;
6647c478bd9Sstevel@tonic-gate 	while (cptr != NULL) {
6657c478bd9Sstevel@tonic-gate 		if (cptr->ctry_id_desc != NULL)
6667c478bd9Sstevel@tonic-gate 			free(cptr->ctry_id_desc);
6677c478bd9Sstevel@tonic-gate 		if (cptr->ctry_display_desc != NULL)
6687c478bd9Sstevel@tonic-gate 			free(cptr->ctry_display_desc);
6697c478bd9Sstevel@tonic-gate 		cprev = cptr;
6707c478bd9Sstevel@tonic-gate 		cptr = cptr->ctry_next;
6717c478bd9Sstevel@tonic-gate 		free(cprev);
6727c478bd9Sstevel@tonic-gate 	}
6737c478bd9Sstevel@tonic-gate 	return (0);
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate int
free_timezones(struct tz_timezone * timezone)6777c478bd9Sstevel@tonic-gate free_timezones(struct tz_timezone *timezone)
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate 	struct tz_timezone *tzptr, *tzprev;
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	tzptr = timezone;
6827c478bd9Sstevel@tonic-gate 	while (tzptr != NULL) {
6837c478bd9Sstevel@tonic-gate 		if (tzptr->tz_id_desc != NULL)
6847c478bd9Sstevel@tonic-gate 			free(tzptr->tz_id_desc);
6857c478bd9Sstevel@tonic-gate 		if (tzptr->tz_display_desc != NULL)
6867c478bd9Sstevel@tonic-gate 			free(tzptr->tz_display_desc);
6877c478bd9Sstevel@tonic-gate 		tzprev = tzptr;
6887c478bd9Sstevel@tonic-gate 		tzptr = tzptr->tz_next;
6897c478bd9Sstevel@tonic-gate 		free(tzprev);
6907c478bd9Sstevel@tonic-gate 	}
6917c478bd9Sstevel@tonic-gate 	return (0);
6927c478bd9Sstevel@tonic-gate }
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate /*
6957c478bd9Sstevel@tonic-gate  *  conv_gmt() returns a GMT-offset style timezone
6967c478bd9Sstevel@tonic-gate  *    If flag = 0, return Quoted POSIX timezone like: <GMT+8>+8
6977c478bd9Sstevel@tonic-gate  *    If flag = 1, return zoneinfo timezone like:  :Etc/GMT+8
6987c478bd9Sstevel@tonic-gate  */
6997c478bd9Sstevel@tonic-gate char *
conv_gmt(int seconds,int flag)7007c478bd9Sstevel@tonic-gate conv_gmt(int seconds, int flag)
7017c478bd9Sstevel@tonic-gate {
7027c478bd9Sstevel@tonic-gate 	int hour;
7037c478bd9Sstevel@tonic-gate 	char *cp;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	if ((seconds < _GMT_MIN) || (seconds > _GMT_MAX)) {
7067c478bd9Sstevel@tonic-gate 		errno = EINVAL;
7077c478bd9Sstevel@tonic-gate 		return (NULL);
7087c478bd9Sstevel@tonic-gate 	}
7097c478bd9Sstevel@tonic-gate 	hour = (seconds / 60) / 60;
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	if (flag == 0) {
7127c478bd9Sstevel@tonic-gate 		cp = _conv_gmt_posix(hour);
7137c478bd9Sstevel@tonic-gate 	} else if (flag == 1) {
7147c478bd9Sstevel@tonic-gate 		cp = _conv_gmt_zoneinfo(hour);
7157c478bd9Sstevel@tonic-gate 	} else {
7167c478bd9Sstevel@tonic-gate 		errno = EINVAL;
7177c478bd9Sstevel@tonic-gate 		return (NULL);
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 	return (cp);
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate static char *
_conv_gmt_posix(int hour)7237c478bd9Sstevel@tonic-gate _conv_gmt_posix(int hour)
7247c478bd9Sstevel@tonic-gate {
7257c478bd9Sstevel@tonic-gate 	char *cp;
7267c478bd9Sstevel@tonic-gate 	char xsign;
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 	if (hour == 0) {
7297c478bd9Sstevel@tonic-gate 		if ((cp = strdup(GMT0_FMT)) == NULL) {
7307c478bd9Sstevel@tonic-gate 			errno = ENOMEM;
7317c478bd9Sstevel@tonic-gate 			return (NULL);
7327c478bd9Sstevel@tonic-gate 		}
7337c478bd9Sstevel@tonic-gate 	} else {
7347c478bd9Sstevel@tonic-gate 		if (hour < 0) {
7357c478bd9Sstevel@tonic-gate 			xsign = '-';
7367c478bd9Sstevel@tonic-gate 			/* make hour positive for snprintf() */
7377c478bd9Sstevel@tonic-gate 			hour = -hour;
7387c478bd9Sstevel@tonic-gate 		} else {
7397c478bd9Sstevel@tonic-gate 			xsign = '+';
7407c478bd9Sstevel@tonic-gate 		}
7417c478bd9Sstevel@tonic-gate 		if ((cp = malloc(GMT_FMT_Q_LEN + 1)) == NULL) {
7427c478bd9Sstevel@tonic-gate 			errno = ENOMEM;
7437c478bd9Sstevel@tonic-gate 			return (NULL);
7447c478bd9Sstevel@tonic-gate 		}
7457c478bd9Sstevel@tonic-gate 		(void) snprintf(cp, GMT_FMT_Q_LEN + 1, GMT_FMT_Q,
7467c478bd9Sstevel@tonic-gate 			xsign, hour, xsign, hour);
7477c478bd9Sstevel@tonic-gate 	}
7487c478bd9Sstevel@tonic-gate 	return (cp);
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate static char *
_conv_gmt_zoneinfo(int hour)7527c478bd9Sstevel@tonic-gate _conv_gmt_zoneinfo(int hour)
7537c478bd9Sstevel@tonic-gate {
7547c478bd9Sstevel@tonic-gate 	char *cp;
7557c478bd9Sstevel@tonic-gate 	char xsign;
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if (hour < 0) {
7587c478bd9Sstevel@tonic-gate 		xsign = '-';
7597c478bd9Sstevel@tonic-gate 		/* make hour positive for snprintf() */
7607c478bd9Sstevel@tonic-gate 		hour = -hour;
7617c478bd9Sstevel@tonic-gate 	} else {
7627c478bd9Sstevel@tonic-gate 		xsign = '+';
7637c478bd9Sstevel@tonic-gate 	}
7647c478bd9Sstevel@tonic-gate 	if ((cp = malloc(GMT_FMT_ZONE_LEN + 1)) == NULL) {
7657c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
7667c478bd9Sstevel@tonic-gate 		return (NULL);
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 	(void) snprintf(cp, GMT_FMT_ZONE_LEN + 1, GMT_FMT_ZONE,
7697c478bd9Sstevel@tonic-gate 		xsign, hour);
7707c478bd9Sstevel@tonic-gate 	return (cp);
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate /* Regular expression for POSIX GMT-offset timezone */
7747c478bd9Sstevel@tonic-gate #define	_GMT_EXPR	"(" _GMT_EXPR_U "|" _GMT_EXPR_Q ")"
7757c478bd9Sstevel@tonic-gate #define	_GMT_EXPR_U	"^[gG][mM][tT][-+]?[0-2]?[0-9]$"
7767c478bd9Sstevel@tonic-gate #define	_GMT_EXPR_Q	"^<[gG][mM][tT][-+]?[0-2]?[0-9]>[-+]?[0-2]?[0-9]$"
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate /*
7797c478bd9Sstevel@tonic-gate  * Regular expression for quoted POSIX timezone.
7807c478bd9Sstevel@tonic-gate  */
7817c478bd9Sstevel@tonic-gate /* Avoid alphabetic ranges (eg, a-z) due to effect of LC_COLLATE */
7827c478bd9Sstevel@tonic-gate #define	_ALPHA	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
7837c478bd9Sstevel@tonic-gate #define	_NUM	"0123456789"    /* for safe */
7847c478bd9Sstevel@tonic-gate #define	_STD_Q_ELM	"[-+" _ALPHA _NUM "]"
7857c478bd9Sstevel@tonic-gate #define	_STD_Q		"<" _STD_Q_ELM _STD_Q_ELM _STD_Q_ELM "+>"
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate /* Regular expression for unquoted POSIX timezone */
7887c478bd9Sstevel@tonic-gate #define	_STD_U_ELM_1	"[^-+,<" _NUM "]"
7897c478bd9Sstevel@tonic-gate #define	_STD_U_ELM	"[^-+,"  _NUM "]"
7907c478bd9Sstevel@tonic-gate #define	_STD_U		_STD_U_ELM_1 _STD_U_ELM _STD_U_ELM "+"
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate /* Regular expression for POSIX timezone */
7937c478bd9Sstevel@tonic-gate #define	_STD		"(" _STD_U "|" _STD_Q ")"
7947c478bd9Sstevel@tonic-gate #define	_DST		_STD
7957c478bd9Sstevel@tonic-gate #define	_OFFSET		"[-+]?" _TIME
7967c478bd9Sstevel@tonic-gate #define	_START		"(" _DATEJ "|" _DATEn "|" _DATEM ")"
7977c478bd9Sstevel@tonic-gate #define	_DATEJ		"J(([0-2]?[0-9]?[0-9])|3[0-5][0-9]|36[0-5])"
7987c478bd9Sstevel@tonic-gate #define	_DATEn		"(([0-2]?[0-9]?[0-9])|3[0-5][0-9]|36[0-5])"
7997c478bd9Sstevel@tonic-gate #define	_DATEM		"M([0-9]|10|11|12)\\.[1-5]\\.[0-6]"
8007c478bd9Sstevel@tonic-gate #define	_END		_START
8017c478bd9Sstevel@tonic-gate #define	_TIME		_HH "(:" _MM "(:" _SS ")?" ")?"
8027c478bd9Sstevel@tonic-gate #define	_HH		"(([0-1]?[0-9])|20|21|22|23|24)"
8037c478bd9Sstevel@tonic-gate #define	_MM		"[0-5]?[0-9]"
8047c478bd9Sstevel@tonic-gate #define	_SS		_MM
8057c478bd9Sstevel@tonic-gate #define	_POSIX_EXPR	"^" _STD _OFFSET "(" _DST "(" _OFFSET ")?" \
8067c478bd9Sstevel@tonic-gate 				"(," _START "(/" _TIME ")?" \
8077c478bd9Sstevel@tonic-gate 				"," _END "(/" _TIME ")?" ")?" ")?" "$"
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate #define	LEN_TZDIR	(sizeof (TZDIR) - 1)
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate /*
8127c478bd9Sstevel@tonic-gate  *  isvalid_tz() checks if timezone is a valid POSIX or zoneinfo
8137c478bd9Sstevel@tonic-gate  *  timezone, depending on the value of flag.  For flag = _VTZ_INSTALL,
8147c478bd9Sstevel@tonic-gate  *  isvalid_tz() behaves according to the behavior of Solaris Install
8157c478bd9Sstevel@tonic-gate  *  in Solaris 9 and earlier, where timezones under /usr/share/lib/zoneinfo
8167c478bd9Sstevel@tonic-gate  *  were validated.  isvalid_tz() has a special check for GMT+-* timezones
8177c478bd9Sstevel@tonic-gate  *  because Solaris Install validated /usr/share/lib/zoneinfo/GMT+-*.
8187c478bd9Sstevel@tonic-gate  *  However, when /usr/share/lib/zoneinfo/GMT+-* are EOF'd, that check
8197c478bd9Sstevel@tonic-gate  *  no longer works.
8207c478bd9Sstevel@tonic-gate  *
8217c478bd9Sstevel@tonic-gate  *  isvalid_tz() returns 1 if a valid timezone is detected.
8227c478bd9Sstevel@tonic-gate  */
8237c478bd9Sstevel@tonic-gate int
isvalid_tz(char * timezone,char * root,int flag)8247c478bd9Sstevel@tonic-gate isvalid_tz(char *timezone, char *root, int flag)
8257c478bd9Sstevel@tonic-gate {
8267c478bd9Sstevel@tonic-gate 	char path[MAXPATHLEN];
8277c478bd9Sstevel@tonic-gate 	char buf[sizeof (struct tzhead)];
8287c478bd9Sstevel@tonic-gate 	int fid, ret;
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	if ((timezone == NULL) || (*timezone == '\0')) {
8317c478bd9Sstevel@tonic-gate 		return (0);
8327c478bd9Sstevel@tonic-gate 	}
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	/* First check if timezone is a valid POSIX timezone */
8357c478bd9Sstevel@tonic-gate 	switch (flag) {
8367c478bd9Sstevel@tonic-gate 	case _VTZ_INSTALL:
8377c478bd9Sstevel@tonic-gate 		/*
8387c478bd9Sstevel@tonic-gate 		 * Special check for POSIX GMT timezone.
8397c478bd9Sstevel@tonic-gate 		 * If no match, check for zoneinfo timezone below
8407c478bd9Sstevel@tonic-gate 		 */
8417c478bd9Sstevel@tonic-gate 		if (_tz_match(_GMT_EXPR, timezone) == 0) {
8427c478bd9Sstevel@tonic-gate 			/* Valid GMT timezone */
8437c478bd9Sstevel@tonic-gate 			return (1);
8447c478bd9Sstevel@tonic-gate 		}
8457c478bd9Sstevel@tonic-gate 		break;
8467c478bd9Sstevel@tonic-gate 	case _VTZ_POSIX:
8477c478bd9Sstevel@tonic-gate 		/* Check for generic POSIX timezone */
8487c478bd9Sstevel@tonic-gate 		if (_tz_match(_POSIX_EXPR, timezone) == 0) {
8497c478bd9Sstevel@tonic-gate 			/* Valid POSIX timezone */
8507c478bd9Sstevel@tonic-gate 			return (1);
8517c478bd9Sstevel@tonic-gate 		}
8527c478bd9Sstevel@tonic-gate 		/* Invalid POSIX timezone */
8537c478bd9Sstevel@tonic-gate 		return (0);
8547c478bd9Sstevel@tonic-gate 	case _VTZ_ALL:
8557c478bd9Sstevel@tonic-gate 		/* Check for generic POSIX timezone */
8567c478bd9Sstevel@tonic-gate 		if (_tz_match(_POSIX_EXPR, timezone) == 0) {
8577c478bd9Sstevel@tonic-gate 			/* Valid POSIX timezone */
8587c478bd9Sstevel@tonic-gate 			return (1);
8597c478bd9Sstevel@tonic-gate 		}
8607c478bd9Sstevel@tonic-gate 		break;
8617c478bd9Sstevel@tonic-gate 	case _VTZ_ZONEINFO:
8627c478bd9Sstevel@tonic-gate 		break;
8637c478bd9Sstevel@tonic-gate 	default:
8647c478bd9Sstevel@tonic-gate 		return (0);
8657c478bd9Sstevel@tonic-gate 	}
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	/*
8687c478bd9Sstevel@tonic-gate 	 * Check for valid zoneinfo timezone -
8697c478bd9Sstevel@tonic-gate 	 * open zoneinfo file and check for magic number
8707c478bd9Sstevel@tonic-gate 	 */
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	/* skip prepended ':' if one exists */
8737c478bd9Sstevel@tonic-gate 	if (*timezone == ':') {
8747c478bd9Sstevel@tonic-gate 		timezone++;
8757c478bd9Sstevel@tonic-gate 	}
8767c478bd9Sstevel@tonic-gate 	/* Construct full zoneinfo pathname */
8777c478bd9Sstevel@tonic-gate 	if ((root != NULL) && (*root != '\0')) {
8787c478bd9Sstevel@tonic-gate 		ret = snprintf(path, sizeof (path),
8797c478bd9Sstevel@tonic-gate 		    "%s%s/%s", root, TZDIR, timezone);
8807c478bd9Sstevel@tonic-gate 		if (ret >= sizeof (path)) {
8817c478bd9Sstevel@tonic-gate 			/* too long */
8827c478bd9Sstevel@tonic-gate 			return (0);
8837c478bd9Sstevel@tonic-gate 		}
8847c478bd9Sstevel@tonic-gate 	} else {
8857c478bd9Sstevel@tonic-gate 		ret = snprintf(path, sizeof (path),
8867c478bd9Sstevel@tonic-gate 		    "%s/%s", TZDIR, timezone);
8877c478bd9Sstevel@tonic-gate 		if (ret >= sizeof (path)) {
8887c478bd9Sstevel@tonic-gate 			/* too long */
8897c478bd9Sstevel@tonic-gate 			return (0);
8907c478bd9Sstevel@tonic-gate 		}
8917c478bd9Sstevel@tonic-gate 	}
8927c478bd9Sstevel@tonic-gate 	if ((fid = open(path, O_RDONLY)) == -1) {
8937c478bd9Sstevel@tonic-gate 		return (0);
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 	if (read(fid, buf, sizeof (struct tzhead)) !=
8967c478bd9Sstevel@tonic-gate 	    sizeof (struct tzhead)) {
8977c478bd9Sstevel@tonic-gate 		(void) close(fid);
8987c478bd9Sstevel@tonic-gate 		return (0);
8997c478bd9Sstevel@tonic-gate 	}
9007c478bd9Sstevel@tonic-gate 	if (strncmp(buf, TZ_MAGIC, sizeof (TZ_MAGIC) - 1) != 0) {
9017c478bd9Sstevel@tonic-gate 		(void) close(fid);
9027c478bd9Sstevel@tonic-gate 		return (0);
9037c478bd9Sstevel@tonic-gate 	}
9047c478bd9Sstevel@tonic-gate 	if (close(fid) == -1) {
9057c478bd9Sstevel@tonic-gate 		return (0);
9067c478bd9Sstevel@tonic-gate 	}
9077c478bd9Sstevel@tonic-gate 	/* Valid zoneinfo timezone */
9087c478bd9Sstevel@tonic-gate 	return (1);
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate #define	N_MATCH		1
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate int
_tz_match(const char * expr,const char * string)9147c478bd9Sstevel@tonic-gate _tz_match(const char *expr, const char *string)
9157c478bd9Sstevel@tonic-gate {
9167c478bd9Sstevel@tonic-gate 	regex_t reg;
9177c478bd9Sstevel@tonic-gate 	regmatch_t pmatch[N_MATCH];
9187c478bd9Sstevel@tonic-gate 	int ret;
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	ret = regcomp(&reg, expr, REG_EXTENDED);
9217c478bd9Sstevel@tonic-gate 	if (ret != 0) {
9227c478bd9Sstevel@tonic-gate 		return (-1);
9237c478bd9Sstevel@tonic-gate 	}
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	ret = regexec((const regex_t *)&reg, string, N_MATCH, pmatch, 0);
9267c478bd9Sstevel@tonic-gate 	if (ret == 0) {
9277c478bd9Sstevel@tonic-gate #ifdef DEBUG
9287c478bd9Sstevel@tonic-gate 		printf("OK matched - %s\n", string);
9297c478bd9Sstevel@tonic-gate #endif
9307c478bd9Sstevel@tonic-gate 		regfree(&reg);
9317c478bd9Sstevel@tonic-gate 		return (0);
9327c478bd9Sstevel@tonic-gate 	}
9337c478bd9Sstevel@tonic-gate #ifdef DEBUG
9347c478bd9Sstevel@tonic-gate 	printf("NOT matched - %s\n", string);
9357c478bd9Sstevel@tonic-gate #endif
9367c478bd9Sstevel@tonic-gate 	regfree(&reg);
9377c478bd9Sstevel@tonic-gate 	return (-1);
9387c478bd9Sstevel@tonic-gate }
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate char *
get_system_tz(char * root)9417c478bd9Sstevel@tonic-gate get_system_tz(char *root)
9427c478bd9Sstevel@tonic-gate {
9437c478bd9Sstevel@tonic-gate 	FILE *ifp;
9447c478bd9Sstevel@tonic-gate 	char buff[512];
9457c478bd9Sstevel@tonic-gate 	int serrno, ret;
9467c478bd9Sstevel@tonic-gate 	char *sp, *ptr, *p;
9477c478bd9Sstevel@tonic-gate 	char fname[MAXPATHLEN];
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	if ((ret = snprintf(fname, sizeof (fname), "%s/%s", root, DEFINIT)) >=
9507c478bd9Sstevel@tonic-gate 			sizeof (fname)) {
9517c478bd9Sstevel@tonic-gate 		errno = ENAMETOOLONG;
9527c478bd9Sstevel@tonic-gate 		return (NULL);
9537c478bd9Sstevel@tonic-gate 	} else if (ret < 0) {
9547c478bd9Sstevel@tonic-gate 		return (NULL);
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 	if ((ifp = fopen(fname, "r")) == NULL)
9577c478bd9Sstevel@tonic-gate 		return (NULL);
9587c478bd9Sstevel@tonic-gate 	while (fgets(buff, sizeof (buff), ifp) != NULL) {
9597c478bd9Sstevel@tonic-gate 		if (strncmp(buff, "TZ=", 3) == 0) {
9607c478bd9Sstevel@tonic-gate 			(void) fclose(ifp);
9617c478bd9Sstevel@tonic-gate 			p = &buff[3];
9627c478bd9Sstevel@tonic-gate 			if ((sp = strchr(p, ';')) != NULL) {
9637c478bd9Sstevel@tonic-gate 				*sp = '\0';
9647c478bd9Sstevel@tonic-gate 			} else if ((sp = strchr(p, '\n')) != NULL) {
9657c478bd9Sstevel@tonic-gate 				*sp = '\0';
9667c478bd9Sstevel@tonic-gate 			}
9677c478bd9Sstevel@tonic-gate 			if (strpbrk(p, "\"'") != NULL) {
9687c478bd9Sstevel@tonic-gate 				strip_quotes(p, p);
9697c478bd9Sstevel@tonic-gate 			}
9707c478bd9Sstevel@tonic-gate 			ptr = strdup(p);
9717c478bd9Sstevel@tonic-gate 			if (ptr == NULL) {
9727c478bd9Sstevel@tonic-gate 				errno = ENOMEM;
9737c478bd9Sstevel@tonic-gate 				return (NULL);
9747c478bd9Sstevel@tonic-gate 			}
9757c478bd9Sstevel@tonic-gate 			return (ptr);
9767c478bd9Sstevel@tonic-gate 		}
9777c478bd9Sstevel@tonic-gate 	}
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	/* Either reached EOF with no TZ= entry, or got fgets() error */
9807c478bd9Sstevel@tonic-gate 	serrno = errno;
9817c478bd9Sstevel@tonic-gate 	if (feof(ifp) != 0) {
9827c478bd9Sstevel@tonic-gate 		/* No "TZ=" entry found */
9837c478bd9Sstevel@tonic-gate 		serrno = EINVAL;
9847c478bd9Sstevel@tonic-gate 	}
9857c478bd9Sstevel@tonic-gate 	(void) fclose(ifp);
9867c478bd9Sstevel@tonic-gate 	errno = serrno;
9877c478bd9Sstevel@tonic-gate 	return (NULL);
9887c478bd9Sstevel@tonic-gate }
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate int
set_system_tz(char * tz,char * root)9917c478bd9Sstevel@tonic-gate set_system_tz(char *tz, char *root)
9927c478bd9Sstevel@tonic-gate {
9937c478bd9Sstevel@tonic-gate 	FILE *ifp, *ofp;	/* Input & output files */
9947c478bd9Sstevel@tonic-gate 	char *tmpdir, *tmp;	/* Temp file name and location */
9957c478bd9Sstevel@tonic-gate 	char buff[1024];
9967c478bd9Sstevel@tonic-gate 	int replaced = 0, ret, serrno;
9977c478bd9Sstevel@tonic-gate 	char *tdb;
9987c478bd9Sstevel@tonic-gate 	struct stat sb;
9997c478bd9Sstevel@tonic-gate 	char fname[MAXPATHLEN];
10007c478bd9Sstevel@tonic-gate 	const char *tzfmt;
10017c478bd9Sstevel@tonic-gate 	int len, fd;
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	if (tz == NULL || root == NULL)
10047c478bd9Sstevel@tonic-gate 		return (-1);
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	if (strchr(tz, '<')) {
10077c478bd9Sstevel@tonic-gate 		tzfmt = TZ_FMT_Q;
10087c478bd9Sstevel@tonic-gate 	} else {
10097c478bd9Sstevel@tonic-gate 		tzfmt = TZ_FMT;
10107c478bd9Sstevel@tonic-gate 	}
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	if ((ret = snprintf(fname, sizeof (fname), "%s/%s", root, DEFINIT)) >=
10137c478bd9Sstevel@tonic-gate 			sizeof (fname)) {
10147c478bd9Sstevel@tonic-gate 		errno = ENAMETOOLONG;
10157c478bd9Sstevel@tonic-gate 		return (-1);
10167c478bd9Sstevel@tonic-gate 	} else if (ret < 0) {
10177c478bd9Sstevel@tonic-gate 		return (-1);
10187c478bd9Sstevel@tonic-gate 	}
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	/*
10217c478bd9Sstevel@tonic-gate 	 * Generate temporary file name to use.  We make sure it's in the same
10227c478bd9Sstevel@tonic-gate 	 * directory as the db we're processing so that we can use rename to
10237c478bd9Sstevel@tonic-gate 	 * do the replace later.  Otherwise we run the risk of being on the
10247c478bd9Sstevel@tonic-gate 	 * wrong filesystem and having rename() fail for that reason.
10257c478bd9Sstevel@tonic-gate 	 */
10267c478bd9Sstevel@tonic-gate 	tdb = fname;
10277c478bd9Sstevel@tonic-gate 	if (trav_link(&tdb) == -1)
10287c478bd9Sstevel@tonic-gate 		return (-1);
10297c478bd9Sstevel@tonic-gate 	if ((tmpdir = strdup(tdb)) == NULL) {
10307c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
10317c478bd9Sstevel@tonic-gate 		return (-1);
10327c478bd9Sstevel@tonic-gate 	}
10337c478bd9Sstevel@tonic-gate 	remove_component(tmpdir);
10347c478bd9Sstevel@tonic-gate 	if ((len = strlen(tmpdir)) == 0) {
10357c478bd9Sstevel@tonic-gate 		(void) strcpy(tmpdir, ".");
10367c478bd9Sstevel@tonic-gate 		len = 1;
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	if ((tmp = malloc(len + TR_LEN + 1)) == NULL) {
10407c478bd9Sstevel@tonic-gate 		free(tmpdir);
10417c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
10427c478bd9Sstevel@tonic-gate 		return (-1);
10437c478bd9Sstevel@tonic-gate 	}
10447c478bd9Sstevel@tonic-gate 	(void) strcpy(tmp, tmpdir);
10457c478bd9Sstevel@tonic-gate 	(void) strcpy(tmp + len, TRAILER);
10467c478bd9Sstevel@tonic-gate 	free(tmpdir);
10477c478bd9Sstevel@tonic-gate 	if ((fd = mkstemp(tmp)) == -1) {
10487c478bd9Sstevel@tonic-gate 		free(tmp);
10497c478bd9Sstevel@tonic-gate 		return (-1);
10507c478bd9Sstevel@tonic-gate 	}
10517c478bd9Sstevel@tonic-gate 	if ((ofp = fdopen(fd, "w")) == NULL) {
10527c478bd9Sstevel@tonic-gate 		serrno = errno;
10537c478bd9Sstevel@tonic-gate 		(void) close(fd);
10547c478bd9Sstevel@tonic-gate 		free(tmp);
10557c478bd9Sstevel@tonic-gate 		errno = serrno;
10567c478bd9Sstevel@tonic-gate 		return (-1);
10577c478bd9Sstevel@tonic-gate 	}
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	/* Preserve permissions of current file if it exists */
10607c478bd9Sstevel@tonic-gate 	if (stat(tdb, &sb) == 0) {
10617c478bd9Sstevel@tonic-gate 		if (fchmod(fileno(ofp), sb.st_mode) == -1) {
10627c478bd9Sstevel@tonic-gate 			serrno = errno;
10637c478bd9Sstevel@tonic-gate 			(void) fclose(ofp);
10647c478bd9Sstevel@tonic-gate 			(void) unlink(tmp);
10657c478bd9Sstevel@tonic-gate 			free(tmp);
10667c478bd9Sstevel@tonic-gate 			errno = serrno;
10677c478bd9Sstevel@tonic-gate 			return (-1);
10687c478bd9Sstevel@tonic-gate 		}
10697c478bd9Sstevel@tonic-gate 		if (fchown(fileno(ofp), sb.st_uid, sb.st_gid) == -1) {
10707c478bd9Sstevel@tonic-gate 			serrno = errno;
10717c478bd9Sstevel@tonic-gate 			(void) fclose(ofp);
10727c478bd9Sstevel@tonic-gate 			(void) unlink(tmp);
10737c478bd9Sstevel@tonic-gate 			free(tmp);
10747c478bd9Sstevel@tonic-gate 			errno = serrno;
10757c478bd9Sstevel@tonic-gate 			return (-1);
10767c478bd9Sstevel@tonic-gate 		}
10777c478bd9Sstevel@tonic-gate 	} else if (errno != ENOENT) {
10787c478bd9Sstevel@tonic-gate 		serrno = errno;
10797c478bd9Sstevel@tonic-gate 		(void) fclose(ofp);
10807c478bd9Sstevel@tonic-gate 		(void) unlink(tmp);
10817c478bd9Sstevel@tonic-gate 		free(tmp);
10827c478bd9Sstevel@tonic-gate 		errno = serrno;
10837c478bd9Sstevel@tonic-gate 		return (-1);
10847c478bd9Sstevel@tonic-gate 	}
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	if ((ifp = fopen(fname, "r+")) != NULL) {
10877c478bd9Sstevel@tonic-gate 		while (fgets(buff, sizeof (buff), ifp) != NULL) {
10887c478bd9Sstevel@tonic-gate 			if (!replaced && (strncmp(buff, "TZ=", 3) == 0)) {
10897c478bd9Sstevel@tonic-gate 				ret = snprintf(buff, sizeof (buff), tzfmt,
10907c478bd9Sstevel@tonic-gate 							tz);
10917c478bd9Sstevel@tonic-gate 				if ((ret >= sizeof (buff)) || (ret < 0)) {
10927c478bd9Sstevel@tonic-gate 					if (ret >= sizeof (buff))
10937c478bd9Sstevel@tonic-gate 						serrno = EINVAL;
10947c478bd9Sstevel@tonic-gate 					(void) fclose(ofp);
10957c478bd9Sstevel@tonic-gate 					(void) fclose(ifp);
10967c478bd9Sstevel@tonic-gate 					(void) unlink(tmp);
10977c478bd9Sstevel@tonic-gate 					free(tmp);
10987c478bd9Sstevel@tonic-gate 					errno = serrno;
10997c478bd9Sstevel@tonic-gate 					return (-1);
11007c478bd9Sstevel@tonic-gate 				}
11017c478bd9Sstevel@tonic-gate 				replaced = 1;
11027c478bd9Sstevel@tonic-gate 			}
11037c478bd9Sstevel@tonic-gate 			if (fputs(buff, ofp) == EOF) {
11047c478bd9Sstevel@tonic-gate 				serrno = errno;
11057c478bd9Sstevel@tonic-gate 				(void) fclose(ofp);
11067c478bd9Sstevel@tonic-gate 				(void) fclose(ifp);
11077c478bd9Sstevel@tonic-gate 				(void) unlink(tmp);
11087c478bd9Sstevel@tonic-gate 				free(tmp);
11097c478bd9Sstevel@tonic-gate 				errno = serrno;
11107c478bd9Sstevel@tonic-gate 				return (-1);
11117c478bd9Sstevel@tonic-gate 			}
11127c478bd9Sstevel@tonic-gate 		}
11137c478bd9Sstevel@tonic-gate 		(void) fclose(ifp);
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	} else if (errno != ENOENT) {
11167c478bd9Sstevel@tonic-gate 		serrno = errno;
11177c478bd9Sstevel@tonic-gate 		(void) fclose(ofp);
11187c478bd9Sstevel@tonic-gate 		(void) unlink(tmp);
11197c478bd9Sstevel@tonic-gate 		free(tmp);
11207c478bd9Sstevel@tonic-gate 		errno = serrno;
11217c478bd9Sstevel@tonic-gate 		return (-1);
11227c478bd9Sstevel@tonic-gate 	}
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 	/*
11257c478bd9Sstevel@tonic-gate 	 * no $(ROOT)/etc/default/init found, or
11267c478bd9Sstevel@tonic-gate 	 * no "TZ=" entry found in the init file.
11277c478bd9Sstevel@tonic-gate 	 */
11287c478bd9Sstevel@tonic-gate 	if (!replaced &&
11297c478bd9Sstevel@tonic-gate 	    (fprintf(ofp, tzfmt, tz) == EOF)) {
11307c478bd9Sstevel@tonic-gate 		serrno = errno;
11317c478bd9Sstevel@tonic-gate 		(void) fclose(ofp);
11327c478bd9Sstevel@tonic-gate 		(void) unlink(tmp);
11337c478bd9Sstevel@tonic-gate 		free(tmp);
11347c478bd9Sstevel@tonic-gate 		errno = serrno;
11357c478bd9Sstevel@tonic-gate 		return (-1);
11367c478bd9Sstevel@tonic-gate 	}
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 	if (fsync(fileno(ofp))) {
11397c478bd9Sstevel@tonic-gate 		serrno = errno;
11407c478bd9Sstevel@tonic-gate 		(void) unlink(tmp);
11417c478bd9Sstevel@tonic-gate 		free(tmp);
11427c478bd9Sstevel@tonic-gate 		errno = serrno;
11437c478bd9Sstevel@tonic-gate 		return (-1);
11447c478bd9Sstevel@tonic-gate 	}
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	(void) fclose(ofp);
11477c478bd9Sstevel@tonic-gate 	if (rename(tmp, tdb) != 0) {
11487c478bd9Sstevel@tonic-gate 		serrno = errno;
11497c478bd9Sstevel@tonic-gate 		(void) unlink(tmp);
11507c478bd9Sstevel@tonic-gate 		free(tmp);
11517c478bd9Sstevel@tonic-gate 		errno = serrno;
11527c478bd9Sstevel@tonic-gate 		return (-1);
11537c478bd9Sstevel@tonic-gate 	} else {
11547c478bd9Sstevel@tonic-gate 		free(tmp);
11557c478bd9Sstevel@tonic-gate 		return (0);
11567c478bd9Sstevel@tonic-gate 	}
11577c478bd9Sstevel@tonic-gate }
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate /*
11607c478bd9Sstevel@tonic-gate  * Function to traverse a symlink path to find the real file at the end of
11617c478bd9Sstevel@tonic-gate  * the rainbow.
11627c478bd9Sstevel@tonic-gate  */
11637c478bd9Sstevel@tonic-gate int
trav_link(char ** path)11647c478bd9Sstevel@tonic-gate trav_link(char **path)
11657c478bd9Sstevel@tonic-gate {
11667c478bd9Sstevel@tonic-gate 	static char newpath[MAXPATHLEN];
11677c478bd9Sstevel@tonic-gate 	char lastpath[MAXPATHLEN];
11687c478bd9Sstevel@tonic-gate 	int len, ret;
11697c478bd9Sstevel@tonic-gate 	char *tp;
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	(void) strcpy(lastpath, *path);
11727c478bd9Sstevel@tonic-gate 	while ((len = readlink(*path, newpath, sizeof (newpath))) != -1) {
11737c478bd9Sstevel@tonic-gate 		newpath[len] = '\0';
11747c478bd9Sstevel@tonic-gate 		if (newpath[0] != '/') {
11757c478bd9Sstevel@tonic-gate 			if ((tp = strdup(newpath)) == NULL) {
11767c478bd9Sstevel@tonic-gate 				errno = ENOMEM;
11777c478bd9Sstevel@tonic-gate 				return (-1);
11787c478bd9Sstevel@tonic-gate 			}
11797c478bd9Sstevel@tonic-gate 			remove_component(lastpath);
11807c478bd9Sstevel@tonic-gate 			ret = snprintf(newpath, sizeof (newpath),
11817c478bd9Sstevel@tonic-gate 				"%s/%s", lastpath, tp);
11827c478bd9Sstevel@tonic-gate 			free(tp);
11837c478bd9Sstevel@tonic-gate 			if ((ret >= sizeof (newpath)) || (ret < 0))
11847c478bd9Sstevel@tonic-gate 				return (-1);
11857c478bd9Sstevel@tonic-gate 		}
11867c478bd9Sstevel@tonic-gate 		(void) strcpy(lastpath, newpath);
11877c478bd9Sstevel@tonic-gate 		*path = newpath;
11887c478bd9Sstevel@tonic-gate 	}
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	/*
11917c478bd9Sstevel@tonic-gate 	 * ENOENT or EINVAL is the normal exit case of the above loop.
11927c478bd9Sstevel@tonic-gate 	 */
11937c478bd9Sstevel@tonic-gate 	if ((errno == ENOENT) || (errno == EINVAL))
11947c478bd9Sstevel@tonic-gate 		return (0);
11957c478bd9Sstevel@tonic-gate 	else
11967c478bd9Sstevel@tonic-gate 		return (-1);
11977c478bd9Sstevel@tonic-gate }
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate void
remove_component(char * path)12007c478bd9Sstevel@tonic-gate remove_component(char *path)
12017c478bd9Sstevel@tonic-gate {
12027c478bd9Sstevel@tonic-gate 	char *p;
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 	p = strrchr(path, '/'); 		/* find last '/' 	*/
12057c478bd9Sstevel@tonic-gate 	if (p == NULL) {
12067c478bd9Sstevel@tonic-gate 		*path = '\0';			/* set path to null str	*/
12077c478bd9Sstevel@tonic-gate 	} else {
12087c478bd9Sstevel@tonic-gate 		*p = '\0';			/* zap it 		*/
12097c478bd9Sstevel@tonic-gate 	}
12107c478bd9Sstevel@tonic-gate }
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate /*
12137c478bd9Sstevel@tonic-gate  *  get_coord() fills in the tz_coord structure of the tz_timezone
12147c478bd9Sstevel@tonic-gate  *  struct.  It returns 0 on success, or -1 on error.
12157c478bd9Sstevel@tonic-gate  *  The format of p_coord is:
12167c478bd9Sstevel@tonic-gate  *
12177c478bd9Sstevel@tonic-gate  *	Latitude and longitude of the zone's principal location
12187c478bd9Sstevel@tonic-gate  *	in ISO 6709 sign-degrees-minutes-seconds format,
12197c478bd9Sstevel@tonic-gate  *	either +-DDMM+-DDDMM or +-DDMMSS+-DDDMMSS,
12207c478bd9Sstevel@tonic-gate  *	first latitude (+ is north), then longitude (+ is east).
12217c478bd9Sstevel@tonic-gate  */
12227c478bd9Sstevel@tonic-gate static int
get_coord(struct tz_timezone * tp,char * p_coord,size_t len_coord)12237c478bd9Sstevel@tonic-gate get_coord(struct tz_timezone *tp, char *p_coord, size_t len_coord)
12247c478bd9Sstevel@tonic-gate {
12257c478bd9Sstevel@tonic-gate 	int i, fmt_flag, nchar;
12267c478bd9Sstevel@tonic-gate 	int *signp, *degp, *minp, *secp;
12277c478bd9Sstevel@tonic-gate 	struct tz_coord *tcp;
12287c478bd9Sstevel@tonic-gate 	char buff[512], *endp;
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	tcp = &(tp->tz_coord);
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 	/* Figure out which format to use */
12337c478bd9Sstevel@tonic-gate 	if (len_coord == COORD_FMTLEN1) {
12347c478bd9Sstevel@tonic-gate 		/* "+-DDMM+-DDDMM" */
12357c478bd9Sstevel@tonic-gate 		fmt_flag = COORD_FMT1;
12367c478bd9Sstevel@tonic-gate 	} else if (len_coord == COORD_FMTLEN2) {
12377c478bd9Sstevel@tonic-gate 		/* "+-DDMMSS+-DDDMMSS" */
12387c478bd9Sstevel@tonic-gate 		fmt_flag = COORD_FMT2;
12397c478bd9Sstevel@tonic-gate 	} else {
12407c478bd9Sstevel@tonic-gate 		/* error */
12417c478bd9Sstevel@tonic-gate 		return (-1);
12427c478bd9Sstevel@tonic-gate 	}
12437c478bd9Sstevel@tonic-gate 	/*
12447c478bd9Sstevel@tonic-gate 	 * First time through, get values for latitude;
12457c478bd9Sstevel@tonic-gate 	 * second time through, get values for longitude.
12467c478bd9Sstevel@tonic-gate 	 */
12477c478bd9Sstevel@tonic-gate 	for (i = 0; i < 2; i++) {
12487c478bd9Sstevel@tonic-gate 		/* Set up pointers */
12497c478bd9Sstevel@tonic-gate 		if (i == 0) {
12507c478bd9Sstevel@tonic-gate 			/* Do latitude */
12517c478bd9Sstevel@tonic-gate 			nchar = COORD_DLEN_LAT;
12527c478bd9Sstevel@tonic-gate 			signp = (int *)&(tcp->lat_sign);
12537c478bd9Sstevel@tonic-gate 			degp = (int *)&(tcp->lat_degree);
12547c478bd9Sstevel@tonic-gate 			minp = (int *)&(tcp->lat_minute);
12557c478bd9Sstevel@tonic-gate 			secp = (int *)&(tcp->lat_second);
12567c478bd9Sstevel@tonic-gate 		} else {
12577c478bd9Sstevel@tonic-gate 			/* Do longitude */
12587c478bd9Sstevel@tonic-gate 			nchar = COORD_DLEN_LONG;
12597c478bd9Sstevel@tonic-gate 			signp = (int *)&(tcp->long_sign);
12607c478bd9Sstevel@tonic-gate 			degp = (int *)&tcp->long_degree;
12617c478bd9Sstevel@tonic-gate 			minp = (int *)&tcp->long_minute;
12627c478bd9Sstevel@tonic-gate 			secp = (int *)&tcp->long_second;
12637c478bd9Sstevel@tonic-gate 		}
12647c478bd9Sstevel@tonic-gate 		/* Get latitude/logitude sign */
12657c478bd9Sstevel@tonic-gate 		if (*p_coord == '+') {
12667c478bd9Sstevel@tonic-gate 			*signp = 1;
12677c478bd9Sstevel@tonic-gate 		} else if (*p_coord == '-') {
12687c478bd9Sstevel@tonic-gate 			*signp = -1;
12697c478bd9Sstevel@tonic-gate 		} else {
12707c478bd9Sstevel@tonic-gate 			return (-1);
12717c478bd9Sstevel@tonic-gate 		}
12727c478bd9Sstevel@tonic-gate 		p_coord++;
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 		/* Get DD latitude, or DDD longitude */
12757c478bd9Sstevel@tonic-gate 		(void) strncpy(buff, p_coord, nchar);
12767c478bd9Sstevel@tonic-gate 		buff[nchar] = '\0';
12777c478bd9Sstevel@tonic-gate 		errno = 0;
12787c478bd9Sstevel@tonic-gate 		*degp = (int)strtol(buff, &endp, 10);
12797c478bd9Sstevel@tonic-gate 		if ((endp != &buff[nchar]) || ((*degp == 0) && (errno != 0)))
12807c478bd9Sstevel@tonic-gate 			return (-1);
12817c478bd9Sstevel@tonic-gate 		p_coord += nchar;
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 		/* Get MM latitude/longitude */
12847c478bd9Sstevel@tonic-gate 		(void) strncpy(buff, p_coord, COORD_MLEN);
12857c478bd9Sstevel@tonic-gate 		buff[COORD_MLEN] = '\0';
12867c478bd9Sstevel@tonic-gate 		errno = 0;
12877c478bd9Sstevel@tonic-gate 		*minp = (int)strtol(buff, &endp, 10);
12887c478bd9Sstevel@tonic-gate 		if ((endp != &buff[COORD_MLEN]) ||
12897c478bd9Sstevel@tonic-gate 				((*degp == 0) && (errno != 0)))
12907c478bd9Sstevel@tonic-gate 			return (-1);
12917c478bd9Sstevel@tonic-gate 		p_coord += COORD_MLEN;
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 		/* If FMT2, then get SS latitude/longitude */
12947c478bd9Sstevel@tonic-gate 		if (fmt_flag == COORD_FMT2) {
12957c478bd9Sstevel@tonic-gate 			(void) strncpy(buff, p_coord, COORD_SLEN);
12967c478bd9Sstevel@tonic-gate 			buff[COORD_SLEN] = '\0';
12977c478bd9Sstevel@tonic-gate 			errno = 0;
12987c478bd9Sstevel@tonic-gate 			*secp = (int)strtol(buff, &endp, 10);
12997c478bd9Sstevel@tonic-gate 			if ((endp != &buff[COORD_SLEN]) ||
13007c478bd9Sstevel@tonic-gate 					((*degp == 0) && (errno != 0)))
13017c478bd9Sstevel@tonic-gate 				return (-1);
13027c478bd9Sstevel@tonic-gate 			p_coord += COORD_SLEN;
13037c478bd9Sstevel@tonic-gate 		} else {
13047c478bd9Sstevel@tonic-gate 			*secp = 0;
13057c478bd9Sstevel@tonic-gate 		}
13067c478bd9Sstevel@tonic-gate 	}
13077c478bd9Sstevel@tonic-gate 	return (0);
13087c478bd9Sstevel@tonic-gate }
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate static char *
skipwhite(char * cp)13117c478bd9Sstevel@tonic-gate skipwhite(char *cp)
13127c478bd9Sstevel@tonic-gate {
13137c478bd9Sstevel@tonic-gate 	while (*cp && ((*cp == ' ') || (*cp == '\t'))) {
13147c478bd9Sstevel@tonic-gate 		cp++;
13157c478bd9Sstevel@tonic-gate 	}
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 	return (cp);
13187c478bd9Sstevel@tonic-gate }
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate /*
13217c478bd9Sstevel@tonic-gate  *  skipline() checks if the line begins with a comment
13227c478bd9Sstevel@tonic-gate  *  comment character anywhere in the line, or if the
13237c478bd9Sstevel@tonic-gate  *  line is only whitespace.
13247c478bd9Sstevel@tonic-gate  *  skipline() also checks if the line read is too long to
13257c478bd9Sstevel@tonic-gate  *  fit in the buffer.
13267c478bd9Sstevel@tonic-gate  *  skipline() returns 1 if the line can be skipped, -1 if
13277c478bd9Sstevel@tonic-gate  *  the line read is too long, and 0 if the line should not be skipped.
13287c478bd9Sstevel@tonic-gate  */
13297c478bd9Sstevel@tonic-gate static int
skipline(char * line)13307c478bd9Sstevel@tonic-gate skipline(char *line)
13317c478bd9Sstevel@tonic-gate {
13327c478bd9Sstevel@tonic-gate 	size_t len;
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	len = strlen(line);
13357c478bd9Sstevel@tonic-gate 	if (line[len - 1] != '\n')
13367c478bd9Sstevel@tonic-gate 		return (-1);
13377c478bd9Sstevel@tonic-gate 	if (line[0] == '#' || line[0] == '\0' ||
13387c478bd9Sstevel@tonic-gate 		(len = strspn(line, " \t\n")) == strlen(line) ||
13397c478bd9Sstevel@tonic-gate 		strchr(line, '#') == line + len)
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 		return (1);
13427c478bd9Sstevel@tonic-gate 	else
13437c478bd9Sstevel@tonic-gate 		return (0);
13447c478bd9Sstevel@tonic-gate }
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate /*
13477c478bd9Sstevel@tonic-gate  * strip_quotes -- strip double (") or single (') quotes
13487c478bd9Sstevel@tonic-gate  */
13497c478bd9Sstevel@tonic-gate static void
strip_quotes(char * from,char * to)13507c478bd9Sstevel@tonic-gate strip_quotes(char *from, char *to)
13517c478bd9Sstevel@tonic-gate {
13527c478bd9Sstevel@tonic-gate 	char *strip_ptr = NULL;
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 	while (*from != '\0') {
13557c478bd9Sstevel@tonic-gate 		if ((*from == '"') || (*from == '\'')) {
13567c478bd9Sstevel@tonic-gate 			if (strip_ptr == NULL)
13577c478bd9Sstevel@tonic-gate 				strip_ptr = to;
13587c478bd9Sstevel@tonic-gate 		} else {
13597c478bd9Sstevel@tonic-gate 			if (strip_ptr != NULL) {
13607c478bd9Sstevel@tonic-gate 				*strip_ptr = *from;
13617c478bd9Sstevel@tonic-gate 				strip_ptr++;
13627c478bd9Sstevel@tonic-gate 			} else {
13637c478bd9Sstevel@tonic-gate 				*to = *from;
13647c478bd9Sstevel@tonic-gate 				to++;
13657c478bd9Sstevel@tonic-gate 			}
13667c478bd9Sstevel@tonic-gate 		}
13677c478bd9Sstevel@tonic-gate 		from++;
13687c478bd9Sstevel@tonic-gate 	}
13697c478bd9Sstevel@tonic-gate 	if (strip_ptr != NULL) {
13707c478bd9Sstevel@tonic-gate 		*strip_ptr = '\0';
13717c478bd9Sstevel@tonic-gate 	} else {
13727c478bd9Sstevel@tonic-gate 		*to = '\0';
13737c478bd9Sstevel@tonic-gate 	}
13747c478bd9Sstevel@tonic-gate }
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate /*
13777c478bd9Sstevel@tonic-gate  * Compare function used by get_tz_countries() - uses strcoll()
13787c478bd9Sstevel@tonic-gate  * for locale-sensitive comparison for the localized country names.
13797c478bd9Sstevel@tonic-gate  */
13807c478bd9Sstevel@tonic-gate static int
compar(struct tz_country * p1,struct tz_country * p2)13817c478bd9Sstevel@tonic-gate compar(struct tz_country *p1, struct tz_country *p2)
13827c478bd9Sstevel@tonic-gate {
13837c478bd9Sstevel@tonic-gate 	int ret;
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	ret = strcoll(p1->ctry_display_desc, p2->ctry_display_desc);
13867c478bd9Sstevel@tonic-gate 	return (ret);
13877c478bd9Sstevel@tonic-gate }
1388