1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 30*7c478bd9Sstevel@tonic-gate #include <stdio.h> 31*7c478bd9Sstevel@tonic-gate #include <string.h> 32*7c478bd9Sstevel@tonic-gate #include <unistd.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 36*7c478bd9Sstevel@tonic-gate #include <tzfile.h> 37*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 38*7c478bd9Sstevel@tonic-gate #include <regex.h> 39*7c478bd9Sstevel@tonic-gate #include <errno.h> 40*7c478bd9Sstevel@tonic-gate #include <libintl.h> 41*7c478bd9Sstevel@tonic-gate #include <libzoneinfo.h> 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate #define DEFINIT "/etc/default/init" 44*7c478bd9Sstevel@tonic-gate #define ZONEINFOTABDIR "/usr/share/lib/zoneinfo/tab/" 45*7c478bd9Sstevel@tonic-gate #define CONTINENT_TAB ZONEINFOTABDIR "continent.tab" 46*7c478bd9Sstevel@tonic-gate #define COUNTRY_TAB ZONEINFOTABDIR "country.tab" 47*7c478bd9Sstevel@tonic-gate #define ZONE_SUN_TAB ZONEINFOTABDIR "zone_sun.tab" 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate #define NEWLINE "\n" 50*7c478bd9Sstevel@tonic-gate #define SLASH "/" 51*7c478bd9Sstevel@tonic-gate #define WHITESPACE "\t " 52*7c478bd9Sstevel@tonic-gate #define WHITESPACE_NL "\t \n" 53*7c478bd9Sstevel@tonic-gate #define DIGITS "0123456789" 54*7c478bd9Sstevel@tonic-gate #define BUFFLEN 1024 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate #define CCLEN 2 /* country code length */ 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate #define GMT_MAX (12*60*60) /* The maximum GMT offset */ 59*7c478bd9Sstevel@tonic-gate #define GMT_MIN (-13*60*60) /* The minimum GMT offset */ 60*7c478bd9Sstevel@tonic-gate #define GMT_FMT_Q "<GMT%c%d>%c%d" 61*7c478bd9Sstevel@tonic-gate #define GMT_FMT_Q_LEN (11) /* "<GMT+dd>+dd" - maximum 11 chars */ 62*7c478bd9Sstevel@tonic-gate #define GMT0_FMT "GMT0" /* backwards compatibility name */ 63*7c478bd9Sstevel@tonic-gate #define GMT_FMT_ZONE ":Etc/GMT%c%d" /* ":Etc/GMT+dd" */ 64*7c478bd9Sstevel@tonic-gate #define GMT_FMT_ZONE_LEN (11) /* ":Etc/GMT+dd" - maximum 11 chars */ 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate #define TZ_FMT "TZ=%s\n" /* format TZ entry init file */ 67*7c478bd9Sstevel@tonic-gate #define TZ_FMT_Q "TZ=\"%s\"\n" /* format quoted TZ entry init file */ 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate #define COORD_FMTLEN1 (sizeof ("+DDMM+DDDMM") - 1) 70*7c478bd9Sstevel@tonic-gate #define COORD_FMTLEN2 (sizeof ("+DDMMSS+DDDMMSS") - 1) 71*7c478bd9Sstevel@tonic-gate #define COORD_FMT1 (1) /* flag for format 1 */ 72*7c478bd9Sstevel@tonic-gate #define COORD_FMT2 (2) /* flag for format 2 */ 73*7c478bd9Sstevel@tonic-gate #define COORD_DLEN_LAT (2) /* length of DD for latitude */ 74*7c478bd9Sstevel@tonic-gate #define COORD_DLEN_LONG (3) /* length of DDD for longtitude */ 75*7c478bd9Sstevel@tonic-gate #define COORD_MLEN (2) /* length of MM */ 76*7c478bd9Sstevel@tonic-gate #define COORD_SLEN (2) /* length of SS */ 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate #define TRAILER "/XXXXXX" 79*7c478bd9Sstevel@tonic-gate #define TR_LEN (sizeof (TRAILER) -1) 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate /* Internal Declarations */ 82*7c478bd9Sstevel@tonic-gate static char *skipwhite(char *); 83*7c478bd9Sstevel@tonic-gate static int skipline(char *); 84*7c478bd9Sstevel@tonic-gate static int trav_link(char **); 85*7c478bd9Sstevel@tonic-gate static void remove_component(char *); 86*7c478bd9Sstevel@tonic-gate static void strip_quotes(char *, char *); 87*7c478bd9Sstevel@tonic-gate static int compar(struct tz_country *, struct tz_country *); 88*7c478bd9Sstevel@tonic-gate static int get_coord(struct tz_timezone *, char *, size_t); 89*7c478bd9Sstevel@tonic-gate static int _tz_match(const char *, const char *); 90*7c478bd9Sstevel@tonic-gate static char *_conv_gmt_zoneinfo(int); 91*7c478bd9Sstevel@tonic-gate static char *_conv_gmt_posix(int); 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate /* 94*7c478bd9Sstevel@tonic-gate * get_tz_continents() reads the continent.tab file, and 95*7c478bd9Sstevel@tonic-gate * returns a list of continents. 96*7c478bd9Sstevel@tonic-gate */ 97*7c478bd9Sstevel@tonic-gate int 98*7c478bd9Sstevel@tonic-gate get_tz_continents(struct tz_continent **cont) 99*7c478bd9Sstevel@tonic-gate { 100*7c478bd9Sstevel@tonic-gate FILE *fp; 101*7c478bd9Sstevel@tonic-gate char buff[BUFFLEN]; 102*7c478bd9Sstevel@tonic-gate char *lp; /* line pointer */ 103*7c478bd9Sstevel@tonic-gate char *lptr, *ptr; /* temp pointer */ 104*7c478bd9Sstevel@tonic-gate struct tz_continent *head = NULL, *lcp, *prev = NULL; 105*7c478bd9Sstevel@tonic-gate int sav_errno = 0, ncount, status; 106*7c478bd9Sstevel@tonic-gate size_t len; 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate /* open continents file */ 109*7c478bd9Sstevel@tonic-gate if ((fp = fopen(CONTINENT_TAB, "r")) == NULL) { 110*7c478bd9Sstevel@tonic-gate /* fopen() sets errno */ 111*7c478bd9Sstevel@tonic-gate return (-1); 112*7c478bd9Sstevel@tonic-gate } 113*7c478bd9Sstevel@tonic-gate /* read and count continents */ 114*7c478bd9Sstevel@tonic-gate ncount = 0; 115*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ 116*7c478bd9Sstevel@tonic-gate while (1) { 117*7c478bd9Sstevel@tonic-gate if (fgets(buff, sizeof (buff), fp) == NULL) { 118*7c478bd9Sstevel@tonic-gate if (feof(fp) == 0) { 119*7c478bd9Sstevel@tonic-gate /* fgets() sets errno */ 120*7c478bd9Sstevel@tonic-gate sav_errno = errno; 121*7c478bd9Sstevel@tonic-gate ncount = -1; 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate break; 124*7c478bd9Sstevel@tonic-gate } 125*7c478bd9Sstevel@tonic-gate /* Skip comments or blank/whitespace lines */ 126*7c478bd9Sstevel@tonic-gate if ((status = skipline(buff)) != 0) { 127*7c478bd9Sstevel@tonic-gate if (status == 1) 128*7c478bd9Sstevel@tonic-gate continue; 129*7c478bd9Sstevel@tonic-gate else { 130*7c478bd9Sstevel@tonic-gate sav_errno = EINVAL; 131*7c478bd9Sstevel@tonic-gate ncount = -1; 132*7c478bd9Sstevel@tonic-gate break; 133*7c478bd9Sstevel@tonic-gate } 134*7c478bd9Sstevel@tonic-gate } 135*7c478bd9Sstevel@tonic-gate /* Get continent name */ 136*7c478bd9Sstevel@tonic-gate lp = skipwhite(&buff[0]); 137*7c478bd9Sstevel@tonic-gate if ((len = strcspn(lp, WHITESPACE)) > _TZBUFLEN -1) { 138*7c478bd9Sstevel@tonic-gate sav_errno = ENAMETOOLONG; 139*7c478bd9Sstevel@tonic-gate ncount = -1; 140*7c478bd9Sstevel@tonic-gate break; 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate /* create continent struct */ 143*7c478bd9Sstevel@tonic-gate if ((lcp = (struct tz_continent *) 144*7c478bd9Sstevel@tonic-gate calloc(1, sizeof (struct tz_continent))) == NULL) { 145*7c478bd9Sstevel@tonic-gate sav_errno = ENOMEM; 146*7c478bd9Sstevel@tonic-gate ncount = -1; 147*7c478bd9Sstevel@tonic-gate break; 148*7c478bd9Sstevel@tonic-gate } 149*7c478bd9Sstevel@tonic-gate (void) strncpy(lcp->ctnt_name, lp, len); 150*7c478bd9Sstevel@tonic-gate lcp->ctnt_name[len] = '\0'; 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate /* Get continent description */ 153*7c478bd9Sstevel@tonic-gate lp = skipwhite(lp + len); 154*7c478bd9Sstevel@tonic-gate len = strcspn(lp, NEWLINE); 155*7c478bd9Sstevel@tonic-gate if ((ptr = malloc(len + 1)) == NULL) { 156*7c478bd9Sstevel@tonic-gate (void) free_tz_continents(lcp); 157*7c478bd9Sstevel@tonic-gate sav_errno = ENOMEM; 158*7c478bd9Sstevel@tonic-gate ncount = -1; 159*7c478bd9Sstevel@tonic-gate break; 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate (void) strncpy(ptr, lp, len); 162*7c478bd9Sstevel@tonic-gate *(ptr + len) = '\0'; 163*7c478bd9Sstevel@tonic-gate lcp->ctnt_id_desc = ptr; 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* Get localized continent description */ 166*7c478bd9Sstevel@tonic-gate lptr = dgettext(TEXT_DOMAIN, lcp->ctnt_id_desc); 167*7c478bd9Sstevel@tonic-gate if ((ptr = strdup(lptr)) == NULL) { 168*7c478bd9Sstevel@tonic-gate (void) free_tz_continents(lcp); 169*7c478bd9Sstevel@tonic-gate sav_errno = ENOMEM; 170*7c478bd9Sstevel@tonic-gate ncount = -1; 171*7c478bd9Sstevel@tonic-gate break; 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate lcp->ctnt_display_desc = ptr; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate if (head == NULL) { 176*7c478bd9Sstevel@tonic-gate head = lcp; 177*7c478bd9Sstevel@tonic-gate } else { 178*7c478bd9Sstevel@tonic-gate prev->ctnt_next = lcp; 179*7c478bd9Sstevel@tonic-gate } 180*7c478bd9Sstevel@tonic-gate prev = lcp; 181*7c478bd9Sstevel@tonic-gate ncount++; 182*7c478bd9Sstevel@tonic-gate } 183*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 184*7c478bd9Sstevel@tonic-gate if (ncount == -1) { 185*7c478bd9Sstevel@tonic-gate if (head != NULL) { 186*7c478bd9Sstevel@tonic-gate (void) free_tz_continents(head); 187*7c478bd9Sstevel@tonic-gate } 188*7c478bd9Sstevel@tonic-gate if (sav_errno) 189*7c478bd9Sstevel@tonic-gate errno = sav_errno; 190*7c478bd9Sstevel@tonic-gate } else { 191*7c478bd9Sstevel@tonic-gate *cont = head; 192*7c478bd9Sstevel@tonic-gate } 193*7c478bd9Sstevel@tonic-gate return (ncount); 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate /* 197*7c478bd9Sstevel@tonic-gate * get_tz_countries() finds the list of countries from the zone_sun.tab 198*7c478bd9Sstevel@tonic-gate * file, for the input continent, and retrieves the country 199*7c478bd9Sstevel@tonic-gate * names from the country.tab file. It also retrieves the localized 200*7c478bd9Sstevel@tonic-gate * country names. The returned list of countries is sorted by the 201*7c478bd9Sstevel@tonic-gate * countries' localized name fields. 202*7c478bd9Sstevel@tonic-gate */ 203*7c478bd9Sstevel@tonic-gate int 204*7c478bd9Sstevel@tonic-gate get_tz_countries(struct tz_country **country, struct tz_continent *cont) 205*7c478bd9Sstevel@tonic-gate { 206*7c478bd9Sstevel@tonic-gate FILE *fp_zone, *fp_cc; 207*7c478bd9Sstevel@tonic-gate char buff[BUFFLEN], ccbuf[_CCBUFLEN], *ptr; 208*7c478bd9Sstevel@tonic-gate char *lp, *lptr, *lp_coord, *lp_cc, *lp_tz; /* line pointer */ 209*7c478bd9Sstevel@tonic-gate struct tz_country *head = NULL, *prev = NULL, *next, *cp, *cp2; 210*7c478bd9Sstevel@tonic-gate int sav_errno = 0, ncount, i; 211*7c478bd9Sstevel@tonic-gate int cmp, status; 212*7c478bd9Sstevel@tonic-gate size_t len, len_coord, len_ctnt; 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate if (cont->ctnt_name == NULL) { 215*7c478bd9Sstevel@tonic-gate errno = EINVAL; 216*7c478bd9Sstevel@tonic-gate return (-1); 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate len_ctnt = strlen(cont->ctnt_name); 219*7c478bd9Sstevel@tonic-gate ccbuf[0] = '\0'; 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate /* open zone_sun.tab and country.tab files */ 222*7c478bd9Sstevel@tonic-gate if ((fp_zone = fopen(ZONE_SUN_TAB, "r")) == NULL) { 223*7c478bd9Sstevel@tonic-gate /* fopen() sets errno */ 224*7c478bd9Sstevel@tonic-gate return (-1); 225*7c478bd9Sstevel@tonic-gate } 226*7c478bd9Sstevel@tonic-gate if ((fp_cc = fopen(COUNTRY_TAB, "r")) == NULL) { 227*7c478bd9Sstevel@tonic-gate /* fopen() sets errno */ 228*7c478bd9Sstevel@tonic-gate (void) fclose(fp_zone); 229*7c478bd9Sstevel@tonic-gate return (-1); 230*7c478bd9Sstevel@tonic-gate } 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate /* read timezones to match continents, and get countries */ 233*7c478bd9Sstevel@tonic-gate ncount = 0; 234*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ 235*7c478bd9Sstevel@tonic-gate while (1) { 236*7c478bd9Sstevel@tonic-gate if (fgets(buff, sizeof (buff), fp_zone) == NULL) { 237*7c478bd9Sstevel@tonic-gate if (feof(fp_zone) == 0) { 238*7c478bd9Sstevel@tonic-gate /* fgets() error - errno set */ 239*7c478bd9Sstevel@tonic-gate sav_errno = errno; 240*7c478bd9Sstevel@tonic-gate ncount = -1; 241*7c478bd9Sstevel@tonic-gate } 242*7c478bd9Sstevel@tonic-gate break; 243*7c478bd9Sstevel@tonic-gate } 244*7c478bd9Sstevel@tonic-gate /* Skip comments or blank/whitespace lines */ 245*7c478bd9Sstevel@tonic-gate if ((status = skipline(buff)) != 0) { 246*7c478bd9Sstevel@tonic-gate if (status == 1) 247*7c478bd9Sstevel@tonic-gate continue; 248*7c478bd9Sstevel@tonic-gate else { 249*7c478bd9Sstevel@tonic-gate sav_errno = EINVAL; 250*7c478bd9Sstevel@tonic-gate ncount = -1; 251*7c478bd9Sstevel@tonic-gate break; 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate } 254*7c478bd9Sstevel@tonic-gate /* 255*7c478bd9Sstevel@tonic-gate * If country matches previously *matched* country, skip 256*7c478bd9Sstevel@tonic-gate * entry, since zone.tab is alphabetized by country code 257*7c478bd9Sstevel@tonic-gate * (It should be a *matched* country, because the same country 258*7c478bd9Sstevel@tonic-gate * can be in different continents.) 259*7c478bd9Sstevel@tonic-gate */ 260*7c478bd9Sstevel@tonic-gate /* Get country code */ 261*7c478bd9Sstevel@tonic-gate lp_cc = skipwhite(&buff[0]); 262*7c478bd9Sstevel@tonic-gate if (strcspn(lp_cc, WHITESPACE) != CCLEN) { 263*7c478bd9Sstevel@tonic-gate ncount = -1; 264*7c478bd9Sstevel@tonic-gate sav_errno = EINVAL; 265*7c478bd9Sstevel@tonic-gate break; 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate /* Check country code cache; skip if already found */ 268*7c478bd9Sstevel@tonic-gate if (strncmp(ccbuf, lp_cc, CCLEN) == 0) { 269*7c478bd9Sstevel@tonic-gate continue; 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate /* Get coordinates */ 272*7c478bd9Sstevel@tonic-gate lp_coord = skipwhite(lp_cc + CCLEN); 273*7c478bd9Sstevel@tonic-gate if (((len_coord = strcspn(lp_coord, WHITESPACE)) != 274*7c478bd9Sstevel@tonic-gate COORD_FMTLEN1) && 275*7c478bd9Sstevel@tonic-gate (len_coord != COORD_FMTLEN2)) { 276*7c478bd9Sstevel@tonic-gate ncount = -1; 277*7c478bd9Sstevel@tonic-gate sav_errno = EINVAL; 278*7c478bd9Sstevel@tonic-gate break; 279*7c478bd9Sstevel@tonic-gate } 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate /* Get timezone name (Skip timezone description) */ 282*7c478bd9Sstevel@tonic-gate lp_tz = skipwhite(lp_coord + len_coord); 283*7c478bd9Sstevel@tonic-gate if ((len = strcspn(lp_tz, SLASH)) == 0) { 284*7c478bd9Sstevel@tonic-gate ncount = -1; 285*7c478bd9Sstevel@tonic-gate sav_errno = EINVAL; 286*7c478bd9Sstevel@tonic-gate break; 287*7c478bd9Sstevel@tonic-gate } 288*7c478bd9Sstevel@tonic-gate /* If continents match, allocate a country struct */ 289*7c478bd9Sstevel@tonic-gate if ((len == len_ctnt) && 290*7c478bd9Sstevel@tonic-gate (strncmp(cont->ctnt_name, lp_tz, len) == 0)) { 291*7c478bd9Sstevel@tonic-gate if ((cp = (struct tz_country *) 292*7c478bd9Sstevel@tonic-gate calloc(1, sizeof (struct tz_country))) == NULL) { 293*7c478bd9Sstevel@tonic-gate sav_errno = ENOMEM; 294*7c478bd9Sstevel@tonic-gate ncount = -1; 295*7c478bd9Sstevel@tonic-gate break; 296*7c478bd9Sstevel@tonic-gate } 297*7c478bd9Sstevel@tonic-gate /* Copy and save country code (len already checked) */ 298*7c478bd9Sstevel@tonic-gate (void) strncpy(cp->ctry_code, lp_cc, CCLEN); 299*7c478bd9Sstevel@tonic-gate cp->ctry_code[CCLEN] = '\0'; 300*7c478bd9Sstevel@tonic-gate (void) strncpy(ccbuf, lp_cc, CCLEN); 301*7c478bd9Sstevel@tonic-gate ccbuf[CCLEN] = '\0'; 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate /* Create linked list */ 304*7c478bd9Sstevel@tonic-gate if (head == NULL) { 305*7c478bd9Sstevel@tonic-gate head = cp; 306*7c478bd9Sstevel@tonic-gate } else { 307*7c478bd9Sstevel@tonic-gate prev->ctry_next = cp; 308*7c478bd9Sstevel@tonic-gate }; 309*7c478bd9Sstevel@tonic-gate prev = cp; 310*7c478bd9Sstevel@tonic-gate ncount++; 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate } /* while */ 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate if (ncount == -1) 315*7c478bd9Sstevel@tonic-gate goto error; 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate /* Get country name from country.tab; get localized country name */ 318*7c478bd9Sstevel@tonic-gate /* Read country list, match country codes to process entry */ 319*7c478bd9Sstevel@tonic-gate cp = head; 320*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ 321*7c478bd9Sstevel@tonic-gate while (1) { 322*7c478bd9Sstevel@tonic-gate if (fgets(buff, sizeof (buff), fp_cc) == NULL) { 323*7c478bd9Sstevel@tonic-gate if (feof(fp_cc) == 0) { 324*7c478bd9Sstevel@tonic-gate /* fgets() sets errno */ 325*7c478bd9Sstevel@tonic-gate ncount = -1; 326*7c478bd9Sstevel@tonic-gate sav_errno = errno; 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate break; 329*7c478bd9Sstevel@tonic-gate } 330*7c478bd9Sstevel@tonic-gate /* Skip comments or blank/whitespace lines */ 331*7c478bd9Sstevel@tonic-gate if ((status = skipline(buff)) != 0) { 332*7c478bd9Sstevel@tonic-gate if (status == 1) 333*7c478bd9Sstevel@tonic-gate continue; 334*7c478bd9Sstevel@tonic-gate else { 335*7c478bd9Sstevel@tonic-gate sav_errno = EINVAL; 336*7c478bd9Sstevel@tonic-gate ncount = -1; 337*7c478bd9Sstevel@tonic-gate break; 338*7c478bd9Sstevel@tonic-gate } 339*7c478bd9Sstevel@tonic-gate } 340*7c478bd9Sstevel@tonic-gate /* Match country codes */ 341*7c478bd9Sstevel@tonic-gate if ((len = strcspn(buff, WHITESPACE)) != CCLEN) { 342*7c478bd9Sstevel@tonic-gate sav_errno = EINVAL; 343*7c478bd9Sstevel@tonic-gate ncount = -1; 344*7c478bd9Sstevel@tonic-gate break; 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate if ((cmp = strncmp(cp->ctry_code, buff, CCLEN)) == 0) { 347*7c478bd9Sstevel@tonic-gate /* Get country description, and localized desc. */ 348*7c478bd9Sstevel@tonic-gate /* Skip to country description */ 349*7c478bd9Sstevel@tonic-gate lp = &buff[CCLEN]; 350*7c478bd9Sstevel@tonic-gate if ((len = strspn(lp, WHITESPACE)) == 0) { 351*7c478bd9Sstevel@tonic-gate sav_errno = EINVAL; 352*7c478bd9Sstevel@tonic-gate ncount = -1; 353*7c478bd9Sstevel@tonic-gate break; 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate lp += len; /* lp points to country desc. */ 356*7c478bd9Sstevel@tonic-gate len = strcspn(lp, NEWLINE); 357*7c478bd9Sstevel@tonic-gate if ((ptr = calloc(len + 1, 1)) == NULL) { 358*7c478bd9Sstevel@tonic-gate ncount = -1; 359*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 360*7c478bd9Sstevel@tonic-gate break; 361*7c478bd9Sstevel@tonic-gate } 362*7c478bd9Sstevel@tonic-gate (void) strncpy(ptr, lp, len); 363*7c478bd9Sstevel@tonic-gate *(ptr + len) = '\0'; 364*7c478bd9Sstevel@tonic-gate cp->ctry_id_desc = ptr; 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate /* Get localized country description */ 367*7c478bd9Sstevel@tonic-gate lptr = dgettext(TEXT_DOMAIN, ptr); 368*7c478bd9Sstevel@tonic-gate if ((ptr = strdup(lptr)) == NULL) { 369*7c478bd9Sstevel@tonic-gate ncount = -1; 370*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 371*7c478bd9Sstevel@tonic-gate break; 372*7c478bd9Sstevel@tonic-gate } 373*7c478bd9Sstevel@tonic-gate cp->ctry_display_desc = ptr; 374*7c478bd9Sstevel@tonic-gate } else if (cmp > 0) { 375*7c478bd9Sstevel@tonic-gate /* Keep searching country.tab */ 376*7c478bd9Sstevel@tonic-gate continue; 377*7c478bd9Sstevel@tonic-gate } else { 378*7c478bd9Sstevel@tonic-gate /* Not found - should not happen */ 379*7c478bd9Sstevel@tonic-gate ncount = -1; 380*7c478bd9Sstevel@tonic-gate errno = EILSEQ; 381*7c478bd9Sstevel@tonic-gate break; 382*7c478bd9Sstevel@tonic-gate } 383*7c478bd9Sstevel@tonic-gate if (cp->ctry_next == NULL) { 384*7c478bd9Sstevel@tonic-gate /* done with countries list */ 385*7c478bd9Sstevel@tonic-gate break; 386*7c478bd9Sstevel@tonic-gate } else { 387*7c478bd9Sstevel@tonic-gate cp = cp->ctry_next; 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate } /* while */ 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate /* Now sort the list by ctry_display_desc field */ 392*7c478bd9Sstevel@tonic-gate if ((ncount != -1) && 393*7c478bd9Sstevel@tonic-gate ((cp2 = calloc(ncount, sizeof (struct tz_country))) != NULL)) { 394*7c478bd9Sstevel@tonic-gate /* 395*7c478bd9Sstevel@tonic-gate * First copy list to a static array for qsort() to use. 396*7c478bd9Sstevel@tonic-gate * Use the cnt_next field to point back to original structure. 397*7c478bd9Sstevel@tonic-gate */ 398*7c478bd9Sstevel@tonic-gate cp = head; 399*7c478bd9Sstevel@tonic-gate for (i = 0; i < ncount; i++) { 400*7c478bd9Sstevel@tonic-gate next = cp->ctry_next; 401*7c478bd9Sstevel@tonic-gate cp->ctry_next = cp; 402*7c478bd9Sstevel@tonic-gate (void) memcpy(&cp2[i], cp, sizeof (struct tz_country)); 403*7c478bd9Sstevel@tonic-gate cp = next; 404*7c478bd9Sstevel@tonic-gate } 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate /* Next, call qsort() using strcoll() to order */ 407*7c478bd9Sstevel@tonic-gate qsort(cp2, ncount, sizeof (struct tz_country), 408*7c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate /* Rearrange the country list according to qsort order */ 411*7c478bd9Sstevel@tonic-gate head = cp2->ctry_next; /* ctry_next is pointer to orig struct */ 412*7c478bd9Sstevel@tonic-gate cp = head; 413*7c478bd9Sstevel@tonic-gate for (i = 0; i < ncount; i++) { 414*7c478bd9Sstevel@tonic-gate prev = cp; 415*7c478bd9Sstevel@tonic-gate cp = cp2[i].ctry_next; 416*7c478bd9Sstevel@tonic-gate prev->ctry_next = cp; 417*7c478bd9Sstevel@tonic-gate } 418*7c478bd9Sstevel@tonic-gate cp->ctry_next = NULL; 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate /* Last, free the static buffer */ 421*7c478bd9Sstevel@tonic-gate free(cp2); 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate } else { 424*7c478bd9Sstevel@tonic-gate if (ncount != -1) 425*7c478bd9Sstevel@tonic-gate ncount = -1; 426*7c478bd9Sstevel@tonic-gate } 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate error: 429*7c478bd9Sstevel@tonic-gate (void) fclose(fp_zone); 430*7c478bd9Sstevel@tonic-gate (void) fclose(fp_cc); 431*7c478bd9Sstevel@tonic-gate if (ncount == -1) { 432*7c478bd9Sstevel@tonic-gate /* free the linked list */ 433*7c478bd9Sstevel@tonic-gate if (head != NULL) 434*7c478bd9Sstevel@tonic-gate (void) free_tz_countries(head); 435*7c478bd9Sstevel@tonic-gate if (sav_errno) 436*7c478bd9Sstevel@tonic-gate errno = sav_errno; 437*7c478bd9Sstevel@tonic-gate } else { 438*7c478bd9Sstevel@tonic-gate *country = head; 439*7c478bd9Sstevel@tonic-gate } 440*7c478bd9Sstevel@tonic-gate return (ncount); 441*7c478bd9Sstevel@tonic-gate } 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate /* 444*7c478bd9Sstevel@tonic-gate * get_timezones_by_country() finds the list of timezones from the 445*7c478bd9Sstevel@tonic-gate * zone_sun.tab file, for the input country. 446*7c478bd9Sstevel@tonic-gate */ 447*7c478bd9Sstevel@tonic-gate int 448*7c478bd9Sstevel@tonic-gate get_timezones_by_country(struct tz_timezone **tmzone, 449*7c478bd9Sstevel@tonic-gate struct tz_country *country) 450*7c478bd9Sstevel@tonic-gate { 451*7c478bd9Sstevel@tonic-gate FILE *fp_zone; /* zone.tab */ 452*7c478bd9Sstevel@tonic-gate int match = 0, ncount = 0, sav_errno = 0, status; 453*7c478bd9Sstevel@tonic-gate char buff[1024]; 454*7c478bd9Sstevel@tonic-gate char *lp_cc, *lp_tz, *lp_otz, *lp_coord, *lp_tzdesc, *ptr, *lptr; 455*7c478bd9Sstevel@tonic-gate size_t len_tz, len_otz, len_coord, len_tzdesc; 456*7c478bd9Sstevel@tonic-gate struct tz_timezone *head = NULL, *prev = NULL, *tp; 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate /* open zone.tab file */ 459*7c478bd9Sstevel@tonic-gate if ((fp_zone = fopen(ZONE_SUN_TAB, "r")) == NULL) 460*7c478bd9Sstevel@tonic-gate return (-1); 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate /* Read through zone.tab until countries match */ 463*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ 464*7c478bd9Sstevel@tonic-gate while (1) { 465*7c478bd9Sstevel@tonic-gate if (fgets(buff, sizeof (buff), fp_zone) == NULL) { 466*7c478bd9Sstevel@tonic-gate if (feof(fp_zone)) { 467*7c478bd9Sstevel@tonic-gate break; 468*7c478bd9Sstevel@tonic-gate } else { 469*7c478bd9Sstevel@tonic-gate /* fgets() sets errno */ 470*7c478bd9Sstevel@tonic-gate ncount = -1; 471*7c478bd9Sstevel@tonic-gate sav_errno = errno; 472*7c478bd9Sstevel@tonic-gate break; 473*7c478bd9Sstevel@tonic-gate } 474*7c478bd9Sstevel@tonic-gate } 475*7c478bd9Sstevel@tonic-gate /* Skip comments or blank/whitespace lines */ 476*7c478bd9Sstevel@tonic-gate if ((status = skipline(buff)) != 0) { 477*7c478bd9Sstevel@tonic-gate if (status == 1) 478*7c478bd9Sstevel@tonic-gate continue; 479*7c478bd9Sstevel@tonic-gate else { 480*7c478bd9Sstevel@tonic-gate sav_errno = EINVAL; 481*7c478bd9Sstevel@tonic-gate ncount = -1; 482*7c478bd9Sstevel@tonic-gate break; 483*7c478bd9Sstevel@tonic-gate } 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate /* 486*7c478bd9Sstevel@tonic-gate * Find country entries, or detect if no country matches. 487*7c478bd9Sstevel@tonic-gate */ 488*7c478bd9Sstevel@tonic-gate lp_cc = skipwhite(&buff[0]); 489*7c478bd9Sstevel@tonic-gate if (strcspn(lp_cc, WHITESPACE) != CCLEN) { 490*7c478bd9Sstevel@tonic-gate sav_errno = EINVAL; 491*7c478bd9Sstevel@tonic-gate ncount = -1; 492*7c478bd9Sstevel@tonic-gate break; 493*7c478bd9Sstevel@tonic-gate } 494*7c478bd9Sstevel@tonic-gate if (strncmp(country->ctry_code, lp_cc, CCLEN) == 0) { 495*7c478bd9Sstevel@tonic-gate match = 1; 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate /* Get coordinates */ 498*7c478bd9Sstevel@tonic-gate lp_coord = skipwhite(lp_cc + CCLEN); 499*7c478bd9Sstevel@tonic-gate if (((len_coord = strcspn(lp_coord, WHITESPACE)) != 500*7c478bd9Sstevel@tonic-gate COORD_FMTLEN1) && 501*7c478bd9Sstevel@tonic-gate (len_coord != COORD_FMTLEN2)) { 502*7c478bd9Sstevel@tonic-gate ncount = -1; 503*7c478bd9Sstevel@tonic-gate sav_errno = EINVAL; 504*7c478bd9Sstevel@tonic-gate break; 505*7c478bd9Sstevel@tonic-gate } 506*7c478bd9Sstevel@tonic-gate /* Get Olson timezone name */ 507*7c478bd9Sstevel@tonic-gate lp_otz = skipwhite(lp_coord + len_coord); 508*7c478bd9Sstevel@tonic-gate len_otz = strcspn(lp_otz, WHITESPACE); 509*7c478bd9Sstevel@tonic-gate 510*7c478bd9Sstevel@tonic-gate /* Get Solaris compatible timezone name */ 511*7c478bd9Sstevel@tonic-gate lp_tz = skipwhite(lp_otz + len_otz); 512*7c478bd9Sstevel@tonic-gate len_tz = strcspn(lp_tz, WHITESPACE_NL); 513*7c478bd9Sstevel@tonic-gate if (*(lp_tz + len_tz - 1) == '\n') { 514*7c478bd9Sstevel@tonic-gate /* No timezone description */ 515*7c478bd9Sstevel@tonic-gate len_tz--; 516*7c478bd9Sstevel@tonic-gate lp_tzdesc = NULL; 517*7c478bd9Sstevel@tonic-gate len_tzdesc = 0; 518*7c478bd9Sstevel@tonic-gate } else { 519*7c478bd9Sstevel@tonic-gate /* Get timezone description */ 520*7c478bd9Sstevel@tonic-gate lp_tzdesc = skipwhite(lp_tz + 521*7c478bd9Sstevel@tonic-gate len_tz); 522*7c478bd9Sstevel@tonic-gate len_tzdesc = strcspn(lp_tzdesc, 523*7c478bd9Sstevel@tonic-gate NEWLINE); 524*7c478bd9Sstevel@tonic-gate } 525*7c478bd9Sstevel@tonic-gate /* 526*7c478bd9Sstevel@tonic-gate * Check tz name lengths. This check assumes the 527*7c478bd9Sstevel@tonic-gate * tz_oname and tz_name fields are the same size. 528*7c478bd9Sstevel@tonic-gate * (since tz_name may be written with lp_otz, if 529*7c478bd9Sstevel@tonic-gate * lp_tz is "-".) 530*7c478bd9Sstevel@tonic-gate */ 531*7c478bd9Sstevel@tonic-gate if ((len_otz > _TZBUFLEN - 1) || 532*7c478bd9Sstevel@tonic-gate (len_tz > _TZBUFLEN - 1)) { 533*7c478bd9Sstevel@tonic-gate sav_errno = ENAMETOOLONG; 534*7c478bd9Sstevel@tonic-gate ncount = -1; 535*7c478bd9Sstevel@tonic-gate break; 536*7c478bd9Sstevel@tonic-gate } 537*7c478bd9Sstevel@tonic-gate /* Create timezone struct */ 538*7c478bd9Sstevel@tonic-gate if ((tp = (struct tz_timezone *) 539*7c478bd9Sstevel@tonic-gate calloc(1, sizeof (struct tz_timezone))) == 540*7c478bd9Sstevel@tonic-gate NULL) { 541*7c478bd9Sstevel@tonic-gate sav_errno = ENOMEM; 542*7c478bd9Sstevel@tonic-gate ncount = -1; 543*7c478bd9Sstevel@tonic-gate break; 544*7c478bd9Sstevel@tonic-gate } 545*7c478bd9Sstevel@tonic-gate /* 546*7c478bd9Sstevel@tonic-gate * Copy the timezone names - use the Solaris 547*7c478bd9Sstevel@tonic-gate * compatible timezone name if one exists, 548*7c478bd9Sstevel@tonic-gate * otherwise use the current Olson timezone 549*7c478bd9Sstevel@tonic-gate * name. 550*7c478bd9Sstevel@tonic-gate */ 551*7c478bd9Sstevel@tonic-gate (void) strncpy(tp->tz_oname, lp_otz, len_otz); 552*7c478bd9Sstevel@tonic-gate tp->tz_oname[len_otz] = '\0'; 553*7c478bd9Sstevel@tonic-gate if (strncmp("-", lp_tz, len_tz) == 0) { 554*7c478bd9Sstevel@tonic-gate lp_tz = lp_otz; 555*7c478bd9Sstevel@tonic-gate len_tz = len_otz; 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate /* If name has numeric digits, prefix ':' */ 558*7c478bd9Sstevel@tonic-gate if (strcspn(lp_tz, DIGITS) < len_tz) { 559*7c478bd9Sstevel@tonic-gate if (len_tz > _TZBUFLEN - 2) { 560*7c478bd9Sstevel@tonic-gate free(tp); 561*7c478bd9Sstevel@tonic-gate sav_errno = ENAMETOOLONG; 562*7c478bd9Sstevel@tonic-gate ncount = -1; 563*7c478bd9Sstevel@tonic-gate break; 564*7c478bd9Sstevel@tonic-gate } 565*7c478bd9Sstevel@tonic-gate tp->tz_name[0] = ':'; 566*7c478bd9Sstevel@tonic-gate (void) strncpy(tp->tz_name + 1, lp_tz, len_tz); 567*7c478bd9Sstevel@tonic-gate tp->tz_name[len_tz + 1] = '\0'; 568*7c478bd9Sstevel@tonic-gate } else { 569*7c478bd9Sstevel@tonic-gate (void) strncpy(tp->tz_name, lp_tz, len_tz); 570*7c478bd9Sstevel@tonic-gate tp->tz_name[len_tz] = '\0'; 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate /* Process timezone description, if one exists */ 573*7c478bd9Sstevel@tonic-gate if ((lp_tzdesc != NULL) && (*lp_tzdesc != '\n')) { 574*7c478bd9Sstevel@tonic-gate if ((ptr = calloc(1, len_tzdesc + 1)) 575*7c478bd9Sstevel@tonic-gate == NULL) { 576*7c478bd9Sstevel@tonic-gate sav_errno = ENOMEM; 577*7c478bd9Sstevel@tonic-gate ncount = -1; 578*7c478bd9Sstevel@tonic-gate (void) free_timezones(tp); 579*7c478bd9Sstevel@tonic-gate break; 580*7c478bd9Sstevel@tonic-gate } 581*7c478bd9Sstevel@tonic-gate (void) strncpy(ptr, lp_tzdesc, len_tzdesc); 582*7c478bd9Sstevel@tonic-gate *(ptr + len_tzdesc) = '\0'; 583*7c478bd9Sstevel@tonic-gate tp->tz_id_desc = ptr; 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate /* Get localized country description */ 586*7c478bd9Sstevel@tonic-gate lptr = dgettext(TEXT_DOMAIN, ptr); 587*7c478bd9Sstevel@tonic-gate if ((ptr = strdup(lptr)) == NULL) { 588*7c478bd9Sstevel@tonic-gate sav_errno = ENOMEM; 589*7c478bd9Sstevel@tonic-gate ncount = -1; 590*7c478bd9Sstevel@tonic-gate (void) free_timezones(tp); 591*7c478bd9Sstevel@tonic-gate break; 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate tp->tz_display_desc = ptr; 594*7c478bd9Sstevel@tonic-gate 595*7c478bd9Sstevel@tonic-gate } else { 596*7c478bd9Sstevel@tonic-gate tp->tz_id_desc = NULL; 597*7c478bd9Sstevel@tonic-gate tp->tz_display_desc = NULL; 598*7c478bd9Sstevel@tonic-gate } 599*7c478bd9Sstevel@tonic-gate /* Get coordinate information */ 600*7c478bd9Sstevel@tonic-gate if (get_coord(tp, lp_coord, len_coord) == -1) { 601*7c478bd9Sstevel@tonic-gate sav_errno = EILSEQ; 602*7c478bd9Sstevel@tonic-gate ncount = -1; 603*7c478bd9Sstevel@tonic-gate (void) free_timezones(tp); 604*7c478bd9Sstevel@tonic-gate break; 605*7c478bd9Sstevel@tonic-gate } 606*7c478bd9Sstevel@tonic-gate /* Store timezone struct in a linked list */ 607*7c478bd9Sstevel@tonic-gate if (head == NULL) { 608*7c478bd9Sstevel@tonic-gate head = tp; 609*7c478bd9Sstevel@tonic-gate } else { 610*7c478bd9Sstevel@tonic-gate prev->tz_next = tp; 611*7c478bd9Sstevel@tonic-gate } 612*7c478bd9Sstevel@tonic-gate prev = tp; 613*7c478bd9Sstevel@tonic-gate ncount++; 614*7c478bd9Sstevel@tonic-gate } else { 615*7c478bd9Sstevel@tonic-gate if (match == 1) { 616*7c478bd9Sstevel@tonic-gate /* 617*7c478bd9Sstevel@tonic-gate * At this point, since zone_sun.tab is ordered, 618*7c478bd9Sstevel@tonic-gate * if we've already found timezone entries for 619*7c478bd9Sstevel@tonic-gate * the input country, then we've found all of 620*7c478bd9Sstevel@tonic-gate * the desired timezone entries (since we will 621*7c478bd9Sstevel@tonic-gate * be past that country's section in 622*7c478bd9Sstevel@tonic-gate * zone_sun.tab), and we are done. 623*7c478bd9Sstevel@tonic-gate */ 624*7c478bd9Sstevel@tonic-gate break; 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate } 627*7c478bd9Sstevel@tonic-gate } 628*7c478bd9Sstevel@tonic-gate 629*7c478bd9Sstevel@tonic-gate /* Finish up */ 630*7c478bd9Sstevel@tonic-gate (void) fclose(fp_zone); 631*7c478bd9Sstevel@tonic-gate if (ncount == -1) { 632*7c478bd9Sstevel@tonic-gate if (head != NULL) 633*7c478bd9Sstevel@tonic-gate (void) free_timezones(head); 634*7c478bd9Sstevel@tonic-gate if (sav_errno) 635*7c478bd9Sstevel@tonic-gate errno = sav_errno; 636*7c478bd9Sstevel@tonic-gate } else { 637*7c478bd9Sstevel@tonic-gate *tmzone = head; 638*7c478bd9Sstevel@tonic-gate } 639*7c478bd9Sstevel@tonic-gate return (ncount); 640*7c478bd9Sstevel@tonic-gate } 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate int 643*7c478bd9Sstevel@tonic-gate free_tz_continents(struct tz_continent *cont) 644*7c478bd9Sstevel@tonic-gate { 645*7c478bd9Sstevel@tonic-gate struct tz_continent *cptr, *cprev; 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate cptr = cont; 648*7c478bd9Sstevel@tonic-gate while (cptr != NULL) { 649*7c478bd9Sstevel@tonic-gate if (cptr->ctnt_id_desc != NULL) 650*7c478bd9Sstevel@tonic-gate free(cptr->ctnt_id_desc); 651*7c478bd9Sstevel@tonic-gate if (cptr->ctnt_display_desc != NULL) 652*7c478bd9Sstevel@tonic-gate free(cptr->ctnt_display_desc); 653*7c478bd9Sstevel@tonic-gate cprev = cptr; 654*7c478bd9Sstevel@tonic-gate cptr = cptr->ctnt_next; 655*7c478bd9Sstevel@tonic-gate free(cprev); 656*7c478bd9Sstevel@tonic-gate } 657*7c478bd9Sstevel@tonic-gate return (0); 658*7c478bd9Sstevel@tonic-gate } 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate int 661*7c478bd9Sstevel@tonic-gate free_tz_countries(struct tz_country *country) 662*7c478bd9Sstevel@tonic-gate { 663*7c478bd9Sstevel@tonic-gate struct tz_country *cptr, *cprev; 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate cptr = country; 666*7c478bd9Sstevel@tonic-gate while (cptr != NULL) { 667*7c478bd9Sstevel@tonic-gate if (cptr->ctry_id_desc != NULL) 668*7c478bd9Sstevel@tonic-gate free(cptr->ctry_id_desc); 669*7c478bd9Sstevel@tonic-gate if (cptr->ctry_display_desc != NULL) 670*7c478bd9Sstevel@tonic-gate free(cptr->ctry_display_desc); 671*7c478bd9Sstevel@tonic-gate cprev = cptr; 672*7c478bd9Sstevel@tonic-gate cptr = cptr->ctry_next; 673*7c478bd9Sstevel@tonic-gate free(cprev); 674*7c478bd9Sstevel@tonic-gate } 675*7c478bd9Sstevel@tonic-gate return (0); 676*7c478bd9Sstevel@tonic-gate } 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate int 679*7c478bd9Sstevel@tonic-gate free_timezones(struct tz_timezone *timezone) 680*7c478bd9Sstevel@tonic-gate { 681*7c478bd9Sstevel@tonic-gate struct tz_timezone *tzptr, *tzprev; 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate tzptr = timezone; 684*7c478bd9Sstevel@tonic-gate while (tzptr != NULL) { 685*7c478bd9Sstevel@tonic-gate if (tzptr->tz_id_desc != NULL) 686*7c478bd9Sstevel@tonic-gate free(tzptr->tz_id_desc); 687*7c478bd9Sstevel@tonic-gate if (tzptr->tz_display_desc != NULL) 688*7c478bd9Sstevel@tonic-gate free(tzptr->tz_display_desc); 689*7c478bd9Sstevel@tonic-gate tzprev = tzptr; 690*7c478bd9Sstevel@tonic-gate tzptr = tzptr->tz_next; 691*7c478bd9Sstevel@tonic-gate free(tzprev); 692*7c478bd9Sstevel@tonic-gate } 693*7c478bd9Sstevel@tonic-gate return (0); 694*7c478bd9Sstevel@tonic-gate } 695*7c478bd9Sstevel@tonic-gate 696*7c478bd9Sstevel@tonic-gate /* 697*7c478bd9Sstevel@tonic-gate * conv_gmt() returns a GMT-offset style timezone 698*7c478bd9Sstevel@tonic-gate * If flag = 0, return Quoted POSIX timezone like: <GMT+8>+8 699*7c478bd9Sstevel@tonic-gate * If flag = 1, return zoneinfo timezone like: :Etc/GMT+8 700*7c478bd9Sstevel@tonic-gate */ 701*7c478bd9Sstevel@tonic-gate char * 702*7c478bd9Sstevel@tonic-gate conv_gmt(int seconds, int flag) 703*7c478bd9Sstevel@tonic-gate { 704*7c478bd9Sstevel@tonic-gate int hour; 705*7c478bd9Sstevel@tonic-gate char *cp; 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate if ((seconds < _GMT_MIN) || (seconds > _GMT_MAX)) { 708*7c478bd9Sstevel@tonic-gate errno = EINVAL; 709*7c478bd9Sstevel@tonic-gate return (NULL); 710*7c478bd9Sstevel@tonic-gate } 711*7c478bd9Sstevel@tonic-gate hour = (seconds / 60) / 60; 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate if (flag == 0) { 714*7c478bd9Sstevel@tonic-gate cp = _conv_gmt_posix(hour); 715*7c478bd9Sstevel@tonic-gate } else if (flag == 1) { 716*7c478bd9Sstevel@tonic-gate cp = _conv_gmt_zoneinfo(hour); 717*7c478bd9Sstevel@tonic-gate } else { 718*7c478bd9Sstevel@tonic-gate errno = EINVAL; 719*7c478bd9Sstevel@tonic-gate return (NULL); 720*7c478bd9Sstevel@tonic-gate } 721*7c478bd9Sstevel@tonic-gate return (cp); 722*7c478bd9Sstevel@tonic-gate } 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate static char * 725*7c478bd9Sstevel@tonic-gate _conv_gmt_posix(int hour) 726*7c478bd9Sstevel@tonic-gate { 727*7c478bd9Sstevel@tonic-gate char *cp; 728*7c478bd9Sstevel@tonic-gate char xsign; 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate if (hour == 0) { 731*7c478bd9Sstevel@tonic-gate if ((cp = strdup(GMT0_FMT)) == NULL) { 732*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 733*7c478bd9Sstevel@tonic-gate return (NULL); 734*7c478bd9Sstevel@tonic-gate } 735*7c478bd9Sstevel@tonic-gate } else { 736*7c478bd9Sstevel@tonic-gate if (hour < 0) { 737*7c478bd9Sstevel@tonic-gate xsign = '-'; 738*7c478bd9Sstevel@tonic-gate /* make hour positive for snprintf() */ 739*7c478bd9Sstevel@tonic-gate hour = -hour; 740*7c478bd9Sstevel@tonic-gate } else { 741*7c478bd9Sstevel@tonic-gate xsign = '+'; 742*7c478bd9Sstevel@tonic-gate } 743*7c478bd9Sstevel@tonic-gate if ((cp = malloc(GMT_FMT_Q_LEN + 1)) == NULL) { 744*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 745*7c478bd9Sstevel@tonic-gate return (NULL); 746*7c478bd9Sstevel@tonic-gate } 747*7c478bd9Sstevel@tonic-gate (void) snprintf(cp, GMT_FMT_Q_LEN + 1, GMT_FMT_Q, 748*7c478bd9Sstevel@tonic-gate xsign, hour, xsign, hour); 749*7c478bd9Sstevel@tonic-gate } 750*7c478bd9Sstevel@tonic-gate return (cp); 751*7c478bd9Sstevel@tonic-gate } 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate static char * 754*7c478bd9Sstevel@tonic-gate _conv_gmt_zoneinfo(int hour) 755*7c478bd9Sstevel@tonic-gate { 756*7c478bd9Sstevel@tonic-gate char *cp; 757*7c478bd9Sstevel@tonic-gate char xsign; 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate if (hour < 0) { 760*7c478bd9Sstevel@tonic-gate xsign = '-'; 761*7c478bd9Sstevel@tonic-gate /* make hour positive for snprintf() */ 762*7c478bd9Sstevel@tonic-gate hour = -hour; 763*7c478bd9Sstevel@tonic-gate } else { 764*7c478bd9Sstevel@tonic-gate xsign = '+'; 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate if ((cp = malloc(GMT_FMT_ZONE_LEN + 1)) == NULL) { 767*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 768*7c478bd9Sstevel@tonic-gate return (NULL); 769*7c478bd9Sstevel@tonic-gate } 770*7c478bd9Sstevel@tonic-gate (void) snprintf(cp, GMT_FMT_ZONE_LEN + 1, GMT_FMT_ZONE, 771*7c478bd9Sstevel@tonic-gate xsign, hour); 772*7c478bd9Sstevel@tonic-gate return (cp); 773*7c478bd9Sstevel@tonic-gate } 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate /* Regular expression for POSIX GMT-offset timezone */ 776*7c478bd9Sstevel@tonic-gate #define _GMT_EXPR "(" _GMT_EXPR_U "|" _GMT_EXPR_Q ")" 777*7c478bd9Sstevel@tonic-gate #define _GMT_EXPR_U "^[gG][mM][tT][-+]?[0-2]?[0-9]$" 778*7c478bd9Sstevel@tonic-gate #define _GMT_EXPR_Q "^<[gG][mM][tT][-+]?[0-2]?[0-9]>[-+]?[0-2]?[0-9]$" 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate /* 781*7c478bd9Sstevel@tonic-gate * Regular expression for quoted POSIX timezone. 782*7c478bd9Sstevel@tonic-gate */ 783*7c478bd9Sstevel@tonic-gate /* Avoid alphabetic ranges (eg, a-z) due to effect of LC_COLLATE */ 784*7c478bd9Sstevel@tonic-gate #define _ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 785*7c478bd9Sstevel@tonic-gate #define _NUM "0123456789" /* for safe */ 786*7c478bd9Sstevel@tonic-gate #define _STD_Q_ELM "[-+" _ALPHA _NUM "]" 787*7c478bd9Sstevel@tonic-gate #define _STD_Q "<" _STD_Q_ELM _STD_Q_ELM _STD_Q_ELM "+>" 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate /* Regular expression for unquoted POSIX timezone */ 790*7c478bd9Sstevel@tonic-gate #define _STD_U_ELM_1 "[^-+,<" _NUM "]" 791*7c478bd9Sstevel@tonic-gate #define _STD_U_ELM "[^-+," _NUM "]" 792*7c478bd9Sstevel@tonic-gate #define _STD_U _STD_U_ELM_1 _STD_U_ELM _STD_U_ELM "+" 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate /* Regular expression for POSIX timezone */ 795*7c478bd9Sstevel@tonic-gate #define _STD "(" _STD_U "|" _STD_Q ")" 796*7c478bd9Sstevel@tonic-gate #define _DST _STD 797*7c478bd9Sstevel@tonic-gate #define _OFFSET "[-+]?" _TIME 798*7c478bd9Sstevel@tonic-gate #define _START "(" _DATEJ "|" _DATEn "|" _DATEM ")" 799*7c478bd9Sstevel@tonic-gate #define _DATEJ "J(([0-2]?[0-9]?[0-9])|3[0-5][0-9]|36[0-5])" 800*7c478bd9Sstevel@tonic-gate #define _DATEn "(([0-2]?[0-9]?[0-9])|3[0-5][0-9]|36[0-5])" 801*7c478bd9Sstevel@tonic-gate #define _DATEM "M([0-9]|10|11|12)\\.[1-5]\\.[0-6]" 802*7c478bd9Sstevel@tonic-gate #define _END _START 803*7c478bd9Sstevel@tonic-gate #define _TIME _HH "(:" _MM "(:" _SS ")?" ")?" 804*7c478bd9Sstevel@tonic-gate #define _HH "(([0-1]?[0-9])|20|21|22|23|24)" 805*7c478bd9Sstevel@tonic-gate #define _MM "[0-5]?[0-9]" 806*7c478bd9Sstevel@tonic-gate #define _SS _MM 807*7c478bd9Sstevel@tonic-gate #define _POSIX_EXPR "^" _STD _OFFSET "(" _DST "(" _OFFSET ")?" \ 808*7c478bd9Sstevel@tonic-gate "(," _START "(/" _TIME ")?" \ 809*7c478bd9Sstevel@tonic-gate "," _END "(/" _TIME ")?" ")?" ")?" "$" 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate #define LEN_TZDIR (sizeof (TZDIR) - 1) 812*7c478bd9Sstevel@tonic-gate 813*7c478bd9Sstevel@tonic-gate /* 814*7c478bd9Sstevel@tonic-gate * isvalid_tz() checks if timezone is a valid POSIX or zoneinfo 815*7c478bd9Sstevel@tonic-gate * timezone, depending on the value of flag. For flag = _VTZ_INSTALL, 816*7c478bd9Sstevel@tonic-gate * isvalid_tz() behaves according to the behavior of Solaris Install 817*7c478bd9Sstevel@tonic-gate * in Solaris 9 and earlier, where timezones under /usr/share/lib/zoneinfo 818*7c478bd9Sstevel@tonic-gate * were validated. isvalid_tz() has a special check for GMT+-* timezones 819*7c478bd9Sstevel@tonic-gate * because Solaris Install validated /usr/share/lib/zoneinfo/GMT+-*. 820*7c478bd9Sstevel@tonic-gate * However, when /usr/share/lib/zoneinfo/GMT+-* are EOF'd, that check 821*7c478bd9Sstevel@tonic-gate * no longer works. 822*7c478bd9Sstevel@tonic-gate * 823*7c478bd9Sstevel@tonic-gate * isvalid_tz() returns 1 if a valid timezone is detected. 824*7c478bd9Sstevel@tonic-gate */ 825*7c478bd9Sstevel@tonic-gate int 826*7c478bd9Sstevel@tonic-gate isvalid_tz(char *timezone, char *root, int flag) 827*7c478bd9Sstevel@tonic-gate { 828*7c478bd9Sstevel@tonic-gate char path[MAXPATHLEN]; 829*7c478bd9Sstevel@tonic-gate char buf[sizeof (struct tzhead)]; 830*7c478bd9Sstevel@tonic-gate int fid, ret; 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate if ((timezone == NULL) || (*timezone == '\0')) { 833*7c478bd9Sstevel@tonic-gate return (0); 834*7c478bd9Sstevel@tonic-gate } 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate /* First check if timezone is a valid POSIX timezone */ 837*7c478bd9Sstevel@tonic-gate switch (flag) { 838*7c478bd9Sstevel@tonic-gate case _VTZ_INSTALL: 839*7c478bd9Sstevel@tonic-gate /* 840*7c478bd9Sstevel@tonic-gate * Special check for POSIX GMT timezone. 841*7c478bd9Sstevel@tonic-gate * If no match, check for zoneinfo timezone below 842*7c478bd9Sstevel@tonic-gate */ 843*7c478bd9Sstevel@tonic-gate if (_tz_match(_GMT_EXPR, timezone) == 0) { 844*7c478bd9Sstevel@tonic-gate /* Valid GMT timezone */ 845*7c478bd9Sstevel@tonic-gate return (1); 846*7c478bd9Sstevel@tonic-gate } 847*7c478bd9Sstevel@tonic-gate break; 848*7c478bd9Sstevel@tonic-gate case _VTZ_POSIX: 849*7c478bd9Sstevel@tonic-gate /* Check for generic POSIX timezone */ 850*7c478bd9Sstevel@tonic-gate if (_tz_match(_POSIX_EXPR, timezone) == 0) { 851*7c478bd9Sstevel@tonic-gate /* Valid POSIX timezone */ 852*7c478bd9Sstevel@tonic-gate return (1); 853*7c478bd9Sstevel@tonic-gate } 854*7c478bd9Sstevel@tonic-gate /* Invalid POSIX timezone */ 855*7c478bd9Sstevel@tonic-gate return (0); 856*7c478bd9Sstevel@tonic-gate case _VTZ_ALL: 857*7c478bd9Sstevel@tonic-gate /* Check for generic POSIX timezone */ 858*7c478bd9Sstevel@tonic-gate if (_tz_match(_POSIX_EXPR, timezone) == 0) { 859*7c478bd9Sstevel@tonic-gate /* Valid POSIX timezone */ 860*7c478bd9Sstevel@tonic-gate return (1); 861*7c478bd9Sstevel@tonic-gate } 862*7c478bd9Sstevel@tonic-gate break; 863*7c478bd9Sstevel@tonic-gate case _VTZ_ZONEINFO: 864*7c478bd9Sstevel@tonic-gate break; 865*7c478bd9Sstevel@tonic-gate default: 866*7c478bd9Sstevel@tonic-gate return (0); 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate 869*7c478bd9Sstevel@tonic-gate /* 870*7c478bd9Sstevel@tonic-gate * Check for valid zoneinfo timezone - 871*7c478bd9Sstevel@tonic-gate * open zoneinfo file and check for magic number 872*7c478bd9Sstevel@tonic-gate */ 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate /* skip prepended ':' if one exists */ 875*7c478bd9Sstevel@tonic-gate if (*timezone == ':') { 876*7c478bd9Sstevel@tonic-gate timezone++; 877*7c478bd9Sstevel@tonic-gate } 878*7c478bd9Sstevel@tonic-gate /* Construct full zoneinfo pathname */ 879*7c478bd9Sstevel@tonic-gate if ((root != NULL) && (*root != '\0')) { 880*7c478bd9Sstevel@tonic-gate ret = snprintf(path, sizeof (path), 881*7c478bd9Sstevel@tonic-gate "%s%s/%s", root, TZDIR, timezone); 882*7c478bd9Sstevel@tonic-gate if (ret >= sizeof (path)) { 883*7c478bd9Sstevel@tonic-gate /* too long */ 884*7c478bd9Sstevel@tonic-gate return (0); 885*7c478bd9Sstevel@tonic-gate } 886*7c478bd9Sstevel@tonic-gate } else { 887*7c478bd9Sstevel@tonic-gate ret = snprintf(path, sizeof (path), 888*7c478bd9Sstevel@tonic-gate "%s/%s", TZDIR, timezone); 889*7c478bd9Sstevel@tonic-gate if (ret >= sizeof (path)) { 890*7c478bd9Sstevel@tonic-gate /* too long */ 891*7c478bd9Sstevel@tonic-gate return (0); 892*7c478bd9Sstevel@tonic-gate } 893*7c478bd9Sstevel@tonic-gate } 894*7c478bd9Sstevel@tonic-gate if ((fid = open(path, O_RDONLY)) == -1) { 895*7c478bd9Sstevel@tonic-gate return (0); 896*7c478bd9Sstevel@tonic-gate } 897*7c478bd9Sstevel@tonic-gate if (read(fid, buf, sizeof (struct tzhead)) != 898*7c478bd9Sstevel@tonic-gate sizeof (struct tzhead)) { 899*7c478bd9Sstevel@tonic-gate (void) close(fid); 900*7c478bd9Sstevel@tonic-gate return (0); 901*7c478bd9Sstevel@tonic-gate } 902*7c478bd9Sstevel@tonic-gate if (strncmp(buf, TZ_MAGIC, sizeof (TZ_MAGIC) - 1) != 0) { 903*7c478bd9Sstevel@tonic-gate (void) close(fid); 904*7c478bd9Sstevel@tonic-gate return (0); 905*7c478bd9Sstevel@tonic-gate } 906*7c478bd9Sstevel@tonic-gate if (close(fid) == -1) { 907*7c478bd9Sstevel@tonic-gate return (0); 908*7c478bd9Sstevel@tonic-gate } 909*7c478bd9Sstevel@tonic-gate /* Valid zoneinfo timezone */ 910*7c478bd9Sstevel@tonic-gate return (1); 911*7c478bd9Sstevel@tonic-gate } 912*7c478bd9Sstevel@tonic-gate 913*7c478bd9Sstevel@tonic-gate #define N_MATCH 1 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate int 916*7c478bd9Sstevel@tonic-gate _tz_match(const char *expr, const char *string) 917*7c478bd9Sstevel@tonic-gate { 918*7c478bd9Sstevel@tonic-gate regex_t reg; 919*7c478bd9Sstevel@tonic-gate regmatch_t pmatch[N_MATCH]; 920*7c478bd9Sstevel@tonic-gate int ret; 921*7c478bd9Sstevel@tonic-gate 922*7c478bd9Sstevel@tonic-gate ret = regcomp(®, expr, REG_EXTENDED); 923*7c478bd9Sstevel@tonic-gate if (ret != 0) { 924*7c478bd9Sstevel@tonic-gate return (-1); 925*7c478bd9Sstevel@tonic-gate } 926*7c478bd9Sstevel@tonic-gate 927*7c478bd9Sstevel@tonic-gate ret = regexec((const regex_t *)®, string, N_MATCH, pmatch, 0); 928*7c478bd9Sstevel@tonic-gate if (ret == 0) { 929*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 930*7c478bd9Sstevel@tonic-gate printf("OK matched - %s\n", string); 931*7c478bd9Sstevel@tonic-gate #endif 932*7c478bd9Sstevel@tonic-gate regfree(®); 933*7c478bd9Sstevel@tonic-gate return (0); 934*7c478bd9Sstevel@tonic-gate } 935*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 936*7c478bd9Sstevel@tonic-gate printf("NOT matched - %s\n", string); 937*7c478bd9Sstevel@tonic-gate #endif 938*7c478bd9Sstevel@tonic-gate regfree(®); 939*7c478bd9Sstevel@tonic-gate return (-1); 940*7c478bd9Sstevel@tonic-gate } 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate char * 943*7c478bd9Sstevel@tonic-gate get_system_tz(char *root) 944*7c478bd9Sstevel@tonic-gate { 945*7c478bd9Sstevel@tonic-gate FILE *ifp; 946*7c478bd9Sstevel@tonic-gate char buff[512]; 947*7c478bd9Sstevel@tonic-gate int serrno, ret; 948*7c478bd9Sstevel@tonic-gate char *sp, *ptr, *p; 949*7c478bd9Sstevel@tonic-gate char fname[MAXPATHLEN]; 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate if ((ret = snprintf(fname, sizeof (fname), "%s/%s", root, DEFINIT)) >= 952*7c478bd9Sstevel@tonic-gate sizeof (fname)) { 953*7c478bd9Sstevel@tonic-gate errno = ENAMETOOLONG; 954*7c478bd9Sstevel@tonic-gate return (NULL); 955*7c478bd9Sstevel@tonic-gate } else if (ret < 0) { 956*7c478bd9Sstevel@tonic-gate return (NULL); 957*7c478bd9Sstevel@tonic-gate } 958*7c478bd9Sstevel@tonic-gate if ((ifp = fopen(fname, "r")) == NULL) 959*7c478bd9Sstevel@tonic-gate return (NULL); 960*7c478bd9Sstevel@tonic-gate while (fgets(buff, sizeof (buff), ifp) != NULL) { 961*7c478bd9Sstevel@tonic-gate if (strncmp(buff, "TZ=", 3) == 0) { 962*7c478bd9Sstevel@tonic-gate (void) fclose(ifp); 963*7c478bd9Sstevel@tonic-gate p = &buff[3]; 964*7c478bd9Sstevel@tonic-gate if ((sp = strchr(p, ';')) != NULL) { 965*7c478bd9Sstevel@tonic-gate *sp = '\0'; 966*7c478bd9Sstevel@tonic-gate } else if ((sp = strchr(p, '\n')) != NULL) { 967*7c478bd9Sstevel@tonic-gate *sp = '\0'; 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate if (strpbrk(p, "\"'") != NULL) { 970*7c478bd9Sstevel@tonic-gate strip_quotes(p, p); 971*7c478bd9Sstevel@tonic-gate } 972*7c478bd9Sstevel@tonic-gate ptr = strdup(p); 973*7c478bd9Sstevel@tonic-gate if (ptr == NULL) { 974*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 975*7c478bd9Sstevel@tonic-gate return (NULL); 976*7c478bd9Sstevel@tonic-gate } 977*7c478bd9Sstevel@tonic-gate return (ptr); 978*7c478bd9Sstevel@tonic-gate } 979*7c478bd9Sstevel@tonic-gate } 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate /* Either reached EOF with no TZ= entry, or got fgets() error */ 982*7c478bd9Sstevel@tonic-gate serrno = errno; 983*7c478bd9Sstevel@tonic-gate if (feof(ifp) != 0) { 984*7c478bd9Sstevel@tonic-gate /* No "TZ=" entry found */ 985*7c478bd9Sstevel@tonic-gate serrno = EINVAL; 986*7c478bd9Sstevel@tonic-gate } 987*7c478bd9Sstevel@tonic-gate (void) fclose(ifp); 988*7c478bd9Sstevel@tonic-gate errno = serrno; 989*7c478bd9Sstevel@tonic-gate return (NULL); 990*7c478bd9Sstevel@tonic-gate } 991*7c478bd9Sstevel@tonic-gate 992*7c478bd9Sstevel@tonic-gate int 993*7c478bd9Sstevel@tonic-gate set_system_tz(char *tz, char *root) 994*7c478bd9Sstevel@tonic-gate { 995*7c478bd9Sstevel@tonic-gate FILE *ifp, *ofp; /* Input & output files */ 996*7c478bd9Sstevel@tonic-gate char *tmpdir, *tmp; /* Temp file name and location */ 997*7c478bd9Sstevel@tonic-gate char buff[1024]; 998*7c478bd9Sstevel@tonic-gate int replaced = 0, ret, serrno; 999*7c478bd9Sstevel@tonic-gate char *tdb; 1000*7c478bd9Sstevel@tonic-gate struct stat sb; 1001*7c478bd9Sstevel@tonic-gate char fname[MAXPATHLEN]; 1002*7c478bd9Sstevel@tonic-gate const char *tzfmt; 1003*7c478bd9Sstevel@tonic-gate int len, fd; 1004*7c478bd9Sstevel@tonic-gate 1005*7c478bd9Sstevel@tonic-gate if (tz == NULL || root == NULL) 1006*7c478bd9Sstevel@tonic-gate return (-1); 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate if (strchr(tz, '<')) { 1009*7c478bd9Sstevel@tonic-gate tzfmt = TZ_FMT_Q; 1010*7c478bd9Sstevel@tonic-gate } else { 1011*7c478bd9Sstevel@tonic-gate tzfmt = TZ_FMT; 1012*7c478bd9Sstevel@tonic-gate } 1013*7c478bd9Sstevel@tonic-gate 1014*7c478bd9Sstevel@tonic-gate if ((ret = snprintf(fname, sizeof (fname), "%s/%s", root, DEFINIT)) >= 1015*7c478bd9Sstevel@tonic-gate sizeof (fname)) { 1016*7c478bd9Sstevel@tonic-gate errno = ENAMETOOLONG; 1017*7c478bd9Sstevel@tonic-gate return (-1); 1018*7c478bd9Sstevel@tonic-gate } else if (ret < 0) { 1019*7c478bd9Sstevel@tonic-gate return (-1); 1020*7c478bd9Sstevel@tonic-gate } 1021*7c478bd9Sstevel@tonic-gate 1022*7c478bd9Sstevel@tonic-gate /* 1023*7c478bd9Sstevel@tonic-gate * Generate temporary file name to use. We make sure it's in the same 1024*7c478bd9Sstevel@tonic-gate * directory as the db we're processing so that we can use rename to 1025*7c478bd9Sstevel@tonic-gate * do the replace later. Otherwise we run the risk of being on the 1026*7c478bd9Sstevel@tonic-gate * wrong filesystem and having rename() fail for that reason. 1027*7c478bd9Sstevel@tonic-gate */ 1028*7c478bd9Sstevel@tonic-gate tdb = fname; 1029*7c478bd9Sstevel@tonic-gate if (trav_link(&tdb) == -1) 1030*7c478bd9Sstevel@tonic-gate return (-1); 1031*7c478bd9Sstevel@tonic-gate if ((tmpdir = strdup(tdb)) == NULL) { 1032*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1033*7c478bd9Sstevel@tonic-gate return (-1); 1034*7c478bd9Sstevel@tonic-gate } 1035*7c478bd9Sstevel@tonic-gate remove_component(tmpdir); 1036*7c478bd9Sstevel@tonic-gate if ((len = strlen(tmpdir)) == 0) { 1037*7c478bd9Sstevel@tonic-gate (void) strcpy(tmpdir, "."); 1038*7c478bd9Sstevel@tonic-gate len = 1; 1039*7c478bd9Sstevel@tonic-gate } 1040*7c478bd9Sstevel@tonic-gate 1041*7c478bd9Sstevel@tonic-gate if ((tmp = malloc(len + TR_LEN + 1)) == NULL) { 1042*7c478bd9Sstevel@tonic-gate free(tmpdir); 1043*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1044*7c478bd9Sstevel@tonic-gate return (-1); 1045*7c478bd9Sstevel@tonic-gate } 1046*7c478bd9Sstevel@tonic-gate (void) strcpy(tmp, tmpdir); 1047*7c478bd9Sstevel@tonic-gate (void) strcpy(tmp + len, TRAILER); 1048*7c478bd9Sstevel@tonic-gate free(tmpdir); 1049*7c478bd9Sstevel@tonic-gate if ((fd = mkstemp(tmp)) == -1) { 1050*7c478bd9Sstevel@tonic-gate free(tmp); 1051*7c478bd9Sstevel@tonic-gate return (-1); 1052*7c478bd9Sstevel@tonic-gate } 1053*7c478bd9Sstevel@tonic-gate if ((ofp = fdopen(fd, "w")) == NULL) { 1054*7c478bd9Sstevel@tonic-gate serrno = errno; 1055*7c478bd9Sstevel@tonic-gate (void) close(fd); 1056*7c478bd9Sstevel@tonic-gate free(tmp); 1057*7c478bd9Sstevel@tonic-gate errno = serrno; 1058*7c478bd9Sstevel@tonic-gate return (-1); 1059*7c478bd9Sstevel@tonic-gate } 1060*7c478bd9Sstevel@tonic-gate 1061*7c478bd9Sstevel@tonic-gate /* Preserve permissions of current file if it exists */ 1062*7c478bd9Sstevel@tonic-gate if (stat(tdb, &sb) == 0) { 1063*7c478bd9Sstevel@tonic-gate if (fchmod(fileno(ofp), sb.st_mode) == -1) { 1064*7c478bd9Sstevel@tonic-gate serrno = errno; 1065*7c478bd9Sstevel@tonic-gate (void) fclose(ofp); 1066*7c478bd9Sstevel@tonic-gate (void) unlink(tmp); 1067*7c478bd9Sstevel@tonic-gate free(tmp); 1068*7c478bd9Sstevel@tonic-gate errno = serrno; 1069*7c478bd9Sstevel@tonic-gate return (-1); 1070*7c478bd9Sstevel@tonic-gate } 1071*7c478bd9Sstevel@tonic-gate if (fchown(fileno(ofp), sb.st_uid, sb.st_gid) == -1) { 1072*7c478bd9Sstevel@tonic-gate serrno = errno; 1073*7c478bd9Sstevel@tonic-gate (void) fclose(ofp); 1074*7c478bd9Sstevel@tonic-gate (void) unlink(tmp); 1075*7c478bd9Sstevel@tonic-gate free(tmp); 1076*7c478bd9Sstevel@tonic-gate errno = serrno; 1077*7c478bd9Sstevel@tonic-gate return (-1); 1078*7c478bd9Sstevel@tonic-gate } 1079*7c478bd9Sstevel@tonic-gate } else if (errno != ENOENT) { 1080*7c478bd9Sstevel@tonic-gate serrno = errno; 1081*7c478bd9Sstevel@tonic-gate (void) fclose(ofp); 1082*7c478bd9Sstevel@tonic-gate (void) unlink(tmp); 1083*7c478bd9Sstevel@tonic-gate free(tmp); 1084*7c478bd9Sstevel@tonic-gate errno = serrno; 1085*7c478bd9Sstevel@tonic-gate return (-1); 1086*7c478bd9Sstevel@tonic-gate } 1087*7c478bd9Sstevel@tonic-gate 1088*7c478bd9Sstevel@tonic-gate if ((ifp = fopen(fname, "r+")) != NULL) { 1089*7c478bd9Sstevel@tonic-gate while (fgets(buff, sizeof (buff), ifp) != NULL) { 1090*7c478bd9Sstevel@tonic-gate if (!replaced && (strncmp(buff, "TZ=", 3) == 0)) { 1091*7c478bd9Sstevel@tonic-gate ret = snprintf(buff, sizeof (buff), tzfmt, 1092*7c478bd9Sstevel@tonic-gate tz); 1093*7c478bd9Sstevel@tonic-gate if ((ret >= sizeof (buff)) || (ret < 0)) { 1094*7c478bd9Sstevel@tonic-gate if (ret >= sizeof (buff)) 1095*7c478bd9Sstevel@tonic-gate serrno = EINVAL; 1096*7c478bd9Sstevel@tonic-gate (void) fclose(ofp); 1097*7c478bd9Sstevel@tonic-gate (void) fclose(ifp); 1098*7c478bd9Sstevel@tonic-gate (void) unlink(tmp); 1099*7c478bd9Sstevel@tonic-gate free(tmp); 1100*7c478bd9Sstevel@tonic-gate errno = serrno; 1101*7c478bd9Sstevel@tonic-gate return (-1); 1102*7c478bd9Sstevel@tonic-gate } 1103*7c478bd9Sstevel@tonic-gate replaced = 1; 1104*7c478bd9Sstevel@tonic-gate } 1105*7c478bd9Sstevel@tonic-gate if (fputs(buff, ofp) == EOF) { 1106*7c478bd9Sstevel@tonic-gate serrno = errno; 1107*7c478bd9Sstevel@tonic-gate (void) fclose(ofp); 1108*7c478bd9Sstevel@tonic-gate (void) fclose(ifp); 1109*7c478bd9Sstevel@tonic-gate (void) unlink(tmp); 1110*7c478bd9Sstevel@tonic-gate free(tmp); 1111*7c478bd9Sstevel@tonic-gate errno = serrno; 1112*7c478bd9Sstevel@tonic-gate return (-1); 1113*7c478bd9Sstevel@tonic-gate } 1114*7c478bd9Sstevel@tonic-gate } 1115*7c478bd9Sstevel@tonic-gate (void) fclose(ifp); 1116*7c478bd9Sstevel@tonic-gate 1117*7c478bd9Sstevel@tonic-gate } else if (errno != ENOENT) { 1118*7c478bd9Sstevel@tonic-gate serrno = errno; 1119*7c478bd9Sstevel@tonic-gate (void) fclose(ofp); 1120*7c478bd9Sstevel@tonic-gate (void) unlink(tmp); 1121*7c478bd9Sstevel@tonic-gate free(tmp); 1122*7c478bd9Sstevel@tonic-gate errno = serrno; 1123*7c478bd9Sstevel@tonic-gate return (-1); 1124*7c478bd9Sstevel@tonic-gate } 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate /* 1127*7c478bd9Sstevel@tonic-gate * no $(ROOT)/etc/default/init found, or 1128*7c478bd9Sstevel@tonic-gate * no "TZ=" entry found in the init file. 1129*7c478bd9Sstevel@tonic-gate */ 1130*7c478bd9Sstevel@tonic-gate if (!replaced && 1131*7c478bd9Sstevel@tonic-gate (fprintf(ofp, tzfmt, tz) == EOF)) { 1132*7c478bd9Sstevel@tonic-gate serrno = errno; 1133*7c478bd9Sstevel@tonic-gate (void) fclose(ofp); 1134*7c478bd9Sstevel@tonic-gate (void) unlink(tmp); 1135*7c478bd9Sstevel@tonic-gate free(tmp); 1136*7c478bd9Sstevel@tonic-gate errno = serrno; 1137*7c478bd9Sstevel@tonic-gate return (-1); 1138*7c478bd9Sstevel@tonic-gate } 1139*7c478bd9Sstevel@tonic-gate 1140*7c478bd9Sstevel@tonic-gate if (fsync(fileno(ofp))) { 1141*7c478bd9Sstevel@tonic-gate serrno = errno; 1142*7c478bd9Sstevel@tonic-gate (void) unlink(tmp); 1143*7c478bd9Sstevel@tonic-gate free(tmp); 1144*7c478bd9Sstevel@tonic-gate errno = serrno; 1145*7c478bd9Sstevel@tonic-gate return (-1); 1146*7c478bd9Sstevel@tonic-gate } 1147*7c478bd9Sstevel@tonic-gate 1148*7c478bd9Sstevel@tonic-gate (void) fclose(ofp); 1149*7c478bd9Sstevel@tonic-gate if (rename(tmp, tdb) != 0) { 1150*7c478bd9Sstevel@tonic-gate serrno = errno; 1151*7c478bd9Sstevel@tonic-gate (void) unlink(tmp); 1152*7c478bd9Sstevel@tonic-gate free(tmp); 1153*7c478bd9Sstevel@tonic-gate errno = serrno; 1154*7c478bd9Sstevel@tonic-gate return (-1); 1155*7c478bd9Sstevel@tonic-gate } else { 1156*7c478bd9Sstevel@tonic-gate free(tmp); 1157*7c478bd9Sstevel@tonic-gate return (0); 1158*7c478bd9Sstevel@tonic-gate } 1159*7c478bd9Sstevel@tonic-gate } 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate /* 1162*7c478bd9Sstevel@tonic-gate * Function to traverse a symlink path to find the real file at the end of 1163*7c478bd9Sstevel@tonic-gate * the rainbow. 1164*7c478bd9Sstevel@tonic-gate */ 1165*7c478bd9Sstevel@tonic-gate int 1166*7c478bd9Sstevel@tonic-gate trav_link(char **path) 1167*7c478bd9Sstevel@tonic-gate { 1168*7c478bd9Sstevel@tonic-gate static char newpath[MAXPATHLEN]; 1169*7c478bd9Sstevel@tonic-gate char lastpath[MAXPATHLEN]; 1170*7c478bd9Sstevel@tonic-gate int len, ret; 1171*7c478bd9Sstevel@tonic-gate char *tp; 1172*7c478bd9Sstevel@tonic-gate 1173*7c478bd9Sstevel@tonic-gate (void) strcpy(lastpath, *path); 1174*7c478bd9Sstevel@tonic-gate while ((len = readlink(*path, newpath, sizeof (newpath))) != -1) { 1175*7c478bd9Sstevel@tonic-gate newpath[len] = '\0'; 1176*7c478bd9Sstevel@tonic-gate if (newpath[0] != '/') { 1177*7c478bd9Sstevel@tonic-gate if ((tp = strdup(newpath)) == NULL) { 1178*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1179*7c478bd9Sstevel@tonic-gate return (-1); 1180*7c478bd9Sstevel@tonic-gate } 1181*7c478bd9Sstevel@tonic-gate remove_component(lastpath); 1182*7c478bd9Sstevel@tonic-gate ret = snprintf(newpath, sizeof (newpath), 1183*7c478bd9Sstevel@tonic-gate "%s/%s", lastpath, tp); 1184*7c478bd9Sstevel@tonic-gate free(tp); 1185*7c478bd9Sstevel@tonic-gate if ((ret >= sizeof (newpath)) || (ret < 0)) 1186*7c478bd9Sstevel@tonic-gate return (-1); 1187*7c478bd9Sstevel@tonic-gate } 1188*7c478bd9Sstevel@tonic-gate (void) strcpy(lastpath, newpath); 1189*7c478bd9Sstevel@tonic-gate *path = newpath; 1190*7c478bd9Sstevel@tonic-gate } 1191*7c478bd9Sstevel@tonic-gate 1192*7c478bd9Sstevel@tonic-gate /* 1193*7c478bd9Sstevel@tonic-gate * ENOENT or EINVAL is the normal exit case of the above loop. 1194*7c478bd9Sstevel@tonic-gate */ 1195*7c478bd9Sstevel@tonic-gate if ((errno == ENOENT) || (errno == EINVAL)) 1196*7c478bd9Sstevel@tonic-gate return (0); 1197*7c478bd9Sstevel@tonic-gate else 1198*7c478bd9Sstevel@tonic-gate return (-1); 1199*7c478bd9Sstevel@tonic-gate } 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate void 1202*7c478bd9Sstevel@tonic-gate remove_component(char *path) 1203*7c478bd9Sstevel@tonic-gate { 1204*7c478bd9Sstevel@tonic-gate char *p; 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate p = strrchr(path, '/'); /* find last '/' */ 1207*7c478bd9Sstevel@tonic-gate if (p == NULL) { 1208*7c478bd9Sstevel@tonic-gate *path = '\0'; /* set path to null str */ 1209*7c478bd9Sstevel@tonic-gate } else { 1210*7c478bd9Sstevel@tonic-gate *p = '\0'; /* zap it */ 1211*7c478bd9Sstevel@tonic-gate } 1212*7c478bd9Sstevel@tonic-gate } 1213*7c478bd9Sstevel@tonic-gate 1214*7c478bd9Sstevel@tonic-gate /* 1215*7c478bd9Sstevel@tonic-gate * get_coord() fills in the tz_coord structure of the tz_timezone 1216*7c478bd9Sstevel@tonic-gate * struct. It returns 0 on success, or -1 on error. 1217*7c478bd9Sstevel@tonic-gate * The format of p_coord is: 1218*7c478bd9Sstevel@tonic-gate * 1219*7c478bd9Sstevel@tonic-gate * Latitude and longitude of the zone's principal location 1220*7c478bd9Sstevel@tonic-gate * in ISO 6709 sign-degrees-minutes-seconds format, 1221*7c478bd9Sstevel@tonic-gate * either +-DDMM+-DDDMM or +-DDMMSS+-DDDMMSS, 1222*7c478bd9Sstevel@tonic-gate * first latitude (+ is north), then longitude (+ is east). 1223*7c478bd9Sstevel@tonic-gate */ 1224*7c478bd9Sstevel@tonic-gate static int 1225*7c478bd9Sstevel@tonic-gate get_coord(struct tz_timezone *tp, char *p_coord, size_t len_coord) 1226*7c478bd9Sstevel@tonic-gate { 1227*7c478bd9Sstevel@tonic-gate int i, fmt_flag, nchar; 1228*7c478bd9Sstevel@tonic-gate int *signp, *degp, *minp, *secp; 1229*7c478bd9Sstevel@tonic-gate struct tz_coord *tcp; 1230*7c478bd9Sstevel@tonic-gate char buff[512], *endp; 1231*7c478bd9Sstevel@tonic-gate 1232*7c478bd9Sstevel@tonic-gate tcp = &(tp->tz_coord); 1233*7c478bd9Sstevel@tonic-gate 1234*7c478bd9Sstevel@tonic-gate /* Figure out which format to use */ 1235*7c478bd9Sstevel@tonic-gate if (len_coord == COORD_FMTLEN1) { 1236*7c478bd9Sstevel@tonic-gate /* "+-DDMM+-DDDMM" */ 1237*7c478bd9Sstevel@tonic-gate fmt_flag = COORD_FMT1; 1238*7c478bd9Sstevel@tonic-gate } else if (len_coord == COORD_FMTLEN2) { 1239*7c478bd9Sstevel@tonic-gate /* "+-DDMMSS+-DDDMMSS" */ 1240*7c478bd9Sstevel@tonic-gate fmt_flag = COORD_FMT2; 1241*7c478bd9Sstevel@tonic-gate } else { 1242*7c478bd9Sstevel@tonic-gate /* error */ 1243*7c478bd9Sstevel@tonic-gate return (-1); 1244*7c478bd9Sstevel@tonic-gate } 1245*7c478bd9Sstevel@tonic-gate /* 1246*7c478bd9Sstevel@tonic-gate * First time through, get values for latitude; 1247*7c478bd9Sstevel@tonic-gate * second time through, get values for longitude. 1248*7c478bd9Sstevel@tonic-gate */ 1249*7c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) { 1250*7c478bd9Sstevel@tonic-gate /* Set up pointers */ 1251*7c478bd9Sstevel@tonic-gate if (i == 0) { 1252*7c478bd9Sstevel@tonic-gate /* Do latitude */ 1253*7c478bd9Sstevel@tonic-gate nchar = COORD_DLEN_LAT; 1254*7c478bd9Sstevel@tonic-gate signp = (int *)&(tcp->lat_sign); 1255*7c478bd9Sstevel@tonic-gate degp = (int *)&(tcp->lat_degree); 1256*7c478bd9Sstevel@tonic-gate minp = (int *)&(tcp->lat_minute); 1257*7c478bd9Sstevel@tonic-gate secp = (int *)&(tcp->lat_second); 1258*7c478bd9Sstevel@tonic-gate } else { 1259*7c478bd9Sstevel@tonic-gate /* Do longitude */ 1260*7c478bd9Sstevel@tonic-gate nchar = COORD_DLEN_LONG; 1261*7c478bd9Sstevel@tonic-gate signp = (int *)&(tcp->long_sign); 1262*7c478bd9Sstevel@tonic-gate degp = (int *)&tcp->long_degree; 1263*7c478bd9Sstevel@tonic-gate minp = (int *)&tcp->long_minute; 1264*7c478bd9Sstevel@tonic-gate secp = (int *)&tcp->long_second; 1265*7c478bd9Sstevel@tonic-gate } 1266*7c478bd9Sstevel@tonic-gate /* Get latitude/logitude sign */ 1267*7c478bd9Sstevel@tonic-gate if (*p_coord == '+') { 1268*7c478bd9Sstevel@tonic-gate *signp = 1; 1269*7c478bd9Sstevel@tonic-gate } else if (*p_coord == '-') { 1270*7c478bd9Sstevel@tonic-gate *signp = -1; 1271*7c478bd9Sstevel@tonic-gate } else { 1272*7c478bd9Sstevel@tonic-gate return (-1); 1273*7c478bd9Sstevel@tonic-gate } 1274*7c478bd9Sstevel@tonic-gate p_coord++; 1275*7c478bd9Sstevel@tonic-gate 1276*7c478bd9Sstevel@tonic-gate /* Get DD latitude, or DDD longitude */ 1277*7c478bd9Sstevel@tonic-gate (void) strncpy(buff, p_coord, nchar); 1278*7c478bd9Sstevel@tonic-gate buff[nchar] = '\0'; 1279*7c478bd9Sstevel@tonic-gate errno = 0; 1280*7c478bd9Sstevel@tonic-gate *degp = (int)strtol(buff, &endp, 10); 1281*7c478bd9Sstevel@tonic-gate if ((endp != &buff[nchar]) || ((*degp == 0) && (errno != 0))) 1282*7c478bd9Sstevel@tonic-gate return (-1); 1283*7c478bd9Sstevel@tonic-gate p_coord += nchar; 1284*7c478bd9Sstevel@tonic-gate 1285*7c478bd9Sstevel@tonic-gate /* Get MM latitude/longitude */ 1286*7c478bd9Sstevel@tonic-gate (void) strncpy(buff, p_coord, COORD_MLEN); 1287*7c478bd9Sstevel@tonic-gate buff[COORD_MLEN] = '\0'; 1288*7c478bd9Sstevel@tonic-gate errno = 0; 1289*7c478bd9Sstevel@tonic-gate *minp = (int)strtol(buff, &endp, 10); 1290*7c478bd9Sstevel@tonic-gate if ((endp != &buff[COORD_MLEN]) || 1291*7c478bd9Sstevel@tonic-gate ((*degp == 0) && (errno != 0))) 1292*7c478bd9Sstevel@tonic-gate return (-1); 1293*7c478bd9Sstevel@tonic-gate p_coord += COORD_MLEN; 1294*7c478bd9Sstevel@tonic-gate 1295*7c478bd9Sstevel@tonic-gate /* If FMT2, then get SS latitude/longitude */ 1296*7c478bd9Sstevel@tonic-gate if (fmt_flag == COORD_FMT2) { 1297*7c478bd9Sstevel@tonic-gate (void) strncpy(buff, p_coord, COORD_SLEN); 1298*7c478bd9Sstevel@tonic-gate buff[COORD_SLEN] = '\0'; 1299*7c478bd9Sstevel@tonic-gate errno = 0; 1300*7c478bd9Sstevel@tonic-gate *secp = (int)strtol(buff, &endp, 10); 1301*7c478bd9Sstevel@tonic-gate if ((endp != &buff[COORD_SLEN]) || 1302*7c478bd9Sstevel@tonic-gate ((*degp == 0) && (errno != 0))) 1303*7c478bd9Sstevel@tonic-gate return (-1); 1304*7c478bd9Sstevel@tonic-gate p_coord += COORD_SLEN; 1305*7c478bd9Sstevel@tonic-gate } else { 1306*7c478bd9Sstevel@tonic-gate *secp = 0; 1307*7c478bd9Sstevel@tonic-gate } 1308*7c478bd9Sstevel@tonic-gate } 1309*7c478bd9Sstevel@tonic-gate return (0); 1310*7c478bd9Sstevel@tonic-gate } 1311*7c478bd9Sstevel@tonic-gate 1312*7c478bd9Sstevel@tonic-gate static char * 1313*7c478bd9Sstevel@tonic-gate skipwhite(char *cp) 1314*7c478bd9Sstevel@tonic-gate { 1315*7c478bd9Sstevel@tonic-gate while (*cp && ((*cp == ' ') || (*cp == '\t'))) { 1316*7c478bd9Sstevel@tonic-gate cp++; 1317*7c478bd9Sstevel@tonic-gate } 1318*7c478bd9Sstevel@tonic-gate 1319*7c478bd9Sstevel@tonic-gate return (cp); 1320*7c478bd9Sstevel@tonic-gate } 1321*7c478bd9Sstevel@tonic-gate 1322*7c478bd9Sstevel@tonic-gate /* 1323*7c478bd9Sstevel@tonic-gate * skipline() checks if the line begins with a comment 1324*7c478bd9Sstevel@tonic-gate * comment character anywhere in the line, or if the 1325*7c478bd9Sstevel@tonic-gate * line is only whitespace. 1326*7c478bd9Sstevel@tonic-gate * skipline() also checks if the line read is too long to 1327*7c478bd9Sstevel@tonic-gate * fit in the buffer. 1328*7c478bd9Sstevel@tonic-gate * skipline() returns 1 if the line can be skipped, -1 if 1329*7c478bd9Sstevel@tonic-gate * the line read is too long, and 0 if the line should not be skipped. 1330*7c478bd9Sstevel@tonic-gate */ 1331*7c478bd9Sstevel@tonic-gate static int 1332*7c478bd9Sstevel@tonic-gate skipline(char *line) 1333*7c478bd9Sstevel@tonic-gate { 1334*7c478bd9Sstevel@tonic-gate size_t len; 1335*7c478bd9Sstevel@tonic-gate 1336*7c478bd9Sstevel@tonic-gate len = strlen(line); 1337*7c478bd9Sstevel@tonic-gate if (line[len - 1] != '\n') 1338*7c478bd9Sstevel@tonic-gate return (-1); 1339*7c478bd9Sstevel@tonic-gate if (line[0] == '#' || line[0] == '\0' || 1340*7c478bd9Sstevel@tonic-gate (len = strspn(line, " \t\n")) == strlen(line) || 1341*7c478bd9Sstevel@tonic-gate strchr(line, '#') == line + len) 1342*7c478bd9Sstevel@tonic-gate 1343*7c478bd9Sstevel@tonic-gate return (1); 1344*7c478bd9Sstevel@tonic-gate else 1345*7c478bd9Sstevel@tonic-gate return (0); 1346*7c478bd9Sstevel@tonic-gate } 1347*7c478bd9Sstevel@tonic-gate 1348*7c478bd9Sstevel@tonic-gate /* 1349*7c478bd9Sstevel@tonic-gate * strip_quotes -- strip double (") or single (') quotes 1350*7c478bd9Sstevel@tonic-gate */ 1351*7c478bd9Sstevel@tonic-gate static void 1352*7c478bd9Sstevel@tonic-gate strip_quotes(char *from, char *to) 1353*7c478bd9Sstevel@tonic-gate { 1354*7c478bd9Sstevel@tonic-gate char *strip_ptr = NULL; 1355*7c478bd9Sstevel@tonic-gate 1356*7c478bd9Sstevel@tonic-gate while (*from != '\0') { 1357*7c478bd9Sstevel@tonic-gate if ((*from == '"') || (*from == '\'')) { 1358*7c478bd9Sstevel@tonic-gate if (strip_ptr == NULL) 1359*7c478bd9Sstevel@tonic-gate strip_ptr = to; 1360*7c478bd9Sstevel@tonic-gate } else { 1361*7c478bd9Sstevel@tonic-gate if (strip_ptr != NULL) { 1362*7c478bd9Sstevel@tonic-gate *strip_ptr = *from; 1363*7c478bd9Sstevel@tonic-gate strip_ptr++; 1364*7c478bd9Sstevel@tonic-gate } else { 1365*7c478bd9Sstevel@tonic-gate *to = *from; 1366*7c478bd9Sstevel@tonic-gate to++; 1367*7c478bd9Sstevel@tonic-gate } 1368*7c478bd9Sstevel@tonic-gate } 1369*7c478bd9Sstevel@tonic-gate from++; 1370*7c478bd9Sstevel@tonic-gate } 1371*7c478bd9Sstevel@tonic-gate if (strip_ptr != NULL) { 1372*7c478bd9Sstevel@tonic-gate *strip_ptr = '\0'; 1373*7c478bd9Sstevel@tonic-gate } else { 1374*7c478bd9Sstevel@tonic-gate *to = '\0'; 1375*7c478bd9Sstevel@tonic-gate } 1376*7c478bd9Sstevel@tonic-gate } 1377*7c478bd9Sstevel@tonic-gate 1378*7c478bd9Sstevel@tonic-gate /* 1379*7c478bd9Sstevel@tonic-gate * Compare function used by get_tz_countries() - uses strcoll() 1380*7c478bd9Sstevel@tonic-gate * for locale-sensitive comparison for the localized country names. 1381*7c478bd9Sstevel@tonic-gate */ 1382*7c478bd9Sstevel@tonic-gate static int 1383*7c478bd9Sstevel@tonic-gate compar(struct tz_country *p1, struct tz_country *p2) 1384*7c478bd9Sstevel@tonic-gate { 1385*7c478bd9Sstevel@tonic-gate int ret; 1386*7c478bd9Sstevel@tonic-gate 1387*7c478bd9Sstevel@tonic-gate ret = strcoll(p1->ctry_display_desc, p2->ctry_display_desc); 1388*7c478bd9Sstevel@tonic-gate return (ret); 1389*7c478bd9Sstevel@tonic-gate } 1390