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