tzsetup.c revision 30999
1141240Snjl/* 2167905Snjl * Copyright 1996 Massachusetts Institute of Technology 3141240Snjl * 4141240Snjl * Permission to use, copy, modify, and distribute this software and 5141240Snjl * its documentation for any purpose and without fee is hereby 6141240Snjl * granted, provided that both the above copyright notice and this 7141240Snjl * permission notice appear in all copies, that both the above 8141240Snjl * copyright notice and this permission notice appear in all 9141240Snjl * supporting documentation, and that the name of M.I.T. not be used 10141240Snjl * in advertising or publicity pertaining to distribution of the 11141240Snjl * software without specific, written prior permission. M.I.T. makes 12141240Snjl * no representations about the suitability of this software for any 13141240Snjl * purpose. It is provided "as is" without express or implied 14141240Snjl * warranty. 15141240Snjl * 16141240Snjl * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 17141240Snjl * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 18141240Snjl * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19141240Snjl * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 20141240Snjl * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21141240Snjl * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22141240Snjl * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 23141240Snjl * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24141240Snjl * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25141240Snjl * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26141240Snjl * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27141240Snjl * SUCH DAMAGE. 28141240Snjl */ 29141240Snjl 30141240Snjl/* 31141240Snjl * Second attempt at a `tzmenu' program, using the separate description 32141240Snjl * files provided in newer tzdata releases. 33141240Snjl */ 34141240Snjl 35142603Snjl#ifndef lint 36141240Snjlstatic const char rcsid[] = 37141240Snjl "$Id: tzsetup.c,v 1.8 1997/10/27 07:49:47 charnier Exp $"; 38141240Snjl#endif /* not lint */ 39141240Snjl 40173204Snjl#include <sys/types.h> 41141240Snjl#include <dialog.h> 42173204Snjl#include <err.h> 43141240Snjl#include <errno.h> 44141240Snjl#include <stdio.h> 45142603Snjl#include <stdlib.h> 46141814Snjl#include <string.h> 47167905Snjl#include <unistd.h> 48141240Snjl 49141240Snjl#include <sys/fcntl.h> 50141240Snjl#include <sys/queue.h> 51141240Snjl#include <sys/stat.h> 52141240Snjl 53141240Snjl#include "paths.h" 54141240Snjl 55141240Snjlstatic int reallydoit = 1; 56141240Snjl 57141240Snjlstatic int continent_country_menu(dialogMenuItem *); 58142395Snjlstatic int set_zone_multi(dialogMenuItem *); 59141240Snjlstatic int set_zone_whole_country(dialogMenuItem *); 60142395Snjlstatic int set_zone_menu(dialogMenuItem *); 61141240Snjl 62150847Sumestruct continent { 63150847Sume dialogMenuItem *menu; 64150847Sume int nitems; 65150847Sume int ch; 66150847Sume int sc; 67150847Sume}; 68141240Snjl 69142603Snjlstatic struct continent africa, america, antarctica, arctic, asia, atlantic; 70141240Snjlstatic struct continent australia, europe, indian, pacific; 71141923Snjl 72150847Sumestatic struct continent_names { 73141923Snjl char *name; 74141413Snjl struct continent *continent; 75141945Snjl} continent_names[] = { 76141240Snjl { "Africa", &africa }, { "America", &america }, 77141240Snjl { "Antarctica", &antarctica }, { "Arctic", &arctic }, 78167905Snjl { "Asia", &asia }, 79141240Snjl { "Atlantic", &atlantic }, { "Australia", &australia }, 80141240Snjl { "Europe", &europe }, { "Indian", &indian }, { "Pacific", &pacific } 81141240Snjl}; 82141240Snjl 83141240Snjlstatic dialogMenuItem continents[] = { 84141240Snjl { "1", "Africa", 0, continent_country_menu, 0, &africa }, 85141240Snjl { "2", "America -- North and South", 0, continent_country_menu, 0, 86141240Snjl &america }, 87141240Snjl { "3", "Antarctica", 0, continent_country_menu, 0, &antarctica }, 88141240Snjl { "4", "Arctic Ocean", 0, continent_country_menu, 0, &arctic }, 89142603Snjl { "5", "Asia", 0, continent_country_menu, 0, &asia }, 90142603Snjl { "6", "Atlantic Ocean", 0, continent_country_menu, 0, &atlantic }, 91142603Snjl { "7", "Australia", 0, continent_country_menu, 0, &australia }, 92142603Snjl { "8", "Europe", 0, continent_country_menu, 0, &europe }, 93142603Snjl { "9", "Indian Ocean", 0, continent_country_menu, 0, &indian }, 94144876Snjl { "0", "Pacific Ocean", 0, continent_country_menu, 0, &pacific } 95144876Snjl}; 96144876Snjl#define NCONTINENTS ((sizeof continents)/(sizeof continents[0])) 97144876Snjl#define OCEANP(x) ((x) == 3 || (x) == 5 || (x) == 8 || (x) == 9) 98144876Snjl 99141240Snjlstatic int 100167905Snjlcontinent_country_menu(dialogMenuItem *continent) 101141240Snjl{ 102141240Snjl int rv; 103141240Snjl struct continent *contp = continent->data; 104141240Snjl char title[256]; 105141240Snjl int isocean = OCEANP(continent - continents); 106141240Snjl int menulen; 107141413Snjl 108141240Snjl /* Short cut -- if there's only one country, don't post a menu. */ 109141413Snjl if (contp->nitems == 1) { 110141413Snjl return set_zone_menu(&contp->menu[0]); 111141413Snjl } 112141413Snjl 113141240Snjl /* It's amazing how much good grammar really matters... */ 114141240Snjl if (!isocean) 115142114Snjl snprintf(title, sizeof title, "Countries in %s", 116141240Snjl continent->title); 117141240Snjl else 118141240Snjl snprintf(title, sizeof title, "Islands and groups in the %s", 119141240Snjl continent->title); 120141240Snjl 121141240Snjl menulen = contp->nitems < 16 ? contp->nitems : 16; 122141240Snjl rv = dialog_menu(title, (isocean ? "Select an island or group" 123141240Snjl : "Select a country"), -1, -1, menulen, 124141240Snjl -contp->nitems, contp->menu, 0, &contp->ch, 125141240Snjl &contp->sc); 126141240Snjl if (rv == 0) 127141240Snjl return DITEM_LEAVE_MENU; 128141240Snjl return DITEM_RECREATE; 129141240Snjl} 130141240Snjl 131141240Snjlstatic struct continent * 132141240Snjlfind_continent(const char *name) 133142590Snjl{ 134144876Snjl int i; 135142590Snjl 136144876Snjl for (i = 0; i < NCONTINENTS; i++) { 137142590Snjl if (strcmp(name, continent_names[i].name) == 0) 138142590Snjl return continent_names[i].continent; 139142590Snjl } 140144876Snjl return 0; 141144876Snjl} 142142590Snjl 143141240Snjlstruct country { 144141240Snjl char *name; 145141240Snjl char *tlc; 146141240Snjl int nzones; 147141240Snjl char *filename; /* use iff nzones < 0 */ 148141240Snjl struct continent *continent; /* use iff nzones < 0 */ 149141240Snjl TAILQ_HEAD(, zone) zones; /* use iff nzones > 0 */ 150144876Snjl dialogMenuItem *submenu; /* use iff nzones > 0 */ 151141240Snjl}; 152141240Snjl 153141240Snjlstruct zone { 154141240Snjl TAILQ_ENTRY(zone) link; 155141240Snjl char *descr; 156142603Snjl char *filename; 157141240Snjl struct continent *continent; 158150847Sume}; 159141945Snjl 160141240Snjl/* 161141240Snjl * This is the easiest organization... we use ISO 3166 country codes, 162141240Snjl * of the two-letter variety, so we just size this array to suit. 163141240Snjl * Beats worrying about dynamic allocation. 164141240Snjl */ 165141240Snjl#define NCOUNTRIES (26*26) 166141240Snjlstatic struct country countries[NCOUNTRIES]; 167141240Snjl#define CODE2INT(s) ((s[0] - 'A') * 26 + (s[1] - 'A')) 168141240Snjl 169141240Snjl/* 170144876Snjl * Read the ISO 3166 country code database in _PATH_ISO3166 171144876Snjl * (/usr/share/misc/iso3166). On error, exit via err(3). 172141240Snjl */ 173141240Snjlstatic void 174141240Snjlread_iso3166_table(void) 175141240Snjl{ 176141240Snjl FILE *fp; 177141240Snjl char *s, *t, *name; 178141240Snjl size_t len; 179141240Snjl int lineno; 180141240Snjl struct country *cp; 181167905Snjl 182167905Snjl fp = fopen(_PATH_ISO3166, "r"); 183167905Snjl if (!fp) 184167905Snjl err(1, _PATH_ISO3166); 185167905Snjl lineno = 0; 186167905Snjl 187167905Snjl while ((s = fgetln(fp, &len)) != 0) { 188141240Snjl lineno++; 189141240Snjl if (s[len - 1] != '\n') 190141240Snjl errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 191167905Snjl s[len - 1] = '\0'; 192167905Snjl if (s[0] == '#' || strspn(s, " \t") == len - 1) 193167905Snjl continue; 194167905Snjl 195167905Snjl /* Isolate the two-letter code. */ 196167905Snjl t = strsep(&s, "\t"); 197167905Snjl if (t == 0 || strlen(t) != 2) 198167905Snjl errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 199141240Snjl if (t[0] < 'A' || t[0] > 'Z' || t[1] < 'A' || t[1] > 'Z') 200141240Snjl errx(1, _PATH_ISO3166 ":%d: invalid code `%s'", 201141240Snjl lineno, t); 202141240Snjl 203150847Sume /* Now skip past the three-letter and numeric codes. */ 204141240Snjl name = strsep(&s, "\t"); /* 3-let */ 205141240Snjl if (name == 0 || strlen(name) != 3) 206144876Snjl errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 207141240Snjl name = strsep(&s, "\t"); /* numeric */ 208141240Snjl if (name == 0 || strlen(name) != 3) 209141240Snjl errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 210150847Sume 211150847Sume name = s; 212150847Sume 213150847Sume cp = &countries[CODE2INT(t)]; 214150847Sume if (cp->name) 215141240Snjl errx(1, _PATH_ISO3166 216141240Snjl ":%d: country code `%s' multiply defined: %s", 217144876Snjl lineno, t, cp->name); 218144876Snjl cp->name = strdup(name); 219144876Snjl cp->tlc = strdup(t); 220141240Snjl } 221141240Snjl 222141240Snjl fclose(fp); 223141240Snjl} 224141240Snjl 225141240Snjlstatic void 226141240Snjladd_zone_to_country(int lineno, const char *tlc, const char *descr, 227141240Snjl const char *file, struct continent *cont) 228141240Snjl{ 229150847Sume struct zone *zp; 230141814Snjl struct country *cp; 231171898Snjl 232141240Snjl if (tlc[0] < 'A' || tlc[0] > 'Z' || tlc[1] < 'A' || tlc[1] > 'Z') 233141240Snjl errx(1, _PATH_ZONETAB ":%d: country code `%s' invalid", 234142603Snjl lineno, tlc); 235142603Snjl 236150847Sume cp = &countries[CODE2INT(tlc)]; 237141240Snjl if (cp->name == 0) 238167905Snjl errx(1, _PATH_ZONETAB ":%d: country code `%s' unknown", 239167905Snjl lineno, tlc); 240167905Snjl 241167905Snjl if (descr) { 242167905Snjl if (cp->nzones < 0) 243156228Smnag errx(1, _PATH_ZONETAB 244141814Snjl ":%d: conflicting zone definition", lineno); 245150847Sume 246150847Sume zp = malloc(sizeof *zp); 247173204Snjl if (zp == 0) 248141923Snjl err(1, "malloc(%lu)", (unsigned long)sizeof *zp); 249173204Snjl 250173204Snjl if (cp->nzones == 0) 251173204Snjl TAILQ_INIT(&cp->zones); 252173204Snjl 253173204Snjl zp->descr = strdup(descr); 254173204Snjl zp->filename = strdup(file); 255173204Snjl zp->continent = cont; 256173204Snjl TAILQ_INSERT_TAIL(&cp->zones, zp, link); 257173204Snjl cp->nzones++; 258173204Snjl } else { 259173204Snjl if (cp->nzones > 0) 260173204Snjl errx(1, _PATH_ZONETAB 261173204Snjl ":%d: zone must have description", lineno); 262173204Snjl if (cp->nzones < 0) 263150847Sume errx(1, _PATH_ZONETAB 264150847Sume ":%d: zone multiply defined", lineno); 265150847Sume cp->nzones = -1; 266150847Sume cp->filename = strdup(file); 267150847Sume cp->continent = cont; 268150847Sume } 269150847Sume} 270150847Sume 271150847Sume/* 272150847Sume * This comparison function intentionally sorts all of the null-named 273150847Sume * ``countries''---i.e., the codes that don't correspond to a real 274141923Snjl * country---to the end. Everything else is lexical by country name. 275141923Snjl */ 276141923Snjlstatic int 277141923Snjlcompare_countries(const void *xa, const void *xb) 278150847Sume{ 279150847Sume const struct country *a = xa, *b = xb; 280144876Snjl 281142603Snjl if (a->name == 0 && b->name == 0) 282142603Snjl return 0; 283142603Snjl if (a->name == 0 && b->name != 0) 284150847Sume return 1; 285150847Sume if (b->name == 0) 286150847Sume return -1; 287150847Sume 288142603Snjl return strcmp(a->name, b->name); 289141923Snjl} 290142590Snjl 291148972Snjl/* 292144876Snjl * This must be done AFTER all zone descriptions are read, since it breaks 293144876Snjl * CODE2INT(). 294142603Snjl */ 295142603Snjlstatic void 296142603Snjlsort_countries(void) 297142590Snjl{ 298141240Snjl qsort(countries, NCOUNTRIES, sizeof countries[0], compare_countries); 299144876Snjl} 300144876Snjl 301144876Snjlstatic void 302149239Sumeread_zones(void) 303144876Snjl{ 304141240Snjl FILE *fp; 305141240Snjl char *line; 306141240Snjl size_t len; 307141240Snjl int lineno; 308141240Snjl char *tlc, *coord, *file, *descr, *p; 309141240Snjl char contbuf[16]; 310141240Snjl struct continent *cont; 311141240Snjl 312141943Snjl fp = fopen(_PATH_ZONETAB, "r"); 313171898Snjl if (!fp) 314141943Snjl err(1, _PATH_ZONETAB); 315171898Snjl lineno = 0; 316171898Snjl 317171898Snjl while ((line = fgetln(fp, &len)) != 0) { 318144876Snjl lineno++; 319144876Snjl if (line[len - 1] != '\n') 320141240Snjl errx(1, _PATH_ZONETAB ":%d: invalid format", lineno); 321171898Snjl line[len - 1] = '\0'; 322171898Snjl if (line[0] == '#') 323171898Snjl continue; 324141240Snjl 325141240Snjl tlc = strsep(&line, "\t"); 326141240Snjl if (strlen(tlc) != 2) 327141240Snjl errx(1, _PATH_ZONETAB ":%d: invalid country code `%s'", 328141240Snjl lineno, tlc); 329141413Snjl coord = strsep(&line, "\t"); 330141413Snjl file = strsep(&line, "\t"); 331141413Snjl p = strchr(file, '/'); 332141413Snjl if (p == 0) 333141413Snjl errx(1, _PATH_ZONETAB ":%d: invalid zone name `%s'", 334141413Snjl lineno, file); 335141413Snjl contbuf[0] = '\0'; 336141943Snjl strncat(contbuf, file, p - file); 337171898Snjl cont = find_continent(contbuf); 338141943Snjl if (!cont) 339171898Snjl errx(1, _PATH_ZONETAB ":%d: invalid region `%s'", 340171898Snjl lineno, contbuf); 341171898Snjl 342144876Snjl descr = (line && *line) ? line : 0; 343144876Snjl 344141413Snjl add_zone_to_country(lineno, tlc, descr, file, cont); 345171898Snjl } 346171898Snjl fclose(fp); 347171898Snjl} 348141413Snjl 349141413Snjlstatic void 350141413Snjlmake_menus(void) 351141413Snjl{ 352141413Snjl struct country *cp; 353141240Snjl struct zone *zp, *zp2; 354149239Sume struct continent *cont; 355141923Snjl dialogMenuItem *dmi; 356141923Snjl int i; 357150847Sume 358141923Snjl /* 359141923Snjl * First, count up all the countries in each continent/ocean. 360150847Sume * Be careful to count those countries which have multiple zones 361144876Snjl * only once for each. NB: some countries are in multiple 362144876Snjl * continents/oceans. 363150847Sume */ 364150847Sume for (cp = countries; cp->name; cp++) { 365150847Sume if (cp->nzones == 0) 366150847Sume continue; 367150847Sume if (cp->nzones < 0) { 368150847Sume cp->continent->nitems++; 369150847Sume } else { 370150847Sume for (zp = cp->zones.tqh_first; zp; 371141923Snjl zp = zp->link.tqe_next) { 372141240Snjl cont = zp->continent; 373141923Snjl for (zp2 = cp->zones.tqh_first; 374141240Snjl zp2->continent != cont; 375150847Sume zp2 = zp2->link.tqe_next) 376150847Sume ; 377150847Sume if (zp2 == zp) 378150847Sume zp->continent->nitems++; 379150847Sume } 380150847Sume } 381150847Sume } 382150847Sume 383141240Snjl /* 384142603Snjl * Now allocate memory for the country menus. We set 385167905Snjl * nitems back to zero so that we can use it for counting 386167905Snjl * again when we actually build the menus. 387167905Snjl */ 388167905Snjl for (i = 0; i < NCONTINENTS; i++) { 389167905Snjl continent_names[i].continent->menu = 390167905Snjl malloc(sizeof(dialogMenuItem) * 391142603Snjl continent_names[i].continent->nitems); 392141240Snjl if (continent_names[i].continent->menu == 0) 393167905Snjl err(1, "malloc for continent menu"); 394141240Snjl continent_names[i].continent->nitems = 0; 395141240Snjl } 396141240Snjl 397141240Snjl /* 398141240Snjl * Now that memory is allocated, create the menu items for 399141240Snjl * each continent. For multiple-zone countries, also create 400141240Snjl * the country's zone submenu. 401141240Snjl */ 402141240Snjl for (cp = countries; cp->name; cp++) { 403141240Snjl if (cp->nzones == 0) 404141240Snjl continue; 405171896Snjl if (cp->nzones < 0) { 406141240Snjl dmi = &cp->continent->menu[cp->continent->nitems]; 407141240Snjl memset(dmi, 0, sizeof *dmi); 408141240Snjl asprintf(&dmi->prompt, "%d", 409142603Snjl ++cp->continent->nitems); 410141240Snjl dmi->title = cp->name; 411141240Snjl dmi->checked = 0; 412141240Snjl dmi->fire = set_zone_whole_country; 413142603Snjl dmi->selected = 0; 414142603Snjl dmi->data = cp; 415144876Snjl } else { 416144876Snjl cp->submenu = malloc(cp->nzones * sizeof *dmi); 417141240Snjl if (cp->submenu == 0) 418144876Snjl err(1, "malloc for submenu"); 419142603Snjl cp->nzones = 0; 420141240Snjl for (zp = cp->zones.tqh_first; zp; 421141240Snjl zp = zp->link.tqe_next) { 422141240Snjl cont = zp->continent; 423141240Snjl dmi = &cp->submenu[cp->nzones]; 424141240Snjl memset(dmi, 0, sizeof *dmi); 425141240Snjl asprintf(&dmi->prompt, "%d", 426141240Snjl ++cp->nzones); 427141240Snjl dmi->title = zp->descr; 428141240Snjl dmi->checked = 0; 429141240Snjl dmi->fire = set_zone_multi; 430141240Snjl dmi->selected = 0; 431142395Snjl dmi->data = zp; 432142395Snjl 433142395Snjl for (zp2 = cp->zones.tqh_first; 434142603Snjl zp2->continent != cont; 435142603Snjl zp2 = zp2->link.tqe_next) 436142395Snjl ; 437141240Snjl if (zp2 != zp) 438142603Snjl continue; 439142603Snjl 440142603Snjl dmi = &cont->menu[cont->nitems]; 441142603Snjl memset(dmi, 0, sizeof *dmi); 442142603Snjl asprintf(&dmi->prompt, "%d", ++cont->nitems); 443142603Snjl dmi->title = cp->name; 444142603Snjl dmi->checked = 0; 445142603Snjl dmi->fire = set_zone_menu; 446142603Snjl dmi->selected = 0; 447142603Snjl dmi->data = cp; 448142603Snjl } 449142603Snjl } 450142603Snjl } 451142603Snjl} 452171896Snjl 453171896Snjlstatic int 454141240Snjlset_zone_menu(dialogMenuItem *dmi) 455171896Snjl{ 456141240Snjl int rv; 457141240Snjl char buf[256]; 458141240Snjl struct country *cp = dmi->data; 459141413Snjl int menulen; 460141240Snjl 461141240Snjl snprintf(buf, sizeof buf, "%s Time Zones", cp->name); 462141240Snjl menulen = cp->nzones < 16 ? cp->nzones : 16; 463141240Snjl rv = dialog_menu(buf, "Select a zone which observes the same time as " 464141240Snjl "your locality.", -1, -1, menulen, -cp->nzones, 465141240Snjl cp->submenu, 0, 0, 0); 466144876Snjl if (rv != 0) 467144876Snjl return DITEM_RECREATE; 468141240Snjl return DITEM_LEAVE_MENU; 469144876Snjl} 470141240Snjl 471141240Snjlstatic int 472141240Snjlinstall_zone_file(const char *filename) 473141240Snjl{ 474141240Snjl struct stat sb; 475141240Snjl int fd1, fd2; 476141240Snjl int copymode; 477141240Snjl char *msg; 478141240Snjl ssize_t len; 479141240Snjl char buf[1024]; 480141240Snjl 481141240Snjl if (lstat(_PATH_LOCALTIME, &sb) < 0) 482141240Snjl /* Nothing there yet... */ 483141240Snjl copymode = 1; 484141240Snjl else if(S_ISLNK(sb.st_mode)) 485144876Snjl copymode = 0; 486141240Snjl else 487141240Snjl copymode = 1; 488141240Snjl 489141240Snjl#ifdef VERBOSE 490141240Snjl if (copymode) 491142603Snjl asprintf(&msg, "Copying %s to " _PATH_LOCALTIME, filename); 492142603Snjl else 493142603Snjl asprintf(&msg, "Creating symbolic link " _PATH_LOCALTIME 494142603Snjl " to %s", filename); 495141240Snjl 496141240Snjl dialog_notify(msg); 497142603Snjl free(msg); 498141240Snjl#endif 499141240Snjl 500141240Snjl if (reallydoit) { 501141240Snjl if (copymode) { 502141240Snjl fd1 = open(filename, O_RDONLY, 0); 503141413Snjl if (fd1 < 0) { 504141240Snjl asprintf(&msg, "Could not open %s: %s", 505141240Snjl filename, strerror(errno)); 506141240Snjl dialog_mesgbox("Error", msg, 8, 72); 507141240Snjl free(msg); 508141240Snjl return DITEM_FAILURE | DITEM_RECREATE; 509141240Snjl } 510141413Snjl 511141240Snjl unlink(_PATH_LOCALTIME); 512141240Snjl fd2 = open(_PATH_LOCALTIME, 513141240Snjl O_CREAT | O_EXCL | O_WRONLY, 514141240Snjl 0444); 515141240Snjl if (fd2 < 0) { 516141240Snjl asprintf(&msg, "Could not open " 517141240Snjl _PATH_LOCALTIME ": %s", 518141240Snjl strerror(errno)); 519141240Snjl dialog_mesgbox("Error", msg, 8, 72); 520141240Snjl free(msg); 521141240Snjl return DITEM_FAILURE | DITEM_RECREATE; 522141240Snjl } 523141240Snjl 524141240Snjl while ((len = read(fd1, buf, sizeof buf)) > 0) 525141240Snjl len = write(fd2, buf, len); 526141240Snjl 527141240Snjl if (len == -1) { 528142603Snjl asprintf(&msg, "Error copying %s to " 529141240Snjl _PATH_LOCALTIME ": %s", 530141824Snjl strerror(errno)); 531141240Snjl dialog_mesgbox("Error", msg, 8, 72); 532141240Snjl free(msg); 533141824Snjl /* Better to leave none than a corrupt one. */ 534141824Snjl unlink(_PATH_LOCALTIME); 535141824Snjl return DITEM_FAILURE | DITEM_RECREATE; 536141824Snjl } 537141824Snjl close(fd1); 538142032Snjl close(fd2); 539144876Snjl } else { 540144876Snjl if (access(filename, R_OK) != 0) { 541144876Snjl asprintf(&msg, "Cannot access %s: %s", 542144876Snjl filename, strerror(errno)); 543144876Snjl dialog_mesgbox("Error", msg, 8, 72); 544142032Snjl free(msg); 545144876Snjl return DITEM_FAILURE | DITEM_RECREATE; 546141240Snjl } 547142032Snjl unlink(_PATH_LOCALTIME); 548142032Snjl if (symlink(filename, _PATH_LOCALTIME) < 0) { 549141240Snjl asprintf(&msg, "Cannot create symbolic link " 550141413Snjl _PATH_LOCALTIME " to %s: %s", 551141824Snjl filename, strerror(errno)); 552141814Snjl dialog_mesgbox("Error", msg, 8, 72); 553141413Snjl free(msg); 554141413Snjl return DITEM_FAILURE | DITEM_RECREATE; 555141413Snjl } 556141413Snjl } 557144876Snjl } 558141413Snjl 559141413Snjl#ifdef VERBOSE 560141413Snjl if (copymode) 561141413Snjl asprintf(&msg, "Copied timezone file from %s to " 562141413Snjl _PATH_LOCALTIME, filename); 563141413Snjl else 564141413Snjl asprintf(&msg, "Created symbolic link from " _PATH_LOCALTIME 565141413Snjl " to %s", filename); 566141413Snjl 567141413Snjl dialog_mesgbox("Done", msg, 8, 72); 568141413Snjl free(msg); 569141413Snjl#endif 570141240Snjl return DITEM_LEAVE_MENU; 571141240Snjl} 572141240Snjl 573141240Snjlstatic int 574141945Snjlconfirm_zone(const char *filename) 575141945Snjl{ 576141945Snjl char *msg; 577141945Snjl struct tm *tm; 578141945Snjl time_t t = time(0); 579141945Snjl int rv; 580141945Snjl 581141240Snjl setenv("TZ", filename, 1); 582141945Snjl tzset(); 583141945Snjl tm = localtime(&t); 584141945Snjl 585141945Snjl asprintf(&msg, "Does the abbreviation `%s' look reasonable?", 586141240Snjl tm->tm_zone); 587141945Snjl rv = !dialog_yesno("Confirmation", msg, 4, 72); 588141945Snjl free(msg); 589141945Snjl return rv; 590141413Snjl} 591141240Snjl 592141240Snjlstatic int 593141240Snjlset_zone_multi(dialogMenuItem *dmi) 594141240Snjl{ 595141413Snjl char *fn; 596141413Snjl struct zone *zp = dmi->data; 597141413Snjl int rv; 598141413Snjl 599141413Snjl if (!confirm_zone(zp->filename)) 600141413Snjl return DITEM_FAILURE | DITEM_RECREATE; 601141413Snjl 602141413Snjl asprintf(&fn, "%s/%s", _PATH_ZONEINFO, zp->filename); 603141413Snjl rv = install_zone_file(fn); 604141413Snjl free(fn); 605141413Snjl return rv; 606141413Snjl} 607141240Snjl 608141240Snjlstatic int 609142590Snjlset_zone_whole_country(dialogMenuItem *dmi) 610148972Snjl{ 611142590Snjl char *fn; 612142590Snjl struct country *cp = dmi->data; 613142590Snjl int rv; 614142590Snjl 615141240Snjl if (!confirm_zone(cp->filename)) 616141240Snjl return DITEM_FAILURE | DITEM_RECREATE; 617141240Snjl 618141413Snjl asprintf(&fn, "%s/%s", _PATH_ZONEINFO, cp->filename); 619141240Snjl rv = install_zone_file(fn); 620141240Snjl free(fn); 621141240Snjl return rv; 622141240Snjl} 623141240Snjl 624141240Snjlstatic void 625141240Snjlusage() 626141240Snjl{ 627142603Snjl fprintf(stderr, "usage: tzsetup [-n]\n"); 628142603Snjl exit(1); 629142603Snjl} 630141413Snjl 631141413Snjlint 632141413Snjlmain(int argc, char **argv) 633141413Snjl{ 634141240Snjl int c; 635141240Snjl 636141240Snjl while ((c = getopt(argc, argv, "n")) != -1) { 637141240Snjl switch(c) { 638141240Snjl case 'n': 639141240Snjl reallydoit = 0; 640141240Snjl break; 641141240Snjl 642141240Snjl default: 643141240Snjl usage(); 644141413Snjl } 645141240Snjl } 646141240Snjl 647141413Snjl if (optind != argc) 648141240Snjl usage(); 649141240Snjl 650141240Snjl read_iso3166_table(); 651142603Snjl read_zones(); 652142603Snjl sort_countries(); 653141413Snjl make_menus(); 654141240Snjl 655141240Snjl init_dialog(); 656141240Snjl if (!dialog_yesno("Select local or UTC (Greenwich Mean Time) clock", 657141240Snjl "Is this machine's CMOS clock set to UTC? If it is set to local time,\n" 658141240Snjl "please choose NO here!", 7, 72)) 659141413Snjl if (reallydoit) 660141413Snjl system("rm -f /etc/wall_cmos_clock"); 661141413Snjl else 662141240Snjl if (reallydoit) 663141240Snjl system("touch /etc/wall_cmos_clock"); 664144876Snjl dialog_clear_norefresh(); 665144876Snjl dialog_menu("Time Zone Selector", "Select a region", -1, -1, 666141240Snjl NCONTINENTS, -NCONTINENTS, continents, 0, NULL, NULL); 667141240Snjl dialog_clear(); 668141240Snjl end_dialog(); 669141240Snjl return 0; 670141240Snjl} 671141413Snjl 672144876Snjl