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(®, 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 *)®, 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(®);
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(®);
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