tzsetup.c revision 22997
159191Skris/* 259191Skris * Copyright 1996 Massachusetts Institute of Technology 3160814Ssimon * 4160814Ssimon * Permission to use, copy, modify, and distribute this software and 5280304Sjkim * its documentation for any purpose and without fee is hereby 6280304Sjkim * granted, provided that both the above copyright notice and this 7280304Sjkim * permission notice appear in all copies, that both the above 8280304Sjkim * copyright notice and this permission notice appear in all 9160814Ssimon * supporting documentation, and that the name of M.I.T. not be used 10280304Sjkim * in advertising or publicity pertaining to distribution of the 11160814Ssimon * software without specific, written prior permission. M.I.T. makes 12280304Sjkim * no representations about the suitability of this software for any 13280304Sjkim * purpose. It is provided "as is" without express or implied 14280304Sjkim * warranty. 1559191Skris * 1659191Skris * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 1759191Skris * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 18280304Sjkim * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1959191Skris * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 20280304Sjkim * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21280304Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22280304Sjkim * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 23280304Sjkim * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24280304Sjkim * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25280304Sjkim * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26280304Sjkim * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27280304Sjkim * SUCH DAMAGE. 28280304Sjkim * 29280304Sjkim * $Id$ 30280304Sjkim */ 31280304Sjkim 3259191Skris/* 3359191Skris * Second attempt at a `tzmenu' program, using the separate description 3459191Skris * files provided in newer tzdata releases. 35280304Sjkim */ 36280304Sjkim 37280304Sjkim#include <sys/types.h> 38280304Sjkim#include <dialog.h> 39280304Sjkim#include <err.h> 40280304Sjkim#include <errno.h> 41280304Sjkim#include <stdio.h> 42280304Sjkim#include <stdlib.h> 43280304Sjkim#include <string.h> 44280304Sjkim#include <unistd.h> 45280304Sjkim 46280304Sjkim#include <sys/fcntl.h> 47280304Sjkim#include <sys/queue.h> 48280304Sjkim#include <sys/stat.h> 49280304Sjkim 50280304Sjkim#include "paths.h" 51280304Sjkim 52280304Sjkimstatic int reallydoit = 1; 53280304Sjkim 54280304Sjkimstatic int continent_country_menu(dialogMenuItem *); 55280304Sjkimstatic int set_zone_multi(dialogMenuItem *); 56280304Sjkimstatic int set_zone_whole_country(dialogMenuItem *); 57280304Sjkimstatic int set_zone_menu(dialogMenuItem *); 58280304Sjkim 59280304Sjkimstruct continent { 60280304Sjkim dialogMenuItem *menu; 61280304Sjkim int nitems; 62280304Sjkim int ch; 63280304Sjkim int sc; 64280304Sjkim}; 65280304Sjkim 66280304Sjkimstatic struct continent africa, america, antarctica, arctic, asia, atlantic; 67280304Sjkimstatic struct continent australia, europe, indian, pacific; 68280304Sjkim 69280304Sjkimstatic struct continent_names { 70280304Sjkim char *name; 71280304Sjkim struct continent *continent; 72280304Sjkim} continent_names[] = { 73280304Sjkim { "Africa", &africa }, { "America", &america }, 74280304Sjkim { "Antarctica", &antarctica }, { "Arctic", &arctic }, 75280304Sjkim { "Asia", &asia }, 76280304Sjkim { "Atlantic", &atlantic }, { "Australia", &australia }, 77280304Sjkim { "Europe", &europe }, { "Indian", &indian }, { "Pacific", &pacific } 78280304Sjkim}; 79280304Sjkim 80280304Sjkimstatic dialogMenuItem continents[] = { 81280304Sjkim { "1", "Africa", 0, continent_country_menu, 0, &africa }, 82280304Sjkim { "2", "America -- North and South", 0, continent_country_menu, 0, 83280304Sjkim &america }, 84280304Sjkim { "3", "Antarctica", 0, continent_country_menu, 0, &antarctica }, 85280304Sjkim { "4", "Arctic Ocean", 0, continent_country_menu, 0, &arctic }, 86280304Sjkim { "5", "Asia", 0, continent_country_menu, 0, &asia }, 87280304Sjkim { "6", "Atlantic Ocean", 0, continent_country_menu, 0, &atlantic }, 88280304Sjkim { "7", "Australia", 0, continent_country_menu, 0, &australia }, 89280304Sjkim { "8", "Europe", 0, continent_country_menu, 0, &europe }, 90280304Sjkim { "9", "Indian Ocean", 0, continent_country_menu, 0, &indian }, 91280304Sjkim { "0", "Pacific Ocean", 0, continent_country_menu, 0, &pacific } 92280304Sjkim}; 93280304Sjkim#define NCONTINENTS ((sizeof continents)/(sizeof continents[0])) 94280304Sjkim#define OCEANP(x) ((x) == 3 || (x) == 5 || (x) == 8 || (x) == 9) 95280304Sjkim 96280304Sjkimstatic int 97280304Sjkimcontinent_country_menu(dialogMenuItem *continent) 98280304Sjkim{ 9959191Skris int rv; 10059191Skris struct continent *contp = continent->data; 10159191Skris char title[256]; 10259191Skris int isocean = OCEANP(continent - continents); 103280304Sjkim int menulen; 104280304Sjkim 105280304Sjkim /* Short cut -- if there's only one country, don't post a menu. */ 106280304Sjkim if (contp->nitems == 1) { 107280304Sjkim return set_zone_menu(&contp->menu[0]); 108280304Sjkim } 109280304Sjkim 110280304Sjkim /* It's amazing how much good grammar really matters... */ 111280304Sjkim if (!isocean) 112280304Sjkim snprintf(title, sizeof title, "Countries in %s", 113280304Sjkim continent->title); 114280304Sjkim else 115280304Sjkim snprintf(title, sizeof title, "Islands and groups in the %s", 116280304Sjkim continent->title); 117280304Sjkim 118280304Sjkim menulen = contp->nitems < 16 ? contp->nitems : 16; 119280304Sjkim rv = dialog_menu(title, (isocean ? "Select an island or group" 120280304Sjkim : "Select a country"), -1, -1, menulen, 121280304Sjkim -contp->nitems, contp->menu, 0, &contp->ch, 122280304Sjkim &contp->sc); 123280304Sjkim if (rv == 0) 124280304Sjkim return DITEM_LEAVE_MENU; 125280304Sjkim return DITEM_RECREATE; 126280304Sjkim} 127280304Sjkim 128280304Sjkimstatic struct continent * 129280304Sjkimfind_continent(const char *name) 130280304Sjkim{ 131280304Sjkim int i; 132280304Sjkim 133280304Sjkim for (i = 0; i < NCONTINENTS; i++) { 134280304Sjkim if (strcmp(name, continent_names[i].name) == 0) 135280304Sjkim return continent_names[i].continent; 136280304Sjkim } 137280304Sjkim return 0; 138280304Sjkim} 139280304Sjkim 140280304Sjkimstruct country { 141280304Sjkim char *name; 142280304Sjkim char *tlc; 143280304Sjkim int nzones; 144280304Sjkim char *filename; /* use iff nzones < 0 */ 145280304Sjkim struct continent *continent; /* use iff nzones < 0 */ 146280304Sjkim TAILQ_HEAD(, zone) zones; /* use iff nzones > 0 */ 147280304Sjkim dialogMenuItem *submenu; /* use iff nzones > 0 */ 148280304Sjkim}; 149280304Sjkim 150280304Sjkimstruct zone { 151280304Sjkim TAILQ_ENTRY(zone) link; 152280304Sjkim char *descr; 153280304Sjkim char *filename; 154280304Sjkim struct continent *continent; 155280304Sjkim}; 156280304Sjkim 157280304Sjkim/* 158280304Sjkim * This is the easiest organization... we use ISO 3166 country codes, 159280304Sjkim * of the two-letter variety, so we just size this array to suit. 160280304Sjkim * Beats worrying about dynamic allocation. 161280304Sjkim */ 162280304Sjkim#define NCOUNTRIES (26*26) 163280304Sjkimstatic struct country countries[NCOUNTRIES]; 164280304Sjkim#define CODE2INT(s) ((s[0] - 'A') * 26 + (s[1] - 'A')) 165280304Sjkim 166280304Sjkim/* 16759191Skris * Read the ISO 3166 country code database in _PATH_ISO3166 16859191Skris * (/usr/share/misc/iso3166). On error, exit via err(3). 169280304Sjkim */ 17059191Skrisstatic void 17159191Skrisread_iso3166_table(void) 172280304Sjkim{ 173280304Sjkim FILE *fp; 174280304Sjkim char *s, *t, *name; 175280304Sjkim size_t len; 176280304Sjkim int lineno; 177280304Sjkim struct country *cp; 17859191Skris 179280304Sjkim fp = fopen(_PATH_ISO3166, "r"); 18059191Skris if (!fp) 181280304Sjkim err(1, _PATH_ISO3166); 18259191Skris lineno = 0; 183280304Sjkim 18459191Skris while ((s = fgetln(fp, &len)) != 0) { 185280304Sjkim lineno++; 18659191Skris if (s[len - 1] != '\n') 187280304Sjkim errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 188280304Sjkim s[len - 1] = '\0'; 189280304Sjkim if (s[0] == '#') 19059191Skris continue; 191280304Sjkim 19259191Skris /* Isolate the two-letter code. */ 193280304Sjkim t = strsep(&s, "\t"); 19459191Skris if (t == 0 || strlen(t) != 2) 195280304Sjkim errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 19659191Skris if (t[0] < 'A' || t[0] > 'Z' || t[1] < 'A' || t[1] > 'Z') 197280304Sjkim errx(1, _PATH_ISO3166 ":%d: invalid code `%s'", 19859191Skris lineno, t); 199280304Sjkim 20059191Skris /* Now skip past the three-letter and numeric codes. */ 201280304Sjkim name = strsep(&s, "\t"); /* 3-let */ 20259191Skris if (name == 0 || strlen(name) != 3) 203280304Sjkim errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 20459191Skris name = strsep(&s, "\t"); /* numeric */ 205280304Sjkim if (name == 0 || strlen(name) != 3) 20659191Skris errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 207280304Sjkim 20859191Skris name = s; 209280304Sjkim 210280304Sjkim cp = &countries[CODE2INT(t)]; 21159191Skris if (cp->name) 21259191Skris errx(1, _PATH_ISO3166 21359191Skris ":%d: country code `%s' multiply defined: %s", 214280304Sjkim lineno, t, cp->name); 215280304Sjkim cp->name = strdup(name); 216280304Sjkim cp->tlc = strdup(t); 21759191Skris } 218280304Sjkim 21959191Skris fclose(fp); 220280304Sjkim} 22159191Skris 222280304Sjkimstatic void 223280304Sjkimadd_zone_to_country(int lineno, const char *tlc, const char *descr, 224280304Sjkim const char *file, struct continent *cont) 22559191Skris{ 226280304Sjkim struct zone *zp; 22759191Skris struct country *cp; 228280304Sjkim 22959191Skris if (tlc[0] < 'A' || tlc[0] > 'Z' || tlc[1] < 'A' || tlc[1] > 'Z') 230280304Sjkim errx(1, _PATH_ZONETAB ":%d: country code `%s' invalid", 23159191Skris lineno, tlc); 232280304Sjkim 23359191Skris cp = &countries[CODE2INT(tlc)]; 234280304Sjkim if (cp->name == 0) 23559191Skris errx(1, _PATH_ZONETAB ":%d: country code `%s' unknown", 236280304Sjkim lineno, tlc); 23759191Skris 238280304Sjkim if (descr) { 23959191Skris if (cp->nzones < 0) 240280304Sjkim errx(1, _PATH_ZONETAB 24159191Skris ":%d: conflicting zone definition", lineno); 242280304Sjkim 24359191Skris zp = malloc(sizeof *zp); 244280304Sjkim if (zp == 0) 24559191Skris err(1, "malloc(%lu)", (unsigned long)sizeof *zp); 246280304Sjkim 24759191Skris if (cp->nzones == 0) 248280304Sjkim TAILQ_INIT(&cp->zones); 249280304Sjkim 25059191Skris zp->descr = strdup(descr); 251280304Sjkim zp->filename = strdup(file); 25259191Skris zp->continent = cont; 253280304Sjkim TAILQ_INSERT_TAIL(&cp->zones, zp, link); 254280304Sjkim cp->nzones++; 255280304Sjkim } else { 256280304Sjkim if (cp->nzones > 0) 257280304Sjkim errx(1, _PATH_ZONETAB 25859191Skris ":%d: zone must have description", lineno); 25959191Skris if (cp->nzones < 0) 260280304Sjkim errx(1, _PATH_ZONETAB 26159191Skris ":%d: zone multiply defined", lineno); 26259191Skris cp->nzones = -1; 26359191Skris cp->filename = strdup(file); 26459191Skris cp->continent = cont; 26559191Skris } 26659191Skris} 26759191Skris 26859191Skris/* 26959191Skris * This comparison function intentionally sorts all of the null-named 27059191Skris * ``countries''---i.e., the codes that don't correspond to a real 27159191Skris * country---to the end. Everything else is lexical by country name. 272280304Sjkim */ 27359191Skrisstatic int 27459191Skriscompare_countries(const void *xa, const void *xb) 27559191Skris{ 27659191Skris const struct country *a = xa, *b = xb; 27759191Skris 27859191Skris if (a->name == 0 && b->name == 0) 27959191Skris return 0; 28059191Skris if (a->name == 0 && b->name != 0) 28159191Skris return 1; 28259191Skris if (b->name == 0) 28359191Skris return -1; 28459191Skris 285 return strcmp(a->name, b->name); 286} 287 288/* 289 * This must be done AFTER all zone descriptions are read, since it breaks 290 * CODE2INT(). 291 */ 292static void 293sort_countries(void) 294{ 295 qsort(countries, NCOUNTRIES, sizeof countries[0], compare_countries); 296} 297 298static void 299read_zones(void) 300{ 301 FILE *fp; 302 char *line; 303 size_t len; 304 int lineno; 305 char *tlc, *coord, *file, *descr, *p; 306 char contbuf[16]; 307 struct continent *cont; 308 309 fp = fopen(_PATH_ZONETAB, "r"); 310 if (!fp) 311 err(1, _PATH_ZONETAB); 312 lineno = 0; 313 314 while ((line = fgetln(fp, &len)) != 0) { 315 lineno++; 316 if (line[len - 1] != '\n') 317 errx(1, _PATH_ZONETAB ":%d: invalid format", lineno); 318 line[len - 1] = '\0'; 319 if (line[0] == '#') 320 continue; 321 322 tlc = strsep(&line, "\t"); 323 if (strlen(tlc) != 2) 324 errx(1, _PATH_ZONETAB ":%d: invalid country code `%s'", 325 lineno, tlc); 326 coord = strsep(&line, "\t"); 327 file = strsep(&line, "\t"); 328 p = strchr(file, '/'); 329 if (p == 0) 330 errx(1, _PATH_ZONETAB ":%d: invalid zone name `%s'", 331 lineno, file); 332 contbuf[0] = '\0'; 333 strncat(contbuf, file, p - file); 334 cont = find_continent(contbuf); 335 if (!cont) 336 errx(1, _PATH_ZONETAB ":%d: invalid region `%s'", 337 lineno, contbuf); 338 339 descr = (line && *line) ? line : 0; 340 341 add_zone_to_country(lineno, tlc, descr, file, cont); 342 } 343 fclose(fp); 344} 345 346static void 347make_menus(void) 348{ 349 struct country *cp; 350 struct zone *zp, *zp2; 351 struct continent *cont; 352 dialogMenuItem *dmi; 353 int i; 354 355 /* 356 * First, count up all the countries in each continent/ocean. 357 * Be careful to count those countries which have multiple zones 358 * only once for each. NB: some countries are in multiple 359 * continents/oceans. 360 */ 361 for (cp = countries; cp->name; cp++) { 362 if (cp->nzones == 0) 363 continue; 364 if (cp->nzones < 0) { 365 cp->continent->nitems++; 366 } else { 367 for (zp = cp->zones.tqh_first; zp; 368 zp = zp->link.tqe_next) { 369 cont = zp->continent; 370 for (zp2 = cp->zones.tqh_first; 371 zp2->continent != cont; 372 zp2 = zp2->link.tqe_next) 373 ; 374 if (zp2 == zp) 375 zp->continent->nitems++; 376 } 377 } 378 } 379 380 /* 381 * Now allocate memory for the country menus. We set 382 * nitems back to zero so that we can use it for counting 383 * again when we actually build the menus. 384 */ 385 for (i = 0; i < NCONTINENTS; i++) { 386 continent_names[i].continent->menu = 387 malloc(sizeof(dialogMenuItem) * 388 continent_names[i].continent->nitems); 389 if (continent_names[i].continent->menu == 0) 390 err(1, "malloc for continent menu"); 391 continent_names[i].continent->nitems = 0; 392 } 393 394 /* 395 * Now that memory is allocated, create the menu items for 396 * each continent. For multiple-zone countries, also create 397 * the country's zone submenu. 398 */ 399 for (cp = countries; cp->name; cp++) { 400 if (cp->nzones == 0) 401 continue; 402 if (cp->nzones < 0) { 403 dmi = &cp->continent->menu[cp->continent->nitems]; 404 memset(dmi, 0, sizeof *dmi); 405 asprintf(&dmi->prompt, "%d", 406 ++cp->continent->nitems); 407 dmi->title = cp->name; 408 dmi->checked = 0; 409 dmi->fire = set_zone_whole_country; 410 dmi->selected = 0; 411 dmi->data = cp; 412 } else { 413 cp->submenu = malloc(cp->nzones * sizeof *dmi); 414 if (cp->submenu == 0) 415 err(1, "malloc for submenu"); 416 cp->nzones = 0; 417 for (zp = cp->zones.tqh_first; zp; 418 zp = zp->link.tqe_next) { 419 cont = zp->continent; 420 dmi = &cp->submenu[cp->nzones]; 421 memset(dmi, 0, sizeof *dmi); 422 asprintf(&dmi->prompt, "%d", 423 ++cp->nzones); 424 dmi->title = zp->descr; 425 dmi->checked = 0; 426 dmi->fire = set_zone_multi; 427 dmi->selected = 0; 428 dmi->data = zp; 429 430 for (zp2 = cp->zones.tqh_first; 431 zp2->continent != cont; 432 zp2 = zp2->link.tqe_next) 433 ; 434 if (zp2 != zp) 435 continue; 436 437 dmi = &cont->menu[cont->nitems]; 438 memset(dmi, 0, sizeof *dmi); 439 asprintf(&dmi->prompt, "%d", ++cont->nitems); 440 dmi->title = cp->name; 441 dmi->checked = 0; 442 dmi->fire = set_zone_menu; 443 dmi->selected = 0; 444 dmi->data = cp; 445 } 446 } 447 } 448} 449 450static int 451set_zone_menu(dialogMenuItem *dmi) 452{ 453 int rv; 454 char buf[256]; 455 struct country *cp = dmi->data; 456 int menulen; 457 458 snprintf(buf, sizeof buf, "%s Time Zones", cp->name); 459 menulen = cp->nzones < 16 ? cp->nzones : 16; 460 rv = dialog_menu(buf, "Select a zone which observes the same time as " 461 "your locality.", -1, -1, menulen, -cp->nzones, 462 cp->submenu, 0, 0, 0); 463 if (rv != 0) 464 return DITEM_RECREATE; 465 return DITEM_LEAVE_MENU; 466} 467 468static int 469install_zone_file(const char *filename) 470{ 471 struct stat sb; 472 int fd1, fd2; 473 int copymode; 474 char *msg; 475 ssize_t len; 476 char buf[1024]; 477 478 if (lstat(_PATH_LOCALTIME, &sb) < 0) 479 /* Nothing there yet... */ 480 copymode = 1; 481 else if(S_ISLNK(sb.st_mode)) 482 copymode = 0; 483 else 484 copymode = 1; 485 486#ifdef VERBOSE 487 if (copymode) 488 asprintf(&msg, "Copying %s to " _PATH_LOCALTIME, filename); 489 else 490 asprintf(&msg, "Creating symbolic link " _PATH_LOCALTIME 491 " to %s", filename); 492 493 dialog_notify(msg); 494 free(msg); 495#endif 496 497 if (reallydoit) { 498 if (copymode) { 499 fd1 = open(filename, O_RDONLY, 0); 500 if (fd1 < 0) { 501 asprintf(&msg, "Could not open %s: %s", 502 filename, strerror(errno)); 503 dialog_mesgbox("Error", msg, 8, 72); 504 free(msg); 505 return DITEM_FAILURE | DITEM_RECREATE; 506 } 507 508 unlink(_PATH_LOCALTIME); 509 fd2 = open(_PATH_LOCALTIME, 510 O_CREAT | O_EXCL | O_WRONLY, 511 0444); 512 if (fd2 < 0) { 513 asprintf(&msg, "Could not open " 514 _PATH_LOCALTIME ": %s", 515 strerror(errno)); 516 dialog_mesgbox("Error", msg, 8, 72); 517 free(msg); 518 return DITEM_FAILURE | DITEM_RECREATE; 519 } 520 521 while ((len = read(fd1, buf, sizeof buf)) > 0) 522 len = write(fd2, buf, len); 523 524 if (len == -1) { 525 asprintf(&msg, "Error copying %s to " 526 _PATH_LOCALTIME ": %s", 527 strerror(errno)); 528 dialog_mesgbox("Error", msg, 8, 72); 529 free(msg); 530 /* Better to leave none than a corrupt one. */ 531 unlink(_PATH_LOCALTIME); 532 return DITEM_FAILURE | DITEM_RECREATE; 533 } 534 close(fd1); 535 close(fd2); 536 } else { 537 if (access(filename, R_OK) != 0) { 538 asprintf(&msg, "Cannot access %s: %s", 539 filename, strerror(errno)); 540 dialog_mesgbox("Error", msg, 8, 72); 541 free(msg); 542 return DITEM_FAILURE | DITEM_RECREATE; 543 } 544 unlink(_PATH_LOCALTIME); 545 if (symlink(filename, _PATH_LOCALTIME) < 0) { 546 asprintf(&msg, "Cannot create symbolic link " 547 _PATH_LOCALTIME " to %s: %s", 548 filename, strerror(errno)); 549 dialog_mesgbox("Error", msg, 8, 72); 550 free(msg); 551 return DITEM_FAILURE | DITEM_RECREATE; 552 } 553 } 554 } 555 556#ifdef VERBOSE 557 if (copymode) 558 asprintf(&msg, "Copied timezone file from %s to " 559 _PATH_LOCALTIME, filename); 560 else 561 asprintf(&msg, "Created symbolic link from " _PATH_LOCALTIME 562 " to %s", filename); 563 564 dialog_mesgbox("Done", msg, 8, 72); 565 free(msg); 566#endif 567 return DITEM_LEAVE_MENU; 568} 569 570static int 571confirm_zone(const char *filename) 572{ 573 char *msg; 574 struct tm *tm; 575 time_t t = time(0); 576 int rv; 577 578 setenv("TZ", filename, 1); 579 tzset(); 580 tm = localtime(&t); 581 582 asprintf(&msg, "Does the abbreviation `%s' look reasonable?", 583 tm->tm_zone); 584 rv = !dialog_yesno("Confirmation", msg, 4, 72); 585 free(msg); 586 return rv; 587} 588 589static int 590set_zone_multi(dialogMenuItem *dmi) 591{ 592 char *fn; 593 struct zone *zp = dmi->data; 594 int rv; 595 596 if (!confirm_zone(zp->filename)) 597 return DITEM_FAILURE | DITEM_RECREATE; 598 599 asprintf(&fn, "%s/%s", _PATH_ZONEINFO, zp->filename); 600 rv = install_zone_file(fn); 601 free(fn); 602 return rv; 603} 604 605static int 606set_zone_whole_country(dialogMenuItem *dmi) 607{ 608 char *fn; 609 struct country *cp = dmi->data; 610 int rv; 611 612 if (!confirm_zone(cp->filename)) 613 return DITEM_FAILURE | DITEM_RECREATE; 614 615 asprintf(&fn, "%s/%s", _PATH_ZONEINFO, cp->filename); 616 rv = install_zone_file(fn); 617 free(fn); 618 return rv; 619} 620 621int 622main(int argc, char **argv) 623{ 624 int c; 625 626 while ((c = getopt(argc, argv, "n")) != -1) { 627 switch(c) { 628 case 'n': 629 reallydoit = 0; 630 break; 631 632 default: 633 fprintf(stderr, "%s: usage:\n\t%s [-n]\n", argv[0], 634 argv[0]); 635 exit(1); 636 } 637 } 638 639 if (optind != argc) { 640 fprintf(stderr, "%s: usage:\n\t%s [-n]\n", argv[0], argv[0]); 641 exit(1); 642 } 643 644 read_iso3166_table(); 645 read_zones(); 646 sort_countries(); 647 make_menus(); 648 649 init_dialog(); 650 if (!dialog_yesno("Select local or UTC (Greenwich Mean Time) clock", 651 "Is this machine's CMOS clock set to UTC? If it is set to local time,\n" 652 "please choose NO here!", 7, 72)) 653 system("rm -f /etc/wall_cmos_clock"); 654 else 655 system("touch /etc/wall_cmos_clock"); 656 dialog_clear_norefresh(); 657 dialog_menu("Time Zone Selector", "Select a region", -1, -1, 658 NCONTINENTS, -NCONTINENTS, continents, 0, NULL, NULL); 659 dialog_clear(); 660 end_dialog(); 661 return 0; 662} 663 664