#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <tzfile.h>
#include <fcntl.h>
#include <regex.h>
#include <errno.h>
#include <libintl.h>
#include <libzoneinfo.h>
#define DEFINIT "/etc/default/init"
#define ZONEINFOTABDIR "/usr/share/lib/zoneinfo/tab/"
#define CONTINENT_TAB ZONEINFOTABDIR "continent.tab"
#define COUNTRY_TAB ZONEINFOTABDIR "country.tab"
#define ZONE_SUN_TAB ZONEINFOTABDIR "zone_sun.tab"
#define NEWLINE "\n"
#define SLASH "/"
#define WHITESPACE "\t "
#define WHITESPACE_NL "\t \n"
#define DIGITS "0123456789"
#define BUFFLEN 1024
#define CCLEN 2
#define GMT_MAX (12*60*60)
#define GMT_MIN (-13*60*60)
#define GMT_FMT_Q "<GMT%c%d>%c%d"
#define GMT_FMT_Q_LEN (11)
#define GMT0_FMT "GMT0"
#define GMT_FMT_ZONE ":Etc/GMT%c%d"
#define GMT_FMT_ZONE_LEN (11)
#define TZ_FMT "TZ=%s\n"
#define TZ_FMT_Q "TZ=\"%s\"\n"
#define COORD_FMTLEN1 (sizeof ("+DDMM+DDDMM") - 1)
#define COORD_FMTLEN2 (sizeof ("+DDMMSS+DDDMMSS") - 1)
#define COORD_FMT1 (1)
#define COORD_FMT2 (2)
#define COORD_DLEN_LAT (2)
#define COORD_DLEN_LONG (3)
#define COORD_MLEN (2)
#define COORD_SLEN (2)
#define TRAILER "/XXXXXX"
#define TR_LEN (sizeof (TRAILER) -1)
static char *skipwhite(char *);
static int skipline(char *);
static int trav_link(char **);
static void remove_component(char *);
static void strip_quotes(char *, char *);
static int compar(struct tz_country *, struct tz_country *);
static int get_coord(struct tz_timezone *, char *, size_t);
static int _tz_match(const char *, const char *);
static char *_conv_gmt_zoneinfo(int);
static char *_conv_gmt_posix(int);
int
get_tz_continents(struct tz_continent **cont)
{
FILE *fp;
char buff[BUFFLEN];
char *lp;
char *lptr, *ptr;
struct tz_continent *head = NULL, *lcp, *prev = NULL;
int sav_errno = 0, ncount, status;
size_t len;
if ((fp = fopen(CONTINENT_TAB, "r")) == NULL) {
return (-1);
}
ncount = 0;
while (1) {
if (fgets(buff, sizeof (buff), fp) == NULL) {
if (feof(fp) == 0) {
sav_errno = errno;
ncount = -1;
}
break;
}
if ((status = skipline(buff)) != 0) {
if (status == 1)
continue;
else {
sav_errno = EINVAL;
ncount = -1;
break;
}
}
lp = skipwhite(&buff[0]);
if ((len = strcspn(lp, WHITESPACE)) > _TZBUFLEN -1) {
sav_errno = ENAMETOOLONG;
ncount = -1;
break;
}
if ((lcp = (struct tz_continent *)
calloc(1, sizeof (struct tz_continent))) == NULL) {
sav_errno = ENOMEM;
ncount = -1;
break;
}
(void) strncpy(lcp->ctnt_name, lp, len);
lcp->ctnt_name[len] = '\0';
lp = skipwhite(lp + len);
len = strcspn(lp, NEWLINE);
if ((ptr = malloc(len + 1)) == NULL) {
(void) free_tz_continents(lcp);
sav_errno = ENOMEM;
ncount = -1;
break;
}
(void) strncpy(ptr, lp, len);
*(ptr + len) = '\0';
lcp->ctnt_id_desc = ptr;
lptr = dgettext(TEXT_DOMAIN, lcp->ctnt_id_desc);
if ((ptr = strdup(lptr)) == NULL) {
(void) free_tz_continents(lcp);
sav_errno = ENOMEM;
ncount = -1;
break;
}
lcp->ctnt_display_desc = ptr;
if (head == NULL) {
head = lcp;
} else {
prev->ctnt_next = lcp;
}
prev = lcp;
ncount++;
}
(void) fclose(fp);
if (ncount == -1) {
if (head != NULL) {
(void) free_tz_continents(head);
}
if (sav_errno)
errno = sav_errno;
} else {
*cont = head;
}
return (ncount);
}
int
get_tz_countries(struct tz_country **country, struct tz_continent *cont)
{
FILE *fp_zone, *fp_cc;
char buff[BUFFLEN], ccbuf[_CCBUFLEN], *ptr;
char *lp, *lptr, *lp_coord, *lp_cc, *lp_tz;
struct tz_country *head = NULL, *prev = NULL, *next, *cp, *cp2;
int sav_errno = 0, ncount, i;
int cmp, status;
size_t len, len_coord, len_ctnt;
len_ctnt = strlen(cont->ctnt_name);
ccbuf[0] = '\0';
if ((fp_zone = fopen(ZONE_SUN_TAB, "r")) == NULL) {
return (-1);
}
if ((fp_cc = fopen(COUNTRY_TAB, "r")) == NULL) {
(void) fclose(fp_zone);
return (-1);
}
ncount = 0;
while (1) {
if (fgets(buff, sizeof (buff), fp_zone) == NULL) {
if (feof(fp_zone) == 0) {
sav_errno = errno;
ncount = -1;
}
break;
}
if ((status = skipline(buff)) != 0) {
if (status == 1)
continue;
else {
sav_errno = EINVAL;
ncount = -1;
break;
}
}
lp_cc = skipwhite(&buff[0]);
if (strcspn(lp_cc, WHITESPACE) != CCLEN) {
ncount = -1;
sav_errno = EINVAL;
break;
}
if (strncmp(ccbuf, lp_cc, CCLEN) == 0) {
continue;
}
lp_coord = skipwhite(lp_cc + CCLEN);
if (((len_coord = strcspn(lp_coord, WHITESPACE)) !=
COORD_FMTLEN1) &&
(len_coord != COORD_FMTLEN2)) {
ncount = -1;
sav_errno = EINVAL;
break;
}
lp_tz = skipwhite(lp_coord + len_coord);
if ((len = strcspn(lp_tz, SLASH)) == 0) {
ncount = -1;
sav_errno = EINVAL;
break;
}
if ((len == len_ctnt) &&
(strncmp(cont->ctnt_name, lp_tz, len) == 0)) {
if ((cp = (struct tz_country *)
calloc(1, sizeof (struct tz_country))) == NULL) {
sav_errno = ENOMEM;
ncount = -1;
break;
}
(void) strncpy(cp->ctry_code, lp_cc, CCLEN);
cp->ctry_code[CCLEN] = '\0';
(void) strncpy(ccbuf, lp_cc, CCLEN);
ccbuf[CCLEN] = '\0';
if (head == NULL) {
head = cp;
} else {
prev->ctry_next = cp;
};
prev = cp;
ncount++;
}
}
if (ncount == -1)
goto error;
cp = head;
while (1) {
if (fgets(buff, sizeof (buff), fp_cc) == NULL) {
if (feof(fp_cc) == 0) {
ncount = -1;
sav_errno = errno;
}
break;
}
if ((status = skipline(buff)) != 0) {
if (status == 1)
continue;
else {
sav_errno = EINVAL;
ncount = -1;
break;
}
}
if ((len = strcspn(buff, WHITESPACE)) != CCLEN) {
sav_errno = EINVAL;
ncount = -1;
break;
}
if ((cmp = strncmp(cp->ctry_code, buff, CCLEN)) == 0) {
lp = &buff[CCLEN];
if ((len = strspn(lp, WHITESPACE)) == 0) {
sav_errno = EINVAL;
ncount = -1;
break;
}
lp += len;
len = strcspn(lp, NEWLINE);
if ((ptr = calloc(len + 1, 1)) == NULL) {
ncount = -1;
errno = ENOMEM;
break;
}
(void) strncpy(ptr, lp, len);
*(ptr + len) = '\0';
cp->ctry_id_desc = ptr;
lptr = dgettext(TEXT_DOMAIN, ptr);
if ((ptr = strdup(lptr)) == NULL) {
ncount = -1;
errno = ENOMEM;
break;
}
cp->ctry_display_desc = ptr;
} else if (cmp > 0) {
continue;
} else {
ncount = -1;
errno = EILSEQ;
break;
}
if (cp->ctry_next == NULL) {
break;
} else {
cp = cp->ctry_next;
}
}
if ((ncount != -1) &&
((cp2 = calloc(ncount, sizeof (struct tz_country))) != NULL)) {
cp = head;
for (i = 0; i < ncount; i++) {
next = cp->ctry_next;
cp->ctry_next = cp;
(void) memcpy(&cp2[i], cp, sizeof (struct tz_country));
cp = next;
}
qsort(cp2, ncount, sizeof (struct tz_country),
(int (*)(const void *, const void *))compar);
head = cp2->ctry_next;
cp = head;
for (i = 0; i < ncount; i++) {
prev = cp;
cp = cp2[i].ctry_next;
prev->ctry_next = cp;
}
cp->ctry_next = NULL;
free(cp2);
} else {
if (ncount != -1)
ncount = -1;
}
error:
(void) fclose(fp_zone);
(void) fclose(fp_cc);
if (ncount == -1) {
if (head != NULL)
(void) free_tz_countries(head);
if (sav_errno)
errno = sav_errno;
} else {
*country = head;
}
return (ncount);
}
int
get_timezones_by_country(struct tz_timezone **tmzone,
struct tz_country *country)
{
FILE *fp_zone;
int match = 0, ncount = 0, sav_errno = 0, status;
char buff[1024];
char *lp_cc, *lp_tz, *lp_otz, *lp_coord, *lp_tzdesc, *ptr, *lptr;
size_t len_tz, len_otz, len_coord, len_tzdesc;
struct tz_timezone *head = NULL, *prev = NULL, *tp;
if ((fp_zone = fopen(ZONE_SUN_TAB, "r")) == NULL)
return (-1);
while (1) {
if (fgets(buff, sizeof (buff), fp_zone) == NULL) {
if (feof(fp_zone)) {
break;
} else {
ncount = -1;
sav_errno = errno;
break;
}
}
if ((status = skipline(buff)) != 0) {
if (status == 1)
continue;
else {
sav_errno = EINVAL;
ncount = -1;
break;
}
}
lp_cc = skipwhite(&buff[0]);
if (strcspn(lp_cc, WHITESPACE) != CCLEN) {
sav_errno = EINVAL;
ncount = -1;
break;
}
if (strncmp(country->ctry_code, lp_cc, CCLEN) == 0) {
match = 1;
lp_coord = skipwhite(lp_cc + CCLEN);
if (((len_coord = strcspn(lp_coord, WHITESPACE)) !=
COORD_FMTLEN1) &&
(len_coord != COORD_FMTLEN2)) {
ncount = -1;
sav_errno = EINVAL;
break;
}
lp_otz = skipwhite(lp_coord + len_coord);
len_otz = strcspn(lp_otz, WHITESPACE);
lp_tz = skipwhite(lp_otz + len_otz);
len_tz = strcspn(lp_tz, WHITESPACE_NL);
if (*(lp_tz + len_tz - 1) == '\n') {
len_tz--;
lp_tzdesc = NULL;
len_tzdesc = 0;
} else {
lp_tzdesc = skipwhite(lp_tz +
len_tz);
len_tzdesc = strcspn(lp_tzdesc,
NEWLINE);
}
if ((len_otz > _TZBUFLEN - 1) ||
(len_tz > _TZBUFLEN - 1)) {
sav_errno = ENAMETOOLONG;
ncount = -1;
break;
}
if ((tp = (struct tz_timezone *)
calloc(1, sizeof (struct tz_timezone))) ==
NULL) {
sav_errno = ENOMEM;
ncount = -1;
break;
}
(void) strncpy(tp->tz_oname, lp_otz, len_otz);
tp->tz_oname[len_otz] = '\0';
if (strncmp("-", lp_tz, len_tz) == 0) {
lp_tz = lp_otz;
len_tz = len_otz;
}
if (strcspn(lp_tz, DIGITS) < len_tz) {
if (len_tz > _TZBUFLEN - 2) {
free(tp);
sav_errno = ENAMETOOLONG;
ncount = -1;
break;
}
tp->tz_name[0] = ':';
(void) strncpy(tp->tz_name + 1, lp_tz, len_tz);
tp->tz_name[len_tz + 1] = '\0';
} else {
(void) strncpy(tp->tz_name, lp_tz, len_tz);
tp->tz_name[len_tz] = '\0';
}
if ((lp_tzdesc != NULL) && (*lp_tzdesc != '\n')) {
if ((ptr = calloc(1, len_tzdesc + 1))
== NULL) {
sav_errno = ENOMEM;
ncount = -1;
(void) free_timezones(tp);
break;
}
(void) strncpy(ptr, lp_tzdesc, len_tzdesc);
*(ptr + len_tzdesc) = '\0';
tp->tz_id_desc = ptr;
lptr = dgettext(TEXT_DOMAIN, ptr);
if ((ptr = strdup(lptr)) == NULL) {
sav_errno = ENOMEM;
ncount = -1;
(void) free_timezones(tp);
break;
}
tp->tz_display_desc = ptr;
} else {
tp->tz_id_desc = NULL;
tp->tz_display_desc = NULL;
}
if (get_coord(tp, lp_coord, len_coord) == -1) {
sav_errno = EILSEQ;
ncount = -1;
(void) free_timezones(tp);
break;
}
if (head == NULL) {
head = tp;
} else {
prev->tz_next = tp;
}
prev = tp;
ncount++;
} else {
if (match == 1) {
break;
}
}
}
(void) fclose(fp_zone);
if (ncount == -1) {
if (head != NULL)
(void) free_timezones(head);
if (sav_errno)
errno = sav_errno;
} else {
*tmzone = head;
}
return (ncount);
}
int
free_tz_continents(struct tz_continent *cont)
{
struct tz_continent *cptr, *cprev;
cptr = cont;
while (cptr != NULL) {
if (cptr->ctnt_id_desc != NULL)
free(cptr->ctnt_id_desc);
if (cptr->ctnt_display_desc != NULL)
free(cptr->ctnt_display_desc);
cprev = cptr;
cptr = cptr->ctnt_next;
free(cprev);
}
return (0);
}
int
free_tz_countries(struct tz_country *country)
{
struct tz_country *cptr, *cprev;
cptr = country;
while (cptr != NULL) {
if (cptr->ctry_id_desc != NULL)
free(cptr->ctry_id_desc);
if (cptr->ctry_display_desc != NULL)
free(cptr->ctry_display_desc);
cprev = cptr;
cptr = cptr->ctry_next;
free(cprev);
}
return (0);
}
int
free_timezones(struct tz_timezone *timezone)
{
struct tz_timezone *tzptr, *tzprev;
tzptr = timezone;
while (tzptr != NULL) {
if (tzptr->tz_id_desc != NULL)
free(tzptr->tz_id_desc);
if (tzptr->tz_display_desc != NULL)
free(tzptr->tz_display_desc);
tzprev = tzptr;
tzptr = tzptr->tz_next;
free(tzprev);
}
return (0);
}
char *
conv_gmt(int seconds, int flag)
{
int hour;
char *cp;
if ((seconds < _GMT_MIN) || (seconds > _GMT_MAX)) {
errno = EINVAL;
return (NULL);
}
hour = (seconds / 60) / 60;
if (flag == 0) {
cp = _conv_gmt_posix(hour);
} else if (flag == 1) {
cp = _conv_gmt_zoneinfo(hour);
} else {
errno = EINVAL;
return (NULL);
}
return (cp);
}
static char *
_conv_gmt_posix(int hour)
{
char *cp;
char xsign;
if (hour == 0) {
if ((cp = strdup(GMT0_FMT)) == NULL) {
errno = ENOMEM;
return (NULL);
}
} else {
if (hour < 0) {
xsign = '-';
hour = -hour;
} else {
xsign = '+';
}
if ((cp = malloc(GMT_FMT_Q_LEN + 1)) == NULL) {
errno = ENOMEM;
return (NULL);
}
(void) snprintf(cp, GMT_FMT_Q_LEN + 1, GMT_FMT_Q,
xsign, hour, xsign, hour);
}
return (cp);
}
static char *
_conv_gmt_zoneinfo(int hour)
{
char *cp;
char xsign;
if (hour < 0) {
xsign = '-';
hour = -hour;
} else {
xsign = '+';
}
if ((cp = malloc(GMT_FMT_ZONE_LEN + 1)) == NULL) {
errno = ENOMEM;
return (NULL);
}
(void) snprintf(cp, GMT_FMT_ZONE_LEN + 1, GMT_FMT_ZONE,
xsign, hour);
return (cp);
}
#define _GMT_EXPR "(" _GMT_EXPR_U "|" _GMT_EXPR_Q ")"
#define _GMT_EXPR_U "^[gG][mM][tT][-+]?[0-2]?[0-9]$"
#define _GMT_EXPR_Q "^<[gG][mM][tT][-+]?[0-2]?[0-9]>[-+]?[0-2]?[0-9]$"
#define _ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define _NUM "0123456789"
#define _STD_Q_ELM "[-+" _ALPHA _NUM "]"
#define _STD_Q "<" _STD_Q_ELM _STD_Q_ELM _STD_Q_ELM "+>"
#define _STD_U_ELM_1 "[^-+,<" _NUM "]"
#define _STD_U_ELM "[^-+," _NUM "]"
#define _STD_U _STD_U_ELM_1 _STD_U_ELM _STD_U_ELM "+"
#define _STD "(" _STD_U "|" _STD_Q ")"
#define _DST _STD
#define _OFFSET "[-+]?" _TIME
#define _START "(" _DATEJ "|" _DATEn "|" _DATEM ")"
#define _DATEJ "J(([0-2]?[0-9]?[0-9])|3[0-5][0-9]|36[0-5])"
#define _DATEn "(([0-2]?[0-9]?[0-9])|3[0-5][0-9]|36[0-5])"
#define _DATEM "M([0-9]|10|11|12)\\.[1-5]\\.[0-6]"
#define _END _START
#define _TIME _HH "(:" _MM "(:" _SS ")?" ")?"
#define _HH "(([0-1]?[0-9])|20|21|22|23|24)"
#define _MM "[0-5]?[0-9]"
#define _SS _MM
#define _POSIX_EXPR "^" _STD _OFFSET "(" _DST "(" _OFFSET ")?" \
"(," _START "(/" _TIME ")?" \
"," _END "(/" _TIME ")?" ")?" ")?" "$"
#define LEN_TZDIR (sizeof (TZDIR) - 1)
int
isvalid_tz(char *timezone, char *root, int flag)
{
char path[MAXPATHLEN];
char buf[sizeof (struct tzhead)];
int fid, ret;
if ((timezone == NULL) || (*timezone == '\0')) {
return (0);
}
switch (flag) {
case _VTZ_INSTALL:
if (_tz_match(_GMT_EXPR, timezone) == 0) {
return (1);
}
break;
case _VTZ_POSIX:
if (_tz_match(_POSIX_EXPR, timezone) == 0) {
return (1);
}
return (0);
case _VTZ_ALL:
if (_tz_match(_POSIX_EXPR, timezone) == 0) {
return (1);
}
break;
case _VTZ_ZONEINFO:
break;
default:
return (0);
}
if (*timezone == ':') {
timezone++;
}
if ((root != NULL) && (*root != '\0')) {
ret = snprintf(path, sizeof (path),
"%s%s/%s", root, TZDIR, timezone);
if (ret >= sizeof (path)) {
return (0);
}
} else {
ret = snprintf(path, sizeof (path),
"%s/%s", TZDIR, timezone);
if (ret >= sizeof (path)) {
return (0);
}
}
if ((fid = open(path, O_RDONLY)) == -1) {
return (0);
}
if (read(fid, buf, sizeof (struct tzhead)) !=
sizeof (struct tzhead)) {
(void) close(fid);
return (0);
}
if (strncmp(buf, TZ_MAGIC, sizeof (TZ_MAGIC) - 1) != 0) {
(void) close(fid);
return (0);
}
if (close(fid) == -1) {
return (0);
}
return (1);
}
#define N_MATCH 1
int
_tz_match(const char *expr, const char *string)
{
regex_t reg;
regmatch_t pmatch[N_MATCH];
int ret;
ret = regcomp(®, expr, REG_EXTENDED);
if (ret != 0) {
return (-1);
}
ret = regexec((const regex_t *)®, string, N_MATCH, pmatch, 0);
if (ret == 0) {
#ifdef DEBUG
printf("OK matched - %s\n", string);
#endif
regfree(®);
return (0);
}
#ifdef DEBUG
printf("NOT matched - %s\n", string);
#endif
regfree(®);
return (-1);
}
char *
get_system_tz(char *root)
{
FILE *ifp;
char buff[512];
int serrno, ret;
char *sp, *ptr, *p;
char fname[MAXPATHLEN];
if ((ret = snprintf(fname, sizeof (fname), "%s/%s", root, DEFINIT)) >=
sizeof (fname)) {
errno = ENAMETOOLONG;
return (NULL);
} else if (ret < 0) {
return (NULL);
}
if ((ifp = fopen(fname, "r")) == NULL)
return (NULL);
while (fgets(buff, sizeof (buff), ifp) != NULL) {
if (strncmp(buff, "TZ=", 3) == 0) {
(void) fclose(ifp);
p = &buff[3];
if ((sp = strchr(p, ';')) != NULL) {
*sp = '\0';
} else if ((sp = strchr(p, '\n')) != NULL) {
*sp = '\0';
}
if (strpbrk(p, "\"'") != NULL) {
strip_quotes(p, p);
}
ptr = strdup(p);
if (ptr == NULL) {
errno = ENOMEM;
return (NULL);
}
return (ptr);
}
}
serrno = errno;
if (feof(ifp) != 0) {
serrno = EINVAL;
}
(void) fclose(ifp);
errno = serrno;
return (NULL);
}
int
set_system_tz(char *tz, char *root)
{
FILE *ifp, *ofp;
char *tmpdir, *tmp;
char buff[1024];
int replaced = 0, ret, serrno;
char *tdb;
struct stat sb;
char fname[MAXPATHLEN];
const char *tzfmt;
int len, fd;
if (tz == NULL || root == NULL)
return (-1);
if (strchr(tz, '<')) {
tzfmt = TZ_FMT_Q;
} else {
tzfmt = TZ_FMT;
}
if ((ret = snprintf(fname, sizeof (fname), "%s/%s", root, DEFINIT)) >=
sizeof (fname)) {
errno = ENAMETOOLONG;
return (-1);
} else if (ret < 0) {
return (-1);
}
tdb = fname;
if (trav_link(&tdb) == -1)
return (-1);
if ((tmpdir = strdup(tdb)) == NULL) {
errno = ENOMEM;
return (-1);
}
remove_component(tmpdir);
if ((len = strlen(tmpdir)) == 0) {
(void) strcpy(tmpdir, ".");
len = 1;
}
if ((tmp = malloc(len + TR_LEN + 1)) == NULL) {
free(tmpdir);
errno = ENOMEM;
return (-1);
}
(void) strcpy(tmp, tmpdir);
(void) strcpy(tmp + len, TRAILER);
free(tmpdir);
if ((fd = mkstemp(tmp)) == -1) {
free(tmp);
return (-1);
}
if ((ofp = fdopen(fd, "w")) == NULL) {
serrno = errno;
(void) close(fd);
free(tmp);
errno = serrno;
return (-1);
}
if (stat(tdb, &sb) == 0) {
if (fchmod(fileno(ofp), sb.st_mode) == -1) {
serrno = errno;
(void) fclose(ofp);
(void) unlink(tmp);
free(tmp);
errno = serrno;
return (-1);
}
if (fchown(fileno(ofp), sb.st_uid, sb.st_gid) == -1) {
serrno = errno;
(void) fclose(ofp);
(void) unlink(tmp);
free(tmp);
errno = serrno;
return (-1);
}
} else if (errno != ENOENT) {
serrno = errno;
(void) fclose(ofp);
(void) unlink(tmp);
free(tmp);
errno = serrno;
return (-1);
}
if ((ifp = fopen(fname, "r+")) != NULL) {
while (fgets(buff, sizeof (buff), ifp) != NULL) {
if (!replaced && (strncmp(buff, "TZ=", 3) == 0)) {
ret = snprintf(buff, sizeof (buff), tzfmt,
tz);
if ((ret >= sizeof (buff)) || (ret < 0)) {
if (ret >= sizeof (buff))
serrno = EINVAL;
(void) fclose(ofp);
(void) fclose(ifp);
(void) unlink(tmp);
free(tmp);
errno = serrno;
return (-1);
}
replaced = 1;
}
if (fputs(buff, ofp) == EOF) {
serrno = errno;
(void) fclose(ofp);
(void) fclose(ifp);
(void) unlink(tmp);
free(tmp);
errno = serrno;
return (-1);
}
}
(void) fclose(ifp);
} else if (errno != ENOENT) {
serrno = errno;
(void) fclose(ofp);
(void) unlink(tmp);
free(tmp);
errno = serrno;
return (-1);
}
if (!replaced &&
(fprintf(ofp, tzfmt, tz) == EOF)) {
serrno = errno;
(void) fclose(ofp);
(void) unlink(tmp);
free(tmp);
errno = serrno;
return (-1);
}
if (fsync(fileno(ofp))) {
serrno = errno;
(void) unlink(tmp);
free(tmp);
errno = serrno;
return (-1);
}
(void) fclose(ofp);
if (rename(tmp, tdb) != 0) {
serrno = errno;
(void) unlink(tmp);
free(tmp);
errno = serrno;
return (-1);
} else {
free(tmp);
return (0);
}
}
int
trav_link(char **path)
{
static char newpath[MAXPATHLEN];
char lastpath[MAXPATHLEN];
int len, ret;
char *tp;
(void) strcpy(lastpath, *path);
while ((len = readlink(*path, newpath, sizeof (newpath))) != -1) {
newpath[len] = '\0';
if (newpath[0] != '/') {
if ((tp = strdup(newpath)) == NULL) {
errno = ENOMEM;
return (-1);
}
remove_component(lastpath);
ret = snprintf(newpath, sizeof (newpath),
"%s/%s", lastpath, tp);
free(tp);
if ((ret >= sizeof (newpath)) || (ret < 0))
return (-1);
}
(void) strcpy(lastpath, newpath);
*path = newpath;
}
if ((errno == ENOENT) || (errno == EINVAL))
return (0);
else
return (-1);
}
void
remove_component(char *path)
{
char *p;
p = strrchr(path, '/');
if (p == NULL) {
*path = '\0';
} else {
*p = '\0';
}
}
static int
get_coord(struct tz_timezone *tp, char *p_coord, size_t len_coord)
{
int i, fmt_flag, nchar;
int *signp, *degp, *minp, *secp;
struct tz_coord *tcp;
char buff[512], *endp;
tcp = &(tp->tz_coord);
if (len_coord == COORD_FMTLEN1) {
fmt_flag = COORD_FMT1;
} else if (len_coord == COORD_FMTLEN2) {
fmt_flag = COORD_FMT2;
} else {
return (-1);
}
for (i = 0; i < 2; i++) {
if (i == 0) {
nchar = COORD_DLEN_LAT;
signp = (int *)&(tcp->lat_sign);
degp = (int *)&(tcp->lat_degree);
minp = (int *)&(tcp->lat_minute);
secp = (int *)&(tcp->lat_second);
} else {
nchar = COORD_DLEN_LONG;
signp = (int *)&(tcp->long_sign);
degp = (int *)&tcp->long_degree;
minp = (int *)&tcp->long_minute;
secp = (int *)&tcp->long_second;
}
if (*p_coord == '+') {
*signp = 1;
} else if (*p_coord == '-') {
*signp = -1;
} else {
return (-1);
}
p_coord++;
(void) strncpy(buff, p_coord, nchar);
buff[nchar] = '\0';
errno = 0;
*degp = (int)strtol(buff, &endp, 10);
if ((endp != &buff[nchar]) || ((*degp == 0) && (errno != 0)))
return (-1);
p_coord += nchar;
(void) strncpy(buff, p_coord, COORD_MLEN);
buff[COORD_MLEN] = '\0';
errno = 0;
*minp = (int)strtol(buff, &endp, 10);
if ((endp != &buff[COORD_MLEN]) ||
((*degp == 0) && (errno != 0)))
return (-1);
p_coord += COORD_MLEN;
if (fmt_flag == COORD_FMT2) {
(void) strncpy(buff, p_coord, COORD_SLEN);
buff[COORD_SLEN] = '\0';
errno = 0;
*secp = (int)strtol(buff, &endp, 10);
if ((endp != &buff[COORD_SLEN]) ||
((*degp == 0) && (errno != 0)))
return (-1);
p_coord += COORD_SLEN;
} else {
*secp = 0;
}
}
return (0);
}
static char *
skipwhite(char *cp)
{
while (*cp && ((*cp == ' ') || (*cp == '\t'))) {
cp++;
}
return (cp);
}
static int
skipline(char *line)
{
size_t len;
len = strlen(line);
if (line[len - 1] != '\n')
return (-1);
if (line[0] == '#' || line[0] == '\0' ||
(len = strspn(line, " \t\n")) == strlen(line) ||
strchr(line, '#') == line + len)
return (1);
else
return (0);
}
static void
strip_quotes(char *from, char *to)
{
char *strip_ptr = NULL;
while (*from != '\0') {
if ((*from == '"') || (*from == '\'')) {
if (strip_ptr == NULL)
strip_ptr = to;
} else {
if (strip_ptr != NULL) {
*strip_ptr = *from;
strip_ptr++;
} else {
*to = *from;
to++;
}
}
from++;
}
if (strip_ptr != NULL) {
*strip_ptr = '\0';
} else {
*to = '\0';
}
}
static int
compar(struct tz_country *p1, struct tz_country *p2)
{
int ret;
ret = strcoll(p1->ctry_display_desc, p2->ctry_display_desc);
return (ret);
}